C语言ASM汇编内嵌语法详解

2020-01-18 19:38:27于丽

首先,你会注意到,在这两个例子中,变量sh没有借助任何寄存器,而是直接参与了指令lidt的操作。

其次,通过仔细观察,你会发现一个惊人的事实,两个例子编译出来的汇编代码是一样的!虽然,一个例子中变量sh作为输入,而另一个例子中变量sh作为输出。这是怎么回事?

原来,使用内存方式进行输入输出时,由于不借助寄存器,所以GCC不会按照你的声明对其作任何的输入输出处理。GCC只会直接拿来用,究竟对这个C/C++表达式而言是输入还是输出,完全依赖与你写在"Instruction List"中的指令对其操作的指令。

由 于上例中,对其操作的指令为lidt,lidt指令的操作数是一个输入型的操作数,所以事实上对变量sh的操作是一个输入操作,即使你把它放在 Output域也不会改变这一点。所以,对此例而言,完全符合语意的写法应该是将sh放在Input域,尽管放在Output域也会有正确的执行结果。

所 以,对于内存约束类型的操作表达式而言,放在Input域还是放在Output域,对编译结果是没有任何影响的,因为本来我们将一个操作表达式放在 Input域或放在Output域是希望GCC能为我们自动通过寄存器将表达式的值输入或输出。既然对于内存约束类型的操作表达式来说,GCC不会自动为 它做任何事情,那么放在哪儿也就无所谓了。但从程序员的角度而言,为了增强代码的可读性,最好能够把它放在符合实际情况的地方。

约束 Input/Output 意义 m I,O 表示使用系统所支持的任何一种内存方式,不需要借助寄存器

3、立即数约束

如果一个Input/Output操作表达式的C/C++表达式是一个数字常数,不想借助于任何寄存器,则可以使用立即数约束。

由于立即数在C/C++中只能作为右值,所以对于使用立即数约束的表达式而言,只能放在Input域。

比如:__asm__ __volatile__("movl %0, %%eax" : : "i" (100) );

立即数约束很简单,也很容易理解,我们在这里就不再赘述。

约束 Input/Output 意义 i I 表示输入表达式是一个立即数(整数),不需要借助任何寄存器 F I 表示输入表达式是一个立即数(浮点数),不需要借助任何寄存器

4、通用约束

约束 Input/Output 意义 g I,O 表示可以使用通用寄存器,内存,立即数等任何一种处理方式。 0,1,2,3,4,5,6,7,8,9 I 表示和第n个操作表达式使用相同的寄存器/内存。

通 用约束g是一个非常灵活的约束,当程序员认为一个C/C++表达式在实际的操作中,究竟使用寄存器方式,还是使用内存方式或立即数方式并无所谓时,或者程 序员想实现一个灵活的模板,让GCC可以根据不同的C/C++表达式生成不同的访问方式时,就可以使用通用约束g。比如:


#define JUST_MOV(foo) __asm__ ("movl %0, %%eax" : : "g"(foo))
JUST_MOV(100)和JUST_MOV(var)则会让编译器产生不同的代码。
int main(int __argc, char* __argv[]) 
{ 
JUST_MOV(100); 
return 0; 
}