1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
27 #include <mach-o/loader.h>
33 #include <Availability.h>
35 #include "mach-o/dyld_priv.h"
36 #include "dyldLibSystemInterface.h"
39 extern void _ZN4dyld3logEPKcz(const char*, ...);
40 extern struct LibSystemHelpers
* _ZN4dyld17gLibSystemHelpersE
;
44 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
45 #define macho_header mach_header_64
46 #define macho_segment_command segment_command_64
47 #define macho_section section_64
48 #define getsectdatafromheader getsectdatafromheader_64
50 #define LC_SEGMENT_COMMAND LC_SEGMENT
51 #define macho_header mach_header
52 #define macho_segment_command segment_command
53 #define macho_section section
58 // The standard versions of __cxa_get_globals*() from libstdc++-static.a cannot be used.
59 // On Mac OS X, they use keymgr which dyld does not implement.
60 // On iPhoneOS, they use pthread_key_create which dyld cannot use.
62 // Implement these ourselves to make upcalls into libSystem to malloc and create a pthread key
64 static pthread_key_t sCxaKey
= 0;
65 static char sPreMainCxaGlobals
[2*sizeof(long)];
67 // called by libstdc++.a
68 char* __cxa_get_globals()
70 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
71 if ( (_ZN4dyld17gLibSystemHelpersE
== NULL
) || (_ZN4dyld17gLibSystemHelpersE
->version
< 7) )
72 return sPreMainCxaGlobals
;
76 // we don't need a lock because only one thread can be in dyld at a time
77 _ZN4dyld17gLibSystemHelpersE
->pthread_key_create(&sCxaKey
, &free
);
79 char* data
= (char*)_ZN4dyld17gLibSystemHelpersE
->pthread_getspecific(sCxaKey
);
81 long* t
= (long*)calloc(2,sizeof(long));
83 _ZN4dyld17gLibSystemHelpersE
->pthread_setspecific(sCxaKey
, data
);
88 // called by libstdc++.a
89 char* __cxa_get_globals_fast()
91 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
92 if ( (_ZN4dyld17gLibSystemHelpersE
== NULL
) || (_ZN4dyld17gLibSystemHelpersE
->version
< 7) )
93 return sPreMainCxaGlobals
;
95 return _ZN4dyld17gLibSystemHelpersE
->pthread_getspecific(sCxaKey
);
100 #if !__USING_SJLJ_EXCEPTIONS__
102 // When dyld uses zero-cost exceptions it just needs to implement
103 // _dyld_find_unwind_sections to return sections inside dyld proper.
106 extern void* ehStart
__asm("section$start$__TEXT$__eh_frame");
107 extern void* ehEnd
__asm("section$end$__TEXT$__eh_frame");
108 extern void* uwStart
__asm("section$start$__TEXT$__unwind_info");
109 extern void* uwEnd
__asm("section$end$__TEXT$__unwind_info");
111 extern void* textStart
__asm("section$start$__TEXT$__text");
112 extern void* textEnd
__asm("section$end$__TEXT$__text");
114 extern void* __dso_handle
;
116 // called by libuwind code to find unwind information sections in dyld
117 bool _dyld_find_unwind_sections(void* addr
, struct dyld_unwind_sections
* info
)
119 if ( ((void*)&textStart
< addr
) && (addr
< (void*)&textEnd
) ) {
120 info
->mh
= (struct mach_header
*)&__dso_handle
;
121 info
->dwarf_section
= &ehStart
;
122 info
->dwarf_section_length
= ((char*)&ehEnd
- (char*)&ehStart
);
123 info
->compact_unwind_section
= &uwStart
;
124 info
->compact_unwind_section_length
= ((char*)&uwEnd
- (char*)&uwStart
);
134 // When dyld uses setjump-longjump exceptions it needs to implement
135 // routines to push and pop a stack of _Unwind_FunctionContext.
138 struct _Unwind_FunctionContext
140 // next function in stack of handlers
141 struct _Unwind_FunctionContext
* prev
;
146 static pthread_key_t sThreadChainKey
= 0;
147 static struct _Unwind_FunctionContext
* sStaticThreadChain
= NULL
;
150 // When libSystem's initializers are run, they call back into dyld's
151 // registerThreadHelpers which creates a pthread key and calls
152 // __Unwind_SjLj_SetThreadKey().
154 void __Unwind_SjLj_SetThreadKey(pthread_key_t key
)
156 sThreadChainKey
= key
;
157 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), sStaticThreadChain=%p\n", key, sStaticThreadChain);
158 // switch static chain to be per thread
159 _ZN4dyld17gLibSystemHelpersE
->pthread_setspecific(sThreadChainKey
, sStaticThreadChain
);
160 sStaticThreadChain
= NULL
;
161 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), result=%d, new top=%p\n", key, result, pthread_getspecific(sThreadChainKey));
165 //static void printChain()
167 // _ZN4dyld3logEPKcz("chain: ");
168 // struct _Unwind_FunctionContext* start = sStaticThreadChain;
169 // if ( sThreadChainKey != 0 ) {
170 // start = (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey);
172 // for (struct _Unwind_FunctionContext* p = start; p != NULL; p = p->prev) {
173 // _ZN4dyld3logEPKcz("%p -> ", p);
175 // _ZN4dyld3logEPKcz("\n");
179 struct _Unwind_FunctionContext
* __Unwind_SjLj_GetTopOfFunctionStack()
181 //_ZN4dyld3logEPKcz("__Unwind_SjLj_GetTopOfFunctionStack(), key=%d, ", sThreadChainKey);
183 if ( sThreadChainKey
!= 0 ) {
184 return (struct _Unwind_FunctionContext
*)pthread_getspecific(sThreadChainKey
);
187 return sStaticThreadChain
;
191 void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext
* fc
)
193 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, prev=%p\n",
194 // fc, sThreadChainKey, (fc != NULL) ? fc->prev : NULL);
195 if ( sThreadChainKey
!= 0 )
196 _ZN4dyld17gLibSystemHelpersE
->pthread_setspecific(sThreadChainKey
, fc
);
198 sStaticThreadChain
= fc
;
199 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, ", fc, sThreadChainKey);