Xcode構建過程的后臺工作(四)(WWDC2018 Behind the Scenes of the Xcode Build Process字幕搬運)

Xcode構建過程的后臺工作(一)構建過程
Xcode構建過程的后臺工作(二)clang構建
Xcode構建過程的后臺工作(三)swift構建

構建過程:鏈接

這是 Xcode構建過程的最后一步。

首先瀏覽一下我們要討論的內容。我們將討論鏈接器是 什么,它所采用的輸入,即dylib和目標文件及其定義。還會講到符號及其內容。最后會舉例總結,因為內容比較難懂。

鏈接器是什么

鏈接器是構建中的最后一個過程。我們所做的是將兩個編譯器構建的所有.o文件 組合成一個可執行文件。它所做的就是移動和修補代碼。 它無法創建代碼,這 很重要,我將在示例中顯示。我們有兩種輸入文件。第一個是目標文件(.o),在構建過程中產生。第二個是庫,包括dylib,tbd和.a文件或靜態文檔。

符號(symbols)

符號是一個代表代碼或數據片段的名稱。當一個函數調用另一個函數,這些片段可能會指向其他符號。符號可以有很多影響鏈接器行為方式的屬性。我只舉一個 弱符號的例子。弱符號的注釋表示當我們在系統上運行或者執行文件時它可能不存在。還有可用性標記,標記這個API用于iOS12,那個API用于iOS11.這就引出了現在的主題鏈接器。鏈接器可以確定哪些符號肯定會出現和哪些符號可以在運行時處理。如前所述,語言可以通過命名修飾將數據編碼為符號。在C++和Swift中都能看到。所以符號就是指代碼和數據的名稱。

目標文件

目標文件就是代碼和數據的集合。它們不可執行。因為是編譯代碼,所以還沒有完成。還有缺失就需要鏈接器整合和修復。每個文件的片段都用符號表示。例如對于printf函數,就以符號代替代碼。對于PetKit的代碼后文會展示。

片段可能引用未定義的符號。 因此,如果您的.o文件引用另一個.o文件中的函數,那么.o文件是未定義的。鏈接器將找到那些未定義的符號并進行匹配。所以目標文件是編譯器操作的輸出。那么什么是庫?庫是定義符號的文件,但不屬于構建的目標。我們有動態庫,那些Mach-O文件,顯示了可執行文件的代碼和數據片段。這些是系統的一部分。這就是我們的框架。你也可能會用自己的框架。

還有TBD文件,基于文本的dylib文件。在為iOS和macOS制作SDK時,會有所有這些dylibs和以及您可能想要使用的功能,如MapKit和WebKit。但是我們不想把所有這些跟SDK一起加載,因為它會很大而且編譯器和鏈接器不需要它,它只在運行程序時有用。因此,我們創建了stub dylib,刪除所有符號的主體,只留下名稱。完成之后,轉用文本表示,這對我們來說更容易使用。目前,它們僅用于分發SDK以減小大小。所以你在項目中看到它們時不必擔心,它們只是符號。

最后是靜態庫(static archives)。靜態庫是使用AR工具構建的.o文件的集合,也可能是lib,它是lib工具的包裝器。根據AR操作文檔,AR創建并維護的文件組,將它們合并為一個庫。聽起來很像TAR文件或ZIP文件,這正是它的本質。實際上,.a格式是UNIX在使用更強大的工具之前使用的原始庫格式。但是現在的編譯器和連接器可以完全理解它們,所以繼續使用它們。它就只是個檔案 文件。值得注意的是,它們孕育了動態鏈接,在過去所有代碼都會被存檔。因此, 不能使用的是一個函數涵蓋所有C庫 。所以行為是,如果.o文件中有符號,我們會將整個.o文件從庫中拉出來。但是不會引入其他.o文件。如果你在它們之間引用符號,只要帶入即可。如果你是非符號行為,比如靜態初始化程序,或者將它們重新導出為您自己的dylib的一部分,您要明確地用到強制加載,或定制加載讓鏈接器提取所有或者這些文件,即便之間沒有關聯。我們通過一個例子串聯起這些內容。

image.png

上面是playSound函數的例子,只看寵物不聽聲音有什么樂趣?cat上有一個調用playSound的函數。上圖右邊是生成的程序集。輸出文件是cat.o。字符串purr.aac,是AAC聲音文件。這會被復制到cat.o. 您會注意到名稱purr文件不見了。因為它是靜態的。如果你熟悉C語言,這是非導出命名。沒有其他人可以引用它。既然如此,我們不需要它,排除掉。


image.png

然后我們看到Cat purr變成了符號:-[Cat purr]。跟預想的差不多。


image.png

然后我們要把這個變量傳遞給playSound。這里出現了兩個指令,這是因為我們不知道這個字符串最后在可執行文件中的位置,我們沒有具體的地址 。 但是我們知道RM64就是這個程序集,它最多可能需要兩條指令。所以編譯器給我們留下了兩條指令。它留下符號偏移量,值為PAGE和PAGEOFF,鏈接器之后回來修復。 最后,既然已經將字符串加載到x0中,我們可以調用playSound,我們寫入__z9playSoundPKc。這是一個變形的符號,如果仔細看會看到cat.mm,這是Objective-C++。playSound實際上是一個C++函數。所以如果你不熟悉,你可以在終端輸入命令。
image.png

如果運行Swift-demangle并傳入符號,然后反修飾。沒有用,它不是swift的符號。但是C++ 反修飾器C++ filts告訴我們這實際上是playSound的符號。 除了playSound,它還有一個實參。這個參數是一個const char* 因為C++會將更多信息編入修飾符號中。現在有了.o文件,實際構建中會有更多。那我們該怎么做呢?
image.png

首先,構建系統將把所有.o作為輸入傳遞給鏈接器。鏈接器會創建一個文件來放入它們 。這里構建的PetKit,是PetWall的內嵌框架。 因此,我們只要復制,創建一個文本片段用來保存app的所有代碼的。然后復制cat.o到這里。但是要分成兩部分,一個用于字符串,一個用于可執行代碼。現在已知這些東西的絕對地址,因此 鏈接器可以重寫cat.o,以從特定偏移量加載。 你會注意到第二條指令就消失了。它被一個null指令代替,沒有任何行動。但我們無法刪除 指令,因為我們無法創建或刪除代碼,這會打亂所有已完成的工作。所以與其刪除,不如替換為無行動。

最后是分支。我們有一個未定義的符號,我們將繼續瀏覽所有已經導入的.o文件。


image.png

所以我們將開始查看靜態庫,上圖是PetSupport.a。在PetSupport.a中有幾個文件,包括PetSounds.o。大家能看到匹配playSound的符號。 所以我們把它拉進來。PetCare.o不能被引入,因為.o文件沒有任何符號能被app的其他部分引用。我們把它拉進來,但現在需要_open,但是我們沒有定義。拉入的對話已經變成_open $stub。為什么呢?因為我們發現open的副本在lib系統的TBD文件中。


image.png

我們知道這不是系統庫的一部分,我不會其復制到我的app中。但是我需要在app中加入足夠的信息 以便調用它。

image.png

因此,我們創建了一個假函數 ,它只是一個模板,用來代替從lib系統拿走的函數,這里就是open。觀察該函數,它實際上是來自指針open$pointer,然后跳到它。這需要一個函數指針,就像任何普通的C函數指針一樣。然后在數據段中 創建它,如果有全局變量,那么就會出現在這里。但它只是設置為零,如果如果空引用會導致崩潰。然后我們添加一個LINKEDIT部分。
image.png

LINKEDIT是鏈接器工具用于為操作系統保留信息的元數據,這就是在運行時解決問題的動態鏈接器。有關這方面的更多信息,請查看2016年的 Optimizing App Startup Time 演講。

相關信息:
Swift
Clang
llbuild

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容