布景

如果想在 自界说section 存储具体服务类,实现服务的操控回转,在常见的做法是界说一个字符串指针,指向方针类的类名,用运行时的方法获得方针类。下面列出一个简单的比如

// 界说
char *className = "MyClass" __attribute((used, section("__DATA,__mysection")));
// 读取
const struct mach_header_64 *mhp = (const struct mach_header_64 *)_dyld_get_image_header(0);  // 注:主macho纷歧定是0
const char *className = (const char *)getsectiondata(mhp, "__DATA", "__mysection", NULL);
Class classObjc = NSClassFromString([NSString stringWithFormat:@"%s", className]);

本文将介绍另外一种写法,直接在 自界说section 存储Objective-C的类目标,就像 __objc_classlistsection 相同,大约作用如下。

// 界说
Class classObjc = [MyClass class] __attribute((used, section("__DATA,__mysection")));
// 读取
const struct mach_header_64 *mhp = (const struct mach_header_64 *)_dyld_get_image_header(0); // 注:主macho纷歧定是0 
Class classObjc = (Class)getsectiondata(mhp, "__DATA", "__mysection", NULL);

完好代码地址

推理过程

  1. 界说一个空类文件 objc.m
@interface MyClass : NSObject
@end
@implementation MyClass
@end
  1. 用指令重写成C++文件 objc.cpp
clang -framework Foundation -rewrite-objc -fobjc-arc objc.m -o objc.cpp
  1. 从C++文件 objc.cpp 提取代码
  • 类结构体界说(struct _class_t)
// 类结构体
struct _class_t {
    struct _class_t *isa;
    struct _class_t *superclass;
    void *cache;
    void *vtable;
    struct _class_ro_t *ro;
};
// 以下是其它相关的结构体
struct _prop_t {
    const char *name;
    const char *attributes;
};
struct _protocol_t;
struct _objc_method {
    struct objc_selector * _cmd;
    const char *method_type;
    void *_imp;
};
struct _protocol_t {
    void * isa; // NULL
    const char *protocol_name;
    const struct _protocol_list_t * protocol_list; // super protocols
    const struct method_list_t *instance_methods;
    const struct method_list_t *class_methods;
    const struct method_list_t *optionalInstanceMethods;
    const struct method_list_t *optionalClassMethods;
    const struct _prop_list_t * properties;
    const unsigned int size; // sizeof(struct _protocol_t)
    const unsigned int flags; // = 0
    const char ** extendedMethodTypes;
};
struct _ivar_t {
    unsigned long int *offset; // pointer to ivar offset location
    const char *name;
    const char *type;
    unsigned int alignment;
    unsigned int size;
};
struct _class_ro_t {
    unsigned int flags;
    unsigned int instanceStart;
    unsigned int instanceSize;
    unsigned int reserved;
    const unsigned char *ivarLayout;
    const char *name;
    const struct _method_list_t *baseMethods;
    const struct _objc_protocol_list *baseProtocols;
    const struct _ivar_list_t *ivars;
    const unsigned char *weakIvarLayout;
    const struct _prop_list_t *properties;
};
  • MyClass 的类数据
// MyClass的类数据
extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_MyClass __attribute__ ((used, section ("__DATA,__objc_data"))) = {
    0, // &OBJC_METACLASS_$_MyClass,
    0, // &OBJC_CLASS_$_NSObject,
    0, // (void *)&_objc_empty_cache,
    0, // unused, was (void *)&_objc_empty_vtable,
    &_OBJC_CLASS_RO_$_MyClass,
};
// 以下是其它相关数据
extern "C" __declspec(dllimport) struct objc_cache _objc_empty_cache;
static struct _class_ro_t _OBJC_METACLASS_RO_$_MyClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    1, sizeof(struct _class_t), sizeof(struct _class_t),
    (unsigned int)0,
    0,
    "MyClass",
    0,
    0,
    0,
    0,
    0,
};
static struct _class_ro_t _OBJC_CLASS_RO_$_MyClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    0, sizeof(struct MyClass_IMPL), sizeof(struct MyClass_IMPL),
    (unsigned int)0,
    0,
    "MyClass",
    0,
    0,
    0,
    0,
    0,
};
extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSObject;
extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_MyClass __attribute__ ((used, section ("__DATA,__objc_data"))) = {
    0, // &OBJC_METACLASS_$_NSObject,
    0, // &OBJC_METACLASS_$_NSObject,
    0, // (void *)&_objc_empty_cache,
    0, // unused, was (void *)&_objc_empty_vtable,
    &_OBJC_METACLASS_RO_$_MyClass,
};
extern "C" __declspec(dllimport) struct _class_t OBJC_CLASS_$_NSObject;

从C++文件 objc.cpp 提取的代码,大致能够获取以下信息

信息 比如
类的符号格局 OBJC_CLASS_$_ + 类名
指向类目标地址写法 &OBJC_CLASS_$_NSObject

结论

自界说section 存储Objective-C的类目标,代码如下

// 结构体声明
struct _prop_t {
    const char *name;
    const char *attributes;
};
struct _protocol_t;
struct _objc_method {
    struct objc_selector * _cmd;
    const char *method_type;
    void *_imp;
};
struct _protocol_t {
    void * isa; // NULL
    const char *protocol_name;
    const struct _protocol_list_t * protocol_list; // super protocols
    const struct method_list_t *instance_methods;
    const struct method_list_t *class_methods;
    const struct method_list_t *optionalInstanceMethods;
    const struct method_list_t *optionalClassMethods;
    const struct _prop_list_t * properties;
    const unsigned int size; // sizeof(struct _protocol_t)
    const unsigned int flags; // = 0
    const char ** extendedMethodTypes;
};
struct _ivar_t {
    unsigned long int *offset; // pointer to ivar offset location
    const char *name;
    const char *type;
    unsigned int alignment;
    unsigned int size;
};
struct _class_ro_t {
    unsigned int flags;
    unsigned int instanceStart;
    unsigned int instanceSize;
    unsigned int reserved;
    const unsigned char *ivarLayout;
    const char *name;
    const struct _method_list_t *baseMethods;
    const struct _objc_protocol_list *baseProtocols;
    const struct _ivar_list_t *ivars;
    const unsigned char *weakIvarLayout;
    const struct _prop_list_t *properties;
};
struct _class_t {
    struct _class_t *isa;
    struct _class_t *superclass;
    void *cache;
    void *vtable;
    struct _class_ro_t *ro;
};
// 界说
__attribute__((dllimport)) struct _class_t OBJC_CLASS_$_MyClass;
struct _class_t *classObjc = &OBJC_CLASS_$__MyClass __attribute((used, section("__DATA,__mysection")));
// 读取
const struct mach_header_64 *mhp = (const struct mach_header_64 *)_dyld_get_image_header(0); // 注:主macho纷歧定是0 
Class classObjc = (Class)getsectiondata(mhp, "__DATA", "__mysection", NULL);

More

  • 这种写法,能够利用编译检查拼写的正确性,并减少读取过程。