/*******8086CPU執行指令的步驟********/
極重要:
1、從CS:IP指向的內存單元讀取指令,讀取的指令進入指令緩衝器
2、(IP)=(IP)+所讀取指令的長度,從而指向下一條指令
3、執行指令,轉到第一步,重複這三步
(注意:CPU是先指向要執行指令的下一條指令再開始執行指令)
/******offset:獲取標記地址******/
獲得僞代碼中的標記地址後,我們可以在這些地址中任意跳躍,非常方便,那麼怎麼獲得這種內存地址呢?下面的例子一看就明白:
assume cs:codeseg
codeseg segment
start:mov ax,offset start
s:mov bx,offset s
codeseg ends
end start
offset 【標號】指令就可以獲取到標號處的地址,上面的例子中,ax寄存器存放了start的首地址,bx存放了s的首地址
/******jmp指令*********/
一種無條件轉移指令
(1)根據位移地址轉移:短轉移
1、jmp short 【標號】---->轉移到標號處執行指令---->對IP修改範圍爲-128~127
等價功能:(IP)=(IP)+8位位移(也就是說CPU只需要知道指令轉移的偏移位置即可)
對應的機器碼:EB【偏移量】(偏移量指的是偏移的字節數,從開始的CPU執行指令的步驟來看,jmp應該跳到位置是:jmp下一條指令的首地址+偏移的字節數)
2、jmp near 【標號】---->功能同上---->對IP的修改範圍爲-32768~32767
等價功能:(IP)=(IP)+16位位移(16位的偏移量就說明爲什麼是-32768~32767)
(注意:上面兩種轉移都只是向CPU提供了偏移量)
(2)根據目的地址轉移:遠轉移
jmp far ptr 【標號】---->實現段間轉移,稱爲遠轉移---->修改的是CS和IP
對應機器碼:EA【IP值】【CS值】
(3)根據寄存器轉移
jmp 16位 寄存器---->通過修改IP值來轉移指令
有點兒類似於mov IP,ax。當然,mov指令是不能直接修改IP寄存器的,這兒只是利於理解
(4)根據內存數據轉移
1、jmp word ptr 內存單元地址---->從內存單元地址處取一個字的數據來實現段內轉移---->修改IP
2、jmp dword ptr 內存單元地址---->從內存單元地址處取兩個字的數據來實現段間轉移---->高地址的字修改CS,低地址的字修改IP
/******jcxz:條件轉移*********/
jcxz是要滿足一定條件才轉移的,所有的條件的轉移指令都是短轉移
jcxz 【標號】---->(cx)=0的時候就轉移到標號處,(cx)不等於0的時候什麼都不做,有點類似於C語言中的if語句
/********loop:循環指令***********/
所有的循環指令都是短轉移
loop 【標號】---->每次執行loop之前,(cx)=(cx)-1,(cx)不等於0就跳到標號處
/***********彙編中的子程序原理*************/
(1)ret、retf 轉移指令詳解
1、ret---->根據棧頂元素來修改IP,實現近轉移
CPU執行ret時的步驟:(IP)=(ss)*16+(SP)---->(SP)=(SP)+2
等價於:pop IP
2、retf---->根據棧頂元素來修改CS和IP,實現遠轉移
CPU執行retf時的步驟:(IP)=(SS)*16+(SP)---->(SP)=(SP)+2---->(CS)=(SS)*16+(SP)---->(SP)=(SP)+2
等價於:pop IP---->pop CS
(2)call指令:
1、概括:CPU執行call指令時:將當前IP或CS和IP壓入棧中,轉移
2、根據位移地址轉移
call 【標號】---->等價於:1.push IP 2.jmp near ptr 【標號】---->根據前面的jmp知識可知轉移位移爲-32678~32767
3、根據目的地址轉移
call far ptr 【標號】---->等價於:1.push CS 2.push IP 3.jmp far ptr 【標號】---->很明顯這是一個段間轉移
4、根據寄存器轉移
call 16位寄存器---->等價於:1.push IP 2.jmp 16位寄存器
5、根據內存數據轉移
call word ptr 內存單元地址---->等價於:1.push IP 2.jmp word ptr 內存單元地址
call dword ptr 內存單元地址---->等價於:1.push CS 2.push IP 3.jmp dword ptr 內存單元地址
(3)模塊化設計-----雙劍合璧:call、ret
我們可以利用這樣的模式來實現一種類似於C語言中的函數調用:
call s
...
s:
...(s段的內容,即子程序實現的功能)
ret
理解這種用法我們就要需要通過CPU執行指令的過程來看:
(子程序原理,極重要)
1、CPU讀取call s指令,作爲將要執行的指令
2、然後IP指向call s的下一條指令
3、這個時候執行call s指令,將IP值入棧,其實就相當於保存了call s指令的下一條指令的首地址
4、轉移到s段開始執行,直到ret處,IP值可以暫時不考慮了,因爲ret會相當於pop IP指令,那麼此時IP就是在執行call s的時候壓入的IP值,即call s指令的下一條指令的首地址
5、很正常的可以想到,此時CPU會從call s的下一條指令開始執行,這就相當於到了s段執行完了子程序功能後又回到上一個地址繼續執行指令
從這個模塊化設計中我們可以瞭解到C語言中函數調用的實現,以及那些比較難理解的過程活動記錄入棧之類的問題都可以很容易想到了。