#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