學習一門新的程式語言,大多會從 Hello world 切入。完成後,總覺得離這門語言更親近一步XD
Day2,我會講解如何使用組合語言寫 Hello world 。僅管中間有很多費解的地方,但我也不打算一次講完(限於時間、篇幅)。未講解的地方,可能會在鐵人賽的後半段,隨著時間一一解鎖!
今天的目標,環境建置與實作,歡迎大家在電腦鍵盤前敲敲打打!
P.S 組合語言(簡稱組語)、Operating System(簡稱OS),我會混著使用,請大家自行切換
我使用的是 Mac OS 環境
ruby -e "$(curl –fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null
Homebrew 是一款 Mac OS 的軟體管理器,你可以把它想像成 Python 的 pip 或 Anaconda 的 conda。簡單來說,它們是用來管理各式套件的軟體。
brew install nasm
NASM 全名是 The Netwide Assembler。簡單來說,它是一款可以編譯32、64位元的程式的編譯器。
將以下程式存成 helloworld.asm
global start
section .text
start:
mov rax, 0x2000004 ; System call number for write
mov rdi, 1 ; Write to standard out
mov rsi, msg ; The address of hello_world string
mov rdx, msg.len ; The size to write
syscall ; Invoke the kernel
mov rax, 0x2000001 ; Exit
mov rdi, 0 ; Exit Success = 0
syscall
section .data
msg: db "Hello, world!", 10
.len: equ $-msg
使用組合語言(簡稱組語)開始寫 Hello world .....等等,為什麼用其他語言寫 Hello world 只要一行,用組語寫要這麼多行......? e.g.
Python3print("Hello, world!")
PHPecho "Hello, world!";
JavaScriptconsole.log("Hello, world!");
因為組合語言比起高階語言(e.g Python)更接近機器語言,但因機器語言比起高階語言離人類理解程度又更遙遠,因此在閱讀、編寫上比較不直觀。簡單來說,就只是自己看不習慣XD(多看幾次就會啦)
[前情提要:因為我是用 HackMD 環境在寫文章,它會顯示行數;沒想到這裡的環境竟無法顯示行數。因此下面所說的行數,可能要請讀者去對應,我會盡量提到該行的關鍵字R]
若是第一次看到用機器語言寫的程式,可能會覺的霧煞煞。稍微說明上面的程式:首先看到第10行的 syscall,其作用是OS呼叫核心,以執行程式。因此第6~9行的程式即準備核心的前置工作:包括,第6行的寫入 System call 的代碼、第7行的寫入輸出、第8行的取得 Hello, world! 的字串位置與第9行的取得字串長度。第11行是離開、第12行是返回0代表成功執行程式。
讀者可能好奇,資料是存在哪邊呢?答案是另外儲存(不是存在 .text,而是在 .data)[資料分段會在後續篇章談到]。我們可以看到,第16行的$ : 表示顯示目前記憶體位置。而$ - msg 即代表目前記憶體位置 -(減) msg 這個變數的記憶體位置開頭,因此等於資料總長度("Hello, world!"的總長度)
/usr/local/bin/nasm -f macho64 helloworld.asm
使用 nasm 的指令編譯 helloworld.asm 後,會得到 helloworld.o
ld -macosx_version_min 10.7.0 -lSystem -o helloworld helloworld.o
./helloworld
真開心,花費一段時間終於執行起來了,恭喜大家XD!不過,明天就會是我們的重頭戲,逆向今天所寫的 Hello world,開始更往底層向下鑽!