iOS-開發(fā)進(jìn)階02:鏈接與Symbol(上)

iOS 開發(fā)進(jìn)階 文章匯總

目錄


一、Mach-O與鏈接器

Mach-O
  • Mach-O(Mach Object)macOS、iOS恶迈、 iPadOS存儲程序和庫的文件格式。對應(yīng)系統(tǒng)通過應(yīng)用二進(jìn)制接口(application binary interface,縮寫為ABI)來運(yùn)行該格式的文件谱醇。

  • Mach-O格式用來替代BSD系統(tǒng)的a.out格式暇仲。Mach-O文件格式保存了在編譯過程鏈接過程中產(chǎn)生的機(jī)器代碼數(shù)據(jù),從而為靜態(tài)鏈接動態(tài)鏈接的代碼提供了單一文件格式副渴。

Mach-O文件就是一個可讀可寫二進(jìn)制文件


可執(zhí)行文件調(diào)用過程:
  1. 調(diào)用fork函數(shù)奈附,創(chuàng)建一個process進(jìn)程
  2. 調(diào)用execve或其衍生函數(shù),在該進(jìn)程上加載煮剧,執(zhí)行我們的Mach-O文件

當(dāng)我們調(diào)用時execve (程序加載器)斥滤,內(nèi)核實(shí)際上在執(zhí)行以下操作:

  1. 將文件加載到內(nèi)存
  2. 開始分析Mach-O中的mach header,以確認(rèn)它是有效的Mach-O文件


通過終端命令查看Mach-O文件:objdump --macho --private-headers 可執(zhí)行文件地址


通過自己的項目查看Mach-O文件

machoinfo項目是用來查看Mach-O文件的,編譯后生成machoinfo的可執(zhí)行文件可作為命令使用:
拷貝machoinfo可執(zhí)行文件到桌面


使用machoinfo項目調(diào)試Mach-O文件讀取過程

通過以下操作將TestCode項目編譯的可執(zhí)行文件路徑拖入到machoinfo項目啟動參數(shù)中勉盅,這樣TestCode可執(zhí)行文件路徑就會傳入到machoinfo項目main函數(shù)的argv參數(shù)中

main函數(shù)中添加斷點(diǎn)后運(yùn)行machoinfo項目就能看到參數(shù)傳入進(jìn)來了佑颇,然后通過這個路徑就能讀取到TestCode可執(zhí)行文件并進(jìn)行Mach-O文件讀取過程


二、符號的種類與作用

Symbol Table
  • Symbol Table:就是用來保存符號草娜。
  • String Table:就是用來保存符號的名稱错蝴。
  • Indirect Symbol Table:間接符號表盐须。保存使用的外部符號敛惊,也就是使用的外部動態(tài)庫的符號(比如NSLog)精堕。是Symbol Table的子集。

通過編譯項目生成可執(zhí)行文件-->然后在終端使用命令查看Mach-O的中的符號操作比較繁瑣议蟆,現(xiàn)在通過配置Shell腳本闷沥,當(dāng)項目編譯成功后直接在終端執(zhí)行命令并展示命令的結(jié)果。

首先通過重定向在Xcode中讓當(dāng)前終端顯示特定內(nèi)容:

Xcode讓終端顯示xcconfig文件中的變量:

現(xiàn)在通過xcode_run_cmd.sh腳本執(zhí)行相關(guān)的命令:

#!/bin/sh

RunCommand() {
  #判斷全局字符串VERBOSE_SCRIPT_LOGGING是否為空咐容。-n string判斷字符串是否非空
  #[[是 bash 程序語言的關(guān)鍵字舆逃。用于判斷
  if [[ -n "$VERBOSE_SCRIPT_LOGGING" ]]; then
    #作為一個字符串輸出所有參數(shù)。使用時加引號"$*" 會將所有的參數(shù)作為一個整體戳粒,以"$1 $2 … $n"的形式輸出所有參數(shù)
      if [[ -n "$TTY" ]]; then
          echo "? $@" 1>$TTY
      else
          echo "? $*"
      fi
      echo "------------------------------------------------------------------------------" 1>$TTY
  fi
  #與$*相同路狮。但是使用時加引號,并在引號中返回每個參數(shù)蔚约。"$@" 會將各個參數(shù)分開奄妨,以"$1" "$2" … "$n" 的形式輸出所有參數(shù)
  if [[ -n "$TTY" ]]; then
      echo `$@ &>$TTY`
  else
      "$@"
  fi
  #顯示最后命令的退出狀態(tài)。0表示沒有錯誤苹祟,其他任何值表明有錯誤砸抛。
  return $?
}

EchoError() {
    #在shell腳本中评雌,默認(rèn)情況下,總是有三個文件處于打開狀態(tài)直焙,標(biāo)準(zhǔn)輸入(鍵盤輸入)景东、標(biāo)準(zhǔn)輸出(輸出到屏幕)、標(biāo)準(zhǔn)錯誤(也是輸出到屏幕)奔誓,它們分別對應(yīng)的文件描述符是0斤吐,1,2
    # >  默認(rèn)為標(biāo)準(zhǔn)輸出重定向厨喂,與 1> 相同
    # 2>&1  意思是把 標(biāo)準(zhǔn)錯誤輸出 重定向到 標(biāo)準(zhǔn)輸出.
    # &>file  意思是把標(biāo)準(zhǔn)輸出 和 標(biāo)準(zhǔn)錯誤輸出 都重定向到文件file中
    # 1>&2 將標(biāo)準(zhǔn)輸出重定向到標(biāo)準(zhǔn)錯誤輸出和措。實(shí)際上就是打印所有參數(shù)已標(biāo)準(zhǔn)錯誤格式
    if [[ -n "$TTY" ]]; then
        echo "$@" 1>&2>$TTY
    else
        echo "$@" 1>&2
    fi
    
}

RunCMDToTTY() {
    if [[ ! -e "$TTY" ]]; then
        EchoError "=========================================="
        EchoError "ERROR: Not Config tty to output."
        exit -1
    fi
    # CMD:終端需要運(yùn)行的命令
    # CMD_FLAG:運(yùn)行的命令的參數(shù)
    # TTY:終端標(biāo)志
    if [[ -n "$CMD" ]]; then
        RunCommand "$CMD" ${CMD_FLAG}
    else
        EchoError "=========================================="
        EchoError "ERROR:Failed to run CMD. THE CMD must not null"
    fi
}

RunCMDToTTY

xcode_run_cmd.sh腳本需需要三個參數(shù)CMD 、CMD_FLAG 杯聚、TTY臼婆,這三個參數(shù)在xcconfig文件中定義就能獲取到

// -p:不排序
// -a: 顯示除了調(diào)試符號的其他所有符號
MACHO_PATH = ${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/$(FULL_PRODUCT_NAME)/$(PRODUCT_NAME)
CMD = nm
CMD_FLAG = -pa ${MACHO_PATH}
TTY = /dev/ttys000

添加shell腳本執(zhí)行命令/bin/sh "$SRCROOT/xcode_run_cmd.sh"并編譯即可在終端看到nm命令執(zhí)行的結(jié)果

編譯日志

Xcode編譯日志中可以看到項目編譯后-簽名前執(zhí)行的shell腳本,因此執(zhí)行shell腳本時Mach-O文件已經(jīng)生成了


三幌绍、strip命令

strip命令可以用來剝離Mach-O文件中的符號,比如調(diào)試符號等故响。strip命令修改的是Symbol Table符號表傀广、不能修改Indirect Symbol Table間接符號表。
Xcode默認(rèn)會在Release編譯情況下剝離所有符號彩届,但是Debug編譯情況下不會剝離符號伪冰。

設(shè)置Debug編譯情況下剝離調(diào)試符號:

  • 從編譯日志中也可以看到,Xcodestrip命令是在shell腳本之后執(zhí)行的
  • 在實(shí)際開發(fā)項目中測試Xcodestrip樟蠕,沒有剝離符號的Mach-O大小為34M贮聂,剝離符號后大小為20.8M,可見剝離符號對于瘦包還是非常有用的


現(xiàn)在不使用Xcodestrip命令寨辩,改在shell腳本中執(zhí)行strip命令

因?yàn)?code>Xcode的strip使用的是clang的命令吓懈,shell腳本使用的是ld鏈接器的命令,所以可以在終端查看ld鏈接器的參數(shù)靡狞,終端輸入命令man ld回車后輸入/-S進(jìn)行搜索:

xcconfig文件添加ld的參數(shù)

OTHER_LDFLAGS = -Xlinker -S

XcodeBuild Sttings中可以看到添加成功了:

編譯后可發(fā)現(xiàn)終端輸出中少了很多調(diào)試符號耻警。

strip 參數(shù)如下:

  • -x: Non-Global
  • 無參數(shù): All Symbol
  • -S: 調(diào)試符號

四、在LLVM項目中調(diào)試nm命令

LLVM項目下載安裝參考:iOS-底層探索29:自定義Clang插件

填入啟動參數(shù)和machoinfo項目查看Mach-O文件添加啟動參數(shù)的方法相同:

運(yùn)行LLVM項目(也就是運(yùn)行LLVM項目中llvm-nm Schemellvm-nm Target)甸怕,控制臺打印如下甘穿,可以看到和shell中使用nm命令輸出到終端的信息相同:

此外在llvm-nm.cpp源碼的main函數(shù)中添加斷點(diǎn)后運(yùn)行項目即可斷點(diǎn)調(diào)試llvm-nm命令的源碼,從llvm-nm的源碼中我們就能看到nm命令是如何讀取Mach-O文件的梢杭。


五温兼、總結(jié)

通過對符號的strip不僅可以減少ipa包體積還可以減少動態(tài)庫、靜態(tài)庫的體積

ipa包瘦身主要有以下操作:

  • 編譯時期:-O0武契、-Os生成目標(biāo)文件
  • 鏈接時期:dead code strip死代碼剝離(也是剝離符號)
  • 生成Mach-O后:strip剝離符號募判,對Mach-O文件進(jìn)行修改


快捷鍵

Command + K清空終端顯示內(nèi)容


參考

iOS-底層探索28:LLVM入門

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荡含,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子兰伤,更是在濱河造成了極大的恐慌内颗,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敦腔,死亡現(xiàn)場離奇詭異均澳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)符衔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門找前,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人判族,你說我怎么就攤上這事躺盛。” “怎么了形帮?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵槽惫,是天一觀的道長。 經(jīng)常有香客問我辩撑,道長界斜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任合冀,我火速辦了婚禮各薇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘君躺。我一直安慰自己峭判,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布棕叫。 她就那樣靜靜地躺著林螃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谍珊。 梳的紋絲不亂的頭發(fā)上治宣,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音砌滞,去河邊找鬼侮邀。 笑死,一個胖子當(dāng)著我的面吹牛贝润,可吹牛的內(nèi)容都是我干的绊茧。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼打掘,長吁一口氣:“原來是場噩夢啊……” “哼华畏!你這毒婦竟也來了鹏秋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤亡笑,失蹤者是張志新(化名)和其女友劉穎侣夷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仑乌,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡百拓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晰甚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衙传。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖厕九,靈堂內(nèi)的尸體忽然破棺而出蓖捶,到底是詐尸還是另有隱情,我是刑警寧澤扁远,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布俊鱼,位于F島的核電站,受9級特大地震影響畅买,放射性物質(zhì)發(fā)生泄漏亭引。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一皮获、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纹冤,春花似錦洒宝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至知残,卻和暖如春靠瞎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背求妹。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工乏盐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人制恍。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓父能,卻偏偏與公主長得像,于是被迫代替她去往敵國和親净神。 傳聞我的和親對象是個殘疾皇子何吝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容