MachO相關(guān)知識

MachO文件

Mach-O其實是Mach Object文件格式的縮寫,是mac以及iOS上可執(zhí)行文件的格式, 類似于windows上的PE格式 (Portable Executable ), linux上的elf格式 (Executable and Linking Format)

MachO格式的常見文件

目標文件.o
庫文件.a .dylib Framework
可執(zhí)行文件
dyld
.dsym
File指令
通過 $file 文件路徑 查看文件類型。


1.png
2.png
3.png
4.png

從截圖中可以看出,MatchO有很多不同的類型,可以通過在Xcode上指定。


22.png
通用二進制文件

蘋果公司提出的一種程序代碼。能同時適用多種架構(gòu)的二進制文件
同一個程序包中同時為多種架構(gòu)提供最理想的性能。
因為需要儲存多種代碼,通用二進制應用程序通常比單一平臺二進制的程序要大。
但是 由于兩種架構(gòu)有共通的非執(zhí)行資源,所以并不會達到單一版本的兩倍之多。
而且由于執(zhí)行中只調(diào)用一部分代碼,運行起來也不需要額外的內(nèi)存。

在Xcode編譯可以指定生成哪些架構(gòu)的Match-O文件(Architectures和Valid Architectures交集)

00383871-FC54-4A10-82FF-24C6F8BDFAB1.png

lipo命令
使用lifo -info 可以查看MachO文件包含的架構(gòu)
lipo -info MachO文件 使用lifo –thin 拆分某種架構(gòu)
lipo MachO文件 –thin 架構(gòu) –output 輸出文件路徑
使用lipo -create 合并多種架構(gòu)
$lipo -create MachO1 MachO2 -output 輸出文件路徑

MachO文件結(jié)構(gòu)

222.png

Mach-O 的組成結(jié)構(gòu)如圖所示包括:

Header 包含該二進制文件的一般信息

字節(jié)順序、架構(gòu)類型、加載指令的數(shù)量等。

使得可以快速確認一些信息,比如當前文件用于32位還是64位,對應的處理器是什么、文件類型是什么
與Mach-O對應的數(shù)據(jù)結(jié)構(gòu)都可以在/usr/include/mach-o/loader.h中找到

/*
 * The 64-bit mach header appears at the very beginning of object files for
 * 64-bit architectures.
 */
struct mach_header_64 {
    uint32_t    magic;        /* mach magic 標識符 */
    cpu_type_t    cputype;    /* CPU 類型標識符,同通用二進制格式中的定義 r */
    cpu_subtype_t    cpusubtype;     /*  CPU 子類型標識符,同通用二級制格式中的定義  */
    uint32_t    filetype;    /* 文件類型  */
    uint32_t    ncmds;        /* 加載器中加載命令的條數(shù)  */
    uint32_t    sizeofcmds;    /* 加載器中加載命令的總大小 */
    uint32_t    flags;        /* dyld 的標志 */

Mach-O 支持多種類型文件,所以此處引入了 filetype 字段來標明,這些文件類型定義在 loader.h 文件存在。

#define MH_OBJECT   0x1     /* Target 文件:編譯器對源碼編譯后得到的中間結(jié)果 */
#define MH_EXECUTE  0x2     /* 可執(zhí)行二進制文件 */
#define MH_FVMLIB   0x3     /* VM 共享庫文件(還不清楚是什么東西) */
#define MH_CORE     0x4     /* Core 文件,一般在 App Crash 產(chǎn)生 */
#define MH_PRELOAD  0x5     /* preloaded executable file */
#define MH_DYLIB    0x6     /* 動態(tài)庫 */
#define MH_DYLINKER 0x7     /* 動態(tài)連接器 /usr/lib/dyld */
#define MH_BUNDLE   0x8     /* 非獨立的二進制文件,往往通過 gcc-bundle 生成 */
#define MH_DYLIB_STUB   0x9     /* 靜態(tài)鏈接文件(還不清楚是什么東西) */
#define MH_DSYM     0xa     /* 符號文件以及調(diào)試信息,在解析堆棧符號中常用 */
#define MH_KEXT_BUNDLE  0xb     /* x86_64 內(nèi)核擴展 */
Load commands 一張包含很多內(nèi)容的表

內(nèi)容包括區(qū)域的位置、符號表、動態(tài)符號表等。描述了文件中數(shù)據(jù)的具體組織結(jié)構(gòu),不同的數(shù)據(jù)類型使用不同的加載命令表示。

在Mach-O文件中,loadCommand是用于加載指令的,它的大小和數(shù)目在header中已經(jīng)被提供,在Mach.h下以loadCommand結(jié)構(gòu)體展示

struct load_command {
    uint32_t cmd;        /* type of load command */
    uint32_t cmdsize;    /* total size of command in bytes */
};

該結(jié)構(gòu)體中有兩個成員,一個cmd提供該loadcommand的類型,cmdsize則表示command的大小.

loadCommands中記錄了很多信息,包括動態(tài)鏈接器(比如dyld)的位置,程序的入口地址(main),依賴庫的信息,代碼的位置.符號表的位置等等.


999.png

LC_SEGMENT_64(_PAGEZERO): 空指針陷阱段,這里是記錄的共享虛擬空間信息,它并不會占用實際的磁盤空間,只是一片虛擬內(nèi)存,這里記錄了它的位置和大小,這片空間一般用于置放空指針.
LC_SEGMENT_64(_TEXT): 只讀數(shù)據(jù)段,記錄了TEXT的起始位置和大小還有偏移值等信息,這些信息會告知具體的TEXT段在哪里.
LC_SEGMENT_64(_DATA):讀寫數(shù)據(jù)段,記錄了DATA段的起始位置和大小還有偏移值等信息,這些信息會告知具體的DATA段在哪里.
LC_SEGMENT_64(_LINKEDIT):鏈接器使用段,這里記錄了鏈接器(通常是dyld)需要的信息的位置.
LC_DYLD_INFO_ONLY:記錄具體的鏈接器需要的信息,比如重定向,懶加載,綁定等.
LC_SYMTAB:符號表的信息,記錄符號表的位置,偏移量,數(shù)據(jù)個數(shù)等,便于dyld使用LC_DYSYMTAB:符號表的額外信息,這些信息也會提供給dyld.
LC_LOAD_DYLINKER:該Mach-O使用的鏈接器信息,記錄了具體使用哪個鏈接器接管內(nèi)核后續(xù)的加載工作,以及鏈接器的位置信息,通常是dyld.
LC_UUID:Mach-O唯一標識符.
LC_VERSION_MIN_IPHONES:該Mach-O運行的最低系統(tǒng)版本.
LC_SOURCE_VERSION:源代碼版本信息.
LC_MAIN:入口地址.dyld會通過這個段去跳轉(zhuǎn)程序的主入口.
LC_ENCRYPTION_INFO_64:加密標識,標識了是否被加密,加密內(nèi)容的偏移及大小等.
LC_LOAD_DYLIB:依賴庫信息,dyld會通過這個段去加載動態(tài)庫,這個段標注了庫的位置以及版本等信息.LC_RPATH:@rpath的路徑信息.
LC_FUNCTION_STARTS:函數(shù)起始地址表.
LC_DATA_IN_CODE:代碼段非指令的表.
LC_CODE_SIGNATURE:代碼簽名信息.

DATA

Mach-O 的 Data 區(qū)域由 Segment 段和 Section 節(jié)組成。先來說 Segment 的組成,

#define SEG_PAGEZERO    "__PAGEZERO" /* 當時 MH_EXECUTE 文件時,捕獲到空指針 */
#define SEG_TEXT    "__TEXT" /* 代碼/只讀數(shù)據(jù)段 */
#define SEG_DATA    "__DATA" /* 數(shù)據(jù)段 */
#define SEG_OBJC    "__OBJC" /* Objective-C runtime 段 */
#define SEG_LINKEDIT    "__LINKEDIT" /* 包含需要被動態(tài)鏈接器使用的符號和其他表,包括符號表、字符串表等 */

進而來看一下 Segment 的數(shù)據(jù)結(jié)構(gòu)具體是什么樣的

struct segment_command_64 { 
    uint32_t    cmd;        /* LC_SEGMENT_64 */
    uint32_t    cmdsize;    /* section_64 結(jié)構(gòu)體所需要的空間 */
    char        segname[16];    /* segment 名字,上述宏中的定義 */
    uint64_t    vmaddr;     /* 所描述段的虛擬內(nèi)存地址 */
    uint64_t    vmsize;     /* 為當前段分配的虛擬內(nèi)存大小 */
    uint64_t    fileoff;    /* 當前段在文件中的偏移量 */
    uint64_t    filesize;   /* 當前段在文件中占用的字節(jié) */
    vm_prot_t   maxprot;    /* 段所在頁所需要的最高內(nèi)存保護,用八進制表示 */
    vm_prot_t   initprot;   /* 段所在頁原始內(nèi)存保護 */
    uint32_t    nsects;     /* 段中 Section 數(shù)量 */
    uint32_t    flags;      /* 標識符 */
};

部分的 Segment (主要指的 __TEXT 和 __DATA)可以進一步分解為 Section,下面給出 Section 具體的數(shù)據(jù)結(jié)構(gòu):

struct section_64 { 
    char        sectname[16];   /* Section 名字 */
    char        segname[16];    /* Section 所在的 Segment 名稱 */
    uint64_t    addr;       /* Section 所在的內(nèi)存地址 */
    uint64_t    size;       /* Section 的大小 */
    uint32_t    offset;     /* Section 所在的文件偏移 */
    uint32_t    align;      /* Section 的內(nèi)存對齊邊界 (2 的次冪) */
    uint32_t    reloff;     /* 重定位信息的文件偏移 */
    uint32_t    nreloc;     /* 重定位條目的數(shù)目 */
    uint32_t    flags;      /* 標志屬性 */
    uint32_t    reserved1;  /* 保留字段1 (for offset or index) */
    uint32_t    reserved2;  /* 保留字段2 (for count or sizeof) */
    uint32_t    reserved3;  /* 保留字段3 */
};

以下列舉一些常見的 Section:
__text: 主程序代碼
__stubs, __stub_helper: 用于動態(tài)鏈接的樁
__cstring: 程序中c語言字符串
__const: 常量
__TEXT,__objc_methname:OC方法名稱
__TEXT__objc_methtype:OC方法類型
__TEXT__objc_classname:OC類名
__DATA,__objc_classlist:OC類列表
__DATA,__objc_protollist:OC原型列表
__DATA,__objc_imageinfo:OC鏡像信息
__DATA,__objc_const:OC常量
__DATA,__objc_selfrefs:OC類自引用(self)
__DATA,__objc_superrefs:OC類超類引用(super)
__DATA,__objc_protolrefs:OC原型引用
__DATA, __bss: 沒有初始化和初始化為0 的全局變量
Dynamic Loader Info:動態(tài)鏈接器所需要使用的信息(重定向,符號綁定,懶加載綁定等..)
后續(xù)的信息就是函數(shù)起始位置,符號表,字符表,代碼簽名等.

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

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

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