符號的種類與作用

全局符號 和本地符號

我們先看一段代碼


屏幕快照 2021-02-21 下午8.29.33.png

查看Mach-O的符號

屏幕快照 2021-02-21 上午9.59.21.png

通過如下命令

objdump --macho --syms patch 
屏幕快照 2021-02-21 下午7.36.01.png
  • 可以看到main.m 生成的mach-O中的符號信息, 全局符號為g
  • static 修飾的變量 為 l

所以 l :就是 local 本地的意思 ,g 就是global 全局的意思

按照功能劃分

Type 說明
f File
F Function
O Data
d Debug
*ABS* Absolute
*COM* Common
*UND* ?
調試符號

可以通過 連接器的參數(shù) 再鏈接的時候 不把調試符號放入我們可執(zhí)行文件

OTHER_LDFLAGS=$(inherited) -Xlinker -S 
屏幕快照 2021-02-21 下午7.50.09.png

編譯一下 再次查看符號表


屏幕快照 2021-02-21 下午8.30.55.png
  • 此時我們發(fā)現(xiàn) 調試符號已經被我們脫掉了,更能清晰的對照原始代碼來查看
  • 調試符號:當一個文件通過匯編器生成.o的時候 會DWARF 格式的調試信息 它被放在了專門的mach-O中的一個 __DWARF段 當去連接的時候它會把整個段變成符號放在符號表中,當鏈接的時候所有的符號都是放在符號表中的。
    DWARF文件 在.o的時候是一個段 ,此時跟符號表并沒有產生關系,當變成可執(zhí)行文件的時候在鏈接的時候 這個段被干掉最終變成了符號 最終 放在了 可執(zhí)行文件中exec
visibility

可通過visibility屬性,控制文件導出符號,限制符號可見性。
截屏2021-01-22 下午4.52.16.png
  • hidden : 用它定義分符號將不被導出
  • default: 用它定義的符號將被導出
  • protected: 受保護的

__attribute__ : 可以把編譯器支持的一些參數(shù)傳遞給編譯器(如上面是傳入的是控制符號的可見性,那最好的隱藏符號是什么?就是是把全局符號變成本地符號)。


屏幕快照 2021-02-21 下午8.31.59.png
拓展
  • 面試題:全局變量 和靜態(tài)變量最大區(qū)別是什么?
    作用域不一樣,本質的區(qū)別就是可見性。
    如果全局變量 那么會對整個項目可見
    如是靜態(tài)變量 則會變成 local

  • 關于 一個同名 全局方法 本地也寫了一個同名方法 調用 是調用 本地的 還是 別的地方的。


    屏幕快照 2021-02-21 下午9.16.13.png

    屏幕快照 2021-02-21 下午9.35.16.png

    直接說答案:此時編譯不會報錯,并且還會調用到

當我在本地寫一個實現(xiàn):


屏幕快照 2021-02-21 下午9.56.20.png

發(fā)現(xiàn)本地的被調用起來了

為什么 會調用起來呢 為啥不沖突 因為連接器默認采用二級命名空間 修改為一級就報錯了。

截屏2021-01-22 下午5.02.24.png
導入和導出符號

是導入 還是導出 相對于來說的,比如你調用了NSLog 那相對于Foundation 庫來說就是 導出,相對于你來說就是導入。

那導出符號一定是 全局符號了?從字面上是這樣的 那么我來看一下

查看mach-O的導出符號命令

objdump --macho --exports-trie 黑不溜秋的
截屏2021-01-22 下午5.11.11.png
  • 所以我們要注意 當我們使用全局變量 全局符號的 時候 它默認會為導出符號,對外界暴露的,也就意味著 其他空間 可以使用這個符號。

那導出符號一定是全局符號嗎?按道理是的 ,但是我們可以通過連接器控制它。

動態(tài)庫 是在運行的時候加載,那就意味這它在編譯連接階段的時候提供符號就可以了。
間接符號表,保存著當前使用的其他動態(tài)庫的符號

查看間接符號表

objdump --macho --indirect-symbols 黑不溜秋的
截屏2021-01-22 下午5.23.47.png

好像只認識NSlog 但是它是Fundation 給我們提供的導出符號
從上面我們可以理解:
1、全局符號可以變成導出符號 ,那么變成導出符號之后 可以給外面使用
2、當我們處理符號,因為符號存在我們Mach-o中是占用一定體積的 。 那能處理能刪除間接符號嗎?那肯定必須的不能刪除啊,為什么?因為對于我們項目mach-o來說 間接符號表 里保存著當前使用著的動態(tài)庫的符號,而動態(tài)庫是運行的時候去加載。所以也就意味著 我們在編譯鏈接的時候只需要提供它所用到的符號就行,而這符號就存在 間接符號表里。
3、當我們站在動態(tài)庫的角度去看,全局符號 可以變成導出符號,供外界使用,那我要去脫符號也就意味著,只能去脫不是全局符號的符號。

這里會有一個問題 假如你的一個動態(tài)庫 有好多好多的全局符號,并且 是OC 這里提一點 OC默認的都是導出符號。那么為了縮小體積該怎么辦?
這就需要鏈接器給我們提供的一個參數(shù)不導出符號

-Xlinker -unexported_symbol  -Xlinker _OBJC_CLASS_$_LGOneObjc
  • 這樣也就可以把不需要對外暴露的導出符號 變成一個不導出也就是local符號。盡可能的來減小體積。

  • 如果有多個符號不想導出 要如上??一個一個得類似,鏈接器也為我們提供了相應的處理方法


     -unexported_symbols_list file
                 The specified filename contains a list of global symbol names
                 that will not remain as global symbols in the output file.
                 The symbols will be treated as if they were marked as __pri-
                 vate_extern__ (aka visibility=hidden) and will not be global
                 in the output file. The symbol names listed in filename must
                 be one per line.  Leading and trailing white space are not
                 part of the symbol name.  Lines starting with # are ignored,
                 as are lines with only white space.  Some wildcards (similar
                 to shell file matching) are supported.  The * matches zero or
                 more characters.  The ? matches one character.  [abc] matches
                 one character which must be an 'a', 'b', or 'c'.  [a-z]
                 matches any single lower case letter from 'a' to 'z'.


  • 也可以將當前可執(zhí)行文件 用到了哪些庫 所有符號輸出出來
 -map map_file_path
                 Writes a map file to the specified path which details all
                 symbols and their addresses in the output image.

具體信息可以通過 來查看

man ld 

按照符號種類劃分

Symbol type 說明 ①:?寫代表local symbol
U undefined(未定義)
A absolute(絕對符號)
T text section symbol(__TEXT.__text)
D data Section symbol(__DATA.__data)
B bass section symbol(__DATA.bass)
C commom symbol (只能出現(xiàn)在‘MH_OBJECT’類型的‘Mach-O’文件中)
- debugger symbol table
S 除了上面所述的,存放在其他‘section’的內容,例如未初始化的全局變量存放在(__DATA,__common)中
I indirect symbol (符號信息相同,代表同一符號)
u 動態(tài)共享庫中的小寫u表示一個未定義引用對同一庫中另外一個模塊中私有外部符號

通過如下命令真實看一下

nm -pa  地址
截屏2021-03-01 下午2.20.23.png

Weak Symbol

Weak defintion Symbol :

表示此符號為若定義符號。如果靜態(tài)鏈接器或動態(tài)鏈接器為此符號找到另一個非弱定義,則若定義將被忽略。只能將合并部分中的符號標記為弱定義


截屏2021-03-04 下午1.45.49.png

截屏2021-03-04 下午1.50.06.png
  • 講道理 如果不對他進行weak修飾,它默認是一個全局符號,還是一個到處符號,我們看一下聲明為若定義之后會不會影響導出符號。

將其加入到Compilp Sources里 并編譯


截屏2021-03-04 下午1.55.37.png

查看可執(zhí)行文件的導出符號

objdump -macho --exports-trie  地址
截屏2021-03-04 下午1.59.25.png
  • 可以看到并不影響 它是一個全局 導出符號。
  • 被hidden修飾的weak 符號 變成 了弱定義的本地符號。

那我在main函數(shù)里寫一個同名實現(xiàn)方法,編譯會報錯嗎?

截屏2021-03-04 下午2.02.57.png
  • 相同的作用域空間,重復的全局符號, 是會報符號沖突的,但是弱定義修飾之后,可以編譯成功。
Weak Reference Symbol:

表示此未定義符號是弱引用。如果動態(tài)鏈接器找不到該符號的定義,則將其符號為0.靜態(tài)鏈接器會將此符號設置弱鏈接標志。

截屏2021-03-04 下午1.46.51.png

截屏2021-03-04 下午2.21.06.png
  • 通過 weak_import 告訴編譯器 此符號是弱引用的
截屏2021-03-04 下午2.28.03.png

此時 運行成功,那有什么意義呢?往下看

此時我們可以把 下圖標紅的地方去掉,在運行。


截屏2021-03-04 下午2.41.52.png

運行


截屏2021-03-04 下午2.44.21.png

咦報錯了? 為啥報錯,因為在ld連接的過程中 找不到當前符號的地址。

那我們可以通過告訴連接器 這個符號你別管,它是動態(tài)鏈接的,通過如下命令

   -U symbol_name
                 Specified that it is ok for symbol_name to have no defini-
                 tion.  With -two_levelnamespace, the resulting symbol will be
                 marked dynamic_lookup which means dyld will search all loaded
                 images.
截屏2021-03-04 下午2.54.57.png

再次運行


截屏2021-03-04 下午2.56.43.png

我們想一下 此時他們在同一片作用域空間中,假如 我編寫的是一個 動態(tài)庫,我將所有的符號變?yōu)槿跻梅枺鞘遣皇且馕吨?延遲到dyld加載的時候 找到某個符號的時候 再去做事情 Σ(⊙▽⊙"a

重新導出符號

我們先看一下當前可執(zhí)行文件的符號表

objdump --macho --syms
截屏2021-03-04 下午3.12.12.png

上面我們將的NSLog 對于我們當前的可執(zhí)行文件來說,

我們看到了 它的符號表它是一個未定義的符號 *UND*,

那假如說別的 庫也想使用我的這個可執(zhí)行文件中的NSLog怎么辦?所以就需要重新導出一下。

同樣連接器也給我們提供了相對的接口


     -alias symbol_name alternate_symbol_name
                 Create an alias named alternate_symbol_name for the symbol
                 symbol_name.  By default the alias symbol has global visibil-
                 ity.  This option was previous the -idef:indir option.
 
  • 這也就意味這我們可以通過其別名的形式讓它進行一個全局可見性。
  • 注意只能給間接符號 表里的符號 起一個別名。

我們試一下


截屏2021-03-04 下午3.23.21.png

我們先看一下當前的符號表

objdump --macho --syms 
截屏2021-03-04 下午3.29.09.png
  • 可以看到我們定義符號已經出現(xiàn)了。

還可以用nm 命令查看一下 可更友好的查看

nm -m 
截屏2021-03-04 下午3.31.38.png

再次查看導出符號

objdump -macho --exports-trie  地址
截屏2021-03-04 下午3.24.22.png
  • 可以看到完美的被我們導出了

OC 的符號 默認都是導出符號,因為它是動態(tài)型語言
swift是編譯型語言,所以很多符號在編譯期就知道是什么類型,可通過public private open 等控制。

Common Symbol

在定義時,未初始化的全局符號


截屏2021-03-01 下午2.25.27.png

未定義符號作用:
1、當它找到定義之后,在編譯連接的時候會把未定義的刪掉。
2、 如果是未定義的符號 鏈接器會把它強制已經定義的 ,比如直接賦值為 0;這就是為什么我定義了一個符號,沒有賦值也沒有使用的時候xcode會報警告 ,這就是鏈接器會識別common 符號 按照一定規(guī)則 ,如你有未定義的 要么給你強制變成 已定義的, 要么給你報警告 要么報錯這是可以選擇的。

strip

首先通過 上面文章 我們知道
對于動態(tài)庫 我們只能去脫不是全局符號的符號。
那對于app來說 我們分析:
1.首先你要考慮要不要給別人使用。那這里這個奇奇怪怪的問題,要不是奇奇怪怪的app 也用不到。
2.通過上面我們也知道 除了間接符號表里的符號不能脫,那是不是意味著別的都可以脫掉 本地的 全局的 弱定義的 都可以干掉 只留下 間接符號表中的。

那對于靜態(tài)庫來說呢?
靜態(tài)庫 是 .o的合集 也就意味著,它里邊還有重定位符號表,那重定位符號表里面是啥來,是保存著你項目用到的符號,那它能刪嗎? 刪了那我連接還怎么重定位。那還有什么可以脫 是不是還有調試符號

大家不妨想一想:
那就符號來說
app 使用靜態(tài)庫體積小 還是動態(tài)庫體積???
答案是靜態(tài)庫 因為 靜態(tài)庫你只能去脫掉調試符號,那app 是不是除了間接符號表 其他的都可以脫掉?
那動態(tài)庫 的符號 是不是最終都放在了app的間接符號表中?

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

推薦閱讀更多精彩內容