this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ObjC work - most super calls working

+1338 -352
+1
CMakeLists.txt
··· 21 21 enable_language(ASM-ATT) 22 22 enable_language(ASM_NASM) 23 23 ADD_DEFINITIONS(-ggdb -DDEBUG) 24 + #ADD_DEFINITIONS(-O3) 24 25 25 26 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 26 27 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+281
src/libobjcdarwin/AppleLayout.h
··· 1 + #ifndef APPLELAYOUT_H 2 + #define APPLELAYOUT_H 3 + #include <iterator> 4 + 5 + struct method_t 6 + { 7 + const char* selName; 8 + const char* types; 9 + void* impl; 10 + }; 11 + 12 + struct method_list_t 13 + { 14 + uint32_t entsize_and_flags; 15 + uint32_t count; 16 + method_t method_list[]; 17 + 18 + uint32_t entsize() const { return entsize_and_flags & ~uint32_t(3); } 19 + }; 20 + 21 + struct ivar_t 22 + { 23 + uintptr_t* offset; 24 + const char* name; 25 + const char* type; 26 + uint32_t alignment, size; 27 + }; 28 + 29 + struct ivar_list_t 30 + { 31 + uint32_t entsize, count; 32 + ivar_t ivar_list[]; 33 + }; 34 + 35 + struct protocol_list_t; 36 + struct property_list_t; 37 + struct protocol_t 38 + { 39 + id isa; 40 + const char* name; 41 + protocol_list_t* protocols; // inherited protocols 42 + method_list_t *methods, *staticMethods, *optMethods, *optStaticMethods; 43 + property_list_t* properties; 44 + uint32_t size, flags; 45 + const char** extMethTypes; // reflects the order and count of methods above as listed in this struct 46 + 47 + inline const protocol_t* next() const 48 + { 49 + uintptr_t ptr = reinterpret_cast<uintptr_t>(this); 50 + ptr += size; 51 + return reinterpret_cast<const protocol_t*>(ptr); 52 + } 53 + }; 54 + 55 + template <typename ProtoList> 56 + class protocol_iterator : public std::iterator<std::input_iterator_tag, const protocol_t*> 57 + { 58 + const ProtoList* m_list; 59 + size_t m_index; 60 + intptr_t m_slide; 61 + public: 62 + protocol_iterator(const ProtoList* list, size_t index, intptr_t slide) : m_list(list), m_index(index), m_slide(slide) {} 63 + protocol_iterator(const protocol_iterator& that) : m_list(that.m_list), m_index(that.m_index), m_slide(that.m_slide) {} 64 + protocol_iterator& operator++() { m_index++; return *this; } 65 + bool operator==(const protocol_iterator& that) { return that.m_index == m_index; } 66 + bool operator!=(const protocol_iterator& that) { return that.m_index != m_index; } 67 + const protocol_t* operator*() { return m_list->elem(m_index, m_slide); } 68 + }; 69 + 70 + struct protocol_list_t 71 + { 72 + uintptr_t count; 73 + uintptr_t list[]; // the compiler doesn't add a rebase here 74 + inline const protocol_t* elem(size_t i, uintptr_t slide) const 75 + { 76 + return reinterpret_cast<const protocol_t*>(list[i] + slide); 77 + } 78 + protocol_iterator<protocol_list_t> begin(intptr_t slide) const { return protocol_iterator<protocol_list_t>(this, 0, slide); } 79 + protocol_iterator<protocol_list_t> end(intptr_t slide) const { return protocol_iterator<protocol_list_t>(this, count, slide); } 80 + }; 81 + 82 + struct old_method_decl 83 + { 84 + const char *name, *types; 85 + }; 86 + struct old_method_decl_list 87 + { 88 + int count; 89 + old_method_decl list[]; 90 + }; 91 + struct property_t 92 + { 93 + const char *name, *attributes; 94 + }; 95 + 96 + struct property_list_t 97 + { 98 + uint32_t entsize, count; 99 + property_t list[]; 100 + }; 101 + typedef property_t old_property; 102 + typedef property_list_t old_property_list; 103 + 104 + struct old_protocol; 105 + struct old_protocol_list 106 + { 107 + old_protocol_list* linked; 108 + long count; 109 + old_protocol* list[]; 110 + }; 111 + 112 + struct old_protocol_ext 113 + { 114 + uint32_t size; 115 + old_method_decl_list *optMethods, *optStaticMethods; 116 + old_property_list* properties; 117 + const char** extMethTypes; 118 + }; 119 + 120 + struct old_protocol 121 + { 122 + union 123 + { 124 + id isa; 125 + old_protocol_ext* ext; // __protocol_ext section 126 + uintptr_t ext_ptrValue; 127 + }; 128 + const char* name; 129 + old_protocol_list* protocols; 130 + old_method_decl_list *methods, *staticMethods; 131 + }; 132 + 133 + struct class_ro_t 134 + { 135 + uint32_t flags, instStart, instSize; 136 + #ifdef __x86_64__ 137 + uint32_t nothing; 138 + #endif 139 + void* ivarLayout; 140 + const char* className; 141 + const method_list_t* baseMethods; // instance methods for classes, static methods for metaclasses 142 + const protocol_list_t* baseProtocols; 143 + const ivar_list_t* ivars; 144 + 145 + void* todo[1]; // TODO: more pointers 146 + const property_list_t* baseProperties; 147 + }; 148 + 149 + #if 0 // UNUSED 150 + struct class_rw_t 151 + { 152 + uint32_t flags, version; 153 + class_ro_t* ro; 154 + 155 + union 156 + { 157 + method_list_t* method_list; 158 + method_list_t** method_lists; 159 + }; 160 + 161 + void* todo[4]; // TODO: four more pointers 162 + }; 163 + #endif 164 + 165 + struct class_t 166 + { 167 + class_t* isa; // instance of 168 + class_t* superclass; 169 + void* cache; // empty cache imported here 170 + void* vtable; 171 + uintptr_t data_and_flags; 172 + 173 + // TODO: WTF? Should be rw data 174 + class_ro_t* data() const 175 + { 176 + uintptr_t p = data_and_flags & ~uintptr_t(3); 177 + return reinterpret_cast<class_ro_t*>(p); 178 + } 179 + }; 180 + 181 + union old_class_ptr 182 + { 183 + struct old_class* cls; 184 + const char* name; 185 + uintptr_t ptrValue; 186 + Class clsNew; 187 + }; 188 + 189 + struct old_class 190 + { 191 + old_class_ptr isa; 192 + old_class_ptr super_class; 193 + const char *name; 194 + long version; 195 + long info; 196 + long instance_size; 197 + struct old_ivar_list *ivars; 198 + struct old_method_list *methodList; 199 + void* cache; 200 + struct old_protocol_list *protocols; 201 + // CLS_EXT only 202 + const uint8_t *ivar_layout; 203 + struct old_class_ext *ext; 204 + }; 205 + 206 + struct old_class_ext 207 + { 208 + uint32_t size; 209 + const uint8_t *weak_ivar_layout; 210 + old_property_list **propertyLists; 211 + }; 212 + 213 + struct old_category 214 + { 215 + char *category_name; 216 + char *class_name; 217 + struct old_method_list *instance_methods; 218 + struct old_method_list *class_methods; 219 + struct old_protocol_list *protocols; 220 + uint32_t size; 221 + old_property_list *instance_properties; 222 + }; 223 + 224 + struct old_ivar 225 + { 226 + char *name; 227 + char *type; 228 + int offset; 229 + #ifdef __x86_64__ 230 + int space; 231 + #endif 232 + }; 233 + 234 + struct old_ivar_list 235 + { 236 + int count; 237 + #ifdef __x86_64__ 238 + int space; 239 + #endif 240 + /* variable length structure */ 241 + struct old_ivar ivar_list[1]; 242 + }; 243 + 244 + 245 + struct old_method 246 + { 247 + const char* selName; 248 + const char* types; 249 + void* impl; 250 + }; 251 + 252 + struct old_method_list 253 + { 254 + struct old_method_list *obsolete; 255 + 256 + int count; 257 + #ifdef __x86_64__ 258 + int space; 259 + #endif 260 + /* variable length structure */ 261 + struct old_method method_list[1]; 262 + }; 263 + 264 + union selref 265 + { 266 + const char* selName; 267 + SEL sel; 268 + }; 269 + struct msgref 270 + { 271 + void* objc_msgSend_fixup; // function pointer 272 + selref sel; 273 + }; 274 + union clsref 275 + { 276 + const char* clsName; 277 + Class cls; 278 + }; 279 + 280 + #endif 281 +
+1 -3
src/libobjcdarwin/CMakeLists.txt
··· 17 17 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fPIC") 18 18 19 19 set(objcdarwin_SRCS 20 - objc_msgSend.nasm 21 20 objc_msgSend_fixup.nasm 22 - objc_msgSend_stret.nasm 23 - registers.nasm 21 + objc_msgSendSuper.nasm 24 22 NameTranslate.cpp 25 23 ClassRegister.mm 26 24 )
+86 -150
src/libobjcdarwin/ClassRegister.h
··· 3 3 #define __STDC_LIMIT_MACROS 4 4 #include <stdint.h> 5 5 #include <cstddef> 6 + #include <algorithm> 6 7 #include <objc/runtime.h> 7 - 8 - #ifndef INTPTR_MAX 9 - #error 10 - #endif 11 - 12 - struct method_t 13 - { 14 - const char* selName; 15 - const char* types; 16 - void* impl; 17 - }; 18 - 19 - struct method_list_t 20 - { 21 - uint32_t entsize_and_flags; 22 - uint32_t count; 23 - method_t method_list[0]; 8 + #include "AppleLayout.h" 9 + #include "../util/log.h" 24 10 25 - uint32_t entsize() const { return entsize_and_flags & ~uint32_t(3); } 26 - }; 27 - 28 - struct ivar_t 29 - { 30 - uintptr_t* offset; 31 - const char* name; 32 - const char* type; 33 - uint32_t alignment, size; 34 - }; 35 - 36 - struct ivar_list_t 37 - { 38 - uint32_t entsize, count; 39 - ivar_t ivar_list[]; 40 - }; 41 - 42 - struct class_ro_t 43 - { 44 - uint32_t flags, instStart, instSize; 45 - #ifdef __x86_64__ 46 - uint32_t nothing; 47 - #endif 48 - void* ivarLayout; 49 - const char* className; 50 - const method_list_t* baseMethods; // instance methods for classes, static methods for metaclasses 51 - const void* baseProtocols; 52 - const ivar_list_t* ivars; 53 - 54 - void* todo[2]; // TODO: two more pointers 55 - }; 11 + /* TODO? 12 + * __DATA,__objc_classlist was __OBJC2,__class_list 13 + * __DATA,__objc_catlist was __OBJC2,__category_list 14 + * __DATA,__objc_protolist was __OBJC2,__protocol_list 15 + * __DATA,__objc_msgrefs was __OBJC2,__message_refs 16 + * __DATA,__objc_classrefs was __OBJC2,__class_refs 17 + * __DATA,__objc_superrefs was __OBJC2,__super_refs 18 + * __DATA,__objc_imageinfo was __OBJC,__image_info 19 + * */ 56 20 57 - struct class_rw_t 58 - { 59 - uint32_t flags, version; 60 - class_ro_t* ro; 21 + static const char* SEG_DATA = "__DATA"; 22 + static const char* SEG_OBJC_CLASSLIST_NEW = SEG_DATA; 23 + static const char* SECT_OBJC_CLASSLIST_NEW = "__objc_classlist"; 24 + static const char* SEG_OBJC_CLASSREFS_NEW = SEG_DATA; 25 + static const char* SECT_OBJC_CLASSREFS_NEW = "__objc_classrefs"; 26 + static const char* SEG_OBJC_SUPERREFS_NEW = SEG_DATA; 27 + static const char* SECT_OBJC_SUPERREFS_NEW = "__objc_superrefs"; 28 + static const char* SEG_OBJC_SELREFS_NEW = SEG_DATA; 29 + static const char* SECT_OBJC_SELREFS_NEW = "__objc_selrefs"; 30 + static const char* SEG_OBJC_MSGREFS_NEW = SEG_DATA; // used with objc_msgSend_fixup 31 + static const char* SECT_OBJC_MSGREFS_NEW = "__objc_msgrefs"; 32 + static const char* SEG_OBJC_PROTOREFS_NEW = SEG_DATA; 33 + static const char* SECT_OBJC_PROTOREFS_NEW = "__objc_protorefs"; 34 + static const char* SEG_OBJC_PROTOLIST_NEW = SEG_DATA; 35 + static const char* SECT_OBJC_PROTOLIST_NEW = "__objc_protolist"; 61 36 62 - union 63 - { 64 - method_list_t* method_list; 65 - method_list_t** method_lists; 66 - }; 37 + static const char* SEG_OBJC = "__OBJC"; 38 + static const char* SEG_OBJC_CLASSLIST_OLD = SEG_OBJC; 39 + static const char* SECT_OBJC_CLASSLIST_OLD = "__class"; 40 + static const char* SEG_OBJC_METALIST_OLD = SEG_OBJC; 41 + static const char* SECT_OBJC_METALIST_OLD = "__meta_class"; 42 + static const char* SEG_OBJC_CLASSREFS_OLD = SEG_OBJC; 43 + static const char* SECT_OBJC_CLASSREFS_OLD = "__cls_refs"; 44 + static const char* SEG_OBJC_SELREFS_OLD = SEG_OBJC; 45 + static const char* SECT_OBJC_SELREFS_OLD = "__message_refs"; 46 + static const char* SEG_OBJC_PROTOCOLS_OLD = SEG_OBJC; 47 + static const char* SECT_OBJC_PROTOCOLS_OLD = "__protocol"; 48 + static const char* SEG_OBJC_PROTOEXT_OLD = SEG_OBJC; 49 + static const char* SECT_OBJC_PROTOEXT_OLD = "__protocol_ext"; 67 50 68 - void* todo[4]; // TODO: four more pointers 69 - }; 51 + static void ProcessImageLoad(const struct mach_header* mh, intptr_t slide); 52 + static void ProcessImageUnload(const struct mach_header* mh, intptr_t slide); 53 + static Class RegisterClass(const class_t* cls, intptr_t slide); 54 + static Class RegisterClass(old_class* cls); 55 + static void ProcessProtocolsNew(const struct mach_header* mh, intptr_t slide); 56 + static void ProcessProtocolsOld(const struct mach_header* mh, intptr_t slide); 57 + static Protocol* RegisterProtocol(const protocol_t* prot, intptr_t slide); 58 + static Protocol* RegisterProtocol(old_protocol* prot, uintptr_t extStart, unsigned long extLen); 59 + static void UpdateSelectors(const struct mach_header* mh, intptr_t slide); 60 + static void ProcessRuntimeOld(const struct mach_header* mh, intptr_t slide, old_class* classes, unsigned long size); 61 + static void ProcessRuntimeNew(const struct mach_header* mh, intptr_t slide, const class_t** classes, unsigned long size); 62 + static void ConvertProperties(Class c, const property_list_t* props); 63 + static void RegisterProtocolMethods(Protocol* p, const method_list_t* list, const char** extTypes, size_t& extIndex, bool required, bool instance); 64 + static void RegisterProtocolMethods(Protocol* p, const old_method_decl_list* list, bool required, bool instance); 70 65 71 - struct class_t 66 + template<typename OrigType, typename NewType> 67 + static void find_and_fix(OrigType** start, OrigType** end, const OrigType* what, const NewType* ptr) 72 68 { 73 - class_t* isa; // instance of 74 - class_t* superclass; 75 - void* cache; // empty cache imported here 76 - void* vtable; 77 - uintptr_t data_and_flags; 78 - 79 - // TODO: WTF? Should be rw data 80 - class_ro_t* data() const 69 + OrigType** pos = std::find(start, end, const_cast<OrigType*>(what)); 70 + if (pos != end) 81 71 { 82 - uintptr_t p = data_and_flags & ~uintptr_t(3); 83 - return reinterpret_cast<class_ro_t*>(p); 72 + LOG << "ObjC fixup @" << pos << ": " << *pos << " -> " << ptr << std::endl; 73 + *reinterpret_cast<uintptr_t*>(pos) = reinterpret_cast<uintptr_t>(ptr); 84 74 } 85 - }; 86 - 87 - union old_class_ptr 88 - { 89 - struct old_class* cls; 90 - const char* name; 91 - uintptr_t ptrValue; 92 - }; 93 - 94 - struct old_class 95 - { 96 - old_class_ptr isa; 97 - old_class_ptr super_class; 98 - const char *name; 99 - long version; 100 - long info; 101 - long instance_size; 102 - struct old_ivar_list *ivars; 103 - struct old_method_list *methodList; 104 - void* cache; 105 - struct old_protocol_list *protocols; 106 - // CLS_EXT only 107 - const uint8_t *ivar_layout; 108 - struct old_class_ext *ext; 109 - }; 110 - 111 - struct old_class_ext 112 - { 113 - uint32_t size; 114 - const uint8_t *weak_ivar_layout; 115 - struct old_property_list **propertyLists; 116 - }; 117 - 118 - struct old_category 119 - { 120 - char *category_name; 121 - char *class_name; 122 - struct old_method_list *instance_methods; 123 - struct old_method_list *class_methods; 124 - struct old_protocol_list *protocols; 125 - uint32_t size; 126 - struct old_property_list *instance_properties; 127 - }; 128 - 129 - struct old_ivar 130 - { 131 - char *name; 132 - char *type; 133 - int offset; 134 - #ifdef __x86_64__ 135 - int space; 136 - #endif 137 - }; 138 - 139 - struct old_ivar_list 140 - { 141 - int count; 142 - #ifdef __x86_64__ 143 - int space; 144 - #endif 145 - /* variable length structure */ 146 - struct old_ivar ivar_list[1]; 147 - }; 75 + } 148 76 77 + // mprotect() requires that mem be on a page boundary. 78 + // This function satisfies this requirement. 79 + static int mprotect_pagemult(void* mem, size_t len, int prot); 149 80 150 - struct old_method 81 + template<typename T> 82 + int mprotect_pagemult(T** mem, size_t len, int prot) 151 83 { 152 - const char* selName; 153 - const char* types; 154 - void* impl; 155 - }; 84 + return mprotect_pagemult(reinterpret_cast<void*>(mem), len, prot); 85 + } 156 86 157 - struct old_method_list 87 + /* UNUSED 88 + template<typename ForwardIterator, typename T, typename Processor> process_split_sections(ForwardIterator start, ForwardIterator end, const T& sep, Processor proc) 158 89 { 159 - struct old_method_list *obsolete; 90 + ForwardIterator beg = start; 91 + while (start != end) 92 + { 93 + if (*start == sep) 94 + { 95 + proc(beg, start); 96 + start++; 97 + beg = start; 98 + } 99 + else 100 + start++; 101 + } 160 102 161 - int count; 162 - #ifdef __x86_64__ 163 - int space; 164 - #endif 165 - /* variable length structure */ 166 - struct old_method method_list[1]; 167 - }; 168 - 169 - 170 - extern "C" Class objcdarwin_class_lookup(const class_t* cls); 103 + if (beg != end) 104 + proc(beg, end); 105 + } 106 + */ 171 107 172 108 #endif 173 109
+658
src/libobjcdarwin/ClassRegister.mm
··· 1 + #include "ClassRegister.h" 2 + #include "../dyld/public.h" 3 + #include "../util/trace.h" 4 + #include "../util/log.h" 5 + #include <climits> 6 + #include <stddef.h> 7 + #include <Foundation/NSObjCRuntime.h> 8 + #include <iostream> 9 + #include <map> 10 + #include <algorithm> 11 + #include <cstring> 12 + #include <cassert> 13 + #include <sys/mman.h> 14 + #include "TopologySort.h" 15 + 16 + static std::pair<uintptr_t,uintptr_t> g_cstringSection; 17 + // Superclass references in Mach-O don't use classref 18 + static std::map<const void*,Class> g_superClasses; 19 + 20 + // Here we process Mach-O files that have been loaded before this native library 21 + // Then we register a handler to process all images loaded in the future 22 + __attribute__((constructor)) 23 + void RegisterAlreadyLoadedClasses() 24 + { 25 + for (uint32_t i = 0; i < _dyld_image_count(); i++) 26 + { 27 + const struct mach_header* hdr = _dyld_get_image_header(i); 28 + ProcessImageLoad(hdr, 0); 29 + } 30 + 31 + _dyld_register_func_for_add_image(ProcessImageLoad); 32 + _dyld_register_func_for_remove_image(ProcessImageUnload); 33 + 34 + //std::cout << "Done registering\n"; 35 + } 36 + 37 + template<typename ListType> void ConvertMethodListGen(Class c, const ListType* list) 38 + { 39 + LOG << list->count << " methods within\n"; 40 + 41 + for (size_t i = 0; i < list->count; i++) 42 + { 43 + auto* m = &list->method_list[i]; 44 + 45 + LOG << "Method: selName: " << m->selName << "; types: " << m->types << "; impl: " << m->impl << std::endl; 46 + 47 + SEL sel = sel_registerName(m->selName); 48 + class_addMethod(c, sel, reinterpret_cast<IMP>(m->impl), m->types); 49 + } 50 + } 51 + 52 + static void ConvertIvarList(Class c, const ivar_list_t* list) 53 + { 54 + LOG << list->count << " ivars within\n"; 55 + 56 + for (size_t i = 0; i < list->count; i++) 57 + { 58 + auto* v = &list->ivar_list[i]; 59 + 60 + LOG << "Ivar: name: " << v->name << "; type: " << v->type << "; offset: " << *v->offset << "; size: " << v->size << "; alignment: " << v->alignment << std::endl; 61 + class_addIvar(c, v->name, v->size, v->alignment, v->type); 62 + } 63 + } 64 + 65 + static void ConvertIvarList(Class c, const old_ivar_list* list) 66 + { 67 + LOG << list->count << " ivars within\n"; 68 + 69 + for (size_t i = 0; i < list->count; i++) 70 + { 71 + auto* v = &list->ivar_list[i]; 72 + NSUInteger size, alignment; 73 + 74 + NSGetSizeAndAlignment(v->type, &size, &alignment); 75 + alignment = 1; // TODO: why do we need alignment when we have an offset? 76 + 77 + LOG << "Ivar: name: " << v->name << "; type: " << v->type << "; offset: " << v->offset << "; size: " << size << "; alignment: " << alignment << std::endl; 78 + class_addIvar(c, v->name, size, alignment, v->type); 79 + } 80 + } 81 + 82 + static bool nextAttribute(objc_property_attribute_t& next, const char*& pos, std::vector<std::string>& strings) 83 + { 84 + if (!*pos) 85 + return false; 86 + else if (*pos == ',') 87 + pos++; 88 + 89 + if (*pos == '"') 90 + { 91 + const char* start = ++pos; 92 + while (*pos != '"' && *pos) 93 + pos++; 94 + 95 + assert(*pos != '\0'); 96 + 97 + strings.push_back(std::string(start, pos-start)); 98 + next.name = strings.back().c_str(); 99 + 100 + start = ++pos; 101 + while (*pos != ',' && *pos) 102 + pos++; 103 + 104 + strings.push_back(std::string(start, pos-start)); 105 + next.value = strings.back().c_str(); 106 + } 107 + else 108 + { 109 + strings.push_back(std::string(1, *pos)); 110 + next.name = strings.back().c_str(); 111 + const char* start = ++pos; 112 + 113 + while (*pos != ',' && *pos) 114 + pos++; 115 + 116 + strings.push_back(std::string(start, pos-start)); 117 + next.value = strings.back().c_str(); 118 + } 119 + 120 + return true; 121 + } 122 + 123 + template<typename Func> 124 + void ConvertProperties(const property_list_t* props, Func f) 125 + { 126 + for (uint32_t i = 0; i < props->count; i++) 127 + { 128 + const property_t* prop = &props->list[i]; 129 + std::vector<objc_property_attribute_t> attribs; 130 + std::vector<std::string> strings; 131 + objc_property_attribute_t next; 132 + const char* pos = prop->attributes; 133 + 134 + while (nextAttribute(next, pos, strings)) 135 + attribs.push_back(next); 136 + 137 + f(prop->name, &attribs[0], attribs.size()); 138 + } 139 + } 140 + 141 + Class RegisterClass(const class_t* cls, intptr_t slide) 142 + { 143 + LOG << "Processing ObjC class " << cls->data()->className << std::endl; 144 + 145 + const class_t* meta = cls->isa; 146 + Class conv, super; 147 + auto itSuper = g_superClasses.find(cls->superclass); 148 + 149 + if (itSuper != g_superClasses.end()) 150 + super = itSuper->second; 151 + else 152 + super = reinterpret_cast<Class>(cls->superclass); 153 + 154 + LOG << "...superclass is @" << super << std::endl; 155 + conv = objc_allocateClassPair(super, cls->data()->className, 0); 156 + 157 + const class_ro_t* ro = cls->data(); 158 + const class_ro_t* roMeta = meta->data(); 159 + 160 + if (ro->baseMethods) 161 + ConvertMethodListGen(conv, ro->baseMethods); 162 + if (roMeta->baseMethods) 163 + ConvertMethodListGen(object_getClass(id(conv)), roMeta->baseMethods); 164 + if (ro->ivars) 165 + ConvertIvarList(conv, ro->ivars); 166 + if (ro->baseProtocols) 167 + { 168 + for (size_t i = 0; i < ro->baseProtocols->count; i++) 169 + { 170 + const char* name = ro->baseProtocols->elem(i, slide)->name; 171 + Protocol* p = objc_getProtocol(name); 172 + assert(p != nullptr); 173 + class_addProtocol(conv, p); 174 + } 175 + } 176 + if (ro->baseProperties) 177 + ConvertProperties(ro->baseProperties, [conv](const char* name, const objc_property_attribute_t* attr, unsigned int count) { class_addProperty(conv, name, attr, count); }); 178 + 179 + // conv->instance_size = ro->instSize; 180 + // conv->isa->instance_size = roMeta->instSize; 181 + 182 + objc_registerClassPair(conv); 183 + LOG << "ObjC class " << cls->data()->className << " now @" << conv << std::endl; 184 + g_superClasses[cls] = conv; 185 + 186 + return conv; 187 + } 188 + 189 + 190 + // This is very wrong. Does it have to be this way? 191 + static old_class* PtrToClass(old_class_ptr ptr) 192 + { 193 + if (ptr.ptrValue >= g_cstringSection.first && ptr.ptrValue < g_cstringSection.first+g_cstringSection.second) 194 + { 195 + //std::cout << ptr.cls << " found to be a string: " << ptr.name << std::endl; 196 + id cls = objc_getClass(ptr.name); // it is a string 197 + 198 + assert(cls != nullptr); 199 + return (old_class*) cls; 200 + } 201 + else 202 + { 203 + //std::cout << ptr.cls << " found to be ptr to class.\n"; 204 + return ptr.cls; 205 + } 206 + } 207 + 208 + Class RegisterClass(old_class* cls) 209 + { 210 + LOG << "Processing old ObjC class " << cls->name << std::endl; 211 + 212 + const old_class* meta = PtrToClass(cls->isa); 213 + Class conv, super; 214 + old_class* psuper = PtrToClass(cls->super_class); 215 + auto itSuper = g_superClasses.find(psuper); // TODO: may not be needed, should always be a string 216 + 217 + if (itSuper != g_superClasses.end()) 218 + super = itSuper->second; 219 + else 220 + super = reinterpret_cast<Class>(psuper); 221 + LOG << "...with superclass @" << super << std::endl; 222 + conv = objc_allocateClassPair(super, cls->name, 0); 223 + 224 + if (cls->methodList) 225 + ConvertMethodListGen(conv, cls->methodList); 226 + if (meta->methodList) 227 + ConvertMethodListGen(object_getClass(id(conv)), meta->methodList); 228 + if (cls->ivars) 229 + ConvertIvarList(conv, cls->ivars); 230 + if (cls->protocols) 231 + { 232 + for (long i = 0; i < cls->protocols->count; i++) 233 + { 234 + Protocol* p = objc_getProtocol(cls->protocols->list[i]->name); 235 + assert(p != nullptr); 236 + class_addProtocol(conv, p); 237 + } 238 + } 239 + // TODO: properties in EXT 240 + 241 + objc_registerClassPair(conv); 242 + g_superClasses[cls] = conv; 243 + g_superClasses[cls->name] = conv; 244 + 245 + LOG << "ObjC class " << cls->name << " @" << conv << std::endl; 246 + 247 + return conv; 248 + } 249 + 250 + void RegisterProtocolMethods(Protocol* p, const method_list_t* list, const char** extTypes, size_t& extIndex, bool required, bool instance) 251 + { 252 + LOG << "Registering Protocol methods (" << required << ", " << instance << "): " << list->count << " methods within\n"; 253 + for (size_t i = 0; i < list->count; i++, extIndex++) 254 + { 255 + SEL sel = sel_registerName(list->method_list[i].selName); 256 + protocol_addMethodDescription(p, sel, list->method_list[i].types, required, instance); 257 + // TODO: what do we do with extTypes? 258 + } 259 + } 260 + 261 + Protocol* RegisterProtocol(const protocol_t* prot, intptr_t slide) 262 + { 263 + // For reasons unknown, the NSObject protocol is duplicated into the binaries 264 + if (strcmp(prot->name, "NSObject") == 0) 265 + return objc_getProtocol(prot->name); 266 + 267 + LOG << "Processing ObjC Protocol: " << prot->name << std::endl; 268 + Protocol* conv = objc_allocateProtocol(prot->name); 269 + size_t methodIndex = 0; 270 + 271 + if (prot->protocols) 272 + { 273 + for (size_t i = 0; i < prot->protocols->count; i++) 274 + { 275 + const char* name = prot->protocols->elem(i, slide)->name; 276 + protocol_addProtocol(conv, objc_getProtocol(name)); 277 + } 278 + } 279 + 280 + if (prot->methods) 281 + RegisterProtocolMethods(conv, prot->methods, prot->extMethTypes, methodIndex, true, true); 282 + if (prot->staticMethods) 283 + RegisterProtocolMethods(conv, prot->staticMethods, prot->extMethTypes, methodIndex, true, false); 284 + if (prot->optMethods) 285 + RegisterProtocolMethods(conv, prot->optMethods, prot->extMethTypes, methodIndex, false, true); 286 + if (prot->optStaticMethods) 287 + RegisterProtocolMethods(conv, prot->optStaticMethods, prot->extMethTypes, methodIndex, false, false); 288 + 289 + if (prot->properties) 290 + ConvertProperties(prot->properties, [conv](const char* name, const objc_property_attribute_t* attr, unsigned int count) { protocol_addProperty(conv, name, attr, count, true, true); }); 291 + 292 + objc_registerProtocol(conv); 293 + return conv; 294 + } 295 + 296 + void RegisterProtocolMethods(Protocol* p, const old_method_decl_list* list, bool required, bool instance) 297 + { 298 + LOG << "Registering Protocol methods (" << required << ", " << instance << "): " << list->count << " methods within\n"; 299 + for (size_t i = 0; i < list->count; i++) 300 + { 301 + SEL sel = sel_registerName(list->list[i].name); 302 + protocol_addMethodDescription(p, sel, list->list[i].types, required, instance); 303 + // TODO: what do we do with extTypes? 304 + } 305 + } 306 + 307 + Protocol* RegisterProtocol(old_protocol* prot, uintptr_t extStart, unsigned long extLen) 308 + { 309 + // For reasons unknown, the NSObject protocol is duplicated into the binaries 310 + if (strcmp(prot->name, "NSObject") == 0) 311 + return objc_getProtocol(prot->name); 312 + 313 + LOG << "Processing old ObjC Protocol: " << prot->name << std::endl; 314 + Protocol* conv = objc_allocateProtocol(prot->name); 315 + 316 + if (prot->protocols) 317 + { 318 + for (size_t i = 0; i < prot->protocols->count; i++) 319 + { 320 + const char* name = prot->protocols->list[i]->name; 321 + protocol_addProtocol(conv, objc_getProtocol(name)); 322 + } 323 + } 324 + 325 + if (prot->methods) 326 + RegisterProtocolMethods(conv, prot->methods, true, true); 327 + if (prot->staticMethods) 328 + RegisterProtocolMethods(conv, prot->staticMethods, true, false); 329 + 330 + // Protocol EXT - weird stuff 331 + if (prot->ext_ptrValue >= extStart && prot->ext_ptrValue < extStart + extLen) 332 + { 333 + // TODO: check if rebase is present 334 + if (prot->ext->optMethods) 335 + RegisterProtocolMethods(conv, prot->ext->optMethods, false, true); 336 + if (prot->ext->optStaticMethods) 337 + RegisterProtocolMethods(conv, prot->ext->optStaticMethods, false, false); 338 + if (prot->ext->properties) 339 + ConvertProperties(prot->ext->properties, [conv](const char* name, const objc_property_attribute_t* attr, unsigned int count) { protocol_addProperty(conv, name, attr, count, true, true); }); 340 + } 341 + 342 + objc_registerProtocol(conv); 343 + return conv; 344 + } 345 + 346 + int mprotect_pagemult(void* mem, size_t len, int prot) 347 + { 348 + /* 349 + static int psize = ::getpagesize(); 350 + uintptr_t ptr = reinterpret_cast<uintptr_t>(mem); 351 + if (uintptr_t diff = ptr % psize) 352 + { 353 + ptr -= diff; 354 + len += diff; 355 + mem = reinterpret_cast<void*>(ptr); 356 + } 357 + return ::mprotect(mem, len, prot); 358 + */ 359 + // Short circuit: the segments that are now in use are always R/W 360 + return 0; 361 + } 362 + 363 + void ProcessRuntimeOld(const struct mach_header* mh, intptr_t slide, old_class* classes, unsigned long size) 364 + { 365 + unsigned long cstrLen; 366 + void* ptr; 367 + std::vector<old_class*> vecClasses; 368 + std::set<old_class*> setClasses; 369 + std::map<const char*,old_class*> mapClassNames; 370 + 371 + ProcessProtocolsOld(mh, slide); 372 + 373 + ptr = getsectdata(mh, "__TEXT", "__cstring", &cstrLen); 374 + if (ptr) 375 + g_cstringSection = std::pair<uintptr_t,uintptr_t>(uintptr_t(ptr), cstrLen); 376 + else 377 + g_cstringSection = std::pair<uintptr_t,uintptr_t>(0, 0); 378 + 379 + for (size_t i = 0; i < size / sizeof(old_class); i++) 380 + { 381 + mapClassNames[classes[i].name] = classes+i; 382 + setClasses.insert(classes+i); 383 + } 384 + 385 + topology_sort(setClasses, vecClasses, 386 + [&mapClassNames](old_class* t) -> std::set<old_class*> { auto it = mapClassNames.find(t->super_class.name); return (it != mapClassNames.end()) ? std::set<old_class*>{it->second} : std::set<old_class*>(); } 387 + ); 388 + 389 + for (old_class* c : vecClasses) 390 + RegisterClass(c); 391 + 392 + clsref* class_refs; 393 + unsigned long refsize; 394 + 395 + class_refs = reinterpret_cast<clsref*>( 396 + getsectdata(mh, SEG_OBJC_CLASSREFS_OLD, SECT_OBJC_CLASSREFS_OLD, &refsize) 397 + ); 398 + 399 + if (class_refs) 400 + { 401 + for (size_t i = 0; i < refsize / sizeof(clsref); i++) 402 + { 403 + Class c = objc_getClass(class_refs[i].clsName); 404 + LOG << "ObjC fixup classref @" << &class_refs[i].cls << ": " << class_refs[i].cls << " -> " << c << std::endl; 405 + class_refs[i].cls = c; 406 + } 407 + } 408 + 409 + // Change class names in 'super_class' from strings to pointers to Class 410 + for (size_t i = 0; i < size / sizeof(old_class); i++) 411 + { 412 + Class c = objc_getClass(classes[i].super_class.name); 413 + LOG << "ObjC fixup super_class @" << &classes[i].super_class << ": " << classes[i].super_class.name << " -> " << c << std::endl; 414 + classes[i].super_class.clsNew = c; 415 + } 416 + 417 + // Fix the same in metaclasses 418 + classes = reinterpret_cast<old_class*>( 419 + getsectdata(mh, SEG_OBJC_METALIST_OLD, SECT_OBJC_METALIST_OLD, &size) 420 + ); 421 + 422 + if (classes) 423 + { 424 + for (size_t i = 0; i < size / sizeof(old_class); i++) 425 + { 426 + Class c = objc_getClass(classes[i].super_class.name); 427 + LOG << "ObjC fixup super_class @" << &classes[i].super_class << ": " << classes[i].super_class.name << " -> " << c << std::endl; 428 + classes[i].super_class.clsNew = c; 429 + } 430 + } 431 + } 432 + 433 + void ProcessProtocolsNew(const struct mach_header* mh, intptr_t slide) 434 + { 435 + const protocol_t** protocol_list; 436 + unsigned long protosize; 437 + 438 + protocol_list = reinterpret_cast<const protocol_t**>( 439 + getsectdata(mh, SEG_OBJC_PROTOLIST_NEW, SECT_OBJC_PROTOLIST_NEW, &protosize) 440 + ); 441 + 442 + if (protocol_list) 443 + { 444 + unsigned long refsize; 445 + protocol_t** protocol_refs; 446 + protocol_t** protocol_refs_end; 447 + std::set<const protocol_t*> setProtocols; 448 + std::vector<const protocol_t*> vecProtocols; 449 + 450 + protocol_refs = reinterpret_cast<protocol_t**>( 451 + getsectdata(mh, SEG_OBJC_PROTOREFS_NEW, SECT_OBJC_PROTOREFS_NEW, &refsize) 452 + ); 453 + 454 + if (protocol_refs) 455 + protocol_refs_end = protocol_refs + refsize / sizeof(protocol_t*); 456 + 457 + std::copy(protocol_list, protocol_list+protosize/sizeof(protocol_t*), std::inserter(setProtocols, setProtocols.begin())); 458 + topology_sort<const protocol_t>(setProtocols, vecProtocols, 459 + [&setProtocols,slide](const protocol_t* p) { return p->protocols ? std::set<const protocol_t*>(p->protocols->begin(slide), p->protocols->end(slide)) : std::set<const protocol_t*>(); }); 460 + 461 + for (const protocol_t* proto : vecProtocols) 462 + { 463 + Protocol* p = RegisterProtocol(proto, slide); 464 + 465 + if (protocol_refs) 466 + find_and_fix(protocol_refs, protocol_refs_end, proto, p); 467 + } 468 + } 469 + } 470 + 471 + void ProcessProtocolsOld(const struct mach_header* mh, intptr_t slide) 472 + { 473 + old_protocol* protocols; 474 + unsigned long protosize; 475 + 476 + protocols = reinterpret_cast<old_protocol*>( 477 + getsectdata(mh, SEG_OBJC_PROTOCOLS_OLD, SECT_OBJC_PROTOCOLS_OLD, &protosize) 478 + ); 479 + 480 + if (protocols) 481 + { 482 + std::vector<old_protocol*> vecProtocols; 483 + std::set<old_protocol*> setProtocols; 484 + // std::map<const char*,old_protocol*> mapProtocols; 485 + 486 + for (size_t i = 0; i < protosize / sizeof(old_protocol); i++) 487 + { 488 + if (strcmp(protocols[i].name, "NSObject") != 0) // No need to re-register protocol NSObject 489 + setProtocols.insert(protocols + i); 490 + // mapProtocols[protocols[i].name] = protocols + i; 491 + } 492 + 493 + topology_sort<old_protocol>(setProtocols, vecProtocols, 494 + [&setProtocols](old_protocol* p) -> std::set<old_protocol*> 495 + { 496 + std::set<old_protocol*> set; 497 + if (p->protocols) 498 + { 499 + for (size_t i = 0; i < p->protocols->count; i++) 500 + { 501 + if (setProtocols.count(p->protocols->list[i])) 502 + set.insert(p->protocols->list[i]); 503 + } 504 + } 505 + return set; 506 + } 507 + ); 508 + 509 + // Find the section that holds protocol_ext structs 510 + uintptr_t extStart; 511 + unsigned long extLen = 0; 512 + 513 + extStart = reinterpret_cast<uintptr_t>( 514 + getsectdata(mh, SEG_OBJC_PROTOEXT_OLD, SECT_OBJC_PROTOEXT_OLD, &extLen) 515 + ); 516 + 517 + for (old_protocol* old : vecProtocols) 518 + { 519 + Protocol* p = RegisterProtocol(old, extStart, extLen); 520 + old->isa = p; // This is what is referenced in the code 521 + } 522 + } 523 + } 524 + 525 + void ProcessRuntimeNew(const struct mach_header* mh, intptr_t slide, const class_t** classes, unsigned long size) 526 + { 527 + class_t **class_refs, **class_refs_end, **super_refs, **super_refs_end; 528 + unsigned long refsize, refsize_s; 529 + std::vector<const class_t*> vecClasses; 530 + std::set<const class_t*> setClasses; 531 + 532 + ProcessProtocolsNew(mh, slide); 533 + 534 + class_refs = reinterpret_cast<class_t**>( 535 + getsectdata(mh, SEG_OBJC_CLASSREFS_NEW, SECT_OBJC_CLASSREFS_NEW, &refsize) 536 + ); 537 + super_refs = reinterpret_cast<class_t**>( 538 + getsectdata(mh, SEG_OBJC_SUPERREFS_NEW, SECT_OBJC_SUPERREFS_NEW, &refsize_s) 539 + ); 540 + if (class_refs) 541 + { 542 + class_refs_end = class_refs + refsize / sizeof(class_t*); 543 + mprotect_pagemult(class_refs, refsize, PROT_READ | PROT_WRITE); 544 + } 545 + 546 + if (super_refs) 547 + { 548 + super_refs_end = super_refs + refsize_s / sizeof(class_t*); 549 + mprotect_pagemult(super_refs, refsize, PROT_READ | PROT_WRITE); 550 + } 551 + 552 + std::copy(classes, classes+size/sizeof(class_t*), std::inserter(setClasses, setClasses.begin())); 553 + 554 + topology_sort<const class_t>(setClasses, vecClasses, 555 + [&setClasses](const class_t* t) { return setClasses.count(t->superclass) ? std::set<const class_t*>{t->superclass} : std::set<const class_t*>(); } 556 + ); 557 + 558 + for (const class_t* cls : vecClasses) 559 + { 560 + Class c = RegisterClass(cls, slide); 561 + 562 + if (class_refs) 563 + find_and_fix(class_refs, class_refs_end, cls, c); 564 + if (super_refs) 565 + find_and_fix(super_refs, super_refs_end, cls, c); 566 + } 567 + 568 + if (class_refs) 569 + mprotect_pagemult(class_refs, refsize, PROT_READ); 570 + if (super_refs) 571 + mprotect_pagemult(super_refs, refsize_s, PROT_READ); 572 + } 573 + 574 + void UpdateSelectors(const struct mach_header* mh, intptr_t slide) 575 + { 576 + selref* sel_refs; 577 + msgref* msg_refs; 578 + unsigned long selsize, msgsize; 579 + 580 + sel_refs = reinterpret_cast<selref*>( 581 + getsectdata(mh, SEG_OBJC_SELREFS_NEW, SECT_OBJC_SELREFS_NEW, &selsize) 582 + ); 583 + 584 + msg_refs = reinterpret_cast<msgref*>( 585 + getsectdata(mh, SEG_OBJC_MSGREFS_NEW, SECT_OBJC_MSGREFS_NEW, &msgsize) 586 + ); 587 + 588 + if (!sel_refs) 589 + { 590 + sel_refs = reinterpret_cast<selref*>( 591 + getsectdata(mh, SEG_OBJC_SELREFS_OLD, SECT_OBJC_SELREFS_OLD, &selsize) 592 + ); 593 + } 594 + 595 + if (sel_refs) 596 + { 597 + mprotect_pagemult(sel_refs, selsize, PROT_READ | PROT_WRITE); 598 + 599 + for (size_t i = 0; i < selsize / sizeof(selref); i++) 600 + { 601 + SEL native = sel_getUid(sel_refs[i].selName); 602 + LOG << "ObjC SEL fixup @" << (sel_refs+i) << ": " << sel_refs[i].sel << " -> " << native << std::endl; 603 + sel_refs[i].sel = native; 604 + } 605 + 606 + mprotect_pagemult(sel_refs, selsize, PROT_READ); 607 + } 608 + if (msg_refs) 609 + { 610 + mprotect_pagemult(msg_refs, msgsize, PROT_READ | PROT_WRITE); 611 + 612 + for (size_t i = 0; i < msgsize / sizeof(msgref); i++) 613 + { 614 + SEL native = sel_getUid(msg_refs[i].sel.selName); 615 + LOG << "ObjC msgref fixup @" << &msg_refs[i].sel.sel << ": " << msg_refs[i].sel.sel << " -> " << native << std::endl; 616 + msg_refs[i].sel.sel = native; 617 + } 618 + 619 + mprotect_pagemult(msg_refs, msgsize, PROT_READ); 620 + } 621 + } 622 + 623 + void ProcessImageLoad(const struct mach_header* mh, intptr_t slide) 624 + { 625 + unsigned long size; 626 + const class_t** classes; 627 + 628 + classes = reinterpret_cast<const class_t**>( 629 + getsectdata(mh, SEG_OBJC_CLASSLIST_NEW, SECT_OBJC_CLASSLIST_NEW, &size) 630 + ); 631 + 632 + if (!classes) 633 + { 634 + // Try the old runtime 635 + old_class* classes; 636 + 637 + classes = reinterpret_cast<old_class*>( 638 + getsectdata(mh, SEG_OBJC_CLASSLIST_OLD, SECT_OBJC_CLASSLIST_OLD, &size) 639 + ); 640 + 641 + if (classes) 642 + { 643 + ProcessRuntimeOld(mh, slide, classes, size); 644 + } 645 + } 646 + else 647 + { 648 + ProcessRuntimeNew(mh, slide, classes, size); 649 + } 650 + 651 + UpdateSelectors(mh, slide); 652 + } 653 + 654 + void ProcessImageUnload(const struct mach_header* mh, intptr_t) 655 + { 656 + // TODO 657 + } 658 +
+45
src/libobjcdarwin/TopologySort.h
··· 1 + #ifndef TOPOLOGYSORT_H 2 + #define TOPOLOGYSORT_H 3 + #include <map> 4 + #include <set> 5 + #include <vector> 6 + #include <cassert> 7 + 8 + // GNUStep ObjC runtime doesn't have "future classes", hence we need a TopologySort 9 + 10 + template <typename T, typename GetDepCb> 11 + void topology_visit(T* t, std::vector<T*>& elems, GetDepCb getDependency, std::set<T*>& visited) 12 + { 13 + if (!visited.count(t)) 14 + { 15 + visited.insert(t); 16 + auto deps = getDependency(t); 17 + 18 + for (T* d : deps) 19 + topology_visit(d, elems, getDependency, visited); 20 + 21 + elems.push_back(t); 22 + } 23 + } 24 + 25 + template <typename T, typename GetDepCb> 26 + void topology_sort(std::vector<T*>& elems, GetDepCb getDependency) 27 + { 28 + std::set<T*> visited; 29 + std::vector<T*> input = std::move(elems); 30 + 31 + elems.clear(); 32 + 33 + for (T* t : input) 34 + topology_visit(t, elems, getDependency, visited); 35 + } 36 + 37 + template <typename T, typename GetDepCb> 38 + void topology_sort(const std::set<T*>& elems, std::vector<T*>& sorted, GetDepCb getDependency) 39 + { 40 + std::set<T*> visited; 41 + for (T* t : elems) 42 + topology_visit(t, sorted, getDependency, visited); 43 + } 44 + 45 + #endif
+39
src/libobjcdarwin/TopologySortTest.cpp
··· 1 + #include "TopologySort.h" 2 + #include <iostream> 3 + #include <cassert> 4 + 5 + using namespace std; 6 + 7 + struct Obj 8 + { 9 + Obj(int n) : num(n), done(false) {} 10 + int num; 11 + bool done; 12 + set<Obj*> deps; 13 + }; 14 + 15 + int main() 16 + { 17 + vector<Obj*> objs; 18 + 19 + for (size_t i = 0; i < 5; i++) 20 + objs.push_back(new Obj(i)); 21 + 22 + objs[1]->deps.insert(objs[0]); 23 + objs[1]->deps.insert(objs[2]); 24 + objs[0]->deps.insert(objs[3]); 25 + objs[4]->deps.insert(objs[1]); 26 + 27 + topology_sort<Obj>(objs, [](Obj* o) { return o->deps; }); 28 + 29 + for (Obj* o : objs) 30 + { 31 + o->done = true; 32 + for (Obj* d : o->deps) 33 + assert(d->done); 34 + std::cout << o->num << std::endl; 35 + } 36 + 37 + return 0; 38 + } 39 +
+3 -2
src/libobjcdarwin/objc_msgSend.nasm
··· 5 5 extern sel_get_any_uid 6 6 extern objcdarwin_SaveRegisters 7 7 extern objcdarwin_RestoreRegisters 8 + extern objcdarwin_sel_lookup 8 9 9 10 %ifidn __OUTPUT_FORMAT__, elf64 10 11 ··· 24 25 25 26 ; move the second argument into the first argument 26 27 mov rdi, [rsp+8] 27 - call sel_get_any_uid WRT ..plt 28 + call objcdarwin_sel_lookup WRT ..plt 28 29 ; rax now has the GNU selector 29 30 ; move rax to the second argument 30 31 mov rsi, rax ··· 55 56 mov ecx, [esp+8] ; second argument 56 57 push ecx 57 58 58 - call sel_get_any_uid ;WRT ..plt 59 + call objcdarwin_sel_lookup ;WRT ..plt 59 60 60 61 add esp, 4 61 62 mov [esp+8], eax
+92
src/libobjcdarwin/objc_msgSendSuper.nasm
··· 1 + global __darwin_objc_msgSendSuper ; TODO: requires extracting superclass from Class 2 + global __darwin_objc_msgSendSuper2 3 + global __darwin_objc_msgSendSuper2_stret 4 + extern objc_msg_lookup_super 5 + 6 + %ifidn __OUTPUT_FORMAT__, elf64 7 + 8 + BITS 64 9 + section text 10 + 11 + __darwin_objc_msgSendSuper2: 12 + mov rdi, [rdi+8] 13 + 14 + __darwin_objc_msgSendSuper: 15 + push rdi 16 + push rsi 17 + push rdx 18 + push rcx 19 + push r8 20 + push r9 21 + 22 + call objc_msg_lookup_super WRT ..plt 23 + 24 + pop r9 25 + pop r8 26 + pop rcx 27 + pop rdx 28 + pop rsi 29 + pop rdi 30 + 31 + jmp rax 32 + 33 + __darwin_objc_msgSendSuper2_stret: 34 + mov rdi, [rdi+8] 35 + __darwin_objc_msgSendSuper_stret: 36 + push rdi 37 + push rsi 38 + push rdx 39 + push rcx 40 + push r8 41 + push r9 42 + 43 + mov rdi, rsi 44 + mov rsi, rdx 45 + 46 + call objc_msg_lookup_super WRT ..plt 47 + 48 + pop r9 49 + pop r8 50 + pop rcx 51 + pop rdx 52 + pop rsi 53 + pop rdi 54 + 55 + jmp rax 56 + 57 + %elifidn __OUTPUT_FORMAT__, elf 58 + 59 + BITS 32 60 + section text 61 + 62 + __darwin_objc_msgSendSuper2: 63 + mov eax, [esp+4] 64 + mov eax, [eax+4] 65 + mov [esp+4], eax 66 + 67 + __darwin_objc_msgSendSuper: 68 + 69 + mov eax, [esp+8] 70 + push eax 71 + mov eax, [esp+8] 72 + push eax 73 + call objc_msg_lookup_super 74 + add esp, 8 75 + jmp eax 76 + 77 + __darwin_objc_msgSendSuper2_stret: 78 + mov eax, [esp+12] 79 + push eax 80 + mov eax, [esp+20] 81 + push eax 82 + 83 + call objc_msg_lookup_super 84 + sub esp, 8 85 + 86 + jmp eax 87 + 88 + %else 89 + 90 + %error "Unsupported platform" 91 + 92 + %endif
+8 -69
src/libobjcdarwin/objc_msgSend_fixup.nasm
··· 1 1 global __darwin_objc_msgSend_fixup 2 - 3 - extern objcdarwin_class_lookup 4 - extern objc_msg_lookup 5 - extern sel_get_any_uid 6 - extern objcdarwin_SaveRegisters 7 - extern objcdarwin_RestoreRegisters 2 + extern objc_msgSend 8 3 9 4 %ifidn __OUTPUT_FORMAT__, elf64 10 5 11 6 BITS 64 12 7 section text 13 8 14 - ;__darwin_objc_msgSend_fixed: 15 - ; add rsi, 8 16 - ; jmp __darwin_objc_msgSend WRT ..plt 17 - 18 9 __darwin_objc_msgSend_fixup: 19 - ; Procedure: 20 - ; 1) get the converted GNU class from an Apple class 21 - ; 2) convert Apple selector to GNU 22 - ; 3) run objc_msg_lookup 23 - ; 4) jump to the pointer returned by objc_msg_lookup 24 - 25 - call objcdarwin_SaveRegisters WRT ..plt 26 - call objcdarwin_class_lookup WRT ..plt 27 - mov [rsp], rax ; save the converted value 28 - 29 - ; move the second argument into the first argument 30 - mov rdi, [rsp+8] 31 - add rdi, 8 ; the selector itself is the second element of what we receive as SEL 32 - mov rdi, [rdi] 33 - call sel_get_any_uid WRT ..plt 34 - ; rax now has the GNU selector 35 - ; move rax to the second argument 36 - mov rsi, rax 37 - 38 - ; restore the first argument 39 - mov rdi, [rsp] 40 - call objc_msg_lookup WRT ..plt 41 - 42 - ; optimize the next call by fixing the function pointer 43 - mov rsi, [rsp+8] 44 - ;mov [rsi], rax ; TODO: fixups not working, the target method still isn't getting the selector it expects 45 - 46 - call objcdarwin_RestoreRegisters WRT ..plt 47 - jmp rax 10 + mov rsi, [rsi+8] 11 + jmp objc_msgSend WRT ..plt 48 12 49 13 %elifidn __OUTPUT_FORMAT__, elf 50 14 51 15 BITS 32 52 16 section text 53 17 18 + ; Is it even used with the old runtime? 54 19 __darwin_objc_msgSend_fixup: 55 - 56 - mov ecx, [esp+4] 57 - push ecx ; arg for func call 58 - 59 - call objcdarwin_class_lookup ;WRT ..plt 60 - 61 - add esp, 4 ; remove argument 62 - mov [esp+4], eax ; change the class id 63 - 64 - mov ecx, [esp+8] ; second argument 65 - add ecx, 4 ; the selector itself is the second element of what we receive as SEL 66 - mov ecx, [ecx] 67 - push ecx 68 - 69 - call sel_get_any_uid ;WRT ..plt 70 - 71 - add esp, 4 72 - mov [esp+8], eax 73 - 74 - push eax ; reuse the sel_get_any_uid retval 75 20 mov eax, [esp+8] 76 - push eax ; class id 77 - 78 - call objc_msg_lookup ;WRT ..plt 79 - add esp, 8 80 - 81 - ; optimize the next call by fixing the function pointer 82 - mov ecx, [esp+8] 83 - ;mov [ecx], eax ; TODO: fixups not working, the target method still isn't getting the selector it expects 84 - 85 - jmp eax 21 + add eax, 4 22 + mov eax, [eax] 23 + mov [esp+8], eax 24 + jmp objc_msgSend 86 25 87 26 %else 88 27
-77
src/libobjcdarwin/objc_msgSend_stret.nasm
··· 1 - global __darwin_objc_msgSend_stret 2 - 3 - extern objcdarwin_class_lookup 4 - extern objc_msg_lookup 5 - extern sel_get_any_uid 6 - extern objcdarwin_SaveRegisters 7 - extern objcdarwin_RestoreRegisters 8 - 9 - %ifidn __OUTPUT_FORMAT__, elf64 10 - 11 - BITS 64 12 - section text 13 - 14 - ; Compared to ordinary msgSend, arguments are shifted by one - first arg is the stret 15 - __darwin_objc_msgSend_stret: 16 - ; Procedure: 17 - ; 1) get the converted GNU class from an Apple class 18 - ; 2) convert Apple selector to GNU 19 - ; 3) run objc_msg_lookup 20 - ; 4) jump to the pointer returned by objc_msg_lookup 21 - 22 - call objcdarwin_SaveRegisters WRT ..plt 23 - mov rdi, rsi 24 - call objcdarwin_class_lookup WRT ..plt 25 - mov [rsp+8], rax ; save the converted value 26 - 27 - ; move the second argument into the first argument 28 - mov rdi, [rsp+16] 29 - call sel_get_any_uid WRT ..plt 30 - ; rax now has the GNU selector 31 - ; move rax to the second argument 32 - mov rsi, rax 33 - mov [rsp+16], rax 34 - ; restore the first argument 35 - mov rdi, [rsp+8] 36 - call objc_msg_lookup WRT ..plt 37 - 38 - call objcdarwin_RestoreRegisters WRT ..plt 39 - jmp rax 40 - 41 - %elifidn __OUTPUT_FORMAT__, elf 42 - 43 - BITS 32 44 - section text 45 - 46 - __darwin_objc_msgSend_stret: 47 - 48 - mov ecx, [esp+8] 49 - push ecx ; arg for func call 50 - 51 - call objcdarwin_class_lookup ;WRT ..plt 52 - 53 - add esp, 4 ; remove argument 54 - mov [esp+8], eax ; change the class id 55 - 56 - mov ecx, [esp+12] ; second argument 57 - push ecx 58 - 59 - call sel_get_any_uid ;WRT ..plt 60 - 61 - add esp, 4 62 - mov [esp+12], eax 63 - 64 - push eax ; reuse the sel_get_any_uid retval 65 - mov eax, [esp+12] 66 - push eax ; class id 67 - 68 - call objc_msg_lookup ;WRT ..plt 69 - add esp, 8 70 - 71 - jmp eax 72 - 73 - %else 74 - 75 - %error "Unsupported platform" 76 - 77 - %endif
-51
src/libobjcdarwin/registers.nasm
··· 1 - %ifidn __OUTPUT_FORMAT__, elf64 2 - 3 - BITS 64 4 - section text 5 - 6 - global objcdarwin_SaveRegisters 7 - global objcdarwin_RestoreRegisters 8 - 9 - objcdarwin_SaveRegisters: 10 - pop r11 11 - 12 - sub rsp, 128 ; 8*16 13 - movdqu [rsp], xmm0 14 - movdqu [rsp+16], xmm1 15 - movdqu [rsp+32], xmm2 16 - movdqu [rsp+48], xmm3 17 - movdqu [rsp+64], xmm4 18 - movdqu [rsp+80], xmm5 19 - movdqu [rsp+96], xmm6 20 - movdqu [rsp+112], xmm7 21 - 22 - push r9 23 - push r8 24 - push rcx 25 - push rdx 26 - push rsi 27 - push rdi 28 - 29 - jmp r11 30 - 31 - objcdarwin_RestoreRegisters: 32 - pop r11 33 - pop rdi 34 - pop rsi 35 - pop rdx 36 - pop rcx 37 - pop r8 38 - pop r9 39 - movdqu xmm7, [rsp+112] 40 - movdqu xmm6, [rsp+96] 41 - movdqu xmm5, [rsp+80] 42 - movdqu xmm4, [rsp+64] 43 - movdqu xmm3, [rsp+48] 44 - movdqu xmm2, [rsp+32] 45 - movdqu xmm1, [rsp+16] 46 - movdqu xmm0, [rsp] 47 - add rsp, 128 48 - 49 - jmp r11 50 - %endif 51 -
+32
tests/src/objc_properties.m
··· 1 + #include <stdio.h> 2 + #import <Foundation/NSObject.h> 3 + #import <objc/runtime.h> 4 + 5 + @interface helloclass : NSObject { 6 + @private int var; 7 + } 8 + @property (readwrite,assign) int var; 9 + @end 10 + 11 + @implementation helloclass 12 + @synthesize var; 13 + @end 14 + 15 + int main() 16 + { 17 + helloclass* c = [helloclass new]; 18 + c.var = 5; 19 + 20 + unsigned int outCount, i; 21 + objc_property_t *properties = class_copyPropertyList([helloclass class], &outCount); 22 + for(i = 0; i < outCount; i++) 23 + { 24 + objc_property_t property = properties[i]; 25 + printf("%s %s\n", property_getName(property), property_getAttributes(property)); 26 + } 27 + free(properties); 28 + 29 + return 0; 30 + } 31 + 32 +
+53
tests/src/objc_protocol.m
··· 1 + #include <stdio.h> 2 + #import <Foundation/NSObject.h> 3 + 4 + @protocol MyProtocol <NSObject> 5 + @required 6 + + (void)doHelloStatic; 7 + - (void)doHello; 8 + @optional 9 + - (void)optFunc; 10 + @end 11 + 12 + @protocol EmptyProtocol 13 + + (void)dummy; 14 + @end 15 + 16 + @interface helloclass : NSObject<MyProtocol> { 17 + } 18 + 19 + + (void)doHelloStatic; 20 + - (void)doHello; 21 + @end 22 + 23 + @interface otherclass : NSObject { 24 + } 25 + 26 + @end 27 + 28 + @implementation otherclass 29 + @end 30 + 31 + @implementation helloclass 32 + + (void)doHelloStatic 33 + { 34 + puts("Hello world static"); 35 + } 36 + - (void)doHello 37 + { 38 + puts("Hello world instance"); 39 + } 40 + @end 41 + 42 + int main() 43 + { 44 + if ([helloclass conformsToProtocol:@protocol(MyProtocol)]) 45 + puts("helloclass conforms"); 46 + if (![otherclass conformsToProtocol:@protocol(MyProtocol)]) 47 + puts("otherclass doesn't conform"); 48 + id<MyProtocol> proto = [helloclass new]; 49 + [proto doHello]; 50 + return 0; 51 + } 52 + 53 +
+39
tests/src/objc_super.m
··· 1 + #include <stdio.h> 2 + #import <Foundation/NSObject.h> 3 + 4 + @interface helloclass : NSObject { 5 + } 6 + 7 + - (void)doHello; 8 + @end 9 + 10 + @implementation helloclass 11 + - (void)doHello 12 + { 13 + puts("Hello world from helloclass"); 14 + } 15 + @end 16 + 17 + @interface subclass : helloclass { 18 + } 19 + 20 + - (void)doHello; 21 + @end 22 + 23 + @implementation subclass 24 + - (void)doHello 25 + { 26 + puts("Calling superclass"); 27 + [super doHello]; 28 + } 29 + @end 30 + 31 + int main() 32 + { 33 + subclass* c = [subclass new]; 34 + [c doHello]; 35 + [c release]; 36 + return 0; 37 + } 38 + 39 +