为什么call和ret函数在汇编中这样工作?

时间:2013-11-10 10:53:09

标签: debugging assembly x86

所以,我正在乱搞集会,偶然发现了奇怪的事情。在写任何东西之前,我将寄存器设置为这些值:

AX 0000, BX 0000, SP 00FD.

让我们说,我们编写简单的代码,增加寄存器AX和BX:

A100
INC AX
CALL 0200

A200
INC BX
RETN

写完之后,我试着看一下使用T命令逐个执行命令时寄存器的变化。第一次,它增加AX,移至0200,增加BX并返回。这是奇怪的一点:当它返回时,它执行命令: ADD [BX+SI],AX,然后再次致电0200

当它再次调用0200时,它会自行重复,但现在,当它返回时,它会返回CALL 0100命令(而不是CALL 0200)并再次增加AX等等。为什么会这样?

我有完整输出的图像,也许这有助于更好地理解我的问题?: http://s18.postimg.org/wt6eracg9/Untitled.png

2 个答案:

答案 0 :(得分:3)

根据您的屏幕截图,您的代码似乎是这样(填充nop,用udcli反汇编):

echo 40 e8 fc 00 01 00 e8 f7 00 e8 f4 ff x{1..244} 43 c3 | sed 's/x[0-9]*\>/90/g' | udcli -o 0x100 -x -16
0000000000000100 40               inc ax
0000000000000101 e8fc00           call word 0x200
0000000000000104 0100             add [bx+si], ax
0000000000000106 e8f700           call word 0x200
0000000000000109 e8f4ff           call word 0x100
000000000000010c *** never reached ***

0000000000000200 43               inc bx                  
0000000000000201 c3               ret                     

代码流程如下,逐行:

0000000000000100 40               inc ax

ax会增加。

0000000000000101 e8fc00           call word 0x200

返回地址0x104被推送到堆栈,ip(指令指针)被设置为0x200。

0000000000000200 43               inc bx

bx会增加。

0000000000000201 c3               ret

接近返回,即从堆栈中弹出ip。新的ip将为0x104。

0000000000000104 0100             add [bx+si], ax

ax的值添加到[bx+si]处的字值。

0000000000000106 e8f700           call word 0x200

返回地址0x109被推送到堆栈,ip(指令指针)设置为0x200。

0000000000000200 43               inc bx

bx会增加。

0000000000000201 c3               ret

接近返回,即从堆栈中弹出ip。新ip将为0x109。

0000000000000109 e8f4ff           call word 0x100

返回地址0x10c被推送到堆栈,ip(指令指针)被设置为0x100。所以这实际上是一个无限的递归函数,并且会耗尽堆栈。

所以你的问题是你没有在CALL 0200之后定义代码。碰巧有01 00add [bx+si], ax)并且在返回后它将被执行,并且在其它未定义的指令之后。

我的建议:尽快下载任何体面的汇编程序(NASM,YASM,FASM ......)并且不要破坏你的生活,试图用DEBUG编写汇编代码。尝试使用DEBUG编写汇编程序是一种注定要失败的尝试。

答案 1 :(得分:2)

可能的原因是你没有退出,你没有使用DOS的0x4c服务,程序绑定代码并开始执行随机命令或执行流命中一些{{ 1}}没有使用ret的指令,然后会出现意外行为。