本次使用的組譯器為 nasm ,其他類似的組譯器還有 masm 與 yasm ,但我們這次不會使用,那環境建置好了就來個慣例的 HelloWorld
extern _main
extern _printf
section .data
HelloWorld: db 'HelloWorld',0
section .text
_main:
push ebp
mov ebp,esp
push HelloWorld
call _printf
add esp,4
pop ebp
retn
將這段程式碼寫進文字編輯器,並在此程式碼的檔案路徑下打開 cmd 並輸入
nasm 檔案名稱.副檔名 -f win32
gcc 檔案名稱.obj -m32
若兩個指令都有成功執行,gcc 會預設輸出執行檔叫 a.exe 可在 gcc 的指令中使用 -o 參數來改變輸出的檔名。得到 a.exe 後便可在 cmd 中鍵入 a 或 a.exe 即可得到輸出為
HelloWorld
得到這行字即代表環境建置成功
我們可以先試著觀察一下這段程式碼,之後都會有主題做更詳盡的解釋,所以現階段我們先觀察就好。
extern _main
extern _printf
這兩行是宣告外部變數
宣告會使用到 _main 與 _printf 函式
可能會有人注意到為甚麼前面會加一個底線,這件事之後的主題會提到,所以先給一個關鍵字供各位查詢 Calling Convention
再來會注意到
section .data
section .text
這裡是將程式碼分成三段,存放程式碼的 .text 、存放已初始化變數的 .data 與存放為初始化變數的 .bss ,在 HelloWorld 中我們沒用到可變變數,所以沒有 .bss 。還有一個很相似的東西叫 segment ,可以去了解看看,據昨天 NASM Tutorial 的網站中,在 Memory Segment 分頁底下有寫到這裡的 section 與 segment 是同樣的作用,要注意這兩個東西大部分是同樣的概念,但若到別的地方就不一定了,例如 ELF 檔,可以到這篇文章稍微了解一下。
HelloWorld: db 'HelloWorld',0
這行是 HelloWorld 變數的定義
這裡能分成三個部份看
HelloWorld:
db
'HelloWorld',0
HelloWorld : 稱為標籤在組語中若有跳轉的時候就需要標籤來作為標記,例如 goto 的用法,直接跳到標籤處。
db 是數據定義,定義該變數每單位要用多大的記憶體去分配。
'HelloWorld',0 是數據初始化的內容 ,後面有一個 0 目前我沒查出一個來源表示作用,但應該會是十進位 ASCII Code ,0 表示 NULL ,若要換行便換成 10 ,即 New Line 。
_main:
push ebp
mov ebp,esp
push HelloWorld
call _printf
add esp,4
pop ebp
retn
這一段便是主要執行的程式碼,相關的 OP Table 可以到這網站去參考。可以注意到正中央的那三行指令,我們先 push 了 HelloWorld 變數進 Stack 中,再去呼叫 printf ,最後再將 esp+4 ,關於 esp 與前後 4 行的解說我會放在後天,所以我們先專注在中間三行,如果請各位先用 C 寫出一支 HelloWorld ,再回來注意我們的組語
#include<stdio.h>
#include<stdlib.h>
int main(){
printf("HelloWorld");
return 0;
}
是不是覺得好像幾乎長的一模一樣 ?
今天先教輸出,接下來幾天我們先補一點理論知識再回來繼續補上輸入。