gccAT&T格式汇编,内联汇编
Linux下默认是AT&T格式的汇编
汇编语言直接同计算机硬件交互,下面是汇编语言的优点:
能够直接访问硬件相关的存储器或或IO端口
能够不受编译器的限制,对生成的二进制代码进行完全的控制
能够对关键代码进行更准确的控制,避免因线程共同访问或者硬件设备共享引起的死锁
能够根据特定的应用对代码做最佳的优化,提高运行速度
能够最大限度地发挥硬件的功能
寄存器名要加上%作为前缀,
$前缀表示一个立即操作数
AT&T和Intel格式中的源操作数和目标操作数的位置正好相反
在Intel汇编格式中,目标操作数在源操作数的左边,而AT&T中目标操作数在源操作数的右边
操作数的字长由操作符的最后一个字母决定,后缀b、w、l、q分别表示操作数为8位,16位,32位和64位,而在Intel汇编格式中,操作数的字长是用 byte ptr、word ptr等前缀来表示
对于内存单元操作数来说,在AT&T中把寄存器用()扩起来,在Intel中用[]
movl %eax, %edx # 寄存器寻址
movl $0x123,%edx # 立即数寻址
movl 0x123, %edx # 直接寻址 将0x123所指向的内存数据放到edx寄存器
movl (%ebx), %edx # 间接寻址 将ebx所存的内存地址的数据放到edx寄存器
mvol 4(%ebx), %edx # 变址寻址 将ebx所存的地址加4后得到的内存地址的值放到edx寄存器
gcc内联汇编
用汇编编写的程序虽然运行速度很快,但开发速度非常慢,效率也很低。如果只是相对关键代码进行优化,或者更好的办法是将汇编指令嵌入到c语言程序中,从而充分利用高级语言和汇编语言各自的特点,
__asm__("asm statements":output:input:registers-modified);
分类 | 限定符 | 描述 |
---|---|---|
通用寄存器 | a | 将输入变量放入eax |
b | 将输入变量放入ebx | |
c | 将输入变量放入ecx | |
d | 将输入变量放入edx | |
s | 将输入变量放入esi | |
D | 将输入变量放入edi | |
q | 将输入变量放入eax、ebx、ecx、edx中一个 | |
r | 将输入变量放入通用寄存器,也就是eax,ebx,ecx,edx,esi,edi中的一个 | |
A | 放入eax和edx,把eax和edx,合成一个64位的寄存器 | |
m | 内存变量 | |
o | 操作数是内存变量,但是其寻址方式是偏移量类型 | |
V | 操作数为内存变量,但寻址方式不是偏移量类型 | |
. | 操作数为内存变量,但寻址方式为自动增量 | |
p | 操作数是一个合法的内存地址(指针) | |
g | 将输入变量放入eax,ebx,ecx,edx中的一个或者作为内存变量 | |
X | 操作数可以是任何类型 | |
I | 0-31之间的立即数,用于32位移位指令 | |
J | 0-63之间的立即数,用于64位移位指令 | |
N | 0-255之间的立即数,用于out指令 | |
i | 立即数 | |
n | 立即数,有些系统不支持除字以外的立即数,这些系统应该使用n | |
= | 操作数在指令中是只写的(输出操作数) | |
+ | 操作数在指令中是读写类型的(输入输出操作数) | |
f | 浮点数 | |
t | 第一个浮点寄存器 | |
u | 第二个浮点寄存器 | |
G | 标准的80387 | |
% | 该操作数可以和下一个操作数交换位置 | |
# | 部分注释,从该字符到其后的逗号之间所有字母被忽略 | |
* | 表示如果选用寄存器,则其后的字母被忽略 |
#include <stdio.h>
int main()
{
unsigned int val1 = 1;
unsigned int val2 = 2;
unsigned int val3 = 0;
asm volatile(
"movl $0, %%eax\n\t"
"addl %1, %%eax\n\t"
"addl %2, %%eax\n\t"
"movl %%eax, %0\n\t"
:"=m"(val3)
:"c"(val1), "d"(val2));
printf("%d\n", val3);
}
更多参考:https://blog.csdn.net/qq_29343201/article/details/52199533
AT&T格式汇编
寄存器前面加%
常数签名加$
基址寄存器放在圆括号内,索引放在圆括号外
有效地址就是索引值加上基址寄存器的值
-8(%ebp)
加入ebp为20
则有效地址为 (-8)+20=12
内联汇编
不需要调用单独编译好的汇编程序
__asm__ ();
__asm__ (汇编语句:输出操作数:输入操作数:已修改过的寄存器);
常用修饰符 __volatile__
告诉编译器不要优化这个内联汇编例程
__asm__ __volatile__ ();
已修改过的寄存器说明主要是为了告诉编译器执行完这个例程后不要使用这些寄存器
\n\t
用在汇编程序中,每天汇编指令各占一行
还没有评论,来说两句吧...