寫作業系統無可避免一定會接觸到組合語言, 但若是能將 C 語言執行環境準備好, 應該不會有人不想用 C 來繼續完成 OS。這個程式測試在 x86 保護模式中, 建立 c runtime 環境。
一開始的我很單純, 以為設定好 stack, 就可以快樂的使用 c 語言了, 而事實上, 的確也可以使用 c 語言, 但執行的結果是不是正確, 那可就不一定了。
ckmain, cckmain 是我用來模擬 C 語言轉成組合語言的部份 (gcc -S k.c 即可得到) 。和
之前錯誤的版本最大不同之處是 (當然一樣要將 stack 設定好):
30 #LABEL_DESC_CODE32: Descriptor 0, (SegCode32Len - 1), (DA_C + DA_32)
31 LABEL_DESC_CODE32: Descriptor 0, 0xfffff, (DA_C + DA_32)由於
LABEL_DESC_CODE32 這個 gdt entry 沒有包含 C function kmain 的大小, 30 那行只有設定到組合語言程式碼的大小, 沒有包含到 k.c 的 kmain function, 透過 objdump -D 5mc.elf 可以得知 kmain 會接在組合語言的後面, 自然 kmain 的部份就超過
(SegCode32Len - 1) 的長度, 造成某例外的發生, 我猜是 #GP 吧!
程式首先進入 x86 保護模式, 呼叫 c function kmain, kmain 呼叫組合語言 write_mem8 在螢幕上印出一個字元。
k.c 會呼叫
write_mem8 填入 address, 以 0xb8000 為 base, address 是 offset, 在螢幕上秀出一個字元。
接下來的 c runtime 環境:
static array - static const u32 hor_regs[] = { 320, 'A'};
以上的 static array 會翻成以下的組合語言:
68 .section .rodata
69 .align 4
70 .type chor_regs, @object
71 .size chor_regs, 8
72 chor_regs:
73 .long 320
74 .long 0x5a # Z
37 write_mem8(160*2+2, 'N');
翻成:
402 .globl cckmain
403 .type cckmain, @function
404 cckmain:
405 pushl %ebp
406 movl %esp, %ebp
407 subl $24, %esp
408 movl (chor_regs+4), %eax
409 movzbl %al, %edx
410 movl (chor_regs), %eax
411 movl %edx, 4(%esp)
412 movl %eax, (%esp)
413 call write_mem8
414 leave
415 ret
但是我目前沒辦法處理 408, 410, 需要改成以下的寫法才可以正確處理 chor_regs 位址。
408 movl (chor_regs+4-LABEL_DATA), %eax
409 movzbl %al, %edx
410 movl (chor_regs-LABEL_DATA), %eax
所以目前在 C 語言只能使用存在 stack 的變數。
在經過幾天的測試後, 目前已經可以使用 static array。
將這個 gdt entry 的 base 設定從 %cs:LABEL_DATA (真實模式的定址法) 改成 %cs:0 (真實模式的定址法), 這樣就不用在減掉 LABEL_DATA, 用以下的程式碼就可以 access chor_regs 的 data。其他細節請參考完整 source code。
408 movl (chor_regs+4), %eax
409 movzbl %al, %edx
410 movl (chor_regs), %eax
我終於理解
30 天打造 OS 裡頭寫的:「 c 語言從來沒有直接讀寫記憶體指令」的意思。
以上的 c code 會被 gcc 翻成
在 x86 保護模式的分段記憶體管理 (還沒使用分頁管理), $753824 (0xb8000+160) 並不一定就是 0xb8000+160 這個 video ram address, movb $68, (%eax) 其實可以看成 movb $68, %ds:(%eax), 而這位址其實是 base + 0xb8000+160, 若是 %ds 這個 selector 指的 gdt entry base 不是 0, 那就不會 access 0xb8000+160 這個位址。
不過和上面的 static array 好像有點衝突, 我無法讓 %ds 的 gdt entry base 指在 %cs:0 (真實模式的定址法) 又同時指在 0 (絕對位址), 所以目前 c runtime 環境無法支援
code 11 的寫法。
x86 真實模式 c runtime 版本:
http://descent-incoming.blogspot.com/2011/10/build-c-runtime-environment-in-x86-real.html
c function 參數
不傳入參數
在 c function 使用自動變數
傳入參數
在 c function 使用自動變數
傳回參數
越深入越搞不定 c runtime 執行環境。
目前的困難:
同一個 c function - a , b call a ok, b call c, c 再 call a 就 fail。
array 變數傳入 function 內似乎也是錯的。
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。