Copyright (慣C) 2019 宅色夫
連結器 (linker) 是很多 C 程式開發者會忽略的議題,但在 Linux 核心和 Android Open Source Project (AOSP) 這樣包含大量 C 程式的專案中,不難見到連結器的身影,像是客製化的 linker script, 針對 gnu ld / gold linker 的最佳化,甚至是搭配編譯器和連結器選項,提供可掛載的核心模組 (Linux kernel module) 功能。
本講座先回顧在 1970 年 UNIX 剛被創造出來時,系統提供的 loader 是如何演化為 ld (現在的 UNIX 世界的 linker),及其名稱暗示著程式載入器的作用,述及 gcc 和連結器相關的 GNU extension 可如何運用 (如嵌入一份圖片內容到執行檔中),搭配分析工具探討 ELF 執行檔和連結器的交叉運作機制。
另外,慶祝高雄愛河正名為「金銀河」,本講座要探討 gold (別懷疑,真的有一個 linker 名稱就叫做「金」) 如何讓 Linux 核心發揮 Link-Time Optimization (LTO) 效益,編譯出更精簡且更高效的 Linux 核心映像檔。
假設有個二進位檔案名為 blob
,可善用 xxd
工具:
為了解說方便,先製造一個檔案,紀錄長度:
將 blob
納入 ELF 檔案中:
觀察產生的 blob.o
:
寫個測試程式 (test.c
):
編譯、連結,和執行:
對照上面的 105
bytes,符合。
回頭看稍早產生的 blob.o
:
另一個示範 objcopy_to_carray
在 F9 microkernel 有個特徵 Init hooks,允許特定程式碼在核心啟動早期就執行。使用方式:
透過 GNU extension 去指定 ELF section: include/init_hook.h:
在 platform/stm32f4/f9.ld 配置了 .init_hook
的空間:
最後在 kernel/init.c 就清晰了:
複習「你所不知道的 C 語言」: 編譯器和最佳化原理篇 動態連結器篇
Ian Wienand 的電子書: Chapter 7. The Toolchain
對照閱讀:
Optimizing large applications (2013)
原本的執行路徑
elfhack 調整後
7.5
MB of relocations → 0.3
MB.Linktime optimization in GCC (2014)
The missing link: explaining ELF static linking, semantically
In the C programming language, a simple program such as 'hello, world!' exercises very few features of the language, and can be compiled even by a toy compiler. However, for a linker, even the smallest C program amounts to a complex job, since it links with the C library—one of the most complex libraries on the system, in terms of the linker features it exercises.
Shrinking the kernel with link-time garbage collection
Shrinking the kernel with link-time optimization
Shrinking the kernel with an axe