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>
34 #include "mach-o/dyld_priv.h"
35 #include "dyldLibSystemInterface.h"
37 extern void _ZN4dyld3logEPKcz(const char*, ...);
38 extern struct LibSystemHelpers
* _ZN4dyld17gLibSystemHelpersE
;
42 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
43 #define macho_header mach_header_64
44 #define macho_segment_command segment_command_64
45 #define macho_section section_64
46 #define getsectdatafromheader getsectdatafromheader_64
48 #define LC_SEGMENT_COMMAND LC_SEGMENT
49 #define macho_header mach_header
50 #define macho_segment_command segment_command
51 #define macho_section section
55 #if __i386__ || __x86_64 || __ppc__
57 static struct dyld_unwind_sections sDyldInfo
;
58 static void* sDyldTextEnd
;
59 static pthread_key_t sCxaKey
= 0;
60 static char sPreMainCxaGlobals
[2*sizeof(long)];
62 // called by dyldStartup.s very early
63 void dyld_exceptions_init(struct mach_header
* mh
, intptr_t slide
)
65 // record location of unwind sections in dyld itself
67 const struct load_command
* cmd
;
69 cmd
= (struct load_command
*) ((char *)mh
+ sizeof(struct macho_header
));
70 for(i
= 0; i
< mh
->ncmds
; i
++) {
71 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
72 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
73 if ( strcmp(seg
->segname
, "__TEXT") == 0 ) {
74 const struct macho_section
* sect
= (struct macho_section
*)( (char*)seg
+ sizeof(struct macho_segment_command
) );
76 for (j
= 0; j
< seg
->nsects
; j
++) {
77 if ( strcmp(sect
[j
].sectname
, "__eh_frame") == 0 ) {
78 sDyldInfo
.dwarf_section
= (void*)(sect
[j
].addr
+ slide
);
79 sDyldInfo
.dwarf_section_length
= sect
[j
].size
;
81 else if ( strcmp(sect
[j
].sectname
, "__unwind_info") == 0 ) {
82 sDyldInfo
.compact_unwind_section
= (void*)(sect
[j
].addr
+ slide
);
83 sDyldInfo
.compact_unwind_section_length
= sect
[j
].size
;
86 sDyldTextEnd
= (void*)(seg
->vmaddr
+ seg
->vmsize
+ slide
);
89 cmd
= (struct load_command
*)( (char*)cmd
+ cmd
->cmdsize
);
93 // called by libuwind code to find unwind information in dyld
94 bool _dyld_find_unwind_sections(void* addr
, struct dyld_unwind_sections
* info
)
96 if ( ((void*)sDyldInfo
.mh
< addr
) && (addr
< sDyldTextEnd
) ) {
107 // called by libstdc++.a
108 char* __cxa_get_globals()
110 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
111 if ( (_ZN4dyld17gLibSystemHelpersE
== NULL
) || (_ZN4dyld17gLibSystemHelpersE
->version
< 5) )
112 return sPreMainCxaGlobals
;
114 if ( sCxaKey
== 0 ) {
116 // we don't need a lock because only one thread can be in dyld at a time
117 _ZN4dyld17gLibSystemHelpersE
->pthread_key_create(&sCxaKey
, &free
);
119 char* data
= (char*)pthread_getspecific(sCxaKey
);
120 if ( data
== NULL
) {
121 data
= calloc(2,sizeof(void*));
122 _ZN4dyld17gLibSystemHelpersE
->pthread_setspecific(sCxaKey
, data
);
127 // called by libstdc++.a
128 char* __cxa_get_globals_fast()
130 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
131 if ( (_ZN4dyld17gLibSystemHelpersE
== NULL
) || (_ZN4dyld17gLibSystemHelpersE
->version
< 5) )
132 return sPreMainCxaGlobals
;
134 return pthread_getspecific(sCxaKey
);
138 // the ppc version of _Znwm in libstdc++.a uses keymgr
139 // need to override that
140 void* _Znwm(size_t size
) { return malloc(size
); }
147 #else /* __i386__ || __x86_64 || __ppc__ */
155 // BEGIN copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
157 #define KEYMGR_API_MAJOR_GCC3 3
158 /* ... with these keys. */
159 #define KEYMGR_GCC3_LIVE_IMAGE_LIST 301 /* loaded images */
160 #define KEYMGR_GCC3_DW2_OBJ_LIST 302 /* Dwarf2 object list */
161 #define KEYMGR_EH_GLOBALS_KEY 13
163 /* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST. Info about each resident image. */
165 unsigned long this_size
; /* sizeof (live_images) */
166 struct mach_header
*mh
; /* the image info */
167 unsigned long vm_slide
;
168 void (*destructor
)(struct live_images
*); /* destructor for this */
169 struct live_images
*next
;
170 unsigned int examined_p
;
173 unsigned long info
[2]; /* Future use. */
176 // END copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
181 // dyld is built as stand alone executable with a static copy of libc, libstdc++, and libgcc.
183 // In order for C++ exceptions to work within dyld, the C++ exception handling code
184 // must be able to find the exception handling frame data inside dyld. The standard
185 // exception handling code uses crt and keymgr to keep track of all images and calls
186 // getsectdatafromheader("__eh_frame") to find the EH data for each image. We implement
187 // our own copy of those functions below to enable exceptions within dyld.
189 // Note: This exception handling is completely separate from any user code exception .
190 // handling which has its own keymgr (in libSystem).
194 static struct live_images sDyldImage
; // zero filled
195 static void* sObjectList
= NULL
;
196 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
197 static void* sEHGlobals
= NULL
;
201 // called by dyldStartup.s very early
202 void dyld_exceptions_init(struct mach_header
*mh
, uintptr_t slide
)
204 sDyldImage
.this_size
= sizeof(struct live_images
);
206 sDyldImage
.vm_slide
= slide
;
211 // Hack for gcc 3.5's use of keymgr includes accessing __keymgr_global
212 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
213 typedef struct Sinfo_Node
{
214 uint32_t size
; /* Size of this node. */
215 uint16_t major_version
; /* API major version. */
216 uint16_t minor_version
; /* API minor version. */
218 static const Tinfo_Node keymgr_info
= { sizeof (Tinfo_Node
), KEYMGR_API_MAJOR_GCC3
, 0 };
219 const Tinfo_Node
* __keymgr_global
[3] = { NULL
, NULL
, &keymgr_info
};
222 static __attribute__((noreturn
))
225 //dyld::log("internal dyld error\n");
229 void* _keymgr_get_and_lock_processwide_ptr(unsigned int key
)
231 // The C++ exception handling code uses two keys. No other keys should be seen
232 if ( key
== KEYMGR_GCC3_LIVE_IMAGE_LIST
) {
235 else if ( key
== KEYMGR_GCC3_DW2_OBJ_LIST
) {
241 void _keymgr_set_and_unlock_processwide_ptr(unsigned int key
, void* value
)
243 // The C++ exception handling code uses just this key. No other keys should be seen
244 if ( key
== KEYMGR_GCC3_DW2_OBJ_LIST
) {
251 void _keymgr_unlock_processwide_ptr(unsigned int key
)
253 // The C++ exception handling code uses just this key. No other keys should be seen
254 if ( key
== KEYMGR_GCC3_LIVE_IMAGE_LIST
) {
260 void* _keymgr_get_per_thread_data(unsigned int key
)
262 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
263 // gcc 3.5 and later use this key
264 if ( key
== KEYMGR_EH_GLOBALS_KEY
)
268 // used by std::termination which dyld does not use
272 void _keymgr_set_per_thread_data(unsigned int key
, void *keydata
)
274 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
275 // gcc 3.5 and later use this key
276 if ( key
== KEYMGR_EH_GLOBALS_KEY
) {
277 sEHGlobals
= keydata
;
281 // used by std::termination which dyld does not use
286 // needed by C++ exception handling code to find __eh_frame section
287 const void* getsectdatafromheader(struct mach_header
* mh
, const char* segname
, const char* sectname
, unsigned long* size
)
289 const struct load_command
* cmd
;
292 cmd
= (struct load_command
*) ((char *)mh
+ sizeof(struct macho_header
));
293 for(i
= 0; i
< mh
->ncmds
; i
++) {
294 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
295 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
296 if ( strcmp(seg
->segname
, segname
) == 0 ) {
297 const struct macho_section
* sect
= (struct macho_section
*)( (char*)seg
+ sizeof(struct macho_segment_command
) );
299 for (j
= 0; j
< seg
->nsects
; j
++) {
300 if ( strcmp(sect
[j
].sectname
, sectname
) == 0 ) {
301 *size
= sect
[j
].size
;
302 return (void*)(sect
[j
].addr
);
307 cmd
= (struct load_command
*)( (char*)cmd
+ cmd
->cmdsize
);
313 // Hack for transition of rdar://problem/3933738
314 // Can be removed later.
315 // Allow C++ runtime to call getsectdatafromheader or getsectdatafromheader_64
317 #undef getsectdatafromheader
318 const void* getsectdatafromheader(struct mach_header
* mh
, const char* segname
, const char* sectname
, unsigned long* size
)
320 return getsectdatafromheader_64(mh
, segname
, sectname
, size
);