汇编语言---80386寄存器,GCC内联汇编语法
一:80386寄存器
8个32-bit寄存器:%eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp;
8个16-bit寄存器:%ax,%bx,%cx,%dx,%di,%si,%bp,%sp;
8个8-bit寄存器:%ah,%al,%bh,%bl,%ch,%cl,%dh,%dl;它们事实是寄存器%ax,%bx,%cx,%dx的高8bit和低8bit
6个段寄存器:%cs(code),%ds(data),%ss(stack),%es(extend),%fs, %gs;
3个控制寄存器:%cr0,%cr2,%cr3;
6个debug寄存器:%db0,%db1,%db2,%db3,%db6,%db7;
2个测试寄存器:%tr6, %tr7
8个浮点寄存器栈:%st(0),%st(1),%st(2),%st(3),%st(4),%st(5),%st(6),%st(7);
eax 累加和结果寄存器
ebx 数据基址寄存器
ecx 循环计数器寄存器
edx i/o指针寄存器
esi 源变址寄存器
edi 目的变址寄存器
esp 栈顶指针寄存器
ebp 栈底指针寄存器cs 代码段寄存器
ds 数据段寄存器
ss 堆栈段寄存器
es,fs及gs 附加数据段寄存器IP:指令指针寄存器,将CS:IP获取到的指令存储EIP(指令寄存器)中
二:内联汇编基本格式为:
asm ( 汇编程序模板
: 输出操作数
: 输入操作数
: 修饰寄存器列表
);由于占位符前面使用一个百分号(%),为了区别占位符和寄存器,GCC规定C/C++表达式的内联汇编中, "Instruction List"中直接写出的寄存器前必须使用两个百分号(%%)
占位符:GCC规定一个内联汇编语句最多可以有10个Input/Output操作表达式,按照它们被列出的顺序依次赋予编号0到9,对于占位符中的数字而言,和这些编号是一一对应的。
三:约束修饰符:
当使用约束时,对于更精确的控制超过了对约束作用的需求,GCC 给我们提供了约束修饰符。最常用的约束修饰符为:
- "=" : 意味着对于这条指令,操作数为只写的;旧值会被忽略并被输出数据所替换。
- "&" : 意味着这个操作数为一个早期改动的操作数,其在该指令完成前通过使用输入操作数被修改了。因此,这个操作数不可以位于一个被用作输出操作数或任何内存地址部分的寄存器。如果在旧值被写入之前它仅用作输入而已,一个输入操作数可以为一个早期改动操作数
- "%":只能用于Input操作表达式中,用于向GCC声明:当前Input操作表达式中的C/C++表达式可以和下一个Input操作数表达式中的C/C++表达式互换,这个修饰符号一般用于符合交换律运算,比如加(+),乘(*),与(&),或(|)等等。
- 例:asm("addl %1, %0\n\t" :"=r"(__out): "%r"(__in1), "0"(__in1));
3.1. 寄存器操作数约束
r : Register(s)
a: %eax, %ax, %al
b: %ebx, %bx, %bl
c: %ecx, %cx, %cl
d: %edx, %dx, %dl
S: %esi, %si
D: %edi, %di
3.2. 内存操作数约束
当操作数位于内存时,任何对它们的操作将直接发生在内存位置,这与寄存器约束相反,后者首先将值存储在要修改的寄存器中,然后将它写回到内存位置。但寄存器约束通常用于一个指令必须使用它们或者它们可以大大提高处理速度的地方。当需要在 “asm” 内更新一个 C 变量,而又不想使用寄存器去保存它的值,使用内存最为有效。
asm("sidt %0\n\t" : :"m"(loc));
3.3. 匹配(数字)约束
在某些情况下,一个变量可能既充当输入操作数,也充当输出操作数。可以通过使用匹配约束在 "asm" 中指定这种情况。
asm("incl %0\n\t" :"=a"(var):"0"(var));
例:
void *memcpy_asm(void *dst, const void *src, size_t n)
{
int d0=0, d1=0, d2=0;
asm volatile(
"shr $2, %0 \n\t"
"rep ; movsl \n\t"
"movl %4,%%ecx \n\t"
"andl $3,%%ecx \n\t"
"jz 1f \n\t"
"rep ; movsb \n\t"
"1:"
/*分别表示第零个操作数(%0)–到第二个(%2)操作数*/
: "=&c"(d0),"=&D"(d1),"=&S"(d2)
/*分别表示第三个操作数(%3)到第六个操作数(%6);其中%3个=第%0个;%5==%1;%6==%2*/
: "0"(n),"g"(n),"1"((long)dst),"2"((long)src)
:"memory");
return dst;
}
寄存器约束:
通用寄存器:
"a":表示使用%eax/%ax/%al
"b":表示使用%ebx/%bx/%bl
"c":表示使用%ecx/%cx/%cl
"d":表示使用%edx/%dx/%dl
"D":表示使用%edi/%di
"S":表示使用%esi/%si
"r":表示使用一个通用寄存器,有GCC在%eax/%ax/%al,%ebx/%bx/%bl,%ecx/%cx/%cl,%edx/%dx/%dl中选择一个GCC认为合适的。
"q":表示通用寄存器,和约束"r"的意义相同。
"A":把eax和edx合成一个64位的寄存器(use long longs)内存:
"m" : 允许一个内存操作数,可以使用机器普遍支持的任一种地址,不需要借助寄存器。
"o" : 允许一个内存操作数,但只有当地址是可偏移的。即,该地址加上一个小的偏移量可以得到一个有效地址。
"V" : 一个不允许偏移的内存操作数。换言之,任何适合 "m" 约束而不适合 "o" 约束的操作数。
" ":操作数位内存变量,但是寻址方式为自动增量
"p":操作数是一个合法的内存地址(指针)寄存器或内存:
"g" : 允许任一寄存器、内存或者立即整形操作数,不包括通用寄存器之外的寄存器。
"X":操作数可以是任何类型立即数:
"i":表示输入表达式是一个立即数(整数),不需要借助寄存器。
"n" : 允许一个带有已知数字的立即整形操作数。许多系统不支持汇编时期的常量,因为操作数少于一个字宽。对于此种操作数,约束应该使用 'n' 而不是'i'。
"I":0~31之间的立即数(用于32位移位指令)
"J":0~63之间的立即数(用于64位移位指令)
"N":0~255之间的立即数(用于out指令)
"K":0xff
"L":0xFFFF
"M":0,1,2或3(lea指令的移位)浮点数约束:
"f":表示使用浮点数寄存器
"t":表示使用第一个浮点数寄存器
"u":表示使用第二个浮点数寄存器
"F":表示输入表达式是一个立即数(浮点数),不需要借助寄存器。
"G":标准的80387浮点数匹配占位符约束:
"0","1",..."9":表示用它限制的操作数与某个指定的操作数匹配,也即该操作数
就是指定的那个操作数,例如用"0"去描述"%1"操作数,那么"%1"引用的其实就是"%0"操作数,注意作为限定符字母的 0~9 与指令中的"%0"-"%9"的区别,前者描述操作数,后者代表操作数。
四:存储器操作数
在Intel语法中,基址寄存器包含在"["和"]"中,然而在AT&T中,它们变为"("和")"。另外,在 Intel 语法中, 间接内存引用为:
"section:[base + index*scale + disp]"
在 AT&T中变为:
"section:disp(base, index, scale)"。
需要牢记的一点是,当一个常量用于disp或scale,不能添加 "$" 前缀。
其中:base和index是任意的32-bit base和index寄存器。scale可以取值1,2,4,8。如果不指定scale,则默认值为1。section可以指定任意的段寄存器作为段前缀。
例:
(1)-4(%ebp):base=%ebp,disp=-4,section没有指定,由于base=%ebp,所以默认的section=%ss,index,scale没有指定,则index为0。
(2)foo(,%eax,4):index=%eax,scale=4,disp=foo。其他域没有指定。这里默认section=%ds。
(3)foo(,1):这个表达式引用的是指针foo指向的地址所存放的值。注意这个表达式中没有base和index,并且只有一个逗号,这是一种异常语法,但却合法。
现在我们看到了Intel语法和AT&T 语法之间的一些主要差别。我仅仅写了它们差别的一部分而已。关于更完整的信息,请参考 GNU 汇编文档。现在为了更好地理解,我们可以看一些示例。
五:pushq和popq指令
汇编语言---80386寄存器,GCC内联汇编语法相关推荐
- gcc 内联汇编用法介绍
前言 大部分内容翻译提取自某国外HOW-TO文档,原地址: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html AT& ...
- 汇编语言---GCC内联汇编
GCC支持在C/C++代码中嵌入汇编代码,这些代码被称作是"GCC Inline ASM"(GCC内联汇编); 一.基本内联汇编(寄存器前一个%) GCC中基本的内联汇编非常易懂, ...
- 最牛X的GCC 内联汇编
导读 正如大家知道的,在C语言中插入汇编语言,其是Linux中使用的基本汇编程序语法.本文将讲解 GCC 提供的内联汇编特性的用途和用法.对于阅读这篇文章,这里只有两个前提要求,很明显,就是 x86 ...
- GCC Inline ASM GCC内联汇编
GCC 支持在C/C++代码中嵌入汇编代码,这些汇编代码被称作GCC Inline ASM--GCC内联汇编.这是一个非常有用的功能,有利于我们将一些C/C++语法无法表达的指令直接潜入C/C++代码 ...
- (转)GCC内联汇编入门
转自:http://blog.csdn.net/wuyao721/article/details/3573598 原文为GCC-Inline-Assembly-HOWTO,在google上可以找到原文 ...
- linux gcc 内联汇编入门
目录 2. 概览(Overview of the whole thing.) 3.GCC汇编语法(GCC Assembler Syntax.) 3.1. 源-目标顺序(Source-Destinati ...
- 【转贴】GCC内联汇编基础
原文作者 Sandeep.S 英文原文 [https://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html] 本文将介绍GCC编译环境下 ...
- linux arm gcc 内联汇编参考手册
关于本文档 GNU C 编译器为 ARM 精简指令系统处理器提供了在 C 代码中内嵌汇编的功能.这种非常酷的特性提供了一些 C 代码没有的功能,比如手工优化软件关键代码.使用相关的处理器指令. 本文假 ...
- 【reverse】通俗易懂的gcc内联汇编入门+示例:实现花指令
文章目录 引言 依赖 Hello world Demo1:读取函数若干个字节的数据 效果 Demo2:基础的花指令 效果 如何去除花指令 参考资料 引言 基于Visual Studio的内联汇编教程已 ...
- C语言 intel架构处理器下利用gcc内联汇编 fcos 指令 实现三角函数计算小程序
Intel提供了丰富的浮点运算指令,fcos就是其中之一.下面就来实际试试看吧. #include <stdio.h>int main(int argc, char** argv) {if ...
最新文章
- 预处理器预处理变量头文件保护条件编译
- Python 赋值、浅拷贝、深拷贝的区别?
- Beanstalkd工作队列
- centos 下载文件很慢_【已解决】Mac中从远程CentOS服务器中加速下载大文件
- 【MySQL性能优化】MySQL分库分表与水平分割取模案例(三)
- 戴尔电脑怎么安装一级计算机,手把手教你戴尔笔记本电脑重装系统教程
- 2009.12.9.工作日记
- js输出100以内的质数
- 【机器人学习】 码垛机器人轨迹规划
- linux查看磁盘naa,linux查看计算机硬件信息
- x / k向上取整转换为向下取整
- 剪不断,理还乱——UML的四种关系
- 计算机网络CiscoPacket Tracer实验
- 【大数据】五、链接分析(PageRank、Topic-sensetive PageRank)
- Android应用开发中,第三方集成新浪微博(sinaWeiboSDK)的过程记录
- 存储笔记5 直连式存储与SCSI
- 鼠标点计算机里面文件有声音怎么办,如何消除鼠标点击的声音
- 2021智慧物流领域最具商业合作价值企业盘点
- [ERP/鼎捷E10][生产制造]生产齐套分析
- 带有 HTML5 <dialog> Tag的原生弹出窗口对话框