「这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战」。
C语言内嵌汇编代码(GCC内联汇编)
格式
asm volatile( ;asm也可写成 __asm__ 或者__asm
"汇编指令"
:"=限制符"(输出参数) ,"=限制符"(输出参数)
:"限制符"(输入参数)
:保留列表
)
;volatile是可选关键字,表示禁止编译器对汇编代码进行优化
;汇编指令之间使用\n进行分隔
;限制符用于和c语言交互,属于可选,多个参数使用逗号进行分隔
代码示例:
//将input的值赋值给result
int main()
{
int result = 0;
int input = 1;
asm volatile (
"movl %1, %0\n" // 通过占位符指定交互的变量 %1赋值给%0
: "=r"(result) // 输出变量,与汇编交互
: "r"(input) // 输入变量,与汇编交互
// 这里的r指示编译器自动将通用寄存器关联到变量
);
printf("result = %d\n", result);
printf("input = %d\n", input);
}
我们看到,movl指令的操作数(operand)中,出现了%1、%0,这往往让新手摸不着头脑。其实只要知道下面的规则就不会产生疑惑了:
在内联汇编中,操作数通常用数字来引用,具体的编号规则为:若命令共涉及n个操作数,则第1个输出操作数(the first output operand)被编号为0,第2个output operand编号为1,依次类推,最后1个输入操作数(the last input operand)则被编号为n-1。
具体到上面的示例代码中,根据上下文,涉及到2个操作数变量a、b,这段汇编代码的作用是将a的值赋给b,可见,a是input operand,而b是output operand,那么根据操作数的引用规则,不难推出,a应该用%1来引用,b应该用%0来引用。
常用限制符参照:
| 限制符 | 说明 |
|---|---|
| r | 通用寄存器 |
| a | eax,ax,al |
| b | ebx,bx,bl |
| c | ecx,cx,cl |
| d | edx,dx,dl |
| S | esi,si |
| D | edi,di |
| q | 寄存器a,b,c,d |
| m | 使用合法的内存代表参数 |
| g | 任意寄存器,内存,立即数 |
为什么有些汇编语法不一致
C语言外链汇编
新建一个汇编原文件, linux平台.s结尾 ,windows平台.asm结尾
;外链汇编
;以下使用的是AT&T的汇编语法
.text ;声明为代码段
.global _sum ;定义为全局函数, 否则无法被外界访问
_sum: ;函数名称必须_开头
movq %rdi,%rax ;方法参数存放在di和di寄存器中
addq %rsi,%rax
retq
然后在C中进行相应调用即可