Linux C中内联汇编的语法格式及使用方法(Inline(2)

2. 常用约束(commonly used constraints)

前面介绍output operands和input operands字段过程中,我们已经知道这些operands通常需要指明各自的constraints,以便更明确地完成我们期望的功能(试想,如果不明确指定约束而由gcc自行决定的话,一旦代码执行结果不符合预期,调试将变得很困难)。

下面开始介绍一些常用的约束项。

1)寄存器操作数约束(register operand constraint, r)

当操作数被指定为这类约束时,表明汇编指令执行时,操作数被将存储在指定的通用寄存器(General Purpose Registers, GPR)中。例如:

asm ("movl %%eax, %0\n" : "=r"(out_val));

该指令的作用是将%eax的值返回给%0所引用的C语言变量out_val,根据"=r"约束可知具体的操作流程为:先将%eax值复制给任一GPR,最终由该寄存器将值写入%0所代表的变量中。"r"约束指明gcc可以先将%eax值存入任一可用的寄存器,然后由该寄存器负责更新内存变量。

通常还可以明确指定作为“中转”的寄存器,约束参数与寄存器的对应关系为:

a : %eax, %ax, %al

b : %ebx, %bx, %bl

c : %ecx, %cx, %cl

d : %edx, %dx, %dl

S : %esi, %si

D : %edi, %di

例如,如果想指定用%ebx作为中转寄存器,则命令为:asm ("movl %%eax, %0\n" : "=b"(out_val));

2)内存操作数约束(Memory operand constraint, m)

当我们不想通过寄存器中转,而是直接操作内存时,可以用"m"来约束。例如:

asm volatile ( "lock; decl %0" : "=m" (counter) : "m" (counter));

该指令实现原子减一操作,输入、输出操作数均直接来自内存(也正因如此,才能保证操作的原子性)。

3)关联约束(matching constraint)

在有些情况下,如果命令的输入、输出均为同一个变量,则可以在内联汇编中指定以matching constraint方式分配寄存器,此时,input operand和output operand共用同一个“中转”寄存器。例如:

asm ("incl %0" :"=a"(var):"0"(var));

该指令对变量var执行incl操作,由于输入、输出均为同一变量,因此可用"0"来指定都用%eax作为中转寄存器。注意"0"约束修饰的是input operands。

4)其它约束

除上面介绍的3中常用约束外,还有一些其它的约束参数(如"o"、"V"、"i"、"g"等),感兴趣的同学可以参考这里

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/94b98bc20b949ae369c4d862a03e2a9c.html