C語言結合彙編開發系統核心

2021-07-22 13:15:15 字數 2418 閱讀 8236

前幾節,我們進入了保護模式,在保護模式下,除了定址空間增大,運算能力增強外,還有一大好處就是能將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...