我正在学习重修,我在阅读装配时遇到了问题。问题:
从表格
的C代码开始1 int test(int x, int y) {
2 int val = ;
3 if ( ) {
4 if ( )
5 val = ;
6 else
7 val = ;
8 } else if ( )
9 val = ;
10 return val;
11}
gcc生成以下汇编代码:
x at%ebp + 8,y at%ebp + 12
1 movl 8(%ebp), %eax
2 movl 12(%ebp), %edx
3 cmpl $-3, %eax
4 jge .L2
5 cmpl %edx, %eax
6 jle .L3
7 imull %edx, %eax
8 jmp .L4
9 .L3:
10 leal (%edx,%eax), %eax
11 jmp .L4
12 .L2:
Section 3.6 Control 197
13 cmpl $2, %eax
14 jg .L5
15 xorl %edx, %eax
16 jmp .L4
17 .L5:
18 subl %edx, %eax
19 .L4:
在C代码中填写缺少的表达式。使代码适合 在C代码模板中,您将需要撤消一些计算的重新排序 由gcc完成。
所以我尝试了这个,我虽然会:
int val = x+y
if -3>x
if 2>x
val = x^y
else
val = x*y
else if y<x
val = x-y
它比较-3&gt; x然后它跳到L2,所以我认为这是我们继续的地方(每次跳跃,这是我继续阅读的地方)。但是,它只是继续从上到下阅读(为什么?)。 接下来,当-3> x,我假设2&gt; x,但现在他们在x> 2中转过来。然而,它仍然是y&lt; x而不是x&lt;年。 所以我基本上不明白为什么我读取代码的整个顺序都是错误的,为什么他们有时会将第二个参数与第一个参数进行比较,有时则相反。正确答案是:
int val = x^y
if x<-3
if y<x
val = x*y
else
val = x+y
else if x>2
val = x-y
答案 0 :(得分:4)
大多数C实现最后一次在堆栈上推送参数,x86堆栈向下增长。由此:
1 movl 8(%ebp), %eax
2 movl 12(%ebp), %edx
我们可以verfiy edx
先保持单词被推,因为它有更高的地址。所以它是y
。 eax
是x
。
此比较是x
? -3
。请注意由于AT&amp; T汇编约定而导致的参数反转。
3 cmpl $-3, %eax
因此,如果L2
,我们会跳转到x >= -3
。
4 jge .L2
同样,我们跳到x <= y
5 cmpl %edx, %eax
6 jle .L3
这里我们计算一个returnValue = x * y
并跳到最后。请注意,编译器已确定不再需要x
,因此它可以使用eax
寄存器作为从此处开始的返回值。
7 imull %edx, %eax
8 jmp .L4
我们在这里计算returnValue = x + y
。
9 .L3:
10 leal (%edx,%eax), %eax
11 jmp .L4
如果x > 2
我们正在跳跃。
12 .L2:
13 cmpl $2, %eax
14 jg .L5
我们在这里计算returnValue = x ^ y
。
15 xorl %edx, %eax
16 jmp .L4
我们有returnValue = x - y
。
17 .L5:
18 subl %edx, %eax
19 .L4:
将其转换为使用gotos作为中间步骤的C:
if (x >= -3) goto L2;
if (x <= y) goto L3;
val = x * y;
goto L4
L3: val = x + y;
goto L4
L2: if (x > 2) goto L5;
val = x ^ y;
goto L4
L5: val = x - y;
L4: return val;
请注意,大多数看到if (x > y) x *= 3; else y -= 4;
的编译器会颠倒比较感并产生汇编级逻辑
if (x <= y) goto L1;
x *= 3;
goto L2;
L1: y -= 4;
L2:
使用此惯例重新安排上述内容,我们得到:
int test(int x, int y) {
int val = x; // Compiler uses eax for both x and return
if (x < -3) {
if (x > y)
val = x * y;
else
val = x + y;
} else {
if (x <= 2)
val = x ^ y;
else
val = x - y;
}
return val;
}
提供的原始C中缺少最后一个else
子句。我们唯一的选择是推断原始代码最初将x-y
放入val
,并且编译器进行了优化,除非实际返回值,否则不计算该值:
int test(int x, int y) {
int val = x - y; // Compiler doesn't compute x-y unless it's returned!
if (x < -3) {
if (x > y)
val = x * y;
else
val = x + y;
} else if (x <= 2)
val = x ^ y;
return val;
}