methodListSmall.h   [plain text]


#include "test.h"

struct ObjCClass {
    struct ObjCClass * __ptrauth_objc_isa_pointer isa;
    struct ObjCClass * __ptrauth_objc_super_pointer superclass;
    void *cachePtr;
    uintptr_t zero;
    struct ObjCClass_ro *data;
};

struct ObjCClass_ro {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name;
    struct ObjCMethodList * __ptrauth_objc_method_list_pointer baseMethodList;
    struct protocol_list_t * baseProtocols;
    const struct ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    struct property_list_t *baseProperties;
};

struct ObjCMethod {
    char *name;
    char *type;
    IMP imp;
};

struct ObjCMethodList {
    uint32_t sizeAndFlags;
    uint32_t count;
    struct ObjCMethod methods[];
};

struct ObjCMethodSmall {
    int32_t nameOffset;
    int32_t typeOffset;
    int32_t impOffset;
};

struct ObjCMethodListSmall {
    uint32_t sizeAndFlags;
    uint32_t count;
    struct ObjCMethodSmall methods[];
};


extern struct ObjCClass OBJC_METACLASS_$_NSObject;
extern struct ObjCClass OBJC_CLASS_$_NSObject;


struct ObjCClass_ro FooMetaclass_ro = {
    .flags = 1,
    .instanceStart = 40,
    .instanceSize = 40,
    .name = "Foo",
};

struct ObjCClass FooMetaclass = {
    .isa = &OBJC_METACLASS_$_NSObject,
    .superclass = &OBJC_METACLASS_$_NSObject,
    .cachePtr = &_objc_empty_cache,
    .data = &FooMetaclass_ro,
};


int ranMyMethod1;
extern "C" void myMethod1(id self __unused, SEL _cmd) {
    testprintf("myMethod1\n");
    testassert(_cmd == @selector(myMethod1));
    ranMyMethod1 = 1;
}

int ranMyMethod2;
extern "C" void myMethod2(id self __unused, SEL _cmd) {
    testprintf("myMethod2\n");
    testassert(_cmd == @selector(myMethod2));
    ranMyMethod2 = 1;
}

int ranMyMethod3;
extern "C" void myMethod3(id self __unused, SEL _cmd) {
    testprintf("myMethod3\n");
    testassert(_cmd == @selector(myMethod3));
    ranMyMethod3 = 1;
}

int ranMyReplacedMethod1;
extern "C" void myReplacedMethod1(id self __unused, SEL _cmd) {
    testprintf("myReplacedMethod1\n");
    testassert(_cmd == @selector(myMethod1));
    ranMyReplacedMethod1 = 1;
}

int ranMyReplacedMethod2;
extern "C" void myReplacedMethod2(id self __unused, SEL _cmd) {
    testprintf("myReplacedMethod2\n");
    testassert(_cmd == @selector(myMethod2));
    ranMyReplacedMethod2 = 1;
}

struct BigStruct {
  uintptr_t a, b, c, d, e, f, g;
};

int ranMyMethodStret;
extern "C" BigStruct myMethodStret(id self __unused, SEL _cmd) {
    testprintf("myMethodStret\n");
    testassert(_cmd == @selector(myMethodStret));
    ranMyMethodStret = 1;
    BigStruct ret = {};
    return ret;
}

int ranMyReplacedMethodStret;
extern "C" BigStruct myReplacedMethodStret(id self __unused, SEL _cmd) {
    testprintf("myReplacedMethodStret\n");
    testassert(_cmd == @selector(myMethodStret));
    ranMyReplacedMethodStret = 1;
    BigStruct ret = {};
    return ret;
}

extern struct ObjCMethodList Foo_methodlistSmall;

asm(R"ASM(
.section __TEXT,__cstring
_MyMethod1Name:
    .asciz "myMethod1"
_MyMethod2Name:
    .asciz "myMethod2"
_MyMethod3Name:
    .asciz "myMethod3"
_BoringMethodType:
    .asciz "v16@0:8"
_MyMethodStretName:
    .asciz "myMethodStret"
_MyMethodNullTypesName:
    .asciz "myMethodNullTypes"
_StretType:
    .asciz "{BigStruct=QQQQQQQ}16@0:8"
)ASM");

#if __LP64__
asm(R"ASM(
.section __DATA,__objc_selrefs,literal_pointers,no_dead_strip
_MyMethod1NameRef:
    .quad _MyMethod1Name
_MyMethod2NameRef:
    .quad _MyMethod2Name
_MyMethod3NameRef:
    .quad _MyMethod3Name
_MyMethodStretNameRef:
    .quad _MyMethodStretName
_MyMethodNullTypesNameRef:
    .quad _MyMethodNullTypesName
)ASM");
#else
asm(R"ASM(
.section __DATA,__objc_selrefs,literal_pointers,no_dead_strip
_MyMethod1NameRef:
    .long _MyMethod1Name
_MyMethod2NameRef:
    .long _MyMethod2Name
_MyMethod3NameRef:
    .long _MyMethod3Name
_MyMethodStretNameRef:
    .long _MyMethodStretName
_MyMethodNullTypesNameRef:
    .long _MyMethodNullTypesName
)ASM");
#endif

#if MUTABLE_METHOD_LIST
asm(".section __DATA,__objc_methlist\n");
#else
asm(".section __TEXT,__objc_methlist\n");
#endif

asm(R"ASM(
    .p2align 2
_Foo_methodlistSmall:
    .long 12 | 0x80000000
    .long 5
    
    .long _MyMethod1NameRef - .
    .long _BoringMethodType - .
    .long _myMethod1 - .
    
    .long _MyMethod2NameRef - .
    .long _BoringMethodType - .
    .long _myMethod2 - .
    
    .long _MyMethod3NameRef - .
    .long _BoringMethodType - .
    .long _myMethod3 - .
    
    .long _MyMethodStretNameRef - .
    .long _StretType - .
    .long _myMethodStret - .

    .long _MyMethodNullTypesNameRef - .
    .long 0
    .long _myMethod1 - .
)ASM");

struct ObjCClass_ro Foo_ro = {
    .instanceStart = 8,
    .instanceSize = 8,
    .name = "Foo",
    .baseMethodList = &Foo_methodlistSmall,
};

struct ObjCClass FooClass = {
    .isa = &FooMetaclass,
    .superclass = &OBJC_CLASS_$_NSObject,
    .cachePtr = &_objc_empty_cache,
    .data = &Foo_ro,
};


@interface Foo: NSObject

- (void)myMethod1;
- (void)myMethod2;
- (void)myMethod3;
- (BigStruct)myMethodStret;

@end