匯編學習筆記(9)-匯編程序的基本語法(NASM)
前言
從本博文開始,我將主要學習NASM的語法格式,輔以MASM語法的相關了解
一個最簡單的helloword
; 功能描述 helloword org 07c00h ; 告訴編譯器程序加載到7c00處,否則strMess位置的計算會出錯的 section .data strMess: db "Hello, OS world!" strlen equ $-strMess ; 計算 strmess的長度
section .text mov ax, strMess mov bp, ax ; ES:BP = 串地址 mov cx, strlen ;CX = 串長度 mov ax, 01301h ; AH = 13, AL = 01h mov bx, 000ch ; 頁號為0(BH = 0) 黑底紅字(BL = 0Ch,高亮) mov dl, 0 int 10h ; 10h 號中斷 ret jmp $ ; 無限循環
流程控制
1. if-else
if-else 語句其實就是 cmp + 條件判斷語句(如, je,ja,jb jne...)語句的組合
原理: 1. 使用cmp來調整標記寄存器的的標記位
2. 使用對應的條件判斷指令來實現條件轉跳,條件轉跳指令會根據CMP指令對標誌寄存器進行判斷從而根據結果進行轉跳
例子:
mov ax, 2 cmp ax, 2 je a ; if( eax = 2) jmp exit ;else a: cmp ax, 1 ja b ; if(eax > 1) jmp exit ;else b: cmp ax, 3 jb c ; if(eax < 3) jmp exit ;elsec:
2. while 和 for 循環
while是使用了loop指令,loop指令就是判斷CX是否為0,如果cx=0,那麽啥都不做,如果cx 不等於 0 則 cx-- 然後轉跳
例子
; while循環
mov cx, 10 mov bx, 0 add: add bx,1 loop add ; while(ecx != 0)
調用子程序
調用子程序其實不像C/C++那樣有明確的界限,你可以使用任意的過程轉跳指令去調用子程序,可以用非條件轉移指令jmp也可以使用條件轉移指令 je ja jb 等等,我現在所說的就是一般意義上用到的子程序調用指令 call和ret、retf。
Call和jmp一樣也分為段內和段間調用,對應的返回函數就風別是ret和retf,ret是段內返回,retf就是段間返回。
Call和jmp的區別在於 call指令在jmp之前將當前地址給壓棧了。
;段內調用 Call: Push ip Jmp newip Ret pop ip ;段間轉移 Call: Push cs Push ip Jmpnewcs:newip Retf: pop ip Pop cs
具體語法MASM和NASM是略有不同的
MASM:
段內: Call sub1 ; sub1是子過程 Call bx Call [bx] Call var ; var是變量 段間: Call sub1 Call far ptr sub1 Call dword ptr [bx] Call var
nasm 有proc偽指令,用於聲明過程調用語句,具體語法如下
過程調用名 PROC [NEAR|FAR]
....
過程調用名 ENDP
所以MASM可以顯式的指明過程調用需要的是段內還是段間調用。
NASM
段內: Call sub1 Call 立即數 Call bx Call var 段間: Call far [bx] Call 立即數:立即數 Call dword var
我不清楚nasm是否能正對標簽識別出是段內和段間調用,但是我沒發現顯式聲明使用標簽的段間調用指令,但是我看到有博客說,nasm的16位匯編模式是沒有段這個概念。我猜意思可能是段這個概念需要編程者自己去管理,nasm認為所有代碼都在同一個段內。
參數傳遞
匯編的參數傳遞是很靈活,具體只要調用方和被調用方約定好基本是隨便傳遞,基本有三種方式
1. 寄存器傳遞參數
2.內存傳遞參數
3.堆棧傳遞參數
其中有幾點需要註意
1. 環境的保護,意思是在子過程中肯定要用到標誌寄存器和一些其他寄存器,但是如果這裏面有調用者重要的信息的話數據就被破壞了會導致調用者的異常。
2. 數據的清理,比如使用堆棧傳遞數據,使用完之後由調用者清理還是被調用者清理。
具體可以看一下c/c++的幾個調用約定,stdcall fastcall 等等。。
匯編學習筆記(9)-匯編程序的基本語法(NASM)