问题已关闭。原因:代为完成个人任务。
提问需要满足:其他人可能遇到相似问题,或问题的解决方法对其他人有所助益。如果通过其他方式解决遇到困难,欢迎提问并说明你的求知过程。

csapp lab2 bomb实验求教?

题目的意思是在这段汇编代码中破解出6个数 本渣第二个炸弹就卡住了……汇编如上,大概是比较数组第0个元素和第三个元素 第一个和第四个 第三个和第五个 不相等就爆炸 一共循环三次。可是怎么知道数组的初始值呢?
关注者
30
被浏览
2602
题主这个是CS:APP 1e的lab2么?
之前我没做过CS:APP的lab,刚去瞄了眼CS:APP 2e和3e的lab2 self study版,都不是长这个样的…
<- 啊,原来是中科大的CS:APP 2e的非self study 32位版lab2。

题主截取的phase_2函数的内容其实很简单,毕竟源程序就很简单而编译的时候又没有加优化。静态读代码然后人肉反编译其实就够了。动用gdb来动态调试并不是必要的(当然也可以作为有效的辅助手段…)
结合上下文人肉反编译一小段就是这样:
// constant printf() may be compiled into a puts() even at -O0
void explode_bomb() {
  puts("BOOM!!!");                // or printf("BOOM!!!\n")
  puts("The bomb has blown up."); // or printf("The bomb has blown up.\n")
  exit(8);
}

void read_six_numbers(char* input, int* nums) {
  if (sscanf(input, "%d %d %d %d %d %d", &nums[0], &nums[1], &nums[2], &nums[3], &nums[4], &nums[5]) <= 5) {
    explode_bomb();
  }
}

void phase_2(char* input) {
  int sum = 0;
  int nums[6];
  read_six_numbers(input, nums);
  for (int i = 0; i < 3; i++) {
    if (nums[i] != nums[i + 3]) {
      explode_bomb();
    }
    sum += nums[i];
  }
  if (sum == 0) {
    explode_bomb();
  }
}

char* read_line() {
  /* ... */
}

int main(int argc, char* argv[]) {
  char* input;
  /* ... */
  input = read_line();
  phase_2(input);
  /* ... */
}
用GCC 4.4.7在Linux x86-64上用-m32 -O0编译这个phase_2()会得到跟题主截图的几乎一样的代码。下面是编译结果:
phase_2:                         # phase_2(char*)
        pushl   %ebp
        movl    %esp, %ebp
        subl    $56, %esp
        movl    $0, -12(%ebp)    #, sum
        leal    -40(%ebp), %eax  #, tmp63
        movl    %eax, 4(%esp)    # tmp63,
        movl    8(%ebp), %eax    # input, tmp64
        movl    %eax, (%esp)     # tmp64,
        call    read_six_numbers # (char*, int*)
        movl    $0, -16(%ebp)    #, i
        jmp     .L5
.L7:
        movl    -16(%ebp), %eax  # i, tmp65
        movl    -40(%ebp,%eax,4), %edx  # nums, D.2039
        movl    -16(%ebp), %eax  # i, tmp66
        addl    $3, %eax         #, D.2040
        movl    -40(%ebp,%eax,4), %eax  # nums, D.2041
        cmpl    %eax, %edx       # D.2041, D.2039
        je      .L6
        call    explode_bomb     # ()
.L6:
        movl    -16(%ebp), %eax  # i, tmp67
        movl    -40(%ebp,%eax,4), %eax  # nums, D.2044
        addl    %eax, -12(%ebp)  # D.2044, sum
        addl    $1, -16(%ebp)    #, i
.L5:
        cmpl    $2, -16(%ebp)    #, i
        jle     .L7
        cmpl    $0, -12(%ebp)    #, sum
        jne     .L4
        call    explode_bomb     # ()
.L4:
        leave
        ret
大家可以看看这个-O0的编译结果是不是跟题主贴出来的截图里的指令一一对应?指令的条数以及每条指令的内容都是对应的。
唯一的区别是我这里编译出来的版本的栈帧多了4个无用的slot。其栈帧布局是这样的:
 esp -> [ outgoing argument 1 ] ebp-56 or esp+0
        [ outgoing argument 0 ] ebp-52 or esp+4
        [                     ] ebp-48 or esp+8
        [                     ] ebp-44 or esp+12
        [ nums[0]             ] ebp-40
        [ nums[1]             ] ebp-36
        [ nums[2]             ] ebp-32
        [ nums[3]             ] ebp-28
        [ nums[4]             ] ebp-24
        [ nums[5]             ] ebp-20
        [ i                   ] ebp-16
        [ sum                 ] ebp-12
        [                     ] ebp-8
        [                     ] ebp-4
 ebp -> [ old frame pointer   ] ebp+0
        [ return address      ] ebp+4
        [ incoming argument 0 ] ebp+8
ebp-4、-8、-44、-48这4个slot在这个函数里是没有被用到的。
而看题主的截图里phase_2()的栈帧布局则是:
 esp -> [ outgoing argument 1 ] ebp-40 or esp+0
        [ outgoing argument 0 ] ebp-36 or esp+4
        [ nums[0]             ] ebp-32
        [ nums[1]             ] ebp-28
        [ nums[2]             ] ebp-24
        [ nums[3]             ] ebp-20
        [ nums[4]             ] ebp-16
        [ nums[5]             ] ebp-12
        [ i                   ] ebp-8
        [ sum                 ] ebp-4
 ebp -> [ old frame pointer   ] ebp+0
        [ return address      ] ebp+4
        [ incoming argument 0 ] ebp+8
正好就是比我用GCC 4.4.7 -O0编译少用了4个slot。


补充:话说可以给GCC再传递个 -mpreferred-stack-boundary=2 参数来让它生成跟题主截图里的代码一模一样的结果:
phase_2:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $40, %esp
        movl    $0, -4(%ebp)
        leal    -32(%ebp), %eax
        movl    %eax, 4(%esp)
        movl    8(%ebp), %eax
        movl    %eax, (%esp)
        call    read_six_numbers
        movl    $0, -8(%ebp)
        jmp     .L7
.L9:
        movl    -8(%ebp), %eax
        movl    -32(%ebp,%eax,4), %edx
        movl    -8(%ebp), %eax
        addl    $3, %eax
        movl    -32(%ebp,%eax,4), %eax
        cmpl    %eax, %edx
        je      .L8
        call    explode_bomb
.L8:
        movl    -8(%ebp), %eax
        movl    -32(%ebp,%eax,4), %eax
        addl    %eax, -4(%ebp)
        addl    $1, -8(%ebp)
.L7:
        cmpl    $2, -8(%ebp)
        jle     .L9
        cmpl    $0, -4(%ebp)
        jne     .L11
        call    explode_bomb
.L11:
        leave
        ret
完美。

=====================================

所以简单来说这样的输入就能通过了:
1 2 3 1 2 3

1 1 1 1 1 1


而下面这几个输入则通不过:
0 0 0 0 0 0

-1 0 1 -1 0 1

3 -2 -1 3 -2 -1
>_<