日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

一步步编写操作系统 69 汇编语言和c语言共同协作 70

發布時間:2023/12/10 windows 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一步步编写操作系统 69 汇编语言和c语言共同协作 70 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

由于有了上一節的鋪墊,本節的內容相對較少,這里給大家準備了兩個小文件來實例演示匯編語言和c語言相互調用。

會兩種不同語言的人,只是掌握了同一件事物的兩種表達方式。人在學習一種新語言時,潛意識里是建立了語言符號與事物形象的映射關系,比如我們在學習grape這個單詞時,我們之所以認為它就是我們所認知的葡萄,是因為我們知道這兩個名詞都是在描述同一種圓圓的、黑紫色、甜酸的這一水果的形象,如果腦子中不存在這個形象的話,不光是學不會grape這個英文單詞,就連中文的葡萄也不知道是何意。總之,對于具體的事物,一定是先有其形象,再有其描述,這樣才能理解該事物,了解了事物的本質形象后,無論該事物的名字怎樣變化,我們都能將它們相互轉換。

也許有同學會問,以上這些所說的目的是什么?各位觀眾稍安勿燥,馬上就要入戲啦^_^。

“匯編語言和C語言可以互相調用”,這句話并不是如表面陳述的那樣,似乎是兩種語言能直接交流,其實并不是這樣。c語言和匯編語言完全是不同的東西,它們怎么能認識對方呢。這就像跟不懂漢語的人說漢語,那人聽了肯定會暈頭轉向的,除非身邊有個翻譯幫忙轉述,這個翻譯所做的工作實質上是在腦子中找到這種語言所描述的事物形象,然后給出這種事物形象的另一種語言表達,這個事物形象才是翻譯的核心。這有些類似上面提到的葡萄的例子,在同一種指令集上的各種計算機程序語言,最終也要編譯為那些相同的機器碼,這些機器碼便是高級語言的本質形象。對于上面提到的翻譯,在計算機世界里,就是編譯器,只不過這個翻譯是有多個,例如本書所說的c語言編譯器gcc和匯編語言編譯器nasm,它們能在一起配合,是因為它們都懂機器語言。舉個例子,就像小明只會漢語和英語,小紅只會漢語和法語,若他們之間在交流時,小明說英語,小紅說法語,他倆相互都聽不懂,所以,當說英文的小明想跟說法語的小紅借作業時,他必須用漢語告訴小紅。

編譯器知道高級語言所描述的事物形象是機器碼,所以各種編譯在高級語言方面的交流,本質上都是將它們都變成統一的機器碼后實現的。

吼吼,一不小心又說多了,不知道我表達清楚了沒有,反正話題就此結束啦,小弟這里給各位看官準備了兩個小文件:C_with_S_c.c和C_with_S_S.S。大家不用細看,快速瀏覽一下即可,在代碼后面我還有話說呢

C_with_S_c.c

1 extern void asm_print(char*,int);2 void c_print(char* str) {3 int len=0;4 while(str[len++]);5 asm_print(str, len);6 }

C_with_S_S.S

1 section .data2 str: db "asm_print says hello world!", 0xa, 03 ;0xa是換行符,0是手工加上的字符串結束符\0的ascii碼。4 str_len equ $-str56 section .text7 extern c_print8 global _start9 _start:10 ;;;;;;;;;;;; 調用c代碼中的函數c_print ;;;;;;;;;;;11 push str ;傳入參數12 call c_print ;調用c函數13 add esp,4 ;回收??臻g1415 ;;;;;;;;;;;;;;;;;;; 退出程序 ;;;;;;;;;;;;;;;;;;;;16 mov eax,1 ;第1號子功能是exit系統調用17 int 0x80 ;發起中斷,通知linux完成請求的功能。1819 global asm_print ;相當于asm_print(str,size)20 asm_print:21 push ebp ;備份ebp22 mov ebp,esp23 mov eax,4 ;第4號子功能是write系統調用24 mov ebx, 1 ;此項固定為文件描述符1,標準輸出(stdout)指向屏幕25 mov ecx, [ebp+8] ;第1個參數26 mov edx, [ebp+12] ;第2個參數27 int 0x80 ;發起中斷,通知linux完成請求的功能。28 pop ebp ;恢復ebp29 ret

代碼C_with_S_c.c中的函數c_print是被匯編代碼C_with_S_S.S調用的,在c_print的實現中,它又調用匯編代碼中的asm_print。它們的關系如圖

?

下節再解釋代碼,先去吃飯了。

接上節,前文請見“一步步編寫操作系統 69 匯編語言和c語言共同協作”,

本節是對前文的代碼說明,代碼再貼過來,C_with_S_c.c如下:

1 extern void asm_print(char*,int);2 void c_print(char* str) {3 int len=0;4 while(str[len++]);5 asm_print(str, len);6 }

代碼C_with_S_c.c的第1行是聲明外部函數asm_print,通知編譯器這個函數并不在當前文件中定義。我們知道它定義在文件C_with_S_S.S中,但編譯器是不知道的,所以只能在鏈接階段將此函數重新定位,編排地址。

第2~6行是c_print的實現,在它的內部,它又調用了匯編代碼C_with_S_S.S中的函數asm_print,經過第1行的聲明,我們要給它提供兩個參數:字符串的起始地址及長度。

特別強調一下,由于這里并不打算把c標準庫也鏈接進來,所以在求字符串長度時,我們不能用string.h中的strlen函數。也就是說即使include <string.h>將其strlen的聲明加進來,沒有strlen實現本身所在的.o文件也是不行的。函數聲明的作用是:一方面是告訴編譯器該函數的參數所需要的棧空間大小及返回值,這樣編譯器能為其準備好執行環境,另一方面是如果該函數是在外部文件中定義的,一定要在鏈接階段時將其對應的目標文件一塊鏈接進來。所以這里第3~4行通過while循環求字符串的長度。字符串結尾必須是空字符’\0’才行,否則while就是死循環了。這個字符串是代碼C_with_S_S.S提供的,我們轉過去看看。

1 section .data2 str: db "asm_print says hello world!", 0xa, 03 ;0xa是換行符,0是手工加上的字符串結束符的ascii碼。4 str_len equ $-str56 section .text7 extern c_print8 global _start9 _start:10 ;;;;;;;;;;;; 調用c代碼中的函數c_print ;;;;;;;;;;;11 push str ;傳入參數12 call c_print ;調用c函數13 add esp,4 ;回收??臻g1415 ;;;;;;;;;;;;;;;;;;; 退出程序 ;;;;;;;;;;;;;;;;;;;;16 mov eax,1 ;第1號子功能是exit系統調用17 int 0x80 ;發起中斷,通知linux完成請求的功能。1819 global asm_print ;相當于asm_print(str,size)20 asm_print:21 push ebp ;備份ebp22 mov ebp,esp23 mov eax,4 ;第4號子功能是write系統調用24 mov ebx, 1 ;此項固定為文件描述符1,標準輸出(stdout)指向屏幕25 mov ecx, [ebp+8] ;第1個參數26 mov edx, [ebp+12] ;第2個參數27 int 0x80 ;發起中斷,通知linux完成請求的功能。28 pop ebp ;恢復ebp29 ret

在代碼C_with_S_S.S的第2行,定義待打印的字符串時,在結尾人為的加了個0,它就是空字符’\0’的ascii碼。

第8~9行是將_start導出為全局符號,為的是給鏈接器用的,之前解釋過了。

為了在匯編文件中引用外部的函數(未必是c代碼中的),需要用extern來聲明所需要的函數名。

由于我們用到了外部的函數c_print,所以在第7行用extern c_print來聲明c_print函數是外部的。第11~13行是為外部函數c_print壓棧傳參,調用它后清理??臻g。

第16~17行是調用exit系統調用告訴linux我要正常退出。

在匯編語言中導出符號名是用global關鍵字,這在之前說_start時大伙已有所耳聞,global是將符號導出為全局屬性,對程序中的所有文件可見,這樣其它外部文件中也可以引用被global導出的符號啦,無論該符號是函數還是變量。

由于在c代碼文件C_with_S_c.c中也調用了這里的asm_print函數,所以為了讓外部代碼可以引用asm_print。我們在第19行用global asm_print將其導出。

第20行之后是asm_print的實現,相信大家已經非常明白了,不解釋。

好啦,通過這兩個例子我相信大伙兒已經掌握c和匯編混合編程的方法啦,確切說是方法之一。對于這種匯編代碼和C代碼單獨編譯的方式還是較容易的,以后咱們會講C內聯匯編的方式難為難為大家的,玩笑玩笑,只要用心沒有學不會的(聽上去似乎覺得更難了^_^,沒事沒事)。

有關混合編程的部分就說完了,總結一下:

  • 在匯編代碼中導出符號供外部引用是用關鍵字global,引用外部文件的符號是用關鍵字extern。
  • 在C代碼中只要將符號定義為全局便可以被外部引用(一般情況下無須用額外關鍵字修飾,具體請參考c語言手冊),引用外部符號時用extern聲明即可。

好了,大爺再來玩哦。

總結

以上是生活随笔為你收集整理的一步步编写操作系统 69 汇编语言和c语言共同协作 70的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。