Ret 和 call 也是轉移指令,可是他們跟jmp不同的是,這兩個轉移指令都跟棧有關系。
<1> ret
用棧中的數據改動IP的地址,從而實現近轉移
( ip ) = ( (ss)*16+ sp )
( sp ) =( sp ) + 2
相當於pop ip
<2>retf
用棧中的數據來改動CS以及IP的值,實現段間轉移
( ip ) = ( (ss)*16+ sp )
( sp ) =( sp ) + 2
( cs ) = ( (ss)*16+ sp )
( sp ) =( sp ) + 2
相當於
Pop ip
Pop cs
<3> call xxx(行號)
先把當前IP壓棧,然后跳轉,相當於實現近轉移
( sp ) = ( sp ) – 2
( (ss)*16+ sp ) = ( ip )
( ip ) = ( ip ) + 16位位移
相當於:
Push ip
Jmp near ptr xxx(行號)
<4>call far ptr
把CS。IP壓棧處理,然后實現跳轉,相當於段間轉移。遠轉移
( sp ) = ( sp ) – 2
( (ss)*16+ sp ) = ( cs )
( sp ) = ( sp ) – 2
( (ss)*16+ sp ) = ( ip )
(cs) = 當前行號段地址
(ip) = 當前行號偏移地址
相當於:
Push cs
Push ip
Jmp far ptr xxx
<5> call reg(16bit)
跳轉到16位寄存器上中存儲的地址
( sp ) = (sp) – 2
( (SS)*16 + (sp) ) = (IP)
(IP) = ( 16bit Reg )
相當於:
Push IP
Jmp 16bit Reg
<6> call word ptr 內存單元地址
相當於
Push IP
Jmp word ptr 內存單元地址
如:call word ptr ds:[0]
<7> call dword ptr 內存單元地址
相當於
Push cs
Push ip
Jmp dword ptr 內存單元地址
比如:jmp dword ptr DS:[0];
<8>寄存器的沖突問題
主程序調用子程序段的時候,可能子程序會用到主程序中使用的寄存器的值。程序在設計的時候不可能做到不讓子程序使用主程序的寄存器,由於兩者是相互獨立的。你永遠不會還有一個會做什么。所以在子程序中採取不使用主程序中調用的寄存器的做法是不可行的。
解決方法:
把寄存器用到的東西,保存到堆棧里面。子程序調用完成。再將堆棧保存的東西彈出。