前幾節,我們進入了保護模式,在保護模式下,除了定址空間增大,運算能力增強外,還有一大好處就是能將c語言引入核心開發,因為c語言編譯後的彙編**,預設的執行環境就是保護模式,所以,只有進入保護模式,那麼c語言才有可能介入到開發流程中,或許大家已經厭倦了組合語言的晦澀,引入c語言,想必我們都能鬆口氣。
下面,我們先看看,彙編如何與c結合,實現相互間的函式呼叫。
彙編與c的交合呼叫
在這個例子中,源**包含兩個檔案:foo.asm, 和 bar.c.程式入口在foo.asm 中,程式先從foo.asm中的_start處開始執行,在_start中,呼叫乙個函式叫bar_func, 而bar_func 函式由bar.c模組來實現,而bar.c實現的bar_func函式中,又呼叫乙個來自foo.asm實現的函式,叫foo_print, 兩個模組的相互互動如下:
接下來我們看看兩個模組的實現,先看看foo.asm
extern bar_func;
[section .data]
arg1 dd 3
arg2 dd 4
[section .text]
global _start
global foo_print
_start:
mov eax, dword[arg1]
push eax
mov eax, dword [arg2]
push eax
call bar_func
add esp, 8
mov ebx,0
mov eax, 1
int 0x80
foo_print:
mov edx, [esp + 8]
mov ecx, [esp + 4]
mov ebx, 1
mov eax, 4
int 0x80
ret
由於需要呼叫另乙個模組的函式,所以開始先要使用extern 宣告,要不然編譯時,編譯器會報錯。由於_start要匯出作為整個可執行程式的入口,因此要用global關鍵字宣告,同時,該模組中的foo_print要匯出給其他介面使用,所以需要用global宣告。
在_start中,在呼叫bar_func函式前,需要傳入引數,c語言的引數傳遞是通過堆疊實現的,函式如果有多個引數的話,那麼最右邊的引數先壓入堆疊,由於**中,我們先壓入arg1, 然後再壓入arg2,所以就相當於以如下方式呼叫來自c語言模組的介面:
bar_func(arg2, arg1);
根據c語言的函式呼叫規則,堆疊的**由呼叫者負責,所以在_start中,bar_func呼叫結束後,需要調整堆疊指標esp, add esp ,8 將堆疊指標往下移動8位元組,這就將開頭壓入堆疊的兩個4位元組引數,arg1,arg2從堆疊上刪除了。
在理解foo_print前,我們需要看看bar.c的實現:
void foo_print(char* a, int len);
int bar_func(int a, int b) else
return
0;}
根據bar.c中,對foo_print的呼叫方式來看,最右邊的引數是13,表示的是第乙個輸入引數,也就是字串的長度。這麼看來在foo.asm的foo_print中,[esp+8] 對應於第二個引數,也就是上面的13,[esp+4]對應第乙個引數,也就是輸入的字串。
mov ebx, 1
mov eax, 4
int 0x80
上面三句實現linux的乙個系統呼叫,該呼叫的作用是將ecx暫存器中指向的記憶體位址中的字元資訊列印到螢幕上。
上面兩個檔案的編譯,需要在linux系統上進行,我用的是ubuntu,先編譯foo.asm:
nasm -f elf32 -o foo.o foo.asm
然後編譯bar.c
gcc -m32 -c -o bar.o bar.c
接下來就可以將兩個模組連線在一起了:
ld -m elf_i386 -o foobar foo.o bar.o
於是在目錄下便會生成乙個可執行檔案 foobar, 通過下面指令可將生成的可執行檔案載入執行:
./foobar
雖然,我們基本實現了將彙編和c語言模組結合的目的,但這種做法有乙個問題,就是最終編譯成的可執行檔案是elf格式,但我們要開發的是系統核心,如果將核心編譯成elf格式,那麼就不能直接將核心載入到記憶體直接執行。所以需要想新的辦法。
我的做法是,將c語言編譯或的.o模組反彙編,將反彙編的**貼到foo.asm裡面,從而形成單個asm檔案,最後編譯這個整合在一起的彙編檔案,直接生成二進位制可執行**。
用反彙編結合c語言和組合語言
在後面的章節中,我們將主要依賴c語言進行核心的開發,只有當c語言力不能逮,特別是需要操作硬體時,才會使用組合語言,下一節,我們看看如何使用c語言繪製作業系統gui.
組合語言開發
1.處理器指令的運算元 表示參與操作物件 具體的常量 儲存在暫存器中的資料 儲存在儲存器的變數 逗號前常是目的運算元,逗號後常是源運算元 mov eax,offset msg 2.偽指令的引數 常量 變數名 表示式等 可以有多個,引數之間用逗號分隔 msg byte hello,assembly 1...
linux下的C語言開發(AT T 組合語言)
同樣是x86的cpu,但是卻可以用不同形式的組合語言來表示。在window上面我們使用的更多是intel格式的組合語言,而在linux系統上面使用的更多的常常是at t格式的組合語言。那什麼是at t格式的彙編 呢?我們可以寫乙個試試看。data message string hello n len...
linux下的C語言開發 AT T 組合語言
同樣是x86的cpu,但是卻可以用不同形式的組合語言來表示。在window上面我們使用的更多是intel格式的組合語言,而在linux系統上面使用的更多的常常是at t格式的組合語言。那什麼是at t格式的彙編 呢?我們可以寫乙個試試看。data message string hello n len...