美文网首页
__data在编译阶段处理协议

__data在编译阶段处理协议

作者: _叮叮当当__ | 来源:发表于2020-06-28 17:59 被阅读0次

问题:如果某些业务场景下,需要很早的注册一些key-value? 怎么办?

很多同学第一反应是+Load方法中进行注册;

当然可以,如果需要在程序编译/链接期间就执行呢?

答案:

可以,我们可以通过attribute((section("name")))编译属性将数据写到可执行文件中,然后在使用的时候,从可执行文件中读取出来.

解释:

attribute是编译属性,用于改变所声明或定义的函数或数据的特性,比如存储特性。

首先定义一个结构体:

struct ProtocolInfo{
    char *key;
    char *value;
};

然后,使用宏定义一段使用attribute((section("name"))) 的代码段:

#define ProtocolRegister(_key_,_value_)\
__attribute__((used)) static struct ProtocolInfo ProtocolInfo##_key_ \
__attribute__ ((used, section ("__DATA,ProtocolInfoData"))) =\
{\
    .key = #_key_,\
    .value = #_value_,\
};

used是告诉编译器不用优化掉此函数,即使没有地方使用。ProtocolInfoData 名字可以自定义,除了结构体,char,int 类型也可以使用。这样我们就可以将协议数据写到可执行文件的__DATA 字段中了。

使用方式:

ProtocolRegister(home,jump1)

ProtocolRegister(my,jump2)

在可执行文件(Mach-O)中的格式如下:


Mach-O文件

读取

#include <dlfcn.h>
#include <mach-o/getsect.h>

...

- (void)readDataFromMachO {
    //1.根据符号找到所在的mach-o文件信息
        Dl_info info;
        dladdr((__bridge void *)[self class], &info);
    
    //2.读取__DATA中自定义的ProtocolInfoDataz数据
    #ifndef __LP64__
        const struct mach_header *mhp = (struct mach_header*)info.dli_fbase;
        unsigned long schemeSize = 0;
        uint32_t *schemeMemory = (uint32_t*)getsectiondata(mhp, "__DATA", "ProtocolInfoData", &schemeSize);
    #else /* defined(__LP64__) */
        const struct mach_header_64 *mhp = (struct mach_header_64*)info.dli_fbase;
        unsigned long schemeSize = 0;
        uint64_t *schemeMemory = (uint64_t*)getsectiondata(mhp, "__DATA", "ProtocolInfoData", &schemeSize);
     
    #endif /* defined(__LP64__) */
    
    //3.遍历ProtocolInfoData中的协议数据
    unsigned long schemeCounter = schemeSize/sizeof(struct ProtocolInfo);
    struct ProtocolInfo *items = (struct ProtocolInfo*)schemeMemory;
    for(int idx = 0; idx < schemeCounter; ++idx){
        NSString * key = [NSString stringWithUTF8String:items[idx].key];
        NSString * value = [NSString stringWithUTF8String:items[idx].value];;
        NSLog(@"-------------key:%@ , value:%@",key,value);
    
    }
}


除了__attribute__((section("name"))) ,常用的如使用__attribute__((constructor))修饰的函数可以在main函数之前调用 ,可以替换load方法使用。

相关文章

  • __data在编译阶段处理协议

    问题:如果某些业务场景下,需要很早的注册一些key-value? 怎么办? 很多同学第一反应是+Load方法中进行...

  • #define宏常量 、const常量区别

    (1) 编译器处理方式不同define宏是在预处理阶段展开。const 常量在 编译阶段 使用(2) 类型和安全检...

  • 深入理解计算机系统笔记(computer system,a pr

    程序的编译处理过程 预处理阶段——编译阶段——汇编阶段——链接阶段 预处理:(修改原始程序,插入一些引用库) 修改...

  • 谈谈 include

    我们知道C的整个编译过程由预处理,编译,链接三个步骤组成。include命令是在预处理阶段解析的。而预处理阶段只是...

  • iOS日记之:const 和 #define区别比较

    (1) 编译器处理方式不同define宏是在预处理阶段展开。const常量是编译运行阶段使用。(2) 类型和安全检...

  • 程序编译与执行的那些事(1):基本过程

    程序编译一般有如下几个过程: 预处理 编译 汇编 链接 程序编译阶段 预处理阶段 (预处理器)对包含源代码的文本文...

  • 宏 const static extern的区别与使用

    一. const 与 宏的区别 编译时刻: 宏是预编译(编译之前处理), const是编译阶段处理 编译检查: 宏...

  • 链接

    原文 1. 编译系统 预处理阶段:处理以 # 开头的预处理命令;编译阶段:翻译成汇编程序;汇编阶段:将汇编程序翻译...

  • C 语言编译流程

    C语言编译四个阶段: 预处理、编译、汇编、链接。 预处理阶段:预处理器cpp根据字符#开头的命令,修改C程序。通常...

  • 有关C++语言基础的问题

    c/c++程序的编译过程(GCC的编译流程) 主要分为四个阶段:预处理,编译阶段,汇编阶段,链接阶段 当我们写好一...

网友评论

      本文标题:__data在编译阶段处理协议

      本文链接:https://www.haomeiwen.com/subject/ooiwfktx.html