iOS中使用Mach-O section進行存儲

理論

編譯器編譯后生成的文件叫目標文件,從文件結(jié)構(gòu)來說,它已經(jīng)是編譯后可執(zhí)行的文件,只是還沒有經(jīng)過鏈接的過程。我們程序編譯后的代碼在.text,數(shù)據(jù).data中。編譯器函數(shù)在編譯時把數(shù)據(jù)寫入可執(zhí)行文件的.data段中,運行時再從.data段中取出數(shù)據(jù)進行相應(yīng)的操作。借助.data段,能夠覆蓋所有的啟動階段,例如main()之前的階段。

Clang提供了很多的編譯器函數(shù),它們可以完成不同的功能。其中一種是section()函數(shù),section()函數(shù)提供了二進制段的讀寫能力,它可以將一些編譯期就可以確定的常量寫入數(shù)據(jù)段。在具體的實現(xiàn)中,主要分為編譯期和運行時兩個部分。在編譯期,編譯器會將標記了attribute((section()))的數(shù)據(jù)寫到指定的數(shù)據(jù)段,例如寫一個{key(key代表不同的啟動階段), *pointer}對到數(shù)據(jù)段。到運行時,在合適的時間節(jié)點,再根據(jù)key讀取出函數(shù)指針,完成函數(shù)的調(diào)用。

使用_ _attribute方法注入

/**
被used修飾以后,意味著即使函數(shù)沒有被引用,在Release下也不會被優(yōu)化。如果不加這個修飾,那么Release環(huán)境鏈接器下會去掉沒有被引用的段
*/
#define HMAnnotationDATA __attribute((used, section("__DATA,HMSectionStore")))

/**
 *  Use this to annotation a `module`
 *  like this: HMSectionStoreModule()
 */
#define HMSectionStoreModule(modName) \
char * kHMSectionStoreModule_##modName HMAnnotationDATA = "M:"#modName"";

/**
調(diào)用上面定義好的宏
*/
HMSectionStoreModule(HMSectionStoreViewController)

獲取存儲數(shù)據(jù)

NSArray<NSString *>* HMSectionStoreReadConfigFromSection(const char *sectionName){
    #ifndef __LP64__
        const struct mach_header *mhp = NULL;
    #else
        const struct mach_header_64 *mhp = NULL;
    #endif
        
        NSMutableArray *configs = [NSMutableArray array];
        Dl_info info;
        if (mhp == NULL) {
            dladdr(HMSectionStoreReadConfigFromSection, &info);
    #ifndef __LP64__
            mhp = (struct mach_header*)info.dli_fbase;
    #else
            mhp = (struct mach_header_64*)info.dli_fbase;
    #endif
        }
        
    #ifndef __LP64__
        unsigned long size = 0;
     // 找到之前存儲的數(shù)據(jù)段的一片內(nèi)存
        uint32_t *memory = (uint32_t*)getsectiondata(mhp, SEG_DATA, sectionName, & size);
    #else /* defined(__LP64__) */
        unsigned long size = 0;
        uint64_t *memory = (uint64_t*)getsectiondata(mhp, SEG_DATA, sectionName, & size);
    #endif /* defined(__LP64__) */
        
        for(int idx = 0; idx < size/sizeof(void*); ++idx){
            char *string = (char*)memory[idx];
            // 把特殊段里面的數(shù)據(jù)都轉(zhuǎn)換成字符串存入數(shù)組中
            NSString *str = [NSString stringWithUTF8String:string];
            if(!str)continue;
            if(str) [configs addObject:str];
        }
        return configs;
}

完整的代碼

#import "HMSectionStoreViewController.h"
#include <mach-o/getsect.h>
#include <mach-o/loader.h>
#include <mach-o/dyld.h>
#include <dlfcn.h>

#define HMAnnotationDATA __attribute((used, section("__DATA,HMSectionStore")))

/**
 *  Use this to annotation a `module`
 *  like this: @HMSectionStoreModule()
 */
#define HMSectionStoreModule(modName) \
char * kHMSectionStoreModule_##modName HMAnnotationDATA = "M:"#modName"";



NSArray<NSString *>* HMSectionStoreReadConfigFromSection(const char *sectionName){
    #ifndef __LP64__
        const struct mach_header *mhp = NULL;
    #else
        const struct mach_header_64 *mhp = NULL;
    #endif
        
        NSMutableArray *configs = [NSMutableArray array];
        Dl_info info;
        if (mhp == NULL) {
            dladdr(HMSectionStoreReadConfigFromSection, &info);
    #ifndef __LP64__
            mhp = (struct mach_header*)info.dli_fbase;
    #else
            mhp = (struct mach_header_64*)info.dli_fbase;
    #endif
        }
        
    #ifndef __LP64__
        unsigned long size = 0;
     // 找到之前存儲的數(shù)據(jù)段的一片內(nèi)存
        uint32_t *memory = (uint32_t*)getsectiondata(mhp, SEG_DATA, sectionName, & size);
    #else /* defined(__LP64__) */
        unsigned long size = 0;
        uint64_t *memory = (uint64_t*)getsectiondata(mhp, SEG_DATA, sectionName, & size);
    #endif /* defined(__LP64__) */
        
        for(int idx = 0; idx < size/sizeof(void*); ++idx){
            char *string = (char*)memory[idx];
            // 把特殊段里面的數(shù)據(jù)都轉(zhuǎn)換成字符串存入數(shù)組中
            NSString *str = [NSString stringWithUTF8String:string];
            if(!str)continue;
            if(str) [configs addObject:str];
        }
        return configs;
}

/**
編譯的時候,存儲數(shù)據(jù)到.data中
*/
HMSectionStoreModule(HMSectionStoreViewController)
@interface HMSectionStoreViewController ()

@end

@implementation HMSectionStoreViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //獲取注入的數(shù)據(jù)
    NSArray<NSString *> *dataListInSection = HMSectionStoreReadConfigFromSection("HMSectionStore");
    for (NSString *dataString in dataListInSection) {
        NSLog(@"獲取section中存儲的數(shù)據(jù)--> %@",dataString);
    }
}
@end

運行結(jié)果

Snip20200414_1.png

運用

路由協(xié)議中,模塊類容加載到內(nèi)存中??蓞⒖?br> AppLord

BeeHive

相關(guān)參考內(nèi)容

美團外賣iOS App冷啟動治理

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

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

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