Gra*_*and 11 x86 gcc inline-assembly
我正在尝试使用GCC的内联汇编程序熟悉x86程序集.我正在尝试添加两个数字(a和b)并存储结果c.我有四个略有不同的尝试,其中三个有效; 最后一个不会产生预期的结果.
前两个示例使用中间寄存器,这些都可以正常工作.第三个和第四个示例尝试直接添加两个值而不使用中间寄存器,但结果会根据优化级别和添加输入值的顺序而有所不同.我错了什么?
环境是:
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)
Run Code Online (Sandbox Code Playgroud)
首先,变量声明如下:
int a = 4;
int b = 7;
int c;
Run Code Online (Sandbox Code Playgroud)
例1:
asm(" movl %1,%%eax;"
" addl %2,%%eax;"
" movl %%eax,%0;"
: "=r" (c)
: "r" (a), "r" (b)
: "%eax"
);
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output: a=4, b=7, c=11
Run Code Online (Sandbox Code Playgroud)
例2:
asm(" movl %2,%%eax;"
" addl %1,%%eax;"
" movl %%eax,%0;"
: "=r" (c)
: "r" (a), "r" (b)
: "%eax"
);
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output: a=4, b=7, c=11
Run Code Online (Sandbox Code Playgroud)
例3:
asm(" movl %2,%0;"
" addl %1,%0;"
: "=r" (c)
: "r" (a), "r" (b)
);
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=11
// output with -O3: a=4, b=7, c=14
Run Code Online (Sandbox Code Playgroud)
例4:
// this one appears to calculate a+a instead of a+b
asm(" movl %1,%0;"
" addl %2,%0;"
: "=r" (c)
: "r" (a), "r" (b)
);
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=8
// output with -O3: a=4, b=7, c=11
Run Code Online (Sandbox Code Playgroud)
解决了. Matthew Slattery的回答是正确的.以前,它试图重用eax两者b和c:
movl -4(%rbp), %edx
movl -8(%rbp), %eax
movl %edx, %eax
addl %eax, %eax
Run Code Online (Sandbox Code Playgroud)
有了Matthew建议的修复,它现在用于单独ecx保存c.
movl -4(%rbp), %edx
movl -8(%rbp), %eax
movl %edx, %ecx
addl %eax, %ecx
Run Code Online (Sandbox Code Playgroud)
默认情况下,gcc假设asm在更新输出操作数之前,内联块将使用输入操作数完成.这意味着输入和输出都可以分配给同一个寄存器.
但是,在您的示例3和4中并不一定如此.
例如在例3中:
asm(" movl %2,%0;"
" addl %1,%0;"
: "=r" (c)
: "r" (a), "r" (b)
);
Run Code Online (Sandbox Code Playgroud)
...你已经更新c(%0阅读前)a(%1).如果gcc碰巧分配相同的注册都%0和%1,然后将计算c = b; c += c,因此会正是你观察的方式失败:
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output with -O0: a=4, b=7, c=11
// output with -O3: a=4, b=7, c=14
Run Code Online (Sandbox Code Playgroud)
您可以通过gcc在输入被消耗之前告知可以使用输出操作数来修复它,方法是在操作数中添加" &"修饰符,如下所示:
asm(" movl %2,%0;"
" addl %1,%0;"
: "=&r" (c)
: "r" (a), "r" (b)
);
Run Code Online (Sandbox Code Playgroud)
(请参阅文档中的"约束修饰符字符"gcc.)
| 归档时间: |
|
| 查看次数: |
2688 次 |
| 最近记录: |