首页 > 技术文章 > CSAPP 3e: Bomb lab (phase_4)

xihuyouyu 2017-09-14 23:04 原文

先贴出phase_4的代码:

0000000000400fce <func4>:            ;%rdi=num_0;%rsi=0;%rdx=0xe;
  400fce:    48 83 ec 08              sub    $0x8,%rsp
  400fd2:    89 d0                    mov    %edx,%eax    ;%eax=0xe;
  400fd4:    29 f0                    sub    %esi,%eax    ;%eax=0xe-0==e;
  400fd6:    89 c1                    mov    %eax,%ecx    ;%ecx=e;
  400fd8:    c1 e9 1f                 shr    $0x1f,%ecx    ;右移31位,注意shr是逻辑右移!!!
  400fdb:    01 c8                    add    %ecx,%eax    ;也就是如果%eax为正数则不变,为负数则+1;
  400fdd:    d1 f8                    sar    %eax            ;(算术)右移1位,即%eax/2;
  400fdf:    8d 0c 30                 lea    (%rax,%rsi,1),%ecx    ;%ecx=e;
  400fe2:    39 f9                    cmp    %edi,%ecx
  400fe4:    7e 0c                    jle    400ff2 <func4+0x24>        ;if(cx<=di)continue;else %edx=-(1+%rcx);
  400fe6:    8d 51 ff                 lea    -0x1(%rcx),%edx
  400fe9:    e8 e0 ff ff ff           callq  400fce <func4>                                        ;%eax=2*%eax.
  400fee:    01 c0                    add    %eax,%eax            ;注意这里,自身调用func4后的操作,%eax乘以2了,然后ret。
  400ff0:    eb 15                    jmp    401007 <func4+0x39>
  400ff2:    b8 00 00 00 00           mov    $0x0, %eax              ;注意这里,%eax=0,然后ret返回。这里才开始停止调用自身。重点中的重点!!!
  400ff7:    39 f9                    cmp    %edi,%ecx
  400ff9:    7d 0c                    jge    401007 <func4+0x39>
  400ffb:    8d 71 01                 lea    0x1(%rcx),%esi
  400ffe:    e8 cb ff ff ff           callq  400fce <func4>                                        ;%eax=2*%eax+1.
  401003:    8d 44 00 01              lea    0x1(%rax,%rax,1),%eax;注意这里,自身调用func4后的操作,%eax乘以2并加1,然后ret。
  401007:    48 83 c4 08              add    $0x8,%rsp
  40100b:    c3                       retq   

000000000040100c <phase_4>:
  40100c:    48 83 ec 18              sub    $0x18,%rsp
  401010:    48 8d 4c 24 0c           lea    0xc(%rsp),%rcx    ;这里跟之前的一样,(%rsp+0xc)存储第二个数字,令其为num_1;
  401015:    48 8d 54 24 08           lea    0x8(%rsp),%rdx    ;(%rsp+8)存储第一数,令其为num_0.
  40101a:    be cf 25 40 00           mov    $0x4025cf,%esi    ;查看内存为字符串"%d %d",说明还是输入两个数。
  40101f:    b8 00 00 00 00           mov    $0x0,%eax
  401024:    e8 c7 fb ff ff           callq  400bf0 <__isoc99_sscanf@plt>
  401029:    83 f8 02                 cmp    $0x2,%eax        ;sscanf正常返回值为2,条件跳转不执行。
  40102c:    75 07                    jne    401035 <phase_4+0x29>
  40102e:    83 7c 24 08 0e           cmpl   $0xe,0x8(%rsp)            ;if(num_0 <= 14) jmp;else to bomb;
  401033:    76 05                    jbe    40103a <phase_4+0x2e>    ;所以这里要求num_0必须小于等于14
  401035:    e8 00 04 00 00           callq  40143a <explode_bomb>
  40103a:    ba 0e 00 00 00           mov    $0xe,%edx
  40103f:    be 00 00 00 00           mov    $0x0,%esi
  401044:    8b 7c 24 08              mov    0x8(%rsp),%edi        ;这里是针对num_0的运算,调用了函数func4,这里是重点!!
  401048:    e8 81 ff ff ff           callq  400fce <func4>
  40104d:    85 c0                    test   %eax,%eax            ;if(%eax==0)jmp;else to bomb;
  40104f:    75 07                    jne    401058 <phase_4+0x4c>;也就是call func4的返回值必须为0,否则爆炸。
  401051:    83 7c 24 0c 00           cmpl   $0x0,0xc(%rsp)
  401056:    74 05                    je     40105d <phase_4+0x51> ;这里比较num_1,要求第二个数必须等于0。
  401058:    e8 dd 03 00 00           callq  40143a <explode_bomb>
  40105d:    48 83 c4 18              add    $0x18,%rsp
  401061:    c3                       retq   

  指令的讲解在注释里了,但是想讲讲我的另一种分析方法:

 

  途中通道的意思,表述可能不对,可以理解为是一个运行的路程吧。

  为了保证总的返回值是0,所以只能走a,c通道(路程),由此可以计算出%ecx的值,只要在这几次计算中有一次num_0(即输入的第一个数)等于%ecx的值,就可以正确返回0了。

  所以最终的答案为 "7 0","3 0","1 0","0 0"。

  到这里,就结束了。

推荐阅读