CPU 機器語言的『解譯器』

電腦裡的『中央處理器CPU Central Processing Unit,是計算機的心臟,從開機後就『不停的』執行著指令,這些 指令構成了 CPU 懂得的指令集,按照  CPU 硬體設計架構分成了複雜指令集 CISC ,比如 PC 上用的 Intelx86,和精簡指令集 RISC ,就像樹莓派上用的 ARM。這些指令資料構成的程式存放在隨機記憶體 RAM ── 可以想像成『編了地址』,可以用任意地址讀寫的『記憶單元』 ── 上,由 CPU 依序『解譯』執行程式裡的指令,存取程式裡的資料。這種『儲存程式』的計算機模型依循著 Von Neumann 先生的計算機『建築學』architecture 而設計。在這個 CPU 指令解譯器裡,有一個『指令地址指標』── 稱作程式計數器 Program Counter ── 告訴 CPU 『下一個』指令在 RAM 上的哪個地址。每個指令不論是『算術邏輯運算』、『記憶體資料存取』和『控制陳述』 …等等的指令執行時,都會『更新』這個程式計數器。於是 CPU 就能從硬體設計上開機時所固有『起始的』地址上『讀取』fetch 第一個指令,然後開始『執行』execution,再讀取下一個指令再執行,一直的讀取.執行持續不停。由於指令與資料並不區分,都放在相同的記憶體上,就可能發生把資料當作指令或是將指令當成資料的情況,一般會導致『當機』。這個前面說的指令集,就是 CPU 唯一會的『機器語言』── 以二進制方式儲存在記憶體上的一長排位元組。即使最簡單的『組合語言Assembler 功能僅僅提供機器語言的『助憶碼』Assembly Mnemonic ,也得把用它寫的程式『組譯』成機器碼 Machine Code,CPU 才能執行;更不要說這個組合語言自己也得能執行才能進行組譯。假使你覺得組合語言很有意思,你可以看看劍橋大學開的烘焙 Pi 開發作業系統公開課;或是裸裸金屬樹莓派編程打算寫的一本書;以及樹莓派組合碼部落客。這裡藉著簡單介紹『思考著的極客』一文上用 Gnu as 組譯程式寫的 first.s 原始碼欣賞程式組譯這回事︰

/* — first.s */
/* This is a comment */
.global main /* ‘main’ is our entry point and must be global */
.func main /* ‘main’ is a function */

main: /* This is main */
mov r0, #2 /* Put a 2 inside the register r0 */
bx lr /* Return from main */

作者費心的在短短的八行裡試圖說明 as 的語法,此處把他文中詳細的說明節錄簡譯如下︰『/* …… */』是註解,as 會忽略;『 . 』起頭的字是 as 的宣告 directive,『.global main』 告訴 as main 是像 C main 程式一樣的主程式進入點 ── 開始執行的地址 ──;『.func main』 說明 main 是一個函數 function;as 會忽略『空白行』;『main:main 函數標籤 label;這個函數只有兩行指令,『mov r0, #2』,將 2 移入 move 到 ro 暫存器;和『bx lr』分支交換  branch and exchange 跳到 lr 暫存器所指的地址

首先用 as 組譯程式,將 first.s 組譯成 first.o 目的碼 object code ── 尚未『連接』link 成執行檔 ──︰

as -o first.o first.s

然後用 Gnu C 編譯程式 gcc 連接成 first 執行檔

gcc -o first first.o

測試 first ,這裡的『 $? 』是 bash 外殼程式代表程式傳回值的符號,而『 ; 』是接續執行多個寫在一行上的命令︰

./first ; echo $?

想必你早已猜到輸出的結果是『2』。從前述的 first.s 內容來看,應當可以了解組合語言,為什麼叫做低階程式語言 low level 了,因為它偏向機器語言,人們必須清楚了解所用的 CPU 硬體架構,才能好好的掌握它。

雖說第一個高階程式語言是德國Konrad Zuse 先生的 Plankalkül,大約構想於第二次世界大戰末期,然而第一個廣為使用的卻是福傳 Fortran ── Formula Translation 的縮寫。1957 年IBM 當時的工程師約翰·華納·巴克斯 John Warner Backus 因深切體會到編寫程式困難,需要更好的程式語言所創。他也就是知名的『 BNF 』巴科斯-諾爾範式 Backus–Naur Form 的創始者之一,這個範式 是一種表示無上下文脈絡關係 Context Free 文法語言,可以用來描述 CF 這一類的形式語言,這包括了絕大部分的電腦程式語言。其後又有了 1969 年在 Bell Labs circa 由 Ken ThompsonDennis Ritchie 所發展的 B 語言,然後於 1971 年之際演變成 New B,最終於 1972 年變成了今天的 C 語言 ── After B ──,形成了美麗的『ABC』語言傳奇

事實上 Von Neumann 的計算機架構,對於電腦程式語言的發展,有著極為深遠的影響,產生了現在叫做 Von Neumann 程式語言,與Von Neumann 的計算機架構,同形 isomorphism 同構

program variables ↔ computer storage cells
程式變數 對映  計算機的儲存單元

control statements ↔ computer test-and-jump instructions
控制陳述  計算機的『測試.跳至』指令

assignment statements ↔ fetching, storing instructions
賦值陳述  計算機的取得、儲存指令

expressions ↔ memory reference and arithmetic instructions.
表達式  記憶體參照和算術指令

John Warner Backus 曾經斷言,由於電腦圈長期過度強調 Von Neumann 的程式語言與計算機架構,已經產生了『惡性循環』,使得非此類的語言由於不符合經濟而日漸式微,比方 APL 語言 ── 註︰有興趣的,可以參照這裡在 Raspbian 上安裝 ──。

行文至此,不得不提及 Charles H. Moore 先生,他認為像 asgcc 那樣的程式語言,依循著 compile-link-go 編譯.連接.執行的步驟都該叫做『第三代』的電腦語言,因而想發明『第四代 FOURTH』語言,但由於 IBM 1130 電腦作業系統,限制檔案名稱長度最多個字元,以至於 FOURTH 被迫變成了現今稱作『Forth』的電腦程式語言。這是一個以『堆疊 Stack』為中心,用『字典』定義『』方式的一種交互式 interactive 的編譯.解譯寫程式的環境,十分有趣獨特。有時還真不好說它算是低階還是高階語言,彷彿是種『由低到高』的程式編寫世界。你可以參考這份文件的說明,進到 Forth 的國度裡『逍遙遊』!!