我正在读一本书Computer Systems: A Programmer's Perspective (2nd Edition) 和实践问题3.23有点困惑我:
函数fun_b具有以下整体结构:
int fun_b(unsigned x) {
int val = 0;
int i;
for ( ____;_____;_____) {
}
return val;
}
gcc C编译器生成以下汇编代码:
x at %ebp+8
1 movl 8(%ebp), %ebx
2 movl $0, %eax
3 movl $0, %ecx
.L13:
5 leal (%eax,%eax), %edx
6 movl %ebx, %eax
7 andl $1, %eax
8 orl %edx, %eax
9 shrl %ebx Shift right by 1
10 addl $1, %ecx
11 cmpl $32, %ecx
12 jne .L13
对此代码的操作进行反向工程,然后执行以下操作:
:一种。使用汇编代码版本填写C代码的缺失部分。
我的解决方案。
int fun_b(unsigned x) {
int val = 0;
int i;
for ( i = 0 ;i < 32;i++) {
val += val; //because leal (%eax,%eax), edx --> %edx = %eax + %eax
val = val | x & 0x1;
x >>= 1;
}
return val;
}
Book的解决方案。
int fun_b(unsigned x) {
int val = 0;
int i;
for (i = 0; i < 32; i++) {
val = (val << 1) | (x & 0x1);
x >>= 1;
}
return val;
}
请向我解释为什么leal函数在此函数中具有非典型行为。
我不明白这个汇编代码如何产生这个语句val = (val << 1) | (x & 0x1)
答案 0 :(得分:0)
在您的代码中:
val += val;
val = val | x & 0x1;
此处,val += val
相当于(val*2)
实际上等于val
左移1
。
但我认为只有当汇编代码类似于:
时,您的解决方案才是正确的x at %ebp+8
1 movl 8(%ebp), %ebx
2 movl $0, %eax
3 movl $0, %ecx
.L13:
5 addl %eax, %eax
6 movl %ebx, %edx
7 andl $1, %edx
8 orl %edx, %eax
9 shrl %ebx # shift right by 1
10 addl $1, %ecx
11 cmpl $32, %ecx
12 jne .L13
因为如果val + val
是一个单独的语句,编译器通常会将它放在eax寄存器中而不是edx中(我不确定这种情况总是如此)。因此,对于您提供的代码,可能的解决方案是:
val = (val << 1) | (x & 0x1);
或
val = (val + val) | (x & 0x1);
或
val = (val * 2) | (x & 0x1);
答案 1 :(得分:0)
x&gt;&gt; = 1;表示将x乘以2,二进制向左移位或在右侧加0;
x >>= 1; == x * 2; == x +=x;