X-Git-Url: https://git.saurik.com/apple/objc4.git/blobdiff_plain/ee974f79090efc52c8d37c74dff5abadabf50296..8972963c21fb120c80c09e06536ba4aa7eb98af3:/runtime/objc-rtp.m diff --git a/runtime/objc-rtp.m b/runtime/objc-rtp.m index c903eb5..2fa1b6c 100644 --- a/runtime/objc-rtp.m +++ b/runtime/objc-rtp.m @@ -20,278 +20,12 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - Implementation of the "objc runtime pages", an fixed area - in high memory that can be reached via an absolute branch. -*/ #import "objc-private.h" #import -#if defined(__ppc__) - -static size_t rtp_copy_code(unsigned* dest, unsigned* source, size_t max_insns); -static void rtp_set_up_objc_msgSend(uintptr_t address, size_t maxsize); -static void rtp_set_up_other(uintptr_t address, size_t maxsize, const char *name, void *gc_code, void *non_gc_code); - -/********************************************************************** -* rtp_init -* Allocate and initialize the Objective-C runtime pages. -* Kills the process if something goes wrong. -**********************************************************************/ -__private_extern__ void rtp_init(void) -{ - kern_return_t ret; - vm_address_t objcRTPages = (vm_address_t)(kRTPagesHi - kRTPagesSize); - - if (PrintRTP) { - _objc_inform("RTP: initializing rtp at [%p..%p)", - (void *)objcRTPages, (void *)kRTPagesHi); - } - - // unprotect the ObjC runtime pages for writing - ret = vm_protect(mach_task_self(), - objcRTPages, kRTPagesSize, - FALSE, VM_PROT_READ | VM_PROT_WRITE); - - if (ret != KERN_SUCCESS) { - if (PrintRTP) { - _objc_inform("RTP: warning: libSystem/kernel did not allocate Objective-C runtime pages; continuing anyway"); - } - return; - } - - // initialize code in ObjC runtime pages - rtp_set_up_objc_msgSend(kRTAddress_objc_msgSend, kRTSize_objc_msgSend); -#ifdef NO_GC - #define objc_assign_ivar_gc objc_assign_ivar_non_gc - #define objc_assign_global_gc objc_assign_global_non_gc - #define objc_assign_strongCast_gc objc_assign_strongCast_non_gc -#endif - rtp_set_up_other(kRTAddress_objc_assign_ivar, kRTSize_objc_assign_ivar, - "objc_assign_ivar", objc_assign_ivar_gc, objc_assign_ivar_non_gc); - - rtp_set_up_other(kRTAddress_objc_assign_global, kRTSize_objc_assign_global, - "objc_assign_global", objc_assign_global_gc, objc_assign_global_non_gc); - - rtp_set_up_other(kRTAddress_objc_assign_strongCast, kRTSize_objc_assign_strongCast, - "objc_assign_strongCast", objc_assign_strongCast_gc, objc_assign_strongCast_non_gc); - - // initialize data in ObjC runtime pages - memset((char *)kRTAddress_zero, 0, 16); - strlcpy((char *)kIgnore, "", OBJC_SIZE_T(19)); - - // re-protect the ObjC runtime pages for execution - ret = vm_protect(mach_task_self(), - objcRTPages, kRTPagesSize, - FALSE, VM_PROT_READ | VM_PROT_EXECUTE); - if (ret != KERN_SUCCESS) { - _objc_inform("RTP: Could not re-protect Objective-C runtime pages!"); - } -} - - -/********************************************************************** -* rtp_set_up_objc_msgSend -* -* Construct the objc runtime page version of objc_msgSend -* address is the entry point of the new implementation. -* maxsize is the number of bytes available for the new implementation. -**********************************************************************/ -static void rtp_set_up_objc_msgSend(uintptr_t address, size_t maxsize) -{ - // Location in the runtime pages of the new function. - unsigned *buffer = (unsigned *)address; - - // Location of the original implementation. - // objc_msgSend is simple enough to copy directly - unsigned *code = (unsigned *)objc_msgSend; - - // If building an instrumented or profiled runtime, simply branch - // directly to the full implementation. -#if defined(OBJC_INSTRUMENTED) || defined(PROFILE) - size_t written = objc_write_branch(buffer, code); - sys_icache_invalidate(buffer, written*4); - if (PrintRTP) { - _objc_inform("RTP: instrumented or profiled libobjc - objc_msgSend " - "in RTP at %p is a %zu instruction branch", - buffer, written); - } - return; -#endif - - if (PrintRTP) { - _objc_inform("RTP: writing objc_msgSend at [%p..%p) ...", - (void *)address, (void *)(address+maxsize)); - } - - // Copy instructions from function to runtime pages - // i is the number of INSTRUCTIONS written so far - size_t max_insns = maxsize / sizeof(unsigned); - size_t i = rtp_copy_code(buffer, code, max_insns); - if (i + objc_branch_size(buffer + i, code + i) > max_insns) { - // objc_msgSend didn't fit in the alloted space. - // Branch to ordinary objc_msgSend instead so the program won't crash. - i = objc_write_branch(buffer, code); - sys_icache_invalidate(buffer, i*4); - _objc_inform("RTP: objc_msgSend is too large to fit in the " - "runtime pages (%zu bytes available)", maxsize); - return; - } - - { - // Replace load of _objc_nilReceiver into r11 - // This assumes that the load of _objc_nilReceiver - // immediately follows the LAST `mflr r0` in objc_msgSend, - // and that the original load sequence is six instructions long. - - // instructions used to load _objc_nilReceiver - const unsigned op_mflr_r0 = 0x7c0802a6u; - const unsigned op_nop = 0x60000000u; - - // get address of _objc_nilReceiver, and its lo and hi halves - uintptr_t address = (uintptr_t)&_objc_nilReceiver; - uint16_t lo = address & 0xffff; - uint16_t ha = ((address - (int16_t)lo) >> 16) & 0xffff; -#if defined(__ppc64__) - uint16_t hi2 = (address >> 32) & 0xffff; - uint16_t hi3 = (address >> 48) & 0xffff; -#endif - - // search for mflr instruction - size_t j; - for (j = i; j-- != 0; ) { - if (buffer[j] == op_mflr_r0) { - const unsigned op_lis_r11 = 0x3d600000u; - const unsigned op_lwz_r11 = 0x816b0000u; -#if defined(__ppc__) - // lis r11, ha - // lwz r11, lo(r11) - buffer[j + 0] = op_lis_r11 | ha; - buffer[j + 1] = op_nop; - buffer[j + 2] = op_nop; - buffer[j + 3] = op_lwz_r11 | lo; - buffer[j + 4] = op_nop; - buffer[j + 5] = op_nop; -#elif defined(__ppc64__) - const unsigned op_ori_r11 = 0x616b0000u; - const unsigned op_oris_r11 = 0x656b0000u; - const unsigned op_sldi_r11 = 0x796b07c6u; - // lis r11, hi3 - // ori r11, r11, hi2 - // sldi r11, r11, 32 - // oris r11, r11, ha - // lwz r11, lo(r11) - buffer[j + 0] = op_lis_r11 | hi3; - buffer[j + 1] = op_ori_r11 | hi2; - buffer[j + 2] = op_sldi_r11; - buffer[j + 3] = op_oris_r11 | ha; - buffer[j + 4] = op_lwz_r11 | lo; - buffer[j + 5] = op_nop; -#endif - break; - } - } - } - - // branch to the cache miss code - i += objc_write_branch(buffer + i, code + i); - - // flush the instruction cache - sys_icache_invalidate(buffer, i*4); - - if (PrintRTP) { - _objc_inform("RTP: wrote objc_msgSend at [%p..%p)", - (void *)address, (void *)(address + i*sizeof(unsigned))); - } -} - - -/********************************************************************** -* rtp_set_up_other -* -* construct the objc runtime page version of the supplied code -* address is the entry point of the new implementation. -* maxsize is the number of bytes available for the new implementation. -* name is the c string name of the routine being set up. -* gc_code is the code to use if collecting is enabled (assumed to be large and requiring a branch.) -* non_gc_code is the code to use if collecting is not enabled (assumed to be small enough to copy.) -**********************************************************************/ -static void rtp_set_up_other(uintptr_t address, size_t maxsize, const char *name, void *gc_code, void *non_gc_code) { - // location in the runtime pages of this function - unsigned *buffer = (unsigned *)address; - - // Location of the original implementation. - unsigned *code = (unsigned *)(objc_collecting_enabled() ? gc_code : non_gc_code); - - if (objc_collecting_enabled()) { - size_t written = objc_write_branch(buffer, code); - sys_icache_invalidate(buffer, written*4); - if (PrintRTP) { - _objc_inform("RTP: %s in RTP at %p is a %zu instruction branch", - name, buffer, written); - } - return; - } - - if (PrintRTP) { - _objc_inform("RTP: writing %s at [%p..%p) ...", - name, (void *)address, (void *)(address + maxsize)); - } - - // Copy instructions from function to runtime pages - // i is the number of INSTRUCTIONS written so far - size_t max_insns = maxsize / sizeof(unsigned); - size_t i = rtp_copy_code(buffer, code, max_insns); - if (i > max_insns) { - // code didn't fit in the alloted space. - // Branch to ordinary objc_assign_ivar instead so the program won't crash. - i = objc_write_branch(buffer, code); - sys_icache_invalidate(buffer, i*4); - _objc_inform("RTP: %s is too large to fit in the " - "runtime pages (%zu bytes available)", name, maxsize); - return; - } - - // flush the instruction cache - sys_icache_invalidate(buffer, i*4); - - if (PrintRTP) { - _objc_inform("RTP: wrote %s at [%p..%p)", - name, (void *)address, - (void *)(address + i * sizeof(unsigned))); - } -} - - -/********************************************************************** -* rtp_copy_code -* -* Copy blr-terminated PPC instructions from source to dest. -* If a blr is reached then that blr is copied, and the return value is -* the number of instructions copied ( <= max_insns ) -* If no blr is reached then exactly max_insns instructions are copied, -* and the return value is max_insns+1. -**********************************************************************/ -static size_t rtp_copy_code(unsigned* dest, unsigned* source, size_t max_insns) -{ - const unsigned op_blr = 0x4e800020u; - size_t i; - - // copy instructions until blr is found - for (i = 0; i < max_insns; i++) { - dest[i] = source[i]; - if (source[i] == op_blr) break; - } - - // return number of instructions copied - // OR max_insns+1 if no blr was found - return i + 1; -} - - -#elif defined(__i386__) +#if defined(__i386__) /********************************************************************** @@ -317,17 +51,19 @@ static void rtp_swap_imp(unsigned *address, void *code, const char *name) } -__private_extern__ void rtp_init(void) +PRIVATE_EXTERN void rtp_init(void) { // At load time, the page on which the objc_assign_* routines live is not // marked as executable. We fix that here, regardless of the GC choice. -#ifndef NO_GC +#if SUPPORT_GC if (UseGC) { rtp_swap_imp((unsigned*)objc_assign_ivar, objc_assign_ivar_gc, "objc_assign_ivar"); rtp_swap_imp((unsigned*)objc_assign_global, objc_assign_global_gc, "objc_assign_global"); + rtp_swap_imp((unsigned*)objc_assign_threadlocal, + objc_assign_threadlocal_gc, "objc_assign_threadlocal"); rtp_swap_imp((unsigned*)objc_assign_strongCast, objc_assign_strongCast_gc, "objc_assign_strongCast"); } @@ -344,7 +80,7 @@ __private_extern__ void rtp_init(void) #else -__private_extern__ void rtp_init(void) +PRIVATE_EXTERN void rtp_init(void) { if (PrintRTP) { _objc_inform("RTP: no rtp implementation for this platform");