先贴出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 <[email protected]> 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"。
到这里,就结束了。
时间: 2024-10-13 16:09:03