對Link Map File的初步認識
什麼是Link Map File
Link Map File中文直譯為連結對映檔案,它是在Xcode生成可執行檔案的同時生成的連結資訊檔案,用於描述可執行檔案的構造部分,包括了程式碼段和資料段的分佈情況。Xcode在生成可執行檔案的時候預設情況下不生成該檔案,需要開發者手動設定Target --> Build Setting --> Write Link Map File為YES:

這裡還可以設定Link Map存放的位置,預設的位置為:
$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt
例如:
/Users/zhanggui/Library/Developer/Xcode/DerivedData/LinkMapTest-ffnpzjkbsmhwvdcxorqbxpyvjtob/Build/Intermediates.noindex/LinkMapTest.build/Debug-iphonesimulator/LinkMapTest.build/LinkMapTest-LinkMap-normal-x86_64.txt
開發者也可以根據自己的需要自行設定該檔案的位置。
Link Map File的組成
開啟Link Map File,裡面包含了以下幾個部分:
1. Path
# Path: /Users/zhanggui/Library/Developer/Xcode/DerivedData/LinkMapTest-ffnpzjkbsmhwvdcxorqbxpyvjtob/Build/Products/Debug-iphonesimulator/LinkMapTest.app/LinkMapTest
Path是生成可執行檔案的路徑。
2. Arch
# Arch: x86_64
Arch指代架構型別。
3. Object files:
# Object files: [ 0] linker synthesized [ 1] /Users/zhanggui/Library/Developer/Xcode/DerivedData/LinkMapTest-ffnpzjkbsmhwvdcxorqbxpyvjtob/Build/Intermediates.noindex/LinkMapTest.build/Debug-iphonesimulator/LinkMapTest.build/LinkMapTest.app-Simulated.xcent [ 2] /Users/zhanggui/Library/Developer/Xcode/DerivedData/LinkMapTest-ffnpzjkbsmhwvdcxorqbxpyvjtob/Build/Intermediates.noindex/LinkMapTest.build/Debug-iphonesimulator/LinkMapTest.build/Objects-normal/x86_64/ViewController.o [ 3] /Users/zhanggui/Library/Developer/Xcode/DerivedData/LinkMapTest-ffnpzjkbsmhwvdcxorqbxpyvjtob/Build/Intermediates.noindex/LinkMapTest.build/Debug-iphonesimulator/LinkMapTest.build/Objects-normal/x86_64/main.o [ 4] /Users/zhanggui/Library/Developer/Xcode/DerivedData/LinkMapTest-ffnpzjkbsmhwvdcxorqbxpyvjtob/Build/Intermediates.noindex/LinkMapTest.build/Debug-iphonesimulator/LinkMapTest.build/Objects-normal/x86_64/AppDelegate.o [ 5] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk/System/Library/Frameworks//Foundation.framework/Foundation.tbd [6]/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk/usr/lib/libobjc.tbd [7]/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk/System/Library/Frameworks//UIKit.framework/UIKit.tbd
Object Files列舉了可執行檔案裡所有的obj以及tbd。每一行代表對檔案的編號。例如ViewController.o檔案,其編號為2。編號的具體作用稍後介紹。
4. Sections
# Sections: # AddressSizeSegment Section 0x100001730 0x00000333__TEXT__text 0x100001A64 0x0000002A__TEXT__stubs 0x100001A90 0x00000056__TEXT__stub_helper 0x100001AE6 0x00000A27__TEXT__objc_methname 0x10000250D 0x0000003C__TEXT__objc_classname 0x100002549 0x0000086D__TEXT__objc_methtype 0x100002DB6 0x0000007A__TEXT__cstring 0x100002E30 0x00000182__TEXT__entitlements 0x100002FB4 0x00000048__TEXT__unwind_info 0x100003000 0x00000010__DATA__nl_symbol_ptr 0x100003010 0x00000010__DATA__got 0x100003020 0x00000038__DATA__la_symbol_ptr 0x100003058 0x00000010__DATA__objc_classlist 0x100003068 0x00000010__DATA__objc_protolist 0x100003078 0x00000008__DATA__objc_imageinfo 0x100003080 0x00000BE8__DATA__objc_const 0x100003C68 0x00000010__DATA__objc_selrefs 0x100003C78 0x00000008__DATA__objc_classrefs 0x100003C80 0x00000008__DATA__objc_superrefs 0x100003C88 0x00000008__DATA__objc_ivar 0x100003C90 0x000000A0__DATA__objc_data 0x100003D30 0x000000C0__DATA__data
單從字面含義理解:每個Section包含了Address、Size、Segment以及Section。介紹之前,這裡先簡單介紹一下Mach-O檔案。
上面第一部分的Path是可執行檔案的路徑,使用iTerm進去到該資料夾,然後使用file命令即可檢視該檔案的型別:
file LinkMapTest
輸出結果為:
LinkMapTest: Mach-O 64-bit executable x86_64
可以知道該檔案是一個Mach-O格式的檔案,它是iOS系統應用執行檔案格式。Mach-O檔案中的虛擬地址最終會被對映到實體地址上,這些地址會被分為不同的段型別:_ _ TEXT 、_ _ DATA以及_ _ LINKEDIT等。各個段的含義如下:
- _ _ TEXT包含了被執行的程式碼。這些程式碼是隻讀、可執行
- _ _ DATA包含了包含了將會被更改的資料,例如全域性變數、靜態變數等,可讀寫,但是不可執行
- _ _ LINKEDIT 包含了載入程式的元資料,比如函式名稱和地址,只讀。
Segment又被劃分成了不同的Section,不同的Section儲存了不同的資訊,例如 _ _ objc _ methname 為方法的名稱。
再回顧上面的Sections,Address是起始位置、Size是大小、Segment是段、Section。
5. Symbols
# AddressSizeFileName 0x100001730 0x0000003C[2] -[ViewController viewDidLoad] 0x100001770 0x00000092[3] _main 0x100001810 0x00000080[4] -[AppDelegate application:didFinishLaunchingWithOptions:] 0x100001890 0x00000040[4] -[AppDelegate applicationWillResignActive:] 0x1000018D0 0x00000040[4] -[AppDelegate applicationDidEnterBackground:] 0x100001910 0x00000040[4] -[AppDelegate applicationWillEnterForeground:] 0x100001950 0x00000040[4] -[AppDelegate applicationDidBecomeActive:] 0x100001990 0x00000040[4] -[AppDelegate applicationWillTerminate:] 0x1000019D0 0x00000020[4] -[AppDelegate window] 0x1000019F0 0x00000040[4] -[AppDelegate setWindow:] 0x100001A30 0x00000033[4] -[AppDelegate .cxx_destruct] 0x100001A64 0x00000006[5] _NSStringFromClass 0x100001A6A 0x00000006[7] _UIApplicationMain 0x100001A70 0x00000006[6] _objc_autoreleasePoolPop 0x100001A76 0x00000006[6] _objc_autoreleasePoolPush 0x100001A7C 0x00000006[6] _objc_msgSendSuper2 0x100001A82 0x00000006[6] _objc_retainAutoreleasedReturnValue 0x100001A88 0x00000006[6] _objc_storeStrong 0x100001A90 0x00000010[0] helper helper 0x100001AA0 0x0000000A[5] _NSStringFromClass 0x100001AAA 0x0000000A[6] _objc_autoreleasePoolPop 0x100001AB4 0x0000000A[6] _objc_autoreleasePoolPush 0x100001ABE 0x0000000A[6] _objc_msgSendSuper2 0x100001AC8 0x0000000A[6] _objc_retainAutoreleasedReturnValue 0x100001AD2 0x0000000A[6] _objc_storeStrong 0x100001ADC 0x0000000A[7] _UIApplicationMain 0x100001AE6 0x0000000C[2] literal string: viewDidLoad . . .
根據Sections的起始地址,可以將Symbols分為Sections個數的組,例如0x100001730到0x100001A64之間,就是 _ _ test程式碼區。
Symbols包含的資訊有:
- Address:起始地址
- Size:所佔記憶體大小,這裡使用16進製表示。
- File:該Name所在的檔案編號,也就是Object files部分的中括號的數字,例如-[ViewController viewDidLoad]對應的檔案編號為2,根據Object files部分可以看到所屬的檔案為:ViewController.o。這樣可以計算某個o檔案所佔記憶體的大小。只需要把Symbols中編號為o編號Symbols累加統計即可。
- Name就是該Sybmols的名稱。
6. Dead Stripped Symbols
# Dead Stripped Symbols: #SizeFileName <<dead>>0x00000018[2] CIE <<dead>>0x00000018[3] CIE <<dead>>0x00000006[4] literal string: class <<dead>>0x00000008[4] literal string: v16@0:8 <<dead>>0x00000018[4] CIE . . .
上面便是對Link map file做了簡單的介紹。
ZLinkMapParser
花了兩天的時間,根據對Link Map File的學習,使用Ruby寫了一個指令碼檔案,可以方便地統計出指定Link Map File中的元件或者tbd佔用記憶體大小,類似:
AppDelegate.o8.50KB ViewController.o735B LinkMapDemo.app-Simulated.xcent386B main.o192B linker synthesized128B libobjc.tbd120B Foundation.tbd24B UIKit.tbd24B 總大小為(僅供參考):10.07KB
想了解更多可以訪問 ofollow,noindex" target="_blank">ZLinkMapParser
總結
- 蘋果開發還是有很多細節的東西需要去學習去了解。
- 學習一門指令碼語言,也會給平時的開發帶來很大的方便。
參考
- Mach-O可執行檔案
- iOS調優|深入理解Link Map File
- iOS APP可執行檔案的組成