組合語言與程序呼叫
組譯器
如果組合語言是可讀的文字,機器碼是處理器真正吃進的原始位元,那就得有東西把一邊翻成另一邊。這個翻譯器就是組譯器(assembler)。把它想成一位極度照字面辦事的書記:你遞給它一串用文字和數字寫成的指令清單,它就照順序為每一道蓋出精確的位元樣式,毫無創意、也不自作主張。
組譯器的工作大多是機械式的。每讀一行,它就查出運算碼(opcode,也就是 add、lw、beq 等的位元代碼),把暫存器編號與任何立即值塞進指令的各個欄位,再寫出對應的機器字組。它還維護一張符號表(symbol table):看到像 loop: 這樣的標籤,就記下那個位置的位址,好讓之後分支到 loop 時能填入正確的數字。多數組譯器會掃過檔案兩遍:第一遍找出每個標籤落在哪,第二遍在所有位址都已知後再吐出位元組。
它的輸出通常還不是能直接執行的程式,而是目的檔(object file):機器碼,加上一張表,記錄它定義了哪些符號、又還需要從別處取得哪些。之後再由連結器把多個目的檔縫合起來。組譯器比編譯器簡單得多,因為它幾乎不重排、不最佳化,忠實反映你寫的內容。正是這份忠實,讓人在需要把機器控制到位元層級時,選擇使用組合語言。
第一遍時組譯器讀到 loop: ... beq t0, zero, loop,記下 loop 位於位址 0x100。第二遍時它算出分支位移(目標位址減去目前位址),把這個數字烤進 beq 指令裡,讓跳躍精準落在 loop 上。
兩遍流程:先找出所有標籤的位址,再以正確的位移吐出機器碼。
組譯器幾乎逐行在同一個 ISA 內翻譯;編譯器則翻譯一整套不同的語言(如 C),並且可以自由重組。別把兩者混為一談。
另見