阅读汇编,跳转和比较语句

时间:2016-12-18 13:55:23

标签: assembly x86

我正在学习重修,我在阅读装配时遇到了问题。问题:

从表格

的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

1 个答案:

答案 0 :(得分:4)

大多数C实现最后一次在堆栈上推送参数,x86堆栈向下增长。由此:

1 movl 8(%ebp), %eax
2 movl 12(%ebp), %edx

我们可以verfiy edx先保持单词被推,因为它有更高的地址。所以它是yeaxx

此比较是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;
}