ASM16 20 花指令和函数调用
花指令
1 | MyStack segment stack |
这种程序可以正常运行,但是反汇编代码时会分析错误,因为有数据的干扰
正常运行
编译器会把b8当成代码进行分析,从而导致后面分析处于出来的代码都是错的
但是如果找到花指令并从正确的地方开始分析,则分析出来的代码是正确的
解决方法是找到花指令并nop
不会影响正常分析
函数调用
1 | MyStack segment stack |
调用 SHOW_HELLO
函数来显示 MY_MSG1
、MY_MSG2
通过改变参数实现对函数的重复利用
1 | mov ax,09h ;参数2 |
- mov ax,09h: 将 09h(参数2)加载到
ax
寄存器。 - push ax: 将
ax
寄存器的值压入堆栈。 - mov ax,offset MY_MSG1: 将
MY_MSG1
的偏移地址(参数1)加载到ax
寄存器。 - push ax: 将
ax
寄存器的值压入堆栈。 - call SHOW_HELLO: 调用
SHOW_HELLO
子程序。 - ; add sp 4: (注释掉的代码)在
stdcall
调用约定中,子程序返回时恢复堆栈指针。
1 | mov ax,09h |
- mov ax,09h: 将 09h(参数2)加载到
ax
寄存器。 - push ax: 将
ax
寄存器的值压入堆栈。 - mov ax,offset MY_MSG2: 将
MY_MSG2
的偏移地址(参数1)加载到ax
寄存器。 - push ax: 将
ax
寄存器的值压入堆栈。 - call SHOW_HELLO: 调用
SHOW_HELLO
子程序。 - ; add sp 4: (注释掉的代码)在
stdcall
调用约定中,子程序返回时恢复堆栈指针。
SHOW_HELLO
子程序(函数)
1 | SHOW_HELLO: |
- push ax: 保存
ax
寄存器的值到堆栈。 - push cx: 保存
cx
寄存器的值到堆栈。 - push dx: 保存
dx
寄存器的值到堆栈。
设置基指针寄存器
1 | mov bp,sp |
- mov bp,sp: 将当前堆栈指针
sp
的值移动到基指针寄存器bp
。 - mov cx,0: 清空
cx
寄存器。 - mov dx,word ptr [bp+8]: 读取堆栈中偏移
bp+8
位置的值(参数1)到dx
寄存器。(因为前面还压了3个寄存器的值和函数运行完后i哦返回的地址进栈,所以参数1被压倒下面) - mov ah,byte ptr [bp+10]: 读取堆栈中偏移
bp+10
位置的值(参数2)到ah
寄存器。(同理参数2被往下压) - int 21h: 调用 DOS 中断 21h,显示字符串。
恢复环境并返回
1 | pop dx |
- pop dx: 从堆栈中恢复
dx
寄存器的值。 - pop cx: 从堆栈中恢复
cx
寄存器的值。 - pop ax: 从堆栈中恢复
ax
寄存器的值。 - retn 4: 返回调用者,并清理堆栈中的4个字节(两个参数)。(平衡堆栈)
运行结果
调试
运行完call指令后,IP的地址改为call后面的地址,堆栈中存放了call指令接下来的指令的地址,还有前面压入栈的两个参数
ax、cx、dx的值被保存到堆栈
从堆栈中取出参数,运行函数得出结果
堆栈被平衡,ax、cx、dx的值被还原,程序回到函数调用后要执行的指令的地方
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hexo!