Day 2 組合語言學習與 Makefile 入門
來解釋這段組語在幹嘛~
1 | ; hello-os |
ORG
指令告訴 nask 程式要從指定的 address 開始,即要把程式 load 到 memory 中指定的 address (這裡總有點半懂不懂)。有這個指令時,Day 1 從計算機結構到組合語言程式入門 提到的 $
不再是 output file 的第幾個 byte,而是代表將要 read 的 memory address。
entry:
是 label,每個 label 都代表一個 address。位置的值是由 assembler 根據 ORG 計算出「label 所在的地方對應的 address」。
MOV
基本上就是 assignment,source 跟 destination 可以是 register、常數或者 memory address。
CPU 裡比較重要的 register 及其完整名稱:
- AX:accumulator
- CX:counter
- DX:data
- BX:base
- SP:stack pointer
- BP:base pointer
- SI:source index
- DI:destination index
這些 register 都是 16 bit。
另外 CPU 還有 8 個 8 bit register:
- AL:accumulator low
- CL:counter low
- DL:data low
- BL:base low
- AH:accumulator high
- CH:counter high
- DH:data high
- BH:base high
這些 register 是上面其中幾個 16 bit register 的高位跟低位而已,不是額外的 register。
那 32 bit register 呢?就是 EAX、ECX、EDX、EBX、ESP、EBP、ESI 跟 EDI 啦~也就是 16 bit register 再擴展一倍,實際上 EAX 有一部分是跟 AX 共用的,跟 8 bit register 與 16 bit register 的關係一樣。
MOV
中,以方括號 [ ]
包起來,表示 memory address。
MOV WORD [678], 123
表示把 123 以 WORD 的大小(16 bit)放到 memory address 678 的地方。數字 123 的二進位表示成 16 bit 是 0000000001111011
,低位 byte 01111011
會放在 address 678(memory address 小),高位 byte 00000000
則會放在 address 679(memory address 大)。
位元組順序(Endianness)是指資料在 memory 或傳輸過程中 byte 的擺放順序。將資料的低位 byte 放在 memory address 小、高位 byte 放在 memory address 大的擺放方式稱為 Little-Endian。反之,資料低位 byte 放在 memory address 大、高位 byte 放在 memory address 小,稱為 Big-Endian。一般 x86 的機器是使用 Little-Endian。
指定 address 的方式,除了用常數,也可以用 register 的值。不過不是所有 register 都可以拿來做這件事,只有 BX、BP、SI 跟 DI 可以。所以 MOV AL, BYTE [SI]
是將 SI register 裡的值當作 address 去 memory 取得一個 byte 的資料並將 assign 給 register AL。另外,MOV
指令有個規則:source 跟 destination 的 byte 數必須相同。能放進 AL 的只有 BYTE,所以上面的指令可以省略 BYTE
變成 MOV AL, [SI]
。
JE
:如果比較結果相等,則 jump 到特定的 address;若不等,則不 jump,繼續做下一個指令。
BIOS 是讓 OS 開發人員可以使用的各種 function 的集合。可以用指令 INT
call 這些 function,它後面是個數字,不同數字代表不同 function,0x10
的功能是控制顯卡。
使用 BIOS 的 function 跟其他 level 的程式 call function 一樣,查要的功能是用哪個數字(像 function name),接著照 function 定義在各 register 放值(像 function 參數),register 設好後用 INT
call function。
HLT
是讓 CPU 進入待機狀態的指令,才不會 infinite loop 瞎跑。
在整個 memory 裡,有些區域是有特定用途、不能隨便用的。其中 0x00007c00
到 0x00007dff
這段是 boot sector 的 loading address。所以 ORG
指令才要寫 0x00007c00
,把這份程式 load 到那個 address 才會被當作 boot sector 來 run~(至於為什麼要是這個 address……不知道又是誰訂的XD)
電腦開機時 BIOS 會在可開機 device 中找 boot signature──在 boot sector 裡最後兩個 byte 0x55 AA
。BIOS 找到這樣的 boot sector,便將 boot sector load 到 memory address 0x00007c00
的位置。接著便開始執行剛 load 進來的 boot record。floppy disk 的整個 boot sector 都是可執行 code(除了最後兩個 byte)。hard disk 的 MBR(Master Boot Record)在(硬碟 boot sector)位置 0x0000
~ 0x01bd
是可執行 code,接著後面是 parition table(0x01be
~ 0x01fd
)以及 boot signature(0x01fe
~ 0x01ff
)。
因為 BIOS 會把 boot sector load 到 memory address 0x00007c00
,所以用 ORG
指令就要寫 0x00007c00
。這樣組譯出來的 machine code 裡的各個 memory address 才會是對的。