一、汇编指令
1.PUSH 和 POP
- 指令的汇编格式:PUSH SRC ;POP DST
- 指令的基本功能:PUSH指令在程序中常用来暂存某些数据,而POP指令又可将这些数据恢复。
PUSH 等价于:
subl $4, %esp
movl %ebp (%esp)
POP 等价于:
movl (%esp), %ead
addl $4, %esp
2.CALL,RET和LEAVE
-
CALL指令的步骤:首先是将返回地址(也就是call指令要执行时EIP的值)压入栈顶,然后是将程序跳转到当前调用的方法的起始地址。执行push和jump指令。
-
RET指令则是将栈顶的返回地址弹出到EIP,然后按照EIP此时指示的指令地址继续执行程序。
-
LEAVE指令是将栈指针指向帧指针,然后POP备份的原帧指针到%EBP。
Leave等价于:
movl %ebp %esp
popl %ebp
3.lea指令
- load effective address, 加载有效地址,可以将有效地址传送到指定的的寄存器。指令形式是从存储器读数据到寄存器, 效果是将存储器的有效地址写入到目的操作数, 简单说, 就是C语言中的”&”.
题目分析:
08048bb4 <phase_2>:
8048bb4: 56
8048bb5: 53 push %ebx //将ebx里面的值写入<phase_2>这个帧。
8048bb6: 83 ec 34 sub $0x34,%esp // 为局部变量划分空间。栈向低地址方向增长,用sub
8048bb9: 8d 44 24 18 lea 0x18(%esp),%eax
8048bbd: 89 44 24 04 mov %eax,0x4(%esp)
8048bc1: 8b 44 24 40 mov 0x40(%esp),%eax
8048bc5: 89 04 24 mov %eax,(%esp)
8048bc8: e8 3f 06 00 00 call 804920c <read_six_numbers> //调用读取六个数字这个函数
8048bcd: 83 7c 24 18 00 cmpl $0x0,0x18(%esp)
8048bd2: 75 07 jne 8048bdb <phase_2+0x27> //jne与cmpl配合判断,第一个数字是否为0,如果是则继续执行,否则将执行下面的explode_bomb函数
8048bd4: 83 7c 24 1c 01 cmpl $0x1,0x1c(%esp)
8048bd9: 74 1f je 8048bfa <phase_2+0x46> //判断,第二个数字是否为1,是则继续执行,不是执行explode_bomb函数
8048bdb: e8 05 06 00 00 call 80491e5 <explode_bomb>
8048be0: eb 18 jmp 8048bfa <phase_2+0x46>
8048be2: 8b 43 f8 mov -0x8(%ebx),%eax //将上上那个数的值赋给eax,可理解为eax=a[i-2]
8048be5: 03 43 fc add -0x4(%ebx),%eax //将上个数与上上个数相加,可理解为
eax=a[i-1]+a[i-2]
8048be8: 39 03 cmp %eax,(%ebx)
8048bea: 74 05 je 8048bf1 <phase_2+0x3d> //判断输入的数是否满足上面,满足跳继续,不满足引爆炸弹。
8048bec: e8 f4 05 00 00 call 80491e5 <explode_bomb>
8048bf1: 83 c3 04 add $0x4,%ebx // ebx+4 指向新位置
8048bf4: 39 f3 cmp %esi,%ebx
8048bf6: 75 ea jne 8048be2 <phase_2+0x2e> //判断ebx是否与esi是否相等,不等就继续执行8048be2;
8048bf8: eb 0a jmp 8048c04 <phase_2+0x50> //相等无条件跳出。
8048bfa: 8d 5c 24 20 lea 0x20(%esp),%ebx //ebx指向新的地址
8048bfe: 8d 74 24 30 lea 0x30(%esp),%esi //esi存的是地址esp+30
8048c02: eb de jmp 8048be2 <ph ase_2+0x2e>
8048c04: 83 c4 34 add $0x34,%esp
8048c07: 5b pop %ebx
8048c08: 5e pop %esi
8048c09: c3 ret
-
根据
8048bc8: e8 3f 06 00 00 call 804920c <read_six_numbers>
然后查看该函数的代码,发现804923a: c7 44 24 04 e3 a3 04 movl $0x804a3e3,0x4(%esp)
,调用gdb调试器查看发现该地址存放的是%d,%d,%d,%d,%d,%d,可知要求是输入六个数字。 - 前两个数字必须为0和1.
8048bcd: 83 7c 24 18 00 cmpl $0x0,0x18(%esp) 8048bd2: 75 07 jne 8048bdb <phase_2+0x27> 8048bd4: 83 7c 24 1c 01 cmpl $0x1,0x1c(%esp)` 8048bd9: 74 1f je 8048bfa <phase_2+0x46>
- 根据最后判断又跳回8048be2,可知8048e2这段代码表示的是一个循环。循环的语句是将前两个输入的值相加作为第三个的值。所以根据0,1可推断之后四个数字依次为1,2,3,5
8048be2: 8b 43 f8 mov -0x8(%ebx),%eax 8048be5: 03 43 fc add -0x4(%ebx),%eax
结果验证
参考链接
汇编语言里 eax, ebx, ecx, edx, esi, edi, ebp, esp
Push, Pop, call, leave 和 Ret 指令图解