iOS:strip

1.探索macho文件

1.1macho簡介

Mach-O(Mach Object)是macOS、iOS、iPadOS存儲(chǔ)程序和庫的文件格 式。對應(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)鏈接和動(dòng)態(tài) 鏈接的代碼提供了單一文件格式。
可執(zhí)行文件調(diào)用過程

  1. 調(diào)用fork函數(shù),創(chuàng)建一個(gè)process
  2. 調(diào)用execve或其衍生函數(shù),在該進(jìn)程上加載,執(zhí)行我們的Mach-O文件
    當(dāng)我們調(diào)用時(shí)execve(程序加載器),內(nèi)核實(shí)際上在執(zhí)行以下操作:
  3. 將文件加載到內(nèi)存
  4. 開始分析Mach-O中的mach_header,以確認(rèn)它是有效的Mach-O文件

1.2查看macho的頭文件

objdump --macho  --private-header macho文件

objdump --macho --private-header PayDemo
//輸出結(jié)果
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64   ARM64        ALL  0x00     EXECUTE    30       4120   NOUNDEFS DYLDLINK TWOLEVEL BINDS_TO_WEAK PIE

otool -h PayDemo //otool -h命令也可以讀出

macho文件的結(jié)構(gòu)


image.png

1.2macho中的代碼段

int main(int argc, char *argv[]) {

  return 0;
}

通過命令
objdump --macho -d 查看

objdump --macho -d macho文件
100003fa0:  55  pushq   %rbp
100003fa1:  48 89 e5    movq    %rsp, %rbp
100003fa4:  31 c0   xorl    %eax, %eax
100003fa6:  c7 45 fc 00 00 00 00    movl    $0, -4(%rbp)
100003fad:  89 7d f8    movl    %edi, -8(%rbp)
100003fb0:  48 89 75 f0 movq    %rsi, -16(%rbp)
100003fb4:  5d  popq    %rbp
100003fb5:  c3  retq

2.符號表

2.1符號表Symbol Table

Symbol Table:就是用來保存符號。
String Table:就是用來保存符號的名稱。
Indirect Symbol Table:間接符號表。保存使用的外部符號。更準(zhǔn)確一點(diǎn)就是使 用的外部動(dòng)態(tài)庫的符號。是Symbol Table的子集。

2.2全局符號和本地符號

我們在main函數(shù)上定義一個(gè)全局變量和一個(gè)靜態(tài)變量

#import <Foundation/Foundation.h>
int global_init_value = 10;
static int static_init_value = 9;
int main(int argc, char *argv[]) {
  return 0;
}

通過objdump命令查看macho的符號表
objdump --macho --syms

0000000100003fa0 l    d  *UND*
0000000100003fa0 l    d  *UND* _main
0000000000000016 l    d  *UND*
0000000000000016 l    d  *UND*
0000000000000000 l    d  *UND* _global_init_value
0000000000000000 l    d  *UND*
0000000100000000 g     F __TEXT,__text __mh_execute_header
0000000100004008 g     O __DATA,__data _global_init_value
0000000100003fa0 g     F __TEXT,__text _main

可以看出全局變量是全局符號,靜態(tài)全局變量是本地符號
怎么把全局符號變成本地符號呢

//定義成全局變量
extern int hidden_y;
extern double default_y;
extern double protected_y;

int hidden_y __attribute__((visibility("hidden"))) = 99; //全局符號便成本地符號
double default_y __attribute__((visibility("default"))) = 100;//如果 //還是全局符號

visibility屬性,控制文件導(dǎo)出符號,限制符號可見性
-fvisibility:clang參數(shù)
default:用它定義的符號將被導(dǎo)出。
hidden:用它定義的符號將不被導(dǎo)出。
全局符號對整個(gè)項(xiàng)目可見
如果我們在一個(gè)庫的m文件中實(shí)現(xiàn)一個(gè)全局的global_object函數(shù),我們可以在項(xiàng)目中通過extern void global_object()之后正常使用,但是如果我們項(xiàng)目中也實(shí)現(xiàn)global_object函數(shù),代碼會(huì)優(yōu)先調(diào)用本項(xiàng)目中的global_object方法,這里涉及到命名空間
two_levelnamespace & flat_namespace:
二級命名空間與一級命名空間。鏈接器默認(rèn)采用二級命名空間,也就是除了會(huì)記錄符號 名稱,還會(huì)記錄符號屬于哪個(gè)Mach-O的,比如會(huì)記錄下來_NSLog來自Foundation。

2.3導(dǎo)出符號導(dǎo)出符號

我們在main中使用NSLog,可知NSLog對于Foundation是導(dǎo)出符號,NSLog對于我們的項(xiàng)目是導(dǎo)入符號
我們看一下我們自己的macho文件的導(dǎo)出符號

objdump --macho --exports-trie 
//打印結(jié)果
Exports trie:
0x100000000  __mh_execute_header
0x100003F40  _global_object
0x100004048  _global_init_value
0x100003F60  _main
0x100004040  _default_y

我們可以看出我們的導(dǎo)出符號也就是我們的全局符號。

2.4間接符號表

間接符號表是我們使用的其他動(dòng)態(tài)庫的符號。
查看間接符號表

 objdump --macho --indirect-symbols
//打印結(jié)果
Indirect symbols for (__TEXT,__stubs) 1 entries
address            index name
0x0000000100003f86    23 _NSLog
Indirect symbols for (__DATA,__nl_symbol_ptr) 1 entries
address            index name
0x0000000100004000 ABSOLUTE
Indirect symbols for (__DATA,__got) 1 entries
address            index name
0x0000000100004008    25 dyld_stub_binder
Indirect symbols for (__DATA,__la_symbol_ptr) 1 entries
address            index name
0x0000000100004010    23 _NSLog

我們strip的話,剝離本地符號,全局符號也就是導(dǎo)出符號不能被剝離。

2.5OC類是導(dǎo)出符號

我們創(chuàng)建OC類,查看OC類和方法是本地符號還是全局符號(導(dǎo)出符號)

 objdump --macho --exports-trie
image.png

我們創(chuàng)建的oc類都是導(dǎo)出符號,如果我們不想讓我們的類作為導(dǎo)出符號被外界使用我們應(yīng)該怎么辦呢?

2.6修改link配置,隱藏導(dǎo)出符號

配置other link flag參數(shù)如下

OTHER_LDFLAGS=$(inherited) -Xlinker -unexported_symbol -Xlinker _OBJC_CLASS_$_LGOneObject
OTHER_LDFLAGS=$(inherited) -Xlinker -unexported_symbol -Xlinker _OBJC_METACLASS_$_LGOneObject

重新查看導(dǎo)出符號

objdump --macho --exports-trie
Exports trie:
0x100000000  __mh_execute_header
0x100003F10  _global_object
0x100004170  _global_init_value
0x100003F30  _main
0x100004168  _default_y

可以看出我們的隱藏了導(dǎo)出符號OBJC_METACLASS_LGOneObject和_OBJC_CLASS__LGOneObject

2.7重定位符號表

重定位符號就是我們在調(diào)用別人的api時(shí),在編譯的時(shí)候需要記錄一下放到重定位符號表中。
查看目標(biāo)文件o的重定位

objdump --macho --reloc test.o
//打印結(jié)果
test.o:
Relocation information (__TEXT,__text) 2 entries
address  pcrel length extern type    scattered symbolnum/value
0000001c True  long   True   BRANCH  False     _NSLog
0000000b True  long   False  SIGNED  False     3 (__DATA,__cfstring)
Relocation information (__DATA,__cfstring) 2 entries
address  pcrel length extern type    scattered symbolnum/value
00000010 False quad   False  UNSIGND False     2 (__TEXT,__cstring)
00000000 False quad   True   UNSIGND False     ___CFConstantStringClassReference
Relocation information (__LD,__compact_unwind) 1 entries
address  pcrel length extern type    scattered symbolnum/value
00000000 False quad   False  UNSIGND False     1 (__TEXT,__text)
image.png

怎么生成目標(biāo)文件可以在靜態(tài)庫查看

3.靜態(tài)鏈接

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容