XX的(de)學習日記(嵌入式)三——編譯器背後的(de)故事 - 新聞資訊 - 雲南小程序開發|雲南軟件開發|雲南網站建設-昆明融晨信息技術有限公司

159-8711-8523

雲南網建設/小程序開發/軟件開發

知識

不(bù)管是(shì)網站,軟件還是(shì)小程序,都要(yào / yāo)直接或間接能爲(wéi / wèi)您産生價值,我們在(zài)追求其視覺表現的(de)同時(shí),更側重于(yú)功能的(de)便捷,營銷的(de)便利,運營的(de)高效,讓網站成爲(wéi / wèi)營銷工具,讓軟件能切實提升企業内部管理水平和(hé / huò)效率。優秀的(de)程序爲(wéi / wèi)後期升級提供便捷的(de)支持!

您當前位置>首頁 » 新聞資訊 » 技術分享 >

XX的(de)學習日記(嵌入式)三——編譯器背後的(de)故事

發表時(shí)間:2020-10-19

發布人(rén):融晨科技

浏覽次數:47

編譯器背後的(de)故事

  • 一、可執行程序是(shì)如何被組裝的(de)?
    • 1. 用 gcc 生成 .a 靜态庫和(hé / huò) .so 動态庫
      • 1.1 編輯得到(dào)舉例的(de)程序:hello.h、hello.c和(hé / huò)main.c
      • 1.2 将hello.c編譯成.o文件;
      • 1.3由.o文件創建靜态庫
      • 1.4 在(zài)程序中使用靜态庫
      • 1.5由.o文件創建動态庫文件
      • 1.6 在(zài)程序中使用動态庫
    • 2.Linux下靜态庫.a與.so庫文件的(de)生成與使用
      • 2.1 編輯所需程序
      • 2.1 靜态庫.a文件的(de)生成與使用
      • 2.2 共享庫.so文件的(de)生成與使用
    • 3. 将第一次學習内容的(de)程序進行改編
      • 3.1 完成目标(1)
      • 3.2 完成目标(2)
  • 二、Gcc不(bù)是(shì)一個(gè)人(rén)在(zài)戰鬥。
    • 1. Linux GCC常用命令
      • 1.1 程序準備
      • 1.2 程序的(de)簡單編譯
      • 1.3 程序的(de)分步編譯
    • 2. 比較hello.asm與C代碼生成的(de)可執行文件
      • 2.1 搭建環境:在(zài)Ubuntu上(shàng)安裝nasm

一、可執行程序是(shì)如何被組裝的(de)?

1. 用 gcc 生成 .a 靜态庫和(hé / huò) .so 動态庫

我們通常把一些公用函數制作成函數庫,供其它程序使用。函數庫分爲(wéi / wèi)靜态庫和(hé / huò)動态庫兩種。靜态庫在(zài)程序編譯時(shí)會被連接到(dào)目标代碼中,程序運行時(shí)将不(bù)再需要(yào / yāo)該靜态庫。動态庫在(zài)程序編譯時(shí)并不(bù)會被連接到(dào)目标代碼中,而(ér)是(shì)在(zài)程序運行是(shì)才被載入,因此在(zài)程序運行時(shí)還需要(yào / yāo)動态庫存在(zài)。
我們通過舉例來(lái)說(shuō)明在(zài)Linux中如何創建靜态庫和(hé / huò)動态庫,以(yǐ)及使用它們,在(zài)創建函數庫前,我們先來(lái)準備舉例用的(de)源程序,并将函數庫的(de)源程序編譯成.o文件。

1.1 編輯得到(dào)舉例的(de)程序:hello.h、hello.c和(hé / huò)main.c

hello.c是(shì)函數庫的(de)源程序,其中包含公用函數hello,該函數将在(zài)屏幕上(shàng)輸出(chū)"Hello XXX!"。hello.h爲(wéi / wèi)該函數庫的(de)頭文件。main.c爲(wéi / wèi)測試庫文件的(de)主程序,在(zài)主程序中調用了(le/liǎo)公用函數hello。
hello.h
在(zài)這(zhè)裏插入圖片描述
hello.c
在(zài)這(zhè)裏插入圖片描述
main.c
在(zài)這(zhè)裏插入圖片描述

1.2 将hello.c編譯成.o文件;

無論靜态庫,還是(shì)動态庫,都是(shì)由.o文件創建的(de)。因此,我們必須将源程序hello.c通過gcc先編譯成.o文件。
在(zài)系統提示符下鍵入以(yǐ)下命令得到(dào)hello.o文件。
gcc -c hello.c
通過ls命令查看是(shì)否生成了(le/liǎo)hello.o文件
在(zài)這(zhè)裏插入圖片描述

1.3由.o文件創建靜态庫

靜态庫文件名的(de)命名規範是(shì)以(yǐ)lib爲(wéi / wèi)前綴,緊接着跟靜态庫名,擴展名爲(wéi / wèi).a。例如:我們将創建的(de)靜态庫名爲(wéi / wèi)myhello,則靜态庫文件名就(jiù)是(shì)libmyhello.a。在(zài)創建和(hé / huò)使用靜态庫時(shí),需要(yào / yāo)注意這(zhè)點。創建靜态庫用ar命令。
在(zài)系統提示符下鍵入以(yǐ)下命令将創建靜态庫文件libmyhello.a,并用ls命令查看結果
ar -crv libmyhello.a hello.o

在(zài)這(zhè)裏插入圖片描述

1.4 在(zài)程序中使用靜态庫

靜态庫制作完了(le/liǎo),如何使用它内部的(de)函數呢?隻需要(yào / yāo)在(zài)使用到(dào)這(zhè)些公用函數的(de)源程序中包含這(zhè)些公用函數的(de)原型聲明,然後在(zài)用gcc命令生成目标文件時(shí)指明靜态庫名,gcc将會從靜态庫中将公用函數連接到(dào)目标文件中。注意,gcc會在(zài)靜态庫名前加上(shàng)前綴lib,然後追加擴展名.a得到(dào)的(de)靜态庫文件名來(lái)查找靜态庫文件。
在(zài)程序3:main.c中,我們包含了(le/liǎo)靜态庫的(de)頭文件hello.h,然後在(zài)主程序main中直接調用公用函數hello。下面先生成目标程序hello,然後運行hello程序看看結果如何。
我們輸入以(yǐ)下指令:gcc main.c libmyhello.a -o hello
在(zài)這(zhè)裏插入圖片描述
我們删除靜态庫文件試試公用函數hello是(shì)否真的(de)連接到(dào)目标文件 hello中了(le/liǎo)。
在(zài)這(zhè)裏插入圖片描述
(這(zhè)裏我打錯了(le/liǎo)一段指令,馬了(le/liǎo)别介意: D)
程序照常運行,靜态庫中的(de)公用函數已經連接到(dào)目标文件中了(le/liǎo)。

1.5由.o文件創建動态庫文件

我們繼續看看如何在(zài)Linux中創建動态庫。我們還是(shì)從.o文件開始。
動态庫文件名命名規範和(hé / huò)靜态庫文件名命名規範類似,也(yě)是(shì)在(zài)動态庫名增加前綴lib,但其文件擴展名爲(wéi / wèi).so。例如:我們将創建的(de)動态庫名爲(wéi / wèi)myhello,則動态庫文件名就(jiù)是(shì)libmyhello.so。用gcc來(lái)創建動态庫。
在(zài)系統提示符下鍵入以(yǐ)下命令得到(dào)動态庫文件libmyhello.so,并用ls命令查看
gcc -shared -fPIC -o libmyhello.so hello.o (-o不(bù)可少)
在(zài)這(zhè)裏插入圖片描述

1.6 在(zài)程序中使用動态庫

在(zài)程序中使用動态庫和(hé / huò)使用靜态庫完全一樣,也(yě)是(shì)在(zài)使用到(dào)這(zhè)些公用函數的(de)源程序中包含這(zhè)些公用函數的(de)原型聲明,然後在(zài)用gcc命令生成目标文件時(shí)指明動态庫名進行編譯。我們先運行gcc命令生成目标文件,再運行它看看結果。
輸入以(yǐ)下指令:gcc -o hello main.c -L. -lmyhello
在(zài)這(zhè)裏插入圖片描述
這(zhè)裏出(chū)現了(le/liǎo)錯誤,我們看看錯誤提示,原來(lái)是(shì)找不(bù)到(dào)動态庫文件libmyhello.so。程序在(zài)運行時(shí),會在(zài)/usr/lib和(hé / huò)/lib等目錄中查找需要(yào / yāo)的(de)動态庫文件。若找到(dào),則載入動态庫,否則将提示類似上(shàng)述錯誤而(ér)終止程序運行。我們将文件libmyhello.so複制到(dào)目錄/usr/lib中,再試試。
在(zài)這(zhè)裏插入圖片描述

2.Linux下靜态庫.a與.so庫文件的(de)生成與使用

如前面一樣,我們先生成舉例所需要(yào / yāo)的(de)文件

2.1 編輯所需程序

A1.c
在(zài)這(zhè)裏插入圖片描述
A2.c
在(zài)這(zhè)裏插入圖片描述

A.h
在(zài)這(zhè)裏插入圖片描述
test.c
在(zài)這(zhè)裏插入圖片描述

2.1 靜态庫.a文件的(de)生成與使用

(1) 生成目标文件(XXX.o)
指令如下:gcc -c A1.c A2.c
在(zài)這(zhè)裏插入圖片描述
(2)生成靜态庫.a文件
指令如下:ar crv libafile.a A1.o A2.o
在(zài)這(zhè)裏插入圖片描述
(3)使用.a 庫文件,創建可執行程序(若采用此種方式,需保證生成的(de).a 文件與.c 文件保存在(zài)同一目錄下,即都在(zài)當前目錄下)
指令如下:

cpp gcc -o test test.c libafile.a
./test

在(zài)這(zhè)裏插入圖片描述

2.2 共享庫.so文件的(de)生成與使用

(1)生成目标文件(XXX.o)(此處生成.o 文件必須添加"-fpic"(小模式,代碼少),否則在(zài)生成.so文件時(shí)會出(chū)錯)
指令:gcc -c -fpic A1.c A2.c
(2)生成共享庫.so文件
指令:gcc -shared *.o -o libsofile.so
(3)使用.so 庫文件,創建可執行程序
指令:gcc -o test test.c libsofile.s
在(zài)這(zhè)裏插入圖片描述
當輸入以(yǐ)下指令時(shí):./test
發現出(chū)現錯誤:
在(zài)這(zhè)裏插入圖片描述
原因與之(zhī)前使用動态庫的(de)情況相同:找不(bù)到(dào)對用的(de).so文件,故需将對應 so 文件拷貝到(dào)對應路徑。
指令
如下:sudo cp libsofile.so /usr/lib
在(zài)這(zhè)裏插入圖片描述
同時(shí)可直接使用 gcc -o test test.c -L. -lname,來(lái)使用相應庫文件
其中,
-L.:表示在(zài)當前目錄下,可自行定義路徑 path,即使用-Lpath 即可。
-lname:name:即對應庫文件的(de)名字(除開 lib),即若使用 libafile.a,則 name 爲(wéi / wèi) afile;若要(yào / yāo)使用 libsofile.so,則 name 爲(wéi / wèi) sofile。

3. 将第一次學習内容的(de)程序進行改編

目标:
(1)除了(le/liǎo)x2x函數之(zhī)外,再擴展寫一個(gè)x2y函數(功能自定),main函數代碼将調用x2x和(hé / huò)x2y ;将這(zhè)3個(gè)函數分别寫成單獨的(de)3個(gè) .c文件,并用gcc分别編譯爲(wéi / wèi)3個(gè).o 目标文件;将x2x、x2y目标文件用 ar工具生成1個(gè) .a 靜态庫文件, 然後用 gcc将 main函數的(de)目标文件與此靜态庫文件進行鏈接,生成最終的(de)可執行程序,記錄文件的(de)大(dà)小。
(2)将x2x、x2y目标文件用 ar工具生成1個(gè) .so 動态庫文件, 然後用 gcc将 main函數的(de)目标文件與此動态庫文件進行鏈接,生成最終的(de)可執行程序,記錄文件的(de)大(dà)小,并與之(zhī)前做對比。

3.1 完成目标(1)

(1)編輯所需程序
x2x.c
在(zài)這(zhè)裏插入圖片描述
x2y.c
在(zài)這(zhè)裏插入圖片描述
main.c
在(zài)這(zhè)裏插入圖片描述
(2)将以(yǐ)上(shàng)文件用gcc編譯成.o文件
在(zài)這(zhè)裏插入圖片描述
在(zài)這(zhè)裏插入圖片描述
(3)将x2x.o和(hé / huò)x2y.o用 ar工具生成 .a 靜态庫文件
在(zài)這(zhè)裏插入圖片描述
(4)使用gcc将main.c文件與此靜态庫文件進行鏈接
在(zài)這(zhè)裏插入圖片描述
(5) 運行xymain程序
在(zài)這(zhè)裏插入圖片描述
在(zài)這(zhè)裏插入圖片描述
記錄文件大(dà)小爲(wéi / wèi)16888B

3.2 完成目标(2)

(1)将x2x.o、x2y.o文件用ar工具生成.so 動态庫文件在(zài)這(zhè)裏插入圖片描述
(2)用gcc将main.c文件與此動态庫文件進行鏈接
在(zài)這(zhè)裏插入圖片描述
(3)運行somain
在(zài)這(zhè)裏插入圖片描述
記錄文件大(dà)小爲(wéi / wèi)16888B


二、Gcc不(bù)是(shì)一個(gè)人(rén)在(zài)戰鬥。

GCC 的(de)意思也(yě)隻是(shì) GNU C Compiler 而(ér)已。經過了(le/liǎo)這(zhè)麽多年的(de)發展,GCC 已經不(bù)僅僅能支持 C語言;它現在(zài)還支持 Ada 語言、C++ 語言、Java 語言、Objective C 語言、Pascal 語言、COBOL語言,以(yǐ)及支持函數式編程和(hé / huò)邏輯編程的(de) Mercury 語言,等等。而(ér) GCC 也(yě)不(bù)再單隻是(shì) GNU C 語言編譯器的(de)意思了(le/liǎo),而(ér)是(shì)變成了(le/liǎo) GNU Compiler Collection 也(yě)即是(shì) GNU 編譯器家族的(de)意思了(le/liǎo)。另一方面,說(shuō)到(dào) GCC 對于(yú)操作系統平台及硬件平台支持,概括起來(lái)就(jiù)是(shì)一句話:無所不(bù)在(zài)。

1. Linux GCC常用命令

1.1 程序準備

在(zài)這(zhè)裏插入圖片描述

1.2 程序的(de)簡單編譯

這(zhè)個(gè)程序的(de)一步到(dào)位的(de)編譯指令是(shì)gcc test.c -o main
在(zài)這(zhè)裏插入圖片描述

1.3 程序的(de)分步編譯

實質上(shàng),上(shàng)述編譯過程是(shì)分爲(wéi / wèi)四個(gè)階段進行的(de),即預處理(也(yě)稱預編譯,Preprocessing)、編譯(Compilation)、彙編 (Assembly)和(hé / huò)連接(Linking)。

gcc -E test.c -o test.i //預處理
gcc -S test.i -o test.s //編譯
gcc -c test.s -o test.o //彙編
gcc test.o -o test //連接

執行以(yǐ)上(shàng)指令後生成以(yǐ)下文件,并查看運行結果
在(zài)這(zhè)裏插入圖片描述

2. 比較hello.asm與C代碼生成的(de)可執行文件

2.1 搭建環境:在(zài)Ubuntu上(shàng)安裝nasm

相關案例查看更多