組合語言學習筆記 四

2022-01-23 14:29:49 字數 4511 閱讀 1240

十三 過程

組合語言的過程可以被理解為方法,過程呼叫採取如下形式

call pname

pname為過程名,call為呼叫指令

pname過程的格式為

pname proc

;過程體

retpname endp

proc 告知編譯程式過程pname的開始,endp告訴編譯程式過程pname的結束。ret指令表明何時返回到呼叫程式中,

ret和高階語言return不一樣,ret不返回任何值給呼叫程式。ret是過程中必不可少的呼叫指令。

舉個過程的例項:

sample      proc

.if eax ==

0mov eax, 1

.else

mov edx, 0

.endif

retsample endp

如果過程中使用到ecx,eax,ebx, edx等通用暫存器,而不確定外界是否也用到這些通用暫存器,

那麼在過程中需要將外界用到的暫存器資料儲存,可以使用臨時變數,也可以使用入棧。

譬如ecx資料在呼叫程式中使用,同時過程mult中也用到ecx,那麼使用ecx之前將ecx入棧。

mult   proc

push

ecx

mov eax, 0

.if x !=

0mov ecx, 1

.while ecx <= y

addeax, x

incecx

.endw

.endif

popecx

retmult endp

出了過程中明顯能從**中看到一些暫存器會被修改,還有一些指令會導致暫存器資料被修改。

invoke指令會導致eax,ecx,edx內容被修改

imul會導致eax,edx被修改。所以可以通過pushad和popad指令儲存和恢復這些暫存器的內容

舉例

blankln   proc

pushad

.repeat

invoke printf, addr blnkfmt

decebx

.until ebx <=

0popad

retblacnkln endp

過程的宣告都是放在main主程式之後。而且過程更看重的是節約空間。

十三 巨集

1   巨集和過程都可以避免編寫同樣功能**,巨集的速度比過程快,但是傾向於浪費一些空間達到提高效率的目的。

巨集的宣告放在main函式之前。

巨集的結構如下:

mname macro

;巨集體endm

巨集的結構和過程的結構不同,巨集內部沒有ret,並且macro 表示巨集的開始 macro前邊為巨集的名字。

endm為巨集的結束,但是endm之前沒有巨集的名字。另外巨集的呼叫不需要使用call指令,直接寫巨集的名字即可。

可以通過檢視彙編列表檔案看看巨集擴充套件是什麼,以及巨集被插入到程式段是什麼指令,下面為某段**呼叫兩次swap巨集

展開後:

88 1d 00000046 表示指令mov ebx , num1,該指令在程式位址為00000000處。

另外需要注意的是巨集擴充套件後,注釋也會擴充套件在指令後邊。雖然會占用一定記憶體,但是注釋可以幫助程式人員排除邏輯錯誤。

如果想使用注釋,僅僅在巨集過程中可見那麼採取;;替代;,這樣注釋不會出現在巨集擴充套件中,使用者可以通過巨集的宣告看到注釋。

呼叫巨集的時候,呼叫幾次巨集就在相應的呼叫位置擴充套件幾次,而過程無論呼叫多少次,僅僅擴充套件一次。這就是過程節省空間的

原因。另外巨集內部盡量不要使用暫存器,如果使用暫存器也不需要儲存和恢復暫存器內容,這些操作放在呼叫巨集的程式裡,因為儲存和恢復

操作一則浪費空間,二則會減少巨集執行的效率。

2  帶引數的巨集

swap macro p1, p2

movebx, p1

xchg

ebx, p2

movp1, ebx

endm

p1,p2為巨集的引數,可以理解為高階語言巨集的兩個引數,呼叫程式呼叫swap時會將實參替代形參完成巨集呼叫。

呼叫swap時會用num1替代p1,num2替代p2,

用x替代p1, y替代p2

如果開發人員只傳入乙個引數怎麼辦?

比如 swap num1?

這樣巨集展開就出現問題。可以通過:req語句指明引數是必須傳入不可缺少的。

swap macro p1:req, p2:

req

movebx,p1

xchg

ebx, p2

movp1, ebx

endm

這樣要求呼叫swap必須傳入兩個引數,缺少引數則提示報錯。

考慮這樣乙個問題,如果呼叫程式呼叫swap num1,1怎麼辦?

xchg ebx,1出錯。

另外如果 swap ebx, ebx 怎麼辦?這種沒必要呼叫swap,雖然呼叫swap不會出錯,

但是造成了空間的浪費。這些問題都可以通過條件彙編解決。

十四  條件彙編

條件彙編和條件指令不同,條件彙編控制編譯程式,而不是控制程式的執行,

條件彙編根據不同的條件將不同的指令或**包含到程式中。

條件彙編指令if

if和之前介紹的高階彙編指令.if不一樣,if後邊的引數為 eq, ne, lt, le, gt, ge, or, and等。

舉例:if num eq 3

;該條件滿足將指令插入程式

endif

除此之外

ifb  判斷如果為空,則執行if下邊的邏輯。

ifnb 判斷如果不為空

ifidn 判斷如果相同

ifidni  不區分大小寫,如果相同

ifdif  如果不相同

ifdifi  不區分大小寫,如果不同

這類指令後邊要用《引數形式》

舉例:

addacc  macro parm

ifb

inceax

else

addeax, parm

endif

endm

在程式中通過幾種方式呼叫addacc

.lst檔案內容如下所示,根據不同條件擴充套件為不同的巨集

根據不同的條件生成了不同的機器指令,達到了節約空間和控制編譯的目的。

僅僅在一部分位址和機器指令行包含了彙編指令,其餘沒有機器指令和位址的彙編**不會

被包含在程式中。

使用條件彙編將之前的swap設計的更完善

swap   macro  p1:req, p2:

req ifidni ,

xchg

p1, ebx

elseifidni ,

xchg

ebx, p2

else

movebx, p1

xchg

ebx, p2

movp1, ebx

endif

endm

通過條件彙編,使swap功能更健全和高效。

十五  過程和巨集對比和總結

1    過程在被呼叫的時候只有乙份程式副本出現,而巨集在被呼叫的時候,每一次對巨集的呼叫都會出現一次巨集**的副本。

2    過程通常會儲存和恢復暫存器的內容,而巨集通常不會去儲存和恢復暫存器的內容。

3    過程傾向於節省記憶體空間,而巨集傾向於節省執行時間

4   呼叫過程的時候,使用call指令,後面跟著過程的名字,而呼叫巨集的時候直接寫巨集的名字。

5   過程中必須包含ret指令,但是巨集中一定不能寫ret

6   把過程名字放到endp語句之前的標記字段,但是endm之前的標記欄位不需要寫巨集的名字。

7   如果要求呼叫巨集必須傳入引數,可在引數後加:req

8   條件編譯if在使用or或and邏輯時需要將兩個引數用括號括起來,如if(x lt 0)or(y gt 1)

組合語言學習筆記 四

存放資料,最大容量ffffh 16bit暫存器 可以分割成高八 ah 低八 al 兩個暫存器 為什麼能分割?cpu最低讀取單位為位元組 8bit,且 8086 的暫存器為 16 位暫存器,8086 cpu 可以處理 兩種尺寸的資料 字 1byte 8bit,8 位暫存器 位元組 2byte 16bi...

組合語言學習四

本人比較懶,可能懶得對前面的文章進行整理,也不怎麼喜歡寫很多,呵呵。今天往後的系列可能會更懶一些,基本翻譯jones 1 and.bartlett.publishers.introduction.to.80x86.assembly.language.and.computer.architecture...

組合語言學習筆記

學習參考資料 大灰狼 講彙編 資料匯流排,位址匯流排,控制匯流排。位址匯流排有多少條就決定了cpu最大的記憶體使用量。80386有32位位址匯流排,所以它的定址能力就是4g.暫存器 通用暫存器,段暫存器,ax暫存器 通用暫存器,存放資料。高位位元組ah,低位位元組al。實體地址表示方法 位址加法器,...