理論
編譯器編譯后生成的文件叫目標文件,從文件結(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