日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

如何使用 gcc 構建 c/c++ 項目,大家都很熟悉了,甚至對鏈接器、靜態庫、共享庫等概念,大家也略知一二。然而,對于 ld 鏈接器、linux 操作系統(OS)及應用程序(exec)之間的詳細交互流程,估計就有點懵了。接下來,我將從單個源文件編譯、編譯期鏈接、程序運行期這三個階段入手,揭開應用程序運行背后的奧秘。

單個源文件編譯

單個 c/cpp 文件可以被 gcc 編譯成目標文件(.o 文件),這部分就不過多贅述,大家應該都很熟悉了。二進制目標文件中的 section 有很多,詳細內容可以打開匯編代碼詳細研究下,下圖列出了其中比較常見的段。

詳解 gcc 編譯、鏈接原理—揭開應用程序運行背后的奧秘

這里的目標文件包括 .o 文件及后面提到的庫文件

符號表的作用是什么?

  1. 記錄該目標文件中定義的全局變量及函數;
  2. 記錄該目標文件中引用的全局變量及函數;
詳解 gcc 編譯、鏈接原理—揭開應用程序運行背后的奧秘

Func 是源文件中引用的外部符號,a 是源文件中定義的全局變量

.rela.* 的作用是什么?

全稱 relocation(重定位),記錄編譯器在編譯時不確定的符號地址——針對引用的外部符號。

dynamic 段中保存了可執行文件依賴哪些動態庫。

GOT 段記錄了需要引用的外部符號的地址。

編譯期鏈接

多個 .o 文件可以通過鏈接器(ld)被打包在一起,組合成庫文件。

庫文件又分為靜態庫(.a 文件)和共享庫(.so 文件)。

什么是 ld 呢?它本身也是可執行文件,屬于 GNU 的一部分,將一堆目標文件通過符號表鏈接成最終的目標文件、庫文件和可執行文件。

.a 文件如何生成?

ld 直接將涉及的所有目標文件打包進靜態庫文件。

.so 文件如何生成?

在鏈接生成共享庫文件的過程中,并不拷貝目標文件中涉及的代碼段,只記錄它需要引用的外部符號位置(在哪些目標文件中)。

所有的目標文件、庫文件和可執行文件都有統一的格式,即 ELF,Executable and Linking Format(可執行鏈接格式)。

詳解 gcc 編譯、鏈接原理—揭開應用程序運行背后的奧秘

libstdc++.so 是標準庫文件

上圖中,多個 .o 文件鏈接在一起形成 .a 文件,多個 .o 和 .so 文件也可以鏈接形成 .so 文件,可執行文件也可以由 .a 文件、.so、.o 文件鏈接而成。

程序運行期

如果可執行文件沒有使用共享庫,那么該程序就可以獨立運行,因為它內部所有的符號都有對應的二進制機器碼。這種情況比較簡單,我們這里主要討論下面這種程序運行方式。

如果可執行文件要使用共享庫,那么該程序就不能獨立運行,它在運行時需要使用共享庫的代碼,且對應的兩種使用方式,分別是運行時動態鏈接運行時動態加載

可執行文件的組成

詳解 gcc 編譯、鏈接原理—揭開應用程序運行背后的奧秘

 

ld-linux.so:不是一個可執行程序,只是一個 shell 腳本。作為解釋器,寫在 elf 文件(可執行文件)中,ld-linux.so 先于 main 函數工作,用于查找主程序所依賴的共享庫,實際上可以直接執行 ld-linux.so. 還有另外一種比較常見的是 ld.so,它是個符號鏈接,指向 ld-linux.so.(通過命令 ln -s ld.so ld-linux.so 創建)。

詳解 gcc 編譯、鏈接原理—揭開應用程序運行背后的奧秘

 


詳解 gcc 編譯、鏈接原理—揭開應用程序運行背后的奧秘

 

為什么這里使用解釋器呢?

解釋器的特點是動態特性和可移植性,比如在解釋器執行時可以動態改變變量的類型、對程序進行修改以及在程序中插入良好的調試診斷信息等。而將解釋器移植到不同的系統上,則程序不用改動就可以在移植了解釋器的系統上運行。

同時解釋器也有很大的缺點,比如執行效率低,占用空間大,因為不僅要給用戶程序分配空間,解釋器本身也占用了寶貴的系統資源。

動態鏈接和動態加載的區別

動態加載和動態鏈接都是在程序運行時發生,并將所需代碼拷貝到內存,這點很重要!

關鍵區別是:動態鏈接的流程是 OS 直接把共享庫的代碼拷貝到內存,而動態加載由人工指定(代碼中的 dlopen() 接口)。

動態鏈接需要 OS 的特殊支持,通過動態鏈接方式拷貝到內存的庫代碼可以在各個進程之間共享。而對動態加載而言,可以在各自進程中打開共享庫代碼。

其他概念

ldconfig:這是個可執行程序,隸屬于 GNU,作用是在默認搜尋目錄(/lib和/usr/lib)以及共享庫配置文件 /etc/ld.so.conf 內所列的目錄下,搜索出共享庫文件(lib*.so*),進而創建出 ld-linux.so 所需要的鏈接和緩存文件。緩存文件默認為 /etc/ld.so.cache,此文件保存已排好序的共享庫名字列表。更新緩存使新添加的庫生效,當然系統啟動時會自動運行 ldconfig。

詳解 gcc 編譯、鏈接原理—揭開應用程序運行背后的奧秘

 

ldd:這是 Linux 內核中自帶的腳本,可以用來查看可執行文件鏈接了哪些共享庫

詳解 gcc 編譯、鏈接原理—揭開應用程序運行背后的奧秘

 

strip <可執行文件名> 去除符號表,可以給可執行文件瘦身

使用 objdump、readelf、nm 等命令可以查詢目標文件的詳細內容。

gcc -print-search-dirs 可以查看 gcc 在編譯、鏈接過程中的共享庫搜索路徑。

分享到:
標簽:編譯 gcc
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定