[Little OS Book 筆記] 手榨作業系統:Getting to C

這一系列是我讀 The little book about OS development 的一些實作紀錄,此篇為介紹有關於 C 的使用,讓組合語言和 C 語言可以結合在一起。


組合語言雖然可以很直接地和電腦溝通,但對於人類來說難以理解。C 語言相對親民得多,所以在控制系統上,我們會傾向用 C 語言,除非有必要才會使用組語。接下來會介紹如何由組合語言呼叫 C 語言所寫的函式。以這本 little book about OS 而言,他們使用 cdecl 呼叫慣例,這也是 C 和 C++ 程式的預設呼叫慣例。

堆疊 Stack

C 語言有個很重要的資料結構概念叫做「Stack」。函數內的參數會從右到左依序堆疊到 stack 裡面,並將結果儲存在 eax 暫存器中。用下面簡單的 C 程式碼和組語說明:

int sum_of_three(int arg1, int arg2, int arg3){
    return arg1 + arg2 + arg3;
}

組語:

external sum_of_three   ; 在別的地方定義函式 sum_of_three

push dword 3            ; push arg3
push dword 2            ; push arg2
push dword 1            ; push arg1
call sum_of_three       ; 呼叫函式,並且把定義存在 eax 內

Struct 的大小

接下來要理解的是 struct 資料結構的大小計算,不過這裡我打算獨立一篇文章來討論,所以這邊不多加說明,屆時會再放連結在這邊。

在本次的目的中,主要是強調 packing 和 padding 的概念。

編譯 C 語言

先隨便寫個程式碼,儲存檔名為 kmain.c,裡面有個名字為 kmain 的函式:

void kmain(){}

當我們程式寫好,最後當然還是必須能成功編譯才有用。我們這個迷你的作業系統目前啥都沒有,不能使用任何的標準函式庫,所以會需要很多個 flags(旗標)。

接下來寫個 Makefile。對了,下面是為了閱讀美觀用了很多空白格對齊,但實際操作不要複製下方的檔按,主要是因為 Makefile 內的 tab 和空格有不同的用法,若直接複製下方會有錯誤。

OBJECTS = loader.o kmain.o
CC = gcc
CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \
         -nostartfiles -nodefaultlibs -Wall -Wextra -Werror -c
LDFLAGS = -T link.ld -melf_i386
AS = nasm
ASFLAGS = -f elf

all: kernel.elf

kernel.elf: $(OBJECTS)
    ld $(LDFLAGS) $(OBJECTS) -o kernel.elf

os.iso: kernel.elf
    cp kernel.elf iso/boot/kernel.elf
    genisoimage -R                              \
                -b boot/grub/stage2_eltorito    \
                -no-emul-boot                   \
                -boot-load-size 4               \
                -A os                           \
                -input-charset utf8             \
                -quiet                          \
                -boot-info-table                \
                -o os.iso                       \
                iso

run: os.iso
    bochs -f bochsrc.txt -q

%.o: %.c
    $(CC) $(CFLAGS)  $< -o $@

%.o: %.s
    $(AS) $(ASFLAGS) $< -o $@

clean:
    rm -rf *.o kernel.elf os.iso

我上傳一個正確版本,但很亂:Makefile ,也可以參考原著 Getting to C 的章節

針對 flag 簡單抓幾個解釋一下:

-m32:編譯 32-bit 程式
-nostdlib:不使用標準函式庫
-nostdinc:不要把系統提供的標頭檔給包進來
-fno-builtin:不使用 C 語言內建的函式
-fno-stack-protector:關閉 stack protector
-Wall -Wextra -Werror:把所有警告變為 error

並且把這兩個檔案 kmain.cMakefile 放入和 loader.s 同一層的位置,並且在這個位置執行指令:

make run

正常來說可以看見 Bochs 啟動。記得和之前一樣,在終端機按 c 並 Enter 後,讓它繼續執行。

讓我知道你在想什麼!