1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2008 Apple Computer, 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"
38 extern void _ZN4dyld3logEPKcz(const char*, ...);
39 extern struct LibSystemHelpers
* _ZN4dyld17gLibSystemHelpersE
;
43 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
44 #define macho_header mach_header_64
45 #define macho_segment_command segment_command_64
46 #define macho_section section_64
47 #define getsectdatafromheader getsectdatafromheader_64
49 #define LC_SEGMENT_COMMAND LC_SEGMENT
50 #define macho_header mach_header
51 #define macho_segment_command segment_command
52 #define macho_section section
57 // The standard versions of __cxa_get_globals*() from libstdc++-static.a cannot be used.
58 // On Mac OS X, they use keymgr which dyld does not implement.
59 // On iPhoneOS, they use pthread_key_create which dyld cannot use.
61 // Implement these ourselves to make upcalls into libSystem to malloc and create a pthread key
63 static pthread_key_t sCxaKey
= 0;
64 static char sPreMainCxaGlobals
[2*sizeof(long)];
66 // called by libstdc++.a
67 char* __cxa_get_globals()
69 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
70 if ( (_ZN4dyld17gLibSystemHelpersE
== NULL
) || (_ZN4dyld17gLibSystemHelpersE
->version
< 5) )
71 return sPreMainCxaGlobals
;
75 // we don't need a lock because only one thread can be in dyld at a time
76 _ZN4dyld17gLibSystemHelpersE
->pthread_key_create(&sCxaKey
, &free
);
78 char* data
= (char*)pthread_getspecific(sCxaKey
);
80 data
= calloc(2,sizeof(void*));
81 _ZN4dyld17gLibSystemHelpersE
->pthread_setspecific(sCxaKey
, data
);
86 // called by libstdc++.a
87 char* __cxa_get_globals_fast()
89 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
90 if ( (_ZN4dyld17gLibSystemHelpersE
== NULL
) || (_ZN4dyld17gLibSystemHelpersE
->version
< 5) )
91 return sPreMainCxaGlobals
;
93 return pthread_getspecific(sCxaKey
);
99 #if __x86_64__ || __i386__ || __ppc__
101 // The intel/ppc versions of dyld uses zero-cost exceptions which are handled by
102 // linking with a special copy of libunwind.a
105 static struct dyld_unwind_sections sDyldInfo
;
106 static void* sDyldTextEnd
;
108 // called by dyldStartup.s very early
109 void dyld_exceptions_init(struct mach_header
* mh
, intptr_t slide
)
111 // record location of unwind sections in dyld itself
113 const struct load_command
* cmd
;
115 cmd
= (struct load_command
*) ((char *)mh
+ sizeof(struct macho_header
));
116 for(i
= 0; i
< mh
->ncmds
; i
++) {
117 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
118 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
119 if ( strcmp(seg
->segname
, "__TEXT") == 0 ) {
120 const struct macho_section
* sect
= (struct macho_section
*)( (char*)seg
+ sizeof(struct macho_segment_command
) );
122 for (j
= 0; j
< seg
->nsects
; j
++) {
123 if ( strcmp(sect
[j
].sectname
, "__eh_frame") == 0 ) {
124 sDyldInfo
.dwarf_section
= (void*)(sect
[j
].addr
+ slide
);
125 sDyldInfo
.dwarf_section_length
= sect
[j
].size
;
127 else if ( strcmp(sect
[j
].sectname
, "__unwind_info") == 0 ) {
128 sDyldInfo
.compact_unwind_section
= (void*)(sect
[j
].addr
+ slide
);
129 sDyldInfo
.compact_unwind_section_length
= sect
[j
].size
;
132 sDyldTextEnd
= (void*)(seg
->vmaddr
+ seg
->vmsize
+ slide
);
135 cmd
= (struct load_command
*)( (char*)cmd
+ cmd
->cmdsize
);
139 // called by libuwind code to find unwind information in dyld
140 bool _dyld_find_unwind_sections(void* addr
, struct dyld_unwind_sections
* info
)
142 if ( ((void*)sDyldInfo
.mh
< addr
) && (addr
< sDyldTextEnd
) ) {
152 // the ppc version of _Znwm in libstdc++.a uses keymgr
153 // need to override that
154 void* _Znwm(size_t size
) { return malloc(size
); }
157 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED
162 struct _Unwind_FunctionContext
164 // next function in stack of handlers
165 struct _Unwind_FunctionContext
* prev
;
170 // The ARM of dyld use SL-LJ based exception handling
171 // which does not require any initialization until libSystem is initialized.
173 void dyld_exceptions_init(struct mach_header
*mh
, uintptr_t slide
)
177 static pthread_key_t sThreadChainKey
= 0;
178 static struct _Unwind_FunctionContext
* sStaticThreadChain
= NULL
;
181 // When libSystem's initializers are run, they call back into dyld's
182 // registerThreadHelpers which creates a pthread key and calls
183 // __Unwind_SjLj_SetThreadKey().
185 void __Unwind_SjLj_SetThreadKey(pthread_key_t key
)
187 sThreadChainKey
= key
;
188 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), sStaticThreadChain=%p\n", key, sStaticThreadChain);
189 // switch static chain to be per thread
190 _ZN4dyld17gLibSystemHelpersE
->pthread_setspecific(sThreadChainKey
, sStaticThreadChain
);
191 sStaticThreadChain
= NULL
;
192 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), result=%d, new top=%p\n", key, result, pthread_getspecific(sThreadChainKey));
196 //static void printChain()
198 // _ZN4dyld3logEPKcz("chain: ");
199 // struct _Unwind_FunctionContext* start = sStaticThreadChain;
200 // if ( sThreadChainKey != 0 ) {
201 // start = (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey);
203 // for (struct _Unwind_FunctionContext* p = start; p != NULL; p = p->prev) {
204 // _ZN4dyld3logEPKcz("%p -> ", p);
206 // _ZN4dyld3logEPKcz("\n");
210 struct _Unwind_FunctionContext
* __Unwind_SjLj_GetTopOfFunctionStack()
212 //_ZN4dyld3logEPKcz("__Unwind_SjLj_GetTopOfFunctionStack(), key=%d, ", sThreadChainKey);
214 if ( sThreadChainKey
!= 0 ) {
215 return (struct _Unwind_FunctionContext
*)pthread_getspecific(sThreadChainKey
);
218 return sStaticThreadChain
;
222 void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext
* fc
)
224 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, prev=%p\n",
225 // fc, sThreadChainKey, (fc != NULL) ? fc->prev : NULL);
226 if ( sThreadChainKey
!= 0 )
227 _ZN4dyld17gLibSystemHelpersE
->pthread_setspecific(sThreadChainKey
, fc
);
229 sStaticThreadChain
= fc
;
230 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, ", fc, sThreadChainKey);