> For the complete documentation index, see [llms.txt](https://koshizuow.gitbook.io/compilerbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://koshizuow.gitbook.io/compilerbook/machine_code_assembler/assembler.md).

# 什麼是組譯器

由於機械語言是直接給 CPU 看的語言，是站在 CPU 的角度所設計，並沒有考慮到人類讀寫的容易與否。想要透過二進制編輯器來讀寫機械語也不是不可能，但也是非常痛苦的作業。組合語言就是為了這個問題才被發明出來。組合語言和機械語言幾乎是一對一對應的語言，但是對人類來說，組合語言要容易讀寫多了。

一般非直譯式或透過虛擬機器（譯注：如 Java 的 JVM），直接輸出二進制執行檔的編譯器，通常都是輸出組合語言。有些編譯器看起來是直接輸出機械語言，其實多半也是先輸出組合語言，再在背後執行組譯器。本書所做的C編譯器也是輸出組合語言。

把組合語言轉換成機械語言也可以說是「編譯」的一種，但是為了強調輸入是組合語言，又被稱作「組譯」。

讀者可能以前也在別的地方看過組合語言也說不定。如果還沒見過的話，現在正好是認識一下組合語言的好機會。用`objdump`指令，隨便找一個執行檔反組譯看看，看一下該執行檔機械語言轉回組合語言的結果吧。以下是`ls`指令反組譯的結果：

```
$ objdump -d -M intel /bin/ls
/bin/ls:     file format elf64-x86-64

Disassembly of section .init:

0000000000003d58 <_init@@Base>:
  3d58:  48 83 ec 08           sub    rsp,0x8
  3d5c:  48 8b 05 7d b9 21 00  mov    rax,QWORD PTR [rip+0x21b97d]
  3d63:  48 85 c0              test   rax,rax
  3d66:  74 02                 je     366a <_init@@Base+0x12>
  3d68:  ff d0                 call   rax
  3d6a:  48 83 c4 08           add    rsp,0x8
  3d6e:  c3                    ret
...
```

在筆者的環境下，`ls`指令約含有2萬個以上的機械語言指令，反組譯就會變成大概有2萬行篇幅的怪物，上面只放了開頭的一部份。

組合語言基本上是一行一個機械語言指令。舉例來說我們來看下面這行：

```
3d58:  48 83 ec 08           sub    rsp,0x8
```

這行是什麼意思呢？`3d58`表示的是存放該機械語言的記憶體位址。也就是說，執行`ls`指令的時候，該行指令會被放到記憶體的 0x3d58 號位置，等程式計數器跑到 0x3d58 時就會執行該行指令。緊接著的四個16進制數字是實際的機械語言的長相。CPU 把這些值讀進去，然後將其作為指令執行。`sub    rsp,0x8`則是對應該機械語言指令的組合語言。關於 CPU 的指令集我們會逐章解釋，上面這個指令是把 RSP 這個暫存器的數值減掉（sub 是 subtract，減去的英文的開頭）8的指令。
