以下示例通过各种不同的操作数约束说明了用法。有如此多的约束以至于无法将它们一一列出,这里只列出了最经常使用的那些约束类型。
"asm" 和寄存器约束 "r"让我们先看一下使用寄存器约束 r 的 "asm"。我们的示例显示了 GCC如何分配寄存器,以及它如何更新输出变量的值。
[Plain Text] 纯文本查看 复制代码 int main(void)
{
int x = 10, y;
asm ("movl %1, %%eax;
"movl %%eax, %0;"
:"=r"(y) /* y is output operand */
:"r"(x) /* x is input operand */
:"%eax"); /* %eax is clobbered register */
}
在该例中,x 的值复制为 "asm" 中的 y。x 和 y都通过存储在寄存器中传递给 "asm"。为该例生成的汇编代码如下:
[Plain Text] 纯文本查看 复制代码 main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
movl $10,-4(%ebp)
movl -4(%ebp),%edx /* x=10 is stored in %edx */
#APP /* asm starts here */
movl %edx, %eax /* x is moved to %eax */
movl %eax, %edx /* y is allocated in edx and updated */
#NO_APP /* asm ends here */
movl %edx,-8(%ebp) /* value of y in stack is updated with the value in %edx */
当使用 "r" 约束时,GCC在这里可以自由分配任何寄存器。在我们的示例中,它选择 %edx 来存储x。在读取了 %edx 中 x 的值后,它为 y 也分配了相同的寄存器。
因为 y 是在输出操作数部分中指定的,所以 %edx 中更新的值存储在-8(%ebp),堆栈上 y 的位置中。如果 y是在输入部分中指定的,那么即使它在 y 的临时寄存器存储值 (%edx)中被更新,堆栈上 y 的值也不会更新。
因为 %eax 是在修饰列表中指定的,GCC不在任何其它地方使用它来存储数据。
输入 x 和输出 y 都分配在同一个 %edx寄存器中,假设输入在输出产生之前被消耗。请注意,如果您有许多指令,就不是这种情况了。要确保输入和输出分配到不同的寄存器中,可以指定& 约束修饰符。下面是添加了约束修饰符的示例。
[Plain Text] 纯文本查看 复制代码 int main(void)
{
int x = 10, y;
asm ("movl %1, %%eax;
"movl %%eax, %0;"
:"=&r"(y) /* y is output operand, note the & constraint modifier. */
:"r"(x) /* x is input operand */
:"%eax"); /* %eax is clobbered register */
}
以下是为该示例生成的汇编代码,从中可以明显地看出 x 和 y 存储在"asm" 中不同的寄存器中。
[Plain Text] 纯文本查看 复制代码 main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
movl $10,-4(%ebp)
movl -4(%ebp),%ecx /* x, the input is in %ecx */
#APP
movl %ecx, %eax
movl %eax, %edx /* y, the output is in %edx */
#NO_APP
movl %edx,-8(%ebp) |