一步步编写操作系统 79 在c代码中内联汇编
基本內聯匯編是最簡單的內聯形式,其格式為:
asm [volatile] (“assembly code”)
各關鍵字之間可以用空格或制表符分隔也可以緊湊挨在一起不分隔,各部分意義如下:
關鍵字asm用于聲明內聯匯編表達式,這是內聯匯編固定的部分,不可少。
asm和__asm__是一樣的,是由gcc定義的宏:#define __asm__ asm。
因為gcc有個優化選項-O,可以指定優化級別。當用-O來編譯時,gcc按照自己的意圖優化代碼,說不定就會把自己所寫的代碼修改了。關鍵字volatile是可選項,它告訴gcc:“不要修改我寫的匯編代碼,請原樣保留”。volatile和__volatile__是一樣的,是由gcc定義的宏:#define __volatile__ volatile。
“assembly code”是咱們所寫的匯編代碼,它必須位于圓括號中,而且必須用雙引號引起來。這是格式要求,只要滿足了這個格式asm [volatile] (“”),assembly code甚至可以為空。
下面說下assembly code的規則:
提醒一下,即使是指令分布在多個雙引號中,gcc最終也要把它們合并到一起來處理,合并之后,指令間必須要有分隔符。所以,當指令在多個雙引號中時,除最后一個雙引號外,其余雙引號中的代碼最后一定要有分隔符,這和其它編程語言中表示代碼結束的分隔符是一樣的,如:
asm(“movl $9,%eax;””pushl %eax”)正確
asm(“movl $9,%eax””pushl %eax”)錯誤
大家注意,在內聯匯編中,咱們要注意操作數的順序啦,現在是和intel反著的。
給大家舉個例子,見文件inlineASM.c
1 char* str="hello,world\n";2 int count = 0;3 void main(){4 asm("pusha; \5 movl $4,%eax; \6 movl $1,%ebx; \7 movl str,%ecx; \8 movl $12,%edx; \9 int $0x80; \ 10 mov %eax,count; \ 11 popa \ 12 "); 13 }代碼inlineASM.c是演示用匯編代碼直接調用“系統調用”write來打印字符患,該系統調用執行后會返回打印的字符數。
第1~2行定義了兩個全局變量,待打印的字符串是str,count是用來存儲返回值
第4~12行是內聯匯編,這是咱們之前說過的c語言中跨過運行庫直接調用系統調用的實例。這完全是AT&T風格的匯編語句:寄存器前面加前綴%,立即數前面加前綴$,操作數由左到右的順序。似乎看上去很簡單。
第4行將8個通用寄存器壓棧,AT&T中的匯編指令是pusha(intel中的是pushad)。
第5行是傳入第4號系統調用,這就是write的調用號。
第6~8行是為write系統調用傳入參數,前面說系統調用的時候有講過參數傳遞所用到的寄存器,不再贅述。
第9行用int 0x80執行系統調用,在AT&T中立即數的地位比較低,要加$前綴才表示數字為立即數(常數)。
第10行是獲取write的返回值,返回值都是存儲在eax寄存器中,所以將其復制到變量count中。
好啦,編譯運行看結果,如圖
?
大家注意到沒有,inlineASM.c中的變量count和str是定義為全局變量。對的,在基本內聯匯編中,若要引用c變量,只能將它定義為全局變量。如果定義為局部變量,鏈接時會找不到這兩個符號,這就是基本內聯匯編的局限性,簡單的東西往往功能不夠強大,所以咱們還得學下擴展內聯匯編形式,下一節走起。
總結
以上是生活随笔為你收集整理的一步步编写操作系统 79 在c代码中内联汇编的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 等等党胜利!AMD Zen 4架构的新一
- 下一篇: 一步步编写操作系统 2 部署工作环境 2