在C/C++程序内使用汇编语言
举例
/* globaltest.c - An example of using C variables */
#include <stdio.h>
int a = 10;
int b = 20;
int result;
int main()
{
asm ( "pusha\n\t"
"movl a, %eax\n\t"
"movl b, %ebx\n\t"
"imull %ebx, %eax\n\t"
"movl %eax, result\n\t"
"popa");
printf("the answer is %d\n", result);
return 0;
}
注意pusha和popa
可以在内联汇编里使用全局变量
使用volatile修饰符表示不希望编译器优化这个代码段 __volatile__
扩展asm
基本的asm输入输出必须使用全局变量,并且在内联代码中不去改变任何寄存器的值
格式
__asm__ (“assembly code”
:output locations
:input oprands
:changed registers
);
汇编代码:使用和基本asm格式相同的语法的内联汇编代码
输出位置:包含内联汇编代码的输出值的寄存器和内存位置的列表
输入操作数:包含内联汇编代码的输入值的寄存器和内存位置的列表
改动的寄存器:内联代码改变的任何其他寄存器的列表
指定输入和输出值
格式: “constraint” (variable)
variable是C程序中的局部/全局变量
constraint定义把输入值存放到哪里,从哪里传送变量
输出值还有一个约束符
e.g.
__
asm__
(“assembly code”
:”=a”(res)
: “d”(data1),”c”(data2)
);
使用寄存器 用%%
__
asm__
(
“imul %%edx, %%ecx \n\t”
“movl %%ecx, %%eax\n\t”
:”=a”(res)
:”d”(data),”c”(data2)
);
引用占位符
汇编代码中使用占位符 %0, %1, %2 ,分别表示输入输出列表中存储相应变量的寄存器
__
asm__
(“imul %1 , %0”
:”=r”(data2)
:”r”(data1), “0”(data2)
);
0标记通知编译器使用第一个命名的寄存器存放输出值data2 。
第二行代码定义第一个命名寄存器,他为输入变量data2分配一个寄存器。
这样确保将使用相同的寄存器保存输入输出值。
当然,内联代码完成时,结果将被存放到值data2中
匹配(数字)约束
在某些情况下,一个变量既要充当输入操作数,也要充当输出操作数。
可以通过使用匹配约束在 “asm” 中指定这种情况。
asm ("incl %0" :"=a"(var):"0"(var));
在匹配约束的示例中,寄存器 %eax 既用作输入变量,也用作输出变量。将 var 输入读取到 %eax,增加后将更新的 %eax 再次存储在 var 中。
这里的 “0” 指定第 0 个输出变量相同的约束。
即,它指定 var 的输出实例只应该存储在 %eax 中。
该约束可以用于以下情况:
• 输入从变量中读取,或者变量被修改后,修改写回到同一变量中
• 不需要将输入操作数和输出操作数的实例分开
使用匹配约束最重要的意义在于它们可以导致有效地使用可用寄存器。
替换的占位符
改动的寄存器列表
编译器假设输入输出使用的寄存器会被改动,程序员不需要再列表中说明,如果写了会出错
使用浮点数
FPU获得输出时,不能使用f约束,必须使用t或u来指定输出值所在的FPU寄存器
处理跳转
JGE JMP指令在asm段内跳转,可以使用标签,但是不同的段标签不能相同;
或者使用局部标签 数字加方向 0: 1: f表示向前查找,b表示向后查找
内联汇编作为 内联汇编宏函数使用较多
参考
https://www.ibm.com/developerworks/cn/linux/sdk/assemble/inline/