【发布时间】:2011-07-10 11:05:46
【问题描述】:
我试图通过移位和加法在汇编程序中进行乘法运算,我从以下代码中得到了最奇怪的输出。如果 int main 中的最后两个函数调用被注释掉,我会得到一个正常的结果,否则我会得到第一个调用的正常结果和第二个和第三个调用的两个垃圾结果?
#include <iostream>
using namespace std;
int times_ten(int multiply_by_ten)
{
int multiplied_by_ten = 0;
//this multiplies by 10
__asm__("shld %%eax,%1;"
"movl %%eax,%%ebx;"
"shld %%eax,%1;"
"shld %%eax,%1;"
"addl %%ebx,%%eax;"
: "=r" (multiplied_by_ten)
: "a" (multiply_by_ten)
);
return multiplied_by_ten;
}
int times_hundred(int multiply_by_hundred)
{
int multiplied_by_hundred = 0;
//this multiplies by 100
__asm__("shld %%eax,%1;"
"shld %%eax,%1;"
"movl %%eax,%%ebx;"
"shld %%eax,%1;"
"shld %%eax,%1;"
"shld %%eax,%1;"
"movl %%eax,%%edx;"
"shld %%eax,%1;"
"addl %%ebx,%%eax;"
"addl %%edx,%%eax;"
: "=r" (multiplied_by_hundred)
: "a" (multiply_by_hundred)
);
return multiplied_by_hundred;
}
int main()
{
cout<<times_hundred(1)<<endl;
cout<<times_ten(1)<<endl;
cout<<times_hundred(1)<<endl;
return 0;
}
以下有clobber 列表,但无法编译。错误在它下面。
#include <iostream>
using namespace std;
int times_ten(int multiply_by_ten)
{
int multiplied_by_ten = 0;
//this multiplies by 10
__asm__("shld %%eax,%1;"
"movl %%eax,%%ebx;"
"shld %%eax,%1;"
"shld %%eax,%1;"
"addl %%ebx,%%eax;"
: "=r" (multiplied_by_ten)
: "a" (multiply_by_ten)
: "%%eax", "%%ebx"
);
return multiplied_by_ten;
}
int times_hundred(int multiply_by_hundred)
{
int multiplied_by_hundred = 0;
//this multiplies by 100
__asm__("shld %%eax,%1;"
"shld %%eax,%1;"
"movl %%eax,%%ebx;"
"shld %%eax,%1;"
"shld %%eax,%1;"
"shld %%eax,%1;"
"movl %%eax,%%edx;"
"shld %%eax,%1;"
"addl %%ebx,%%eax;"
"addl %%edx,%%eax;"
: "=r" (multiplied_by_hundred)
: "a" (multiply_by_hundred)
: "%%eax", "%%ebx", "%%edx"
);
return multiplied_by_hundred;
}
int main()
{
cout<<times_hundred(1)<<endl;
cout<<times_ten(1)<<endl;
cout<<times_hundred(1)<<endl;
return 0;
}
|In function 'int times_ten(int)':|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
In function 'int times_hundred(int)':|
error: unknown register name '%%edx' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
In function 'int main()':|
error: unknown register name '%%edx' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
error: unknown register name '%%edx' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
||=== Build finished: 13 errors, 0 warnings ===|
【问题讨论】:
-
你的clobber列表中可能需要eax、abx、edx。
-
我试过了,但它不会编译。
-
“不会编译”是什么意思?发布实际代码和实际错误消息。
-
您知道 gcc 非常擅长使用普通 C 运算符和
-O2进行这种优化(包括除以倒数),对吧?这不受特定寄存器的约束。那么您编写此汇编程序例程的原因可能是出于教育目的?在任何情况下,如果性能很重要,您都希望摆脱%%eax之类的东西,转而支持r()约束。否则,您会不必要地阻碍编译器分配寄存器。 -
%%eax 正在硬编码一个特定的寄存器。您可以像之前那样将一些变量绑定到 =r(),但您也可以将输入绑定到 r() 并以这种方式分配您需要的任何本地变量。您可以参考寄存器,例如使用 %0、%1 等(或通过绑定名称),它使用编译器在其分配策略中认为最好的寄存器,而不是强制执行特定寄存器,这很可能会强制编译器生成额外的移动。