什么是機器語言?
機器語言就是由二進制數字構成的程序,CPU 可以直接對其解釋、執行。
匯編語言、C 語言、JAVA、BASIC 等編程語言編寫的程序,也都需要先轉換成機器語言才能被執行。機器語言有時也叫作“原生代碼”(Native Code)。
本篇文章我們就來學習一下如何編寫匯編語言,匯編語言是低級語言,所以它是最接近機器語言的編程語言。
學習匯編語言,能讓你更深刻的理解計算機的運行機制和原理,使你猶如撥云見日, 找到長期困惑著自己的問題的答案,不僅能因“我能看懂程序了”而獲得成就感,更能因發現“計算機原來很簡單啊”而信心倍增。
使用匯編語言編寫一段程序然后讓計算機運行你編寫的程序,你就知道計算機是如何把匯編語言轉換成機器語言執行的。
你可能會問,我們為什么不直接使用機器語言編寫程序呢?原因就是機器語言是一堆的0和1的組合,但是每個組合都是有特定的含義的指令或數據,所以對人來說,如果只看0和1的話很難判斷出各個組合都表示什么。
簡單地說,就是機器語言不適合人類書寫和閱讀。
于是就有人發明了匯編語言,可以用一些英文單詞或者英文簡寫來表示指令功能,這種類似的英語單詞叫作“助記符”,使用助記符的編程語言叫作“匯編語言”。
無論是使用機器語言還是匯編語言,所實現的功能都是一樣的, 區別只在于程序是用數字表示,還是用助記符表示。
也就是說,如果理解了匯編語言,也就理解了機器語言,更進一步也就理解了計算機 的原始的工作方式。
匯編語言的語法十分簡單,以至于語法只有一個,即把“標簽” “操作碼(指令)”和“操作數(指令的對象)”并排寫在一行上,僅此而已。
如下是一段匯編語言:
標簽 操作碼 操作數
LD A, 207
OUT (2), A
LD A, 255
OUT (2), A
LD A, 207
OUT (3), A
LD A, 0
OUT (3), A
LOOP: IN A, (0)
OUT (1), A
JP LOOP
標簽的作用是為該行代碼對應的內存地址起一個名字。
編程時如果總要考慮這一行的內存地址是什么?就會很不方便,所以在匯編語言中用標簽來代替地址。用匯編語言編程時可以在任何需要標簽的地方貼上名稱任意的標簽。
在上述代碼程序中,使用了名稱為“LOOP:”的標簽,操作碼就是表示“做什么”的指令。
因為用助記符表示的指令是英語單詞的縮寫,比如 LD 是 Load(加載)的縮寫,所以多多少少能猜出其中的含義。匯編語言中提供了多少種助記符,CPU 就有多少種功能。
比如Z80 CPU 的指令全部加起來有 70 條左右。
CPU 的寄存器、內存地址、I/O 地址或者直接給出的數字都可以作為操作數。
如果某條指令需要多個操作數,那么它們之間就要用逗號分割。操作數的個數取決于指令的種類。也有不需要操作數的指令,比如用于停止 CPU 運轉的 HALT 指令。
匯編語言的語法和英語祈使句的語法很像。對比英語的祈使句 Give me money 和匯編語言的語句,就可以看出在英語的祈使句中,一 開頭放置了一個表示“做什么”的動詞,這個動詞就相當于匯編語言中的操作碼。
在動詞后面放置了一個表示“動作作用到什么上”的賓語, 這個賓語就相當于匯編語言中的操作數。
因為程序的作用是向 CPU 發出指令,而且編程語言又是由說英語的人發明的,所以編程語言與英語祈使句類似也就不足為奇了。
構成機器語言的是二進制數,而在匯編語言中,則使用十進制數和十六進制數記錄數據。若僅僅寫出123這樣的數字,表示的就是十進制數;而像123H這樣在數字末尾加上了一個H(H 表示 Hexadecimal, 即十六進制數),表示的就是十六進制數。
這里先把主要的指令列在如下表中,請大家粗略地瀏覽一下。
在瀏覽的過程中請注意這些指令的分類,按功能這些指令可以分成運算、與內存的輸入輸出和 與 I/O 的輸入輸出三類。
這是因為計算機能做的事也只有輸入、運算、輸出這三種了。 操作數表示的是指令執行的對象。
指令的種類 |
助記符 |
功能 |
運算指令
|
ADD A, num ADD A, reg SUB num SUB reg INC reg DEC reg AND num AND reg OR num OR reg XOR num XOR reg SLA reg SRA reg SRL reg CP num CP reg |
把數值 num 加到寄存器 A 的值上 把寄存器 reg 的值加到寄存器 A 的值上 從寄存器 A 的值中減去數值 num 從寄存器 A 的值中減去寄存器 reg 的值 將寄存器 reg 的值加 1 將寄存器 reg 的值減 1 計算寄存器 A 的值和數值 num 的邏輯積 計算寄存器 A 的值和寄存器 reg 的值的邏輯積 計算寄存器 A 的值和數值 num 的邏輯和 計算寄存器 A 的值和寄存器 reg 的值的的邏輯和 計算寄存器 A 的值和數值 num 的邏輯異或 計算寄存器 A 的值和寄存器 reg 的值的邏輯異或 對寄存器 reg 的值進行算數左移運算 對寄存器 reg 的值進行算數右移運算 對寄存器 reg 的值進行邏輯右移運算 比較寄存器 A 的值和數值 num 的大小 比較寄存器 A 的值和寄存器 reg 的值的大小 |
內存與 CPU 之間的輸入 輸出指令 |
LD reg, num LD reg1, reg2 LD (num), reg LD (reg), reg
PUSH reg POP reg |
把數值 num 寫入到寄存器 reg 中 把寄存器 reg2 的值寫入到寄存器 reg1 中 把寄存器 reg 的值寫入到地址 num 上 把寄存器 reg2 的值寫入到存放在寄存器 reg1 中的地址上 把寄存器 reg 的值寫入到棧中 把由棧頂讀出的數據存放到寄存器 reg 中 |
I/O 與 CPU 之間的輸入 輸出指令 |
IN A, (num) IN reg, (C)
OUT (num), A OUT (C), reg |
從地址 num 中讀出數據,存放到寄存器 A 中 從存儲在寄存器 C 中的地址上讀出數據,存放到 寄存器 reg 中 把寄存器 A 的值寫入到地址 num 上 把寄存器 reg 的值寫入到存儲在寄存器 C 中的地址上 |
程序流程控 制指令 |
JP num |
使程序的流程跳轉到地址 num 上,接下來從那個 地址上的指令開始執行 |
CALL num RET HALT |
調用存放在地址 num 上的子例程 從 子例程中返回 中止 CPU 的運行 |
歡迎關注我,學習更多計算機知識!