iT邦幫忙

2021 iThome 鐵人賽

DAY 2
1
Software Development

Port Alpine Linux to open source RISC-V platform系列 第 2

musl libc 簡介與其 porting(一)

musl libc的起源為當時glibc於設計上有諸多不足之處,例如全靜態連結因NSS機制而有狀況、內部機制甚多而難以維護/移植、組語甚多、pthread實做有bug、子函式庫......等等;Rich Felker在維運EWONTFIX此一網站記載甚多後,決定自己打造一套新的libc/runtime。

然而一個非常大的設計更動是,musl libc不支援lazy binding,也就是在動態連結時,符號解析僅在使用時才作連結。這點在musl的rtld (runtime dynamic loader上的設計非常特別,會在 __dls2 這個phase時,直接運行reloc_all()進行權符號解析[1],若有無法解析的symbol則會拒絕運行、形同於glibc下的LD_BIND_NOW;另一個特點是當時使用dlopen()時,僅有RTLD_NOW被接受。這件事情直到非常後期musl引入了自創的一套流程:deffered binding [2],在dlopen新的shared object時,會盡可能resolve多數的symbol。其中一個有趣的comment如下:〝call-time plt resolver is intentionally not implemented 〞、〝it is a huge bug surface and demands significant amounts of arch-specific code〞這也是musl libc設計的一個重點 — — 他要盡量減少architecture的porting困難。

好的,說到這邊我們切入正題,到底musl libc porting與自身啟動上有什麼部份。

首先最重要的是CRT,也就是所謂的C runtime,這邊掌管了作業系統核心(i.e. Linux elf loader)跳轉進user C program時,最初的初始化與最後的收屍(?)。
然而,出於musl對於RISC-V此類新平台不再支援傳統的_init與_fini,故在 "crt" 此一資料夾下,沒有平台相依的程式碼,僅有stub用的空檔案crtn.c。
平台相依的部份被封裝在 arch/<platform>/crt_arch.h 中,而PIE時使用的Scrt1,與一般的程式的crt1.c一致。
對於RISC-V平台(或多數平台而言)來說,最原初所需要作的事情包含:
global pointer的初始化、傳遞dynamic linking時PT_DYNAMIC segment的資料位置、stack pointer的初始化。
其中gp的值與_DYNAMIC的值為link time才知道,故為weak symbol待linker填入。

接下來,便會跳轉至crt1.c、做完argc與argv的shifting後,直接掉入 src/env/__libc_start_main.c ,開始作幾個重要的處理:
(1) Auxiliary Vector 設定,這是一個許多平台優化程式會常常仰賴的陣列。內含作業系統核心提供的平台資訊,例如有哪些擴增指令集、cache大小、alignment資訊......etc,這點在user program可以使用getauxval()此一函數取得。
(2) Thread Local Storage初始化。在現行multi-threading的世界觀下,thread與thread之間共用除了stack外多數的資源,若真的需要thread專屬的空間存放資料,會使用TLS,而職掌TLS在哪、大小、初始值,就是CRT的工作。
(3) Stack Smash Protector的canary word初始化。在現代的compiler下,為了避免return address被攻擊者覆寫,一個簡單的機制是透過設定canary word,compiler會自動在stack尾巴插入檢查canary word有沒有被破壞的code。不過如果編譯musl libc時有設定no stack protector時,這點會被關閉。

最後,如果user program有好好使用GCC提供的 constructor 修飾字,musl的作者即便很不情願(他多次在許多場合抨擊相關設計),還是會去執行init_array中的function。

到這邊,musl libc CRT的啟動已經完全簡介過一輪,在下一篇時,我們將會開始進行真正平台相依的程式碼移植。

到時會使用的repo在:
https://github.com/Ruinland/musl-rv32port

[1] http://git.musl-libc.org/cgit/musl/tree/ldso/dynlink.c?id=b7a130e0b9195625ea96044ea9fbe99167b112bf#n1689
[2] http://git.musl-libc.org/cgit/musl/commit/?id=6476b8135760659b25c93ff9308425ca98a9e777


上一篇
引言與大綱
下一篇
musl libc 簡介與其 porting(二)Say hello to my little friend!
系列文
Port Alpine Linux to open source RISC-V platform30

尚未有邦友留言

立即登入留言