From bf52b13b3df7288713273b38d8e92bbdcfcc6223 Mon Sep 17 00:00:00 2001 From: Apple Date: Mon, 20 Feb 2006 21:40:19 +0000 Subject: [PATCH] objc4-274.tar.gz --- Makefile | 10 +- libobjc.order | 135 +++++++ objc-exports-i386 => objc-exports | 0 objc-exports-ppc | 185 --------- runtime/Messengers.subproj/objc-msg-i386.s | 44 +-- runtime/Messengers.subproj/objc-msg-ppc.s | 28 +- runtime/objc-rtp.h | 5 +- runtime/objc-rtp.m | 1 + runtime/objc-runtime.h | 9 + runtime/objc-runtime.m | 417 +-------------------- 10 files changed, 205 insertions(+), 629 deletions(-) create mode 100644 libobjc.order rename objc-exports-i386 => objc-exports (100%) delete mode 100644 objc-exports-ppc diff --git a/Makefile b/Makefile index 65f4cb1..ee26d8e 100644 --- a/Makefile +++ b/Makefile @@ -79,7 +79,7 @@ NMEDIT = /usr/bin/nmedit LIPO = /usr/bin/lipo ifeq "$(PLATFORM)" "Darwin" -WARNING_FLAGS = -Wmost -Wno-precomp -Wno-four-char-constants +WARNING_FLAGS = -Wmost -Wno-four-char-constants endif ARCH_LIST= @@ -101,7 +101,7 @@ endif ifeq "$(ORDERFILE)" "" -ORDERFILE = $(wildcard /usr/local/lib/OrderFiles/libobjc.order) +ORDERFILE = $(SRCROOT)/libobjc.order endif ifneq "$(ORDERFILE)" "" ORDER = -sectorder __TEXT __text $(ORDERFILE) @@ -113,7 +113,7 @@ ifeq "$(USER)" "" USER = unknown endif -CFLAGS = -g -fno-common -fobjc-exceptions -pipe $(PLATFORM_CFLAGS) $(WARNING_FLAGS) -I$(SYMROOT) -I. -I$(SYMROOT)/ProjectHeaders +CFLAGS = -g -fno-common -fobjc-exceptions -fdollars-in-identifiers -pipe $(PLATFORM_CFLAGS) $(WARNING_FLAGS) -I$(SYMROOT) -I. -I$(SYMROOT)/ProjectHeaders LDFLAGS = LIBRARY_EXT = .dylib @@ -200,7 +200,7 @@ MODULE_SOURCES += runtime/Messengers.subproj/objc-msg-stub.s OTHER_SOURCES += runtime/Messengers.subproj/objc-msg-stub-ppc.s runtime/Messengers.subproj/objc-msg-stub-i386.s # project root -OTHER_SOURCES += Makefile APPLE_LICENSE objc-exports-i386 objc-exports-ppc +OTHER_SOURCES += Makefile APPLE_LICENSE objc-exports libobjc.order OBJECTS = $(addprefix $(OBJROOT)/, $(addsuffix .o, $(basename $(SOURCES) ) ) ) OBJECTS_OPTIMIZED = $(OBJECTS:.o=.opt.o) @@ -462,7 +462,7 @@ define link $3 ; \ $(SILENT) $(CC) $2 \ -arch $A \ - -Wl,-exported_symbols_list,$(SRCROOT)/objc-exports-$(A) \ + -Wl,-exported_symbols_list,$(SRCROOT)/objc-exports \ $(ORDER) \ -sectcreate __DATA __commpage $(OBJROOT)/runtime/objc-rtp-sym.$A.o \ -install_name /$(INSTALLDIR)/libobjc$1.$(VERSION_NAME)$(LIBRARY_EXT) \ diff --git a/libobjc.order b/libobjc.order new file mode 100644 index 0000000..de39416 --- /dev/null +++ b/libobjc.order @@ -0,0 +1,135 @@ +__objc_notify_images +___i686.get_pc_thunk.bx +_map_images +_getsegbynamefromheader +___i686.get_pc_thunk.cx +_verify_gc_readiness +_objc_msgSend +__class_lookupMethodAndLoadCache +_class_initialize +_objc_getClass +_look_up_class +_NXHashGet +_classHash +_classIsEqual +__class_changeInfo +__fetchInitializingClassList +__cache_getMethod +_fixupSelectorsInMethodList +__malloc_internal +__objc_internal_zone +_sel_lock +_sel_registerNameNoLock +___sel_registerName +__objc_search_builtins +___objc_sel_set_get +___objc_sel_set_findBuckets +___objc_sel_set_add +_sel_unlock +__cache_fill +__cache_getImp +__cache_create +__cache_malloc +__calloc_internal +_objc_assign_global +_objc_collecting_enabled +__internal_class_createInstanceFromZone +_object_cxxConstructFromClass +_object_getClassName +_objc_msgSendSuper +_objc_assign_ivar +dyld_stub_binding_helper +__cache_collect_free +_sel_registerName +__internal_object_dispose +_object_cxxDestruct +_object_cxxDestructFromClass +__objc_getFreedObjectClass +_objc_exception_try_enter +_objc_exception_try_exit +__strdup_internal +_class_respondsToMethod +__cache_addForwardEntry +_objc_assign_strongCast +_objc_msgSend_stret +_objc_msgSend_fpret +_class_getInstanceMethod +_objc_memmove_collectable +-[Protocol descriptionForInstanceMethod:] +_class_nextMethodList +_objc_getOrigClass +_NXMapGet +__mapStrHash +__free_internal +_NXUniqueString +_NXCreateHashTable +_NXCreateHashTableFromZone +_hashPrototype +_isEqualPrototype +_NXHashInsert +__NXHashRehashToCapacity +_freeBuckets +_NXNoEffectFree +_NXStrHash +_NXStrIsEqual +_class_poseAs +__objc_addOrigClass +__mapStrIsEqual +_NXMapInsert +_objc_getClasses +_NXHashRemove +__mapPtrHash +_NXInitHashState +_NXNextHashState +__objc_headerStart +__getObjcClassRefs +_sel_getName +_object_setInstanceVariable +_class_getInstanceVariable +_objc_setMultithreaded +-[Object self] +__objc_defaultClassHandler +_class_lookupMethod +__internal_object_copyFromZone +__objc_msgForward +_objc_msgSendv +_objc_loadModule +__getObjcModules +__getObjcImageInfo +__getImageSlide +__NXHashCapacity +_lookupNamedMethodInMethodList +_log2 +_resolve_categories_for_class +_connect_class +_class_is_connected +_NXHashMember +_really_connect_class +_NXCountHashTable +_NXFreeHashTable +__objc_fixup_selector_refs +__getObjcMessageRefs +__getObjcProtocols ++[Protocol _fixup:numElements:] +-[Protocol conformsTo:] +__objc_insertMethods +__objc_flush_caches +_flush_caches +_objc_getClassList +__realloc_internal +__cache_flush +__class_setInfo +__class_clearInfo +_map_method_descs +_objc_msgSendSuper_stret +_cache_region_calloc +_objc_msgSendv_stret +_objc_sync_enter +_id2data +_objc_sync_exit +__mapPtrIsEqual +__objc_pthread_destroyspecific +__destroyInitializingClassList +__objcInit +_objc_exception_extract +_objc_exception_match diff --git a/objc-exports-i386 b/objc-exports similarity index 100% rename from objc-exports-i386 rename to objc-exports diff --git a/objc-exports-ppc b/objc-exports-ppc deleted file mode 100644 index 7ae4460..0000000 --- a/objc-exports-ppc +++ /dev/null @@ -1,185 +0,0 @@ -# Functions and variables explicitly exported from ObjC. -# GrP 2002-2-4 -# Note that some commonly used functions are *not* listed in the -# ObjC headers (e.g. objc_flush_caches()) -# List.h -.objc_class_name_List -# objc-class.h -_object_setInstanceVariable -_object_getInstanceVariable -_class_createInstance -_class_createInstanceFromZone -_class_setVersion -_class_getVersion -_class_getInstanceVariable -_class_getInstanceMethod -_class_getClassMethod -_class_addMethods -_class_removeMethods -_class_poseAs -_method_getNumberOfArguments -_method_getSizeOfArguments -_method_getArgumentInfo -_class_nextMethodList -# objc-auto.h - actually, everything possible for now -_objc_collect -_objc_collect_generation -_objc_numberAllocated -_objc_isAuto -_objc_collecting_enabled -_objc_allocate_object -_objc_assign_strongCast -_objc_assign_global -_objc_assign_ivar -_objc_assign_strongCast_generic -_objc_assign_global_generic -_objc_assign_ivar_generic -_objc_assign_strongCast_CF -_objc_assign_ivar_address_CF -_objc_collect_init -_objc_is_finalized -_objc_memmove_collectable -_objc_collect_if_needed -# objc-exception.h -_objc_exception_throw -_objc_exception_try_enter -_objc_exception_try_exit -_objc_exception_extract -_objc_exception_match -_objc_exception_get_functions -_objc_exception_set_functions -# objc-sync.h -_objc_sync_enter -_objc_sync_exit -_objc_sync_wait -_objc_sync_notify -_objc_sync_notifyAll -# objc-load.h -_objc_loadModules -_objc_loadModule -_objc_unloadModules -# objc-runtime.h -_objc_getClass -_objc_getMetaClass -_objc_msgSend -# non-nil entry points disabled for now -# _objc_msgSendNonNil -_objc_msgSend_stret -# _objc_msgSendNonNil_stret -_objc_msgSendSuper -_objc_msgSendSuper_stret -_objc_msgSendv -_objc_msgSendv_stret -_objc_getClassList -_objc_getClasses -_objc_lookUpClass -_objc_getRequiredClass -_objc_addClass -_objc_setClassHandler -_objc_setMultithreaded -__alloc -__copy -__realloc -__dealloc -__zoneAlloc -__zoneRealloc -__zoneCopy -__error -# objc.h -_sel_isMapped -_sel_getName -_sel_getUid -_sel_registerName -_object_getClassName -_object_getIndexedIvars -# Object.h -.objc_class_name_Object -_object_dispose -_object_copy -_object_copyFromZone -_object_realloc -_object_reallocFromZone -# Protocol.h -.objc_class_name_Protocol -# error.h -# everything inside is declared but no longer defined?! -# hashtable2.h -_NXCreateHashTableFromZone -_NXCreateHashTable -_NXFreeHashTable -_NXEmptyHashTable -_NXResetHashTable -_NXCompareHashTables -_NXCopyHashTable -_NXCountHashTable -_NXHashMember -_NXHashGet -_NXHashInsert -_NXHashInsertIfAbsent -_NXHashRemove -_NXInitHashState -_NXNextHashState -_NXPtrHash -_NXStrHash -_NXPtrIsEqual -_NXStrIsEqual -_NXNoEffectFree -_NXReallyFree -_NXPtrPrototype -_NXStrPrototype -_NXPtrStructKeyPrototype -_NXStrStructKeyPrototype -_NXUniqueString -_NXUniqueStringWithLength -_NXUniqueStringNoCopy -_NXCopyStringBuffer -_NXCopyStringBufferFromZone -# maptable.h -_NXCreateMapTableFromZone -_NXCreateMapTable -_NXFreeMapTable -_NXResetMapTable -_NXCompareMapTables -_NXCountMapTable -_NXMapMember -_NXMapGet -_NXMapInsert -_NXMapRemove -_NXInitMapState -_NXNextMapState -_NXPtrValueMapPrototype -_NXStrValueMapPrototype -_NXObjectMapPrototype -# -# Functions that aren't in the headers but are used or are useful. -# -# sudo find / -xdev -type f -perm -0111 \! -name "libobjc*dylib" -print -exec nm -u {} \; > /tmp/all-used-symbols -# (repeat with any other disks you want checked, appending to the same file) -# nm /usr/lib/libobjc.dylib | awk '$2 ~ /^[ADST]$/' | colrm 1 11 | sort -u > /tmp/objc-exports -# (note that you need an unstripped, un-nmedited libobjc.dylib) -# grep -f /tmp/objc-exports /tmp/all-used-symbols | sort -u > /tmp/used-objc-symbols -# grep -v -f /tmp/used-objc-symbols /tmp/objc-exports | sort -u > /tmp/unused-objc-symbols -# -__class_printDuplicateCacheEntries -__class_printMethodCaches -__class_printMethodCacheStatistics -__objc_create_zone -__objc_error -__objc_flush_caches -__objc_msgForward -__objc_resolve_categories_for_class -__objc_setClassLoader -__objc_setNilReceiver -__objc_getNilReceiver -__objcInit -_class_lookupMethod -_class_respondsToMethod -_instrumentObjcMessageSends -_objc_getOrigClass -# magic, or garbage? -__dummy -_do_not_remove_this_dummy_function -# used by debugging tools like heap -__objc_debug_class_hash -# used by Foundation's NSAutoreleaseFreedObjectCheckEnabled -__objc_getFreedObjectClass diff --git a/runtime/Messengers.subproj/objc-msg-i386.s b/runtime/Messengers.subproj/objc-msg-i386.s index fc1dd57..d379ddc 100644 --- a/runtime/Messengers.subproj/objc-msg-i386.s +++ b/runtime/Messengers.subproj/objc-msg-i386.s @@ -324,24 +324,21 @@ $0: ////////////////////////////////////////////////////////////////////// // -// CALL_MCOUNTER counterName +// CALL_MCOUNTER // -// Allocate and maintain a counter for the call site. +// Calls mcount() profiling routine. Must be called immediately on +// function entry, before any prologue executes. // -// Takes: counterName - name of counter. ////////////////////////////////////////////////////////////////////// .macro CALL_MCOUNTER #ifdef PROFILE + // Current stack contents: ret pushl %ebp movl %esp,%ebp - LOAD_STATIC_WORD %eax, $0, LOCAL_SYMBOL + subl $kEight,%esp + // Current stack contents: ret, ebp, pad, pad CALL_EXTERN(mcount) - .data - .align 2 -$0: - .long 0 - .text movl %ebp,%esp popl %ebp #endif @@ -717,7 +714,7 @@ LGetImpExit: ********************************************************************/ ENTRY _objc_msgSend - CALL_MCOUNTER LP0 + CALL_MCOUNTER movl self(%esp), %eax @@ -742,9 +739,12 @@ LMsgSendNilSelf: call L_get_pc_thunk.edx // load new receiver 1: movl __objc_nilReceiver-1b(%edx),%eax testl %eax, %eax // return nil if no new receiver - je LMsgSendDone + je LMsgSendReturnZero movl %eax, self(%esp) // send to new receiver jmp LMsgSendReceiverOk +LMsgSendReturnZero: + // %eax is already zero + movl $0,%edx LMsgSendDone: ret @@ -768,7 +768,7 @@ LMsgSendExit: ********************************************************************/ ENTRY _objc_msgSendSuper - CALL_MCOUNTER LP1 + CALL_MCOUNTER movl super(%esp), %eax @@ -804,6 +804,7 @@ LMsgSendSuperExit: #else pushl %ebp movl %esp, %ebp + // stack is currently aligned assuming no extra arguments movl (marg_list+4)(%ebp), %edx addl $8, %edx // skip self & selector movl (marg_size+4)(%ebp), %ecx @@ -811,13 +812,12 @@ LMsgSendSuperExit: shrl $2, %ecx je LMsgSendvArgsOK - // %esp = %esp - (16 - ((numVariableArguments && 3) << 2)) + // %esp = %esp - (16 - ((numVariableArguments & 3) << 2)) movl %ecx, %eax // 16-byte align stack andl $3, %eax shll $2, %eax - neg %eax - addl $16, %eax - subl %eax, %esp + subl $16, %esp + addl %eax, %esp LMsgSendvArgLoop: decl %ecx @@ -838,7 +838,6 @@ LMsgSendvArgsOK: #endif END_ENTRY _objc_msgSendv - /******************************************************************** * * double objc_msgSend_fpret(id self, SEL _cmd,...); @@ -846,6 +845,7 @@ LMsgSendvArgsOK: ********************************************************************/ ENTRY _objc_msgSend_fpret + CALL_MCOUNTER movl self(%esp), %eax @@ -948,7 +948,7 @@ LMsgSendvFpretArgsOK: ********************************************************************/ ENTRY _objc_msgSend_stret - CALL_MCOUNTER LP2 + CALL_MCOUNTER movl self_stret(%esp), %eax @@ -982,7 +982,7 @@ LMsgSendStretDone: // guaranteed non-nil entry point (disabled for now) // .globl _objc_msgSendNonNil_stret // _objc_msgSendNonNil_stret: -// CALL_MCOUNTER LP3 +// CALL_MCOUNTER // movl self_stret(%esp), %eax // jmp LMsgSendStretReceiverOk @@ -1009,7 +1009,7 @@ LMsgSendStretExit: ********************************************************************/ ENTRY _objc_msgSendSuper_stret - CALL_MCOUNTER LP4 + CALL_MCOUNTER movl super_stret(%esp), %eax @@ -1050,6 +1050,7 @@ LMsgSendSuperStretExit: #else pushl %ebp movl %esp, %ebp + subl $12, %esp // align stack assuming no extra arguments movl (marg_list_stret+4)(%ebp), %edx addl $8, %edx // skip self & selector movl (marg_size_stret+4)(%ebp), %ecx @@ -1057,10 +1058,11 @@ LMsgSendSuperStretExit: shrl $2, %ecx jle LMsgSendvStretArgsOK + // %esp = %esp - (16 - ((numVariableArguments & 3) << 2)) movl %ecx, %eax // 16-byte align stack andl $3, %eax shll $2, %eax - subl $12, %esp + subl $16, %esp addl %eax, %esp LMsgSendvStretArgLoop: diff --git a/runtime/Messengers.subproj/objc-msg-ppc.s b/runtime/Messengers.subproj/objc-msg-ppc.s index 61b0bb0..da2bc6e 100644 --- a/runtime/Messengers.subproj/objc-msg-ppc.s +++ b/runtime/Messengers.subproj/objc-msg-ppc.s @@ -868,12 +868,19 @@ LMsgSendNilSelf: ; DO NOT CHANGE THE PREVIOUS SIX INSTRUCTIONS - see note above cmplwi r11,0 ; return nil if no new receiver - beqlr + beq LMsgSendReturnZero mr r3,r11 ; send to new receiver lwz r12,ISA(r11) ; class = receiver->isa b LMsgSendReceiverOk +LMsgSendReturnZero: + li r3, 0 + li r4, 0 + lis r12, ha16(kRTAddress_zero) + lfd f1, lo16(kRTAddress_zero)(r12) + lfd f2, lo16(kRTAddress_zero)(r12) + ; WARNING - This blr marks the end of the copy to the ObjC runtime pages and ; also marks the beginning of the cache miss code. Do not move ; around without checking the ObjC runtime pages initialization code. @@ -888,6 +895,15 @@ LMsgSendCacheMiss: LMsgSendExit: END_ENTRY _objc_msgSend +/******************************************************************** + * + * double objc_msgSend_fpret(id self, SEL op, ...); + * + ********************************************************************/ + + ENTRY _objc_msgSend_fpret + b _objc_msgSend + END_ENTRY _objc_msgSend_fpret /******************************************************************** * struct_type objc_msgSend_stret(id self, @@ -939,7 +955,7 @@ LMsgSendStretNilSelf: lwz r11,lo16(__objc_nilReceiver-1b)(r11) mtlr r0 - cmplwi r11,0 ; return nil if no new receiver + cmplwi r11,0 ; return if no new receiver beqlr mr r4,r11 ; send to new receiver @@ -1282,6 +1298,14 @@ LMsgSendvSendIt: END_ENTRY _objc_msgSendv +/******************************************************************** + * double objc_msgSendv_fpret(id self, SEL op, unsigned arg_size, + * marg_list arg_frame); + ********************************************************************/ + + ENTRY _objc_msgSendv_fpret + b _objc_msgSendv + END_ENTRY _objc_msgSendv_fpret /******************************************************************** * struct_type objc_msgSendv_stret(id self, diff --git a/runtime/objc-rtp.h b/runtime/objc-rtp.h index faae2ba..aa4e2c7 100644 --- a/runtime/objc-rtp.h +++ b/runtime/objc-rtp.h @@ -108,9 +108,10 @@ // Absolute address of data in the RTP area // These count forwards from the lo end of the RTP area. // These are not locked down and can be moved if necessary. -#define kRTAddress_ignoredSelector OBJC_UINTPTR_T(kRTPagesHi-kRTPagesSize) +#define kRTAddress_zero OBJC_UINTPTR_T(kRTPagesHi-kRTPagesSize) // 16 zero bytes +#define kRTAddress_ignoredSelector OBJC_UINTPTR_T(kRTAddress_zero+16) // string "" -#define kIgnore kRTAddress_ignoredSelector // ppc 0xfffef000 +#define kIgnore kRTAddress_ignoredSelector // ppc 0xfffef010 /********************************************************************* End of runtime page layout. diff --git a/runtime/objc-rtp.m b/runtime/objc-rtp.m index 2dd4071..4e5bbee 100644 --- a/runtime/objc-rtp.m +++ b/runtime/objc-rtp.m @@ -103,6 +103,7 @@ __private_extern__ void rtp_init(void) "objc_assign_strongCast", objc_assign_strongCast_gc, objc_assign_strongCast_non_gc); // initialize data in ObjC runtime pages + memset((char *)kRTAddress_zero, 0, 16); strcpy((char *)kIgnore, ""); // re-protect the ObjC runtime pages for execution diff --git a/runtime/objc-runtime.h b/runtime/objc-runtime.h index 8e0d02d..21acf92 100644 --- a/runtime/objc-runtime.h +++ b/runtime/objc-runtime.h @@ -125,8 +125,17 @@ OBJC_EXPORT double objc_msgSend_fpret(id self, SEL op, ...); /* Forwarding */ +/* Note that objc_msgSendv_stret() does not return a structure type, + * and should not be cast to do so. This is unlike objc_msgSend_stret() + * and objc_msgSendSuper_stret(). + */ + OBJC_EXPORT id objc_msgSendv(id self, SEL op, unsigned arg_size, marg_list arg_frame); OBJC_EXPORT void objc_msgSendv_stret(void * stretAddr, id self, SEL op, unsigned arg_size, marg_list arg_frame); +#ifdef __i386__ +OBJC_EXPORT double objc_msgSendv_fpret(id self, SEL op, unsigned arg_size, marg_list arg_frame); +#endif + /* getting all the classes in the application... diff --git a/runtime/objc-runtime.m b/runtime/objc-runtime.m index 6a61be9..3b90f09 100644 --- a/runtime/objc-runtime.m +++ b/runtime/objc-runtime.m @@ -289,10 +289,6 @@ static void _objc_fixup_selector_refs (const header_info * hi); static void _objc_unmap_image(const headerType *mh); static BOOL connect_class(struct objc_class *cls); static void add_category_to_loadable_list(struct objc_category *cat); -static vm_range_t get_shared_range(vm_address_t start, vm_address_t end); -static void offer_shared_range(vm_address_t start, vm_address_t end); -static void install_shared_range(vm_range_t remote, vm_address_t local); -static void clear_shared_range_file_cache(void); /*********************************************************************** @@ -1022,6 +1018,7 @@ static void _objc_read_categories_from_image (header_info * hi) return; } + // Major loop - process all modules in the header mods = hi->mod_ptr; @@ -2355,11 +2352,6 @@ static void verify_gc_readiness(BOOL wantsGC, header_info *hi) /*********************************************************************** * _objc_fixup_selector_refs. Register all of the selectors in each * image, and fix them all up. -* -* If the image is a dylib (not a bundle or an executable), and contains -* at least one full aligned page of selector refs, this function uses -* the shared range functions to try to recycle already-written memory -* from other processes. **********************************************************************/ static void _objc_fixup_selector_refs (const header_info * hi) { @@ -2381,75 +2373,8 @@ static void _objc_fixup_selector_refs (const header_info * hi) aligned_start = round_page(local_sels); aligned_end = trunc_page(local_sels + local_size); - if (aligned_start >= aligned_end || - hi->mhdr->filetype == MH_BUNDLE || - hi->mhdr->filetype == MH_EXECUTE) - { - // Less than a page of sels, OR bundle or executable - fix in place - - map_selrefs((SEL *)local_sels, (SEL *)local_sels, local_size, - hi->mhdr->filetype == MH_BUNDLE); - - if (PrintSharing) { - _objc_inform("SHARING: NONE [%p..%p) (%d pages) for %s", - local_sels, local_sels+local_size, - (aligned_end > aligned_start ? - (aligned_end-aligned_start) / vm_page_size : 0), - _nameForHeader(hi->mhdr)); - } - } - else { - // At least one page of sels - try to use sharing - vm_range_t remote_range; - - if (PrintSharing) { - _objc_inform("SHARING: looking for range [%p..%p) ...", - aligned_start, aligned_end); - } - - remote_range = get_shared_range(aligned_start, aligned_end); - - if (remote_range.address != 0) { - // Sharing succeeded - fix using remote_range - BOOL stomped; - - // local_sels..aligned_start (unshared) - map_selrefs((SEL *)local_sels, (SEL *)local_sels, - aligned_start - local_sels, NO); - // aligned_start..aligned_end (shared) - stomped = - map_selrefs((SEL *)aligned_start, (SEL *)remote_range.address, - aligned_end - aligned_start, NO); - // aligned_end..local_sels+local_size (unshared) - map_selrefs((SEL *)aligned_end, (SEL *)aligned_end, - local_sels+local_size - aligned_end, NO); - - install_shared_range(remote_range, aligned_start); - - if (PrintSharing) { - _objc_inform("SHARING: %s [%p..%p) (%d pages) for %s", - stomped ? "TRIED" : "USING", - local_sels, local_sels+local_size, - (aligned_end-aligned_start) / vm_page_size, - _nameForHeader(hi->mhdr)); - } - } - else { - // Sharing failed, including first process - - // fix in place and then offer to share - - map_selrefs((SEL *)local_sels, (SEL *)local_sels, local_size, NO); - - offer_shared_range(aligned_start, aligned_end); - - if (PrintSharing) { - _objc_inform("SHARING: OFFER [%p..%p) (%d pages) for %s", - local_sels, local_sels+local_size, - (aligned_end-aligned_start) / vm_page_size, - _nameForHeader(hi->mhdr)); - } - } - } + map_selrefs((SEL *)local_sels, (SEL *)local_sels, local_size, + hi->mhdr->filetype == MH_BUNDLE); } } @@ -2670,9 +2595,6 @@ static void map_images(const struct dyld_image_info infoList[], _objc_fixup_protocol_objects_for_image(hInfo); } - // Close any shared range file left open during selector uniquing - clear_shared_range_file_cache(); - firstTime = NO; // Call pending +load methods. @@ -3177,336 +3099,3 @@ __private_extern__ int secure_open(const char *filename, int flags, uid_t euid) } -/********************************************************************** - * Shared range support: - * - * Some libraries contain many pages worth of selector references. - * In most processes, these libraries get loaded at the same addresses, - * so the selectors are uniqued to the same values. To save memory, - * the runtime tries to share these memory pages across processes. - * - * A file /tmp/objc_sharing__ records memory ranges and process - * IDs. When a set of selector refs is to be uniqued, this file is checked - * for a matching memory range being shared by another process. If - * such a range is found: - * 1. map the sharing process's memory somewhere into this address space - * 2. read from the real selector refs and write into the mapped memory. - * 3. vm_copy from the mapped memory to the real selector refs location - * 4. deallocate the mapped memory - * - * The mapped memory is merely used as a guess. Correct execution is - * guaranteed no matter what values the mapped memory actually contains. - * If the mapped memory really matches the values needed in this process, - * the mapped memory will be unchanged. If the mapped memory doesn't match, - * or contains random values, it will be fixed up to the correct values. - * The memory is shared whenever the guess happens to be correct. - * - * The file of shared ranges is imprecise. Processes may die leaving - * their entries in the file. A PID may be recycled to some process that - * does not use Objective-C. The sharing mechanism is robust in the face - * of these failures. Bad shared memory is simply fixed up. No shared - * memory means the selectors are fixed in place. If an entry in the - * file is found to be unusable, the process that finds it will instead - * offer to share its own memory, replacing the bad entry in the file. - * - * Individual entries in the file are written atomically, but the file is - * otherwise unsynchronized. At worst, a sharing opportunity may be missed - * because two new entries are written simultaneously in the same place. - **********************************************************************/ - - -struct remote_range_t { - vm_range_t range; - pid_t pid; -}; - - -// Cache for the last shared range file used, and its EUID. -static pthread_mutex_t sharedRangeLock = PTHREAD_MUTEX_INITIALIZER; -static uid_t sharedRangeEUID = 0; -static FILE * sharedRangeFile = NULL; -static BOOL sharedRangeFileInUse = NO; - - -/********************************************************************** -* open_shared_range_file -* Open the shared range file "/tmp/objc_sharing__" in -* the given mode. -* The returned file should be closed with close_shared_range_file(). -**********************************************************************/ -static FILE *open_shared_range_file(BOOL create) -{ - const char arch[] = -#if defined(__ppc__) || defined(ppc) - "ppc"; -#elif defined(__ppc64__) || defined(ppc64) - "ppc64"; -#elif defined(__i386__) || defined(i386) - "i386"; -#else -# error "unknown architecture" -#endif - char filename[18 + sizeof(arch) + 1 + 3*sizeof(uid_t) + 1]; - uid_t euid; - FILE *file = NULL; - int fd; - - // Never share when superuser - euid = geteuid(); - if (euid == 0) { - if (PrintSharing) { - _objc_inform("SHARING: superuser never shares"); - } - return NULL; - } - - // Return cached file if it matches and it's not still being used - pthread_mutex_lock(&sharedRangeLock); - if (!sharedRangeFileInUse && euid == sharedRangeEUID) { - file = sharedRangeFile; - sharedRangeFileInUse = YES; - pthread_mutex_unlock(&sharedRangeLock); - rewind(file); - return file; - } - pthread_mutex_unlock(&sharedRangeLock); - - // Open /tmp/objc_sharing_ - snprintf(filename,sizeof(filename), "/tmp/objc_sharing_%s_%u", arch, euid); - fd = secure_open(filename, O_RDWR | (create ? O_CREAT : 0), euid); - if (fd >= 0) { - file = fdopen(fd, "r+"); - } - - if (file) { - // Cache this file if there's no already-open file cached - pthread_mutex_lock(&sharedRangeLock); - if (!sharedRangeFileInUse) { - sharedRangeFile = file; - sharedRangeEUID = euid; - sharedRangeFileInUse = YES; - } - pthread_mutex_unlock(&sharedRangeLock); - } - else { - // open() or fdopen() failed - if (PrintSharing) { - _objc_inform("SHARING: bad or missing sharing file '%s': %s", - filename, errno ? strerror(errno) : - "potential security violation"); - } - } - - return file; -} - - -/********************************************************************** -* close_shared_range_file -* Close a file opened with open_shared_range_file. -* The file may actually be kept open and cached for a future -* open_shared_range_file call. If so, clear_shared_range_file_cache() -* can be used to really close the file. -**********************************************************************/ -static void close_shared_range_file(FILE *file) -{ - // Flush any writes in case the file is kept open. - fflush(file); - - pthread_mutex_lock(&sharedRangeLock); - if (file == sharedRangeFile && sharedRangeFileInUse) { - // This file is the cached shared file. - // Leave the file open and cached, but no longer in use. - sharedRangeFileInUse = NO; - } else { - // This is not the cached file. - fclose(file); - } - pthread_mutex_unlock(&sharedRangeLock); -} - - -/********************************************************************** -* clear_shared_range_file_cache -* Really close any file left open by close_shared_range_file. -* This is called by map_images() after loading multiple images, each -* of which may have used the shared range file. -**********************************************************************/ -static void clear_shared_range_file_cache(void) -{ - pthread_mutex_lock(&sharedRangeLock); - if (sharedRangeFile && !sharedRangeFileInUse) { - fclose(sharedRangeFile); - sharedRangeFile = NULL; - sharedRangeEUID = 0; - sharedRangeFileInUse = 0; - } - pthread_mutex_unlock(&sharedRangeLock); -} - - -/********************************************************************** -* get_shared_range -* Try to find a shared range matching addresses [aligned_start..aligned_end). -* If a range is found, it is mapped into this process and returned. -* If no range is found, or the found range could not be mapped for -* some reason, the range {0, 0} is returned. -* aligned_start and aligned_end must be page-aligned. -**********************************************************************/ -static vm_range_t get_shared_range(vm_address_t aligned_start, - vm_address_t aligned_end) -{ - struct remote_range_t remote; - vm_range_t result; - FILE *file; - - result.address = 0; - result.size = 0; - - // Open shared range file, but don't create it - file = open_shared_range_file(NO); - if (!file) return result; - - // Search for the desired memory range - while (1 == fread(&remote, sizeof(remote), 1, file)) { - if (remote.pid != 0 && - remote.range.address == aligned_start && - remote.range.size == aligned_end - aligned_start) - { - // Found a match in the file - try to grab the memory - mach_port_name_t remote_task; - vm_prot_t cur_prot, max_prot; - vm_address_t local_addr; - kern_return_t kr; - - // Find the task offering the memory - kr = task_for_pid(mach_task_self(), remote.pid, &remote_task); - if (kr != KERN_SUCCESS) { - // task is dead - if (PrintSharing) { - _objc_inform("SHARING: no task for pid %d: %s", - remote.pid, mach_error_string(kr)); - } - break; - } - - // Map the memory into our process - local_addr = 0; - kr = vm_remap(mach_task_self(), &local_addr, remote.range.size, - 0 /*alignment*/, 1 /*anywhere*/, - remote_task, remote.range.address, - 1 /*copy*/, &cur_prot, &max_prot, VM_INHERIT_NONE); - mach_port_deallocate(mach_task_self(), remote_task); - - if (kr != KERN_SUCCESS) { - // couldn't map memory - if (PrintSharing) { - _objc_inform("SHARING: vm_remap from pid %d failed: %s", - remote.pid, mach_error_string(kr)); - } - break; - } - - if (!(cur_prot & VM_PROT_READ) || !(cur_prot & VM_PROT_WRITE)) { - // Received memory is not mapped read/write - don't use it - // fixme try to change permissions? check max_prot? - if (PrintSharing) { - _objc_inform("SHARING: memory from pid %d not read/write", - remote.pid); - } - vm_deallocate(mach_task_self(), local_addr, remote.range.size); - break; - } - - // Success - result.address = local_addr; - result.size = remote.range.size; - } - } - - close_shared_range_file(file); - return result; -} - - -/********************************************************************** -* offer_shared_range -* Offer memory range [aligned_start..aligned_end) in this process -* to other Objective-C-using processes. -* If some other entry in the shared range list matches this range, -* is is overwritten with this process's PID. (Thus any stale PIDs are -* replaced.) -* If the shared range file could not be updated for any reason, this -* function fails silently. -* aligned_start and aligned_end must be page-aligned. -**********************************************************************/ -static void offer_shared_range(vm_address_t aligned_start, - vm_address_t aligned_end) -{ - struct remote_range_t remote; - struct remote_range_t local; - BOOL found = NO; - FILE *file; - int err = 0; - - local.range.address = aligned_start; - local.range.size = aligned_end - aligned_start; - local.pid = getpid(); - - // Open shared range file, creating if necessary - file = open_shared_range_file(YES); - if (!file) return; - - // Find an existing entry for this range, if any - while (1 == fread(&remote, sizeof(remote), 1, file)) { - if (remote.pid != 0 && - remote.range.address == aligned_start && - remote.range.size == aligned_end - aligned_start) - { - // Found a match - overwrite it - err = fseek(file, -sizeof(remote), SEEK_CUR); - found = YES; - break; - } - } - - if (!found) { - // No existing entry - write at the end of the file - err = fseek(file, 0, SEEK_END); - } - - if (err == 0) { - fwrite(&local, sizeof(local), 1, file); - } - - close_shared_range_file(file); -} - - -/********************************************************************** -* install_shared_range -* Install a shared range received from get_shared_range() into -* its final resting place. -* If possible, the memory is copied using virtual memory magic rather -* than actual data writes. dst always gets updated values, even if -* virtual memory magic is not possible. -* The shared range is always deallocated. -* src and dst must be page-aligned. -**********************************************************************/ -static void install_shared_range(vm_range_t src, vm_address_t dst) -{ - kern_return_t kr; - - // Copy from src to dst - kr = vm_copy(mach_task_self(), src.address, src.size, dst); - if (kr != KERN_SUCCESS) { - // VM copy failed. Use non-VM copy. - if (PrintSharing) { - _objc_inform("SHARING: vm_copy failed: %s", mach_error_string(kr)); - } - memmove((void *)dst, (void *)src.address, src.size); - } - - // Unmap the shared range at src - vm_deallocate(mach_task_self(), src.address, src.size); -} -- 2.47.2