查询地址 :0x804a1f3
所以要输入两个参数
综合分析:
- 首先,整个函数的输入是两个数字,调用的func4的函数是一个递归函数。
- 通过phase_4后面比较返回值和19,第二个参数和19的大小,不相等则爆炸,推出递归函数的返回值是19,第二个参数是19。
- 通过调用前的传参,可以判断三个参数依次是:V1(输入的第一个数)、0、14
- 分析func4,结合我上面写的注释,可以总结该递归函数的原理:
int func4(int v1, int x1, int x2) { int result = x1+((x2–x1)+(x2–x1)>>31)/2; if(v1 < result) return result + fun4(v1, x1, result-1); if(v1 > result) return result + fun4(v1, result+1, x2); else return result; }
- 最后返回值要为19,并且此时递归结束的条件是结果等于输入的第一个数v1,根据递归关系,可以推出第一个数是4
测试结果:
08048c83 <func4>:
8048c83: 55 push %ebp
8048c84: 89 e5 mov %esp,%ebp 开辟栈帧
8048c86: 56 push %esi
8048c87: 53 push %ebx 因为要用到这两个寄存器,被调用者保存现场
8048c88: 8b 55 08 mov 0x8(%ebp),%edx ebp+8第一个参数给edx,即输入的第一个数,这里记为v1
8048c8b: 8b 4d 0c mov 0xc(%ebp),%ecx ebp+12第二个参数给ecx,记为x1
8048c8e: 8b 75 10 mov 0x10(%ebp),%esi ebp+16第三个参数给esi,记为x2
8048c91: 89 f0 mov %esi,%eax eax = x2(值传给eax,这里用=表示)
8048c93: 29 c8 sub %ecx,%eax eax = x2 – x1
8048c95: 89 c3 mov %eax,%ebx ebx = eax = x2 – x1
8048c97: c1 eb 1f shr $0x1f,%ebx ebx>>31 =(x2 – x1)>>31逻辑右移
8048c9a: 01 d8 add %ebx,%eax eax = (x2–x1)+(x2–x1)>>31
8048c9c: d1 f8 sar %eax eax/=2 算数右移
8048c9e: 8d 1c 08 lea (%eax,%ecx,1),%ebx ebx=eax+ecx, 即此时ebx为x1+((x2–x1)+(x2–x1)>>31)/2
8048ca1: 39 d3 cmp %edx,%ebx 比较ebx和edx大小,即上式和第一个输入值比较
8048ca3: 7e 15 jle 8048cba <func4+0x37> ebx <= v1则跳转
8048ca5: 83 ec 04 sub $0x4,%esp 以下部分不跳转,即ebx > v1
8048ca8: 8d 43 ff lea -0x1(%ebx),%eax ebx-1传给eax
8048cab: 50 push %eax 传参,第三个参数是此次运算结果ebx-1
8048cac: 51 push %ecx 第二个参数是x1
8048cad: 52 push %edx 第一个参数仍是输入的第一个数v1
8048cae: e8 d0 ff ff ff call 8048c83 <func4> 递归调用
8048cb3: 83 c4 10 add $0x10,%esp
8048cb6: 01 d8 add %ebx,%eax eax += ebx本次调用返回值为本次的运算结果ebx和递归调用函数的返回值eax的和
8048cb8: eb 19 jmp 8048cd3 <func4+0x50> 执行完跳转,结束
8048cba: 89 d8 mov %ebx,%eax eax = ebx
8048cbc: 39 d3 cmp %edx,%ebx 如果ebx>=v1,则跳转,因为上面判断过ebx<=v1,所以和这个地方大于等于结合起来,跳转条件是ebx=v1,递归结束
8048cbe: 7d 13 jge 8048cd3 <func4+0x50> ebx=v1跳转结束
8048cc0: 83 ec 04 sub $0x4,%esp 以下部分不跳转,即ebx < v1
8048cc3: 56 push %esi 传参,第三个参数是x2
8048cc4: 8d 43 01 lea 0x1(%ebx),%eax eax = ebx + 1
8048cc7: 50 push %eax 第二个参数是ebx + 1
8048cc8: 52 push %edx 第一个参数是V1
8048cc9: e8 b5 ff ff ff call 8048c83 <func4>
8048cce: 83 c4 10 add $0x10,%esp
8048cd1: 01 d8 add %ebx,%eax eax += ebx 同上
8048cd3: 8d 65 f8 lea -0x8(%ebp),%esp
8048cd6: 5b pop %ebx
8048cd7: 5e pop %esi
8048cd8: 5d pop %ebp 函数调用结束,恢复现场
8048cd9: c3 ret
08048cda <phase_4>:
8048cda: 55 push %ebp
8048cdb: 89 e5 mov %esp,%ebp 开辟栈帧
8048cdd: 83 ec 18 sub $0x18,%esp 分配0x18即24个字节的空间
8048ce0: 65 a1 14 00 00 00 mov %gs:0x14,%eax 堆栈金丝雀
8048ce6: 89 45 f4 mov %eax,-0xc(%ebp)
8048ce9: 31 c0 xor %eax,%eax
8048ceb: 8d 45 f0 lea -0x10(%ebp),%eax ebp-16的值传给eax
8048cee: 50 push %eax
8048cef: 8d 45 ec lea -0x14(%ebp),%eax ebp-20的值传给eax
8048cf2: 50 push %eax
8048cf3: 68 f3 a1 04 08 push $0x804a1f3 通过gdb查出输入两个数
8048cf8: ff 75 08 pushl 0x8(%ebp)
8048cfb: e8 10 fb ff ff call 8048810 <__isoc99_sscanf@plt>过程调用,8048870为被调用过程起始点指令地址
8048d00: 83 c4 10 add $0x10,%esp esp下移,开辟16个字节的空间
8048d03: 83 f8 02 cmp $0x2,%eax 判断立即数2和eax的值是否相等
8048d06: 75 06 jne 8048d0e <phase_4+0x34> 不等则爆炸
8048d08: 83 7d ec 0e cmpl $0xe,-0x14(%ebp) 第一个数需要小于等于20
8048d0c: 76 05 jbe 8048d13 <phase_4+0x39> 否则爆炸
8048d0e: e8 ed 03 00 00 call 8049100 <explode_bomb>
8048d13: 83 ec 04 sub $0x4,%esp
8048d16: 6a 0e push $0xe 函数传参,第三个参数是14
8048d18: 6a 00 push $0x0 第二个参数是0
8048d1a: ff 75 ec pushl -0x14(%ebp) 第一个参数是输入的第一个数
8048d1d: e8 61 ff ff ff call 8048c83 <func4> 函数调用
8048d22: 83 c4 10 add $0x10,%esp
8048d25: 83 f8 13 cmp $0x13,%eax 比较19和返回值的大小(返回值默认在eax中)
8048d28: 75 06 jne 8048d30 <phase_4+0x56> 不等则爆炸
8048d2a: 83 7d f0 13 cmpl $0x13,-0x10(%ebp) 比较19和第二个参数的大小
8048d2e: 74 05 je 8048d35 <phase_4+0x5b>等于则不爆炸,可以推出第二个参数是19
8048d30: e8 cb 03 00 00 call 8049100 <explode_bomb>
8048d35: 8b 45 f4 mov -0xc(%ebp),%eax
8048d38: 65 33 05 14 00 00 00 xor %gs:0x14,%eax 金丝雀判断堆栈是否受损
8048d3f: 74 05 je 8048d46 <phase_4+0x6c>
8048d41: e8 4a fa ff ff call 8048790 <__stack_chk_fail@plt>
8048d46: c9 leave
8048d47: c3 ret