Mercurial > hg > CbC > CbC_gcc
comparison gcc/config/darwin-crt3.c @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
1 /* __cxa_atexit backwards-compatibility support for Darwin. | |
2 Copyright (C) 2006, 2009 Free Software Foundation, Inc. | |
3 | |
4 This file is part of GCC. | |
5 | |
6 GCC is free software; you can redistribute it and/or modify it under | |
7 the terms of the GNU General Public License as published by the Free | |
8 Software Foundation; either version 3, or (at your option) any later | |
9 version. | |
10 | |
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 Under Section 7 of GPL version 3, you are granted additional | |
17 permissions described in the GCC Runtime Library Exception, version | |
18 3.1, as published by the Free Software Foundation. | |
19 | |
20 You should have received a copy of the GNU General Public License and | |
21 a copy of the GCC Runtime Library Exception along with this program; | |
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 <http://www.gnu.org/licenses/>. */ | |
24 | |
25 /* Don't do anything if we are compiling for a kext multilib. */ | |
26 #ifdef __PIC__ | |
27 | |
28 /* It is incorrect to include config.h here, because this file is being | |
29 compiled for the target, and hence definitions concerning only the host | |
30 do not apply. */ | |
31 | |
32 #include "tconfig.h" | |
33 #include "tsystem.h" | |
34 | |
35 #include <dlfcn.h> | |
36 #include <stdbool.h> | |
37 #include <stdlib.h> | |
38 #include <string.h> | |
39 | |
40 /* This file works around two different problems. | |
41 | |
42 The first problem is that there is no __cxa_atexit on Mac OS versions | |
43 before 10.4. It fixes this by providing a complete atexit and | |
44 __cxa_atexit emulation called from the regular atexit. | |
45 | |
46 The second problem is that on all shipping versions of Mac OS, | |
47 __cxa_finalize and exit() don't work right: they don't run routines | |
48 that were registered while other atexit routines are running. This | |
49 is worked around by wrapping each atexit/__cxa_atexit routine with | |
50 our own routine which ensures that any __cxa_atexit calls while it | |
51 is running are honoured. | |
52 | |
53 There are still problems which this does not solve. Before 10.4, | |
54 shared objects linked with previous compilers won't have their | |
55 atexit calls properly interleaved with code compiled with newer | |
56 compilers. Also, atexit routines registered from shared objects | |
57 linked with previous compilers won't get the bug fix. */ | |
58 | |
59 typedef int (*cxa_atexit_p)(void (*func) (void*), void* arg, const void* dso); | |
60 typedef void (*cxa_finalize_p)(const void *dso); | |
61 typedef int (*atexit_p)(void (*func)(void)); | |
62 | |
63 /* These are from "keymgr.h". */ | |
64 extern void *_keymgr_get_and_lock_processwide_ptr (unsigned key); | |
65 extern int _keymgr_get_and_lock_processwide_ptr_2 (unsigned, void **); | |
66 extern int _keymgr_set_and_unlock_processwide_ptr (unsigned key, void *ptr); | |
67 | |
68 extern void *__keymgr_global[]; | |
69 typedef struct _Sinfo_Node { | |
70 unsigned int size ; /*size of this node*/ | |
71 unsigned short major_version ; /*API major version.*/ | |
72 unsigned short minor_version ; /*API minor version.*/ | |
73 } _Tinfo_Node ; | |
74 | |
75 #ifdef __ppc__ | |
76 #define CHECK_KEYMGR_ERROR(e) \ | |
77 (((_Tinfo_Node *)__keymgr_global[2])->major_version >= 4 ? (e) : 0) | |
78 #else | |
79 #define CHECK_KEYMGR_ERROR(e) (e) | |
80 #endif | |
81 | |
82 /* Our globals are stored under this keymgr index. */ | |
83 #define KEYMGR_ATEXIT_LIST 14 | |
84 | |
85 /* The different kinds of callback routines. */ | |
86 typedef void (*atexit_callback)(void); | |
87 typedef void (*cxa_atexit_callback)(void *); | |
88 | |
89 /* This structure holds a routine to call. There may be extra fields | |
90 at the end of the structure that this code doesn't know about. */ | |
91 struct one_atexit_routine | |
92 { | |
93 union { | |
94 atexit_callback ac; | |
95 cxa_atexit_callback cac; | |
96 } callback; | |
97 /* has_arg is 0/2/4 if 'ac' is live, 1/3/5 if 'cac' is live. | |
98 Higher numbers indicate a later version of the structure that this | |
99 code doesn't understand and will ignore. */ | |
100 int has_arg; | |
101 void * arg; | |
102 }; | |
103 | |
104 struct atexit_routine_list | |
105 { | |
106 struct atexit_routine_list * next; | |
107 struct one_atexit_routine r; | |
108 }; | |
109 | |
110 /* The various possibilities for status of atexit(). */ | |
111 enum atexit_status { | |
112 atexit_status_unknown = 0, | |
113 atexit_status_missing = 1, | |
114 atexit_status_broken = 2, | |
115 atexit_status_working = 16 | |
116 }; | |
117 | |
118 struct keymgr_atexit_list | |
119 { | |
120 /* Version of this list. This code knows only about version 0. | |
121 If the version is higher than 0, this code may add new atexit routines | |
122 but should not attempt to run the list. */ | |
123 short version; | |
124 /* 1 if an atexit routine is currently being run by this code, 0 | |
125 otherwise. */ | |
126 char running_routines; | |
127 /* Holds a value from 'enum atexit_status'. */ | |
128 unsigned char atexit_status; | |
129 /* The list of atexit and cxa_atexit routines registered. If | |
130 atexit_status_missing it contains all routines registered while | |
131 linked with this code. If atexit_status_broken it contains all | |
132 routines registered during cxa_finalize while linked with this | |
133 code. */ | |
134 struct atexit_routine_list *l; | |
135 /* &__cxa_atexit; set if atexit_status >= atexit_status_broken. */ | |
136 cxa_atexit_p cxa_atexit_f; | |
137 /* &__cxa_finalize; set if atexit_status >= atexit_status_broken. */ | |
138 cxa_finalize_p cxa_finalize_f; | |
139 /* &atexit; set if atexit_status >= atexit_status_working | |
140 or atexit_status == atexit_status_missing. */ | |
141 atexit_p atexit_f; | |
142 }; | |
143 | |
144 /* Return 0 if __cxa_atexit has the bug it has in Mac OS 10.4: it | |
145 fails to call routines registered while an atexit routine is | |
146 running. Return 1 if it works properly, and -1 if an error occurred. */ | |
147 | |
148 struct atexit_data | |
149 { | |
150 int result; | |
151 cxa_atexit_p cxa_atexit; | |
152 }; | |
153 | |
154 static void cxa_atexit_check_2 (void *arg) | |
155 { | |
156 ((struct atexit_data *)arg)->result = 1; | |
157 } | |
158 | |
159 static void cxa_atexit_check_1 (void *arg) | |
160 { | |
161 struct atexit_data * aed = arg; | |
162 if (aed->cxa_atexit (cxa_atexit_check_2, arg, arg) != 0) | |
163 aed->result = -1; | |
164 } | |
165 | |
166 static int | |
167 check_cxa_atexit (cxa_atexit_p cxa_atexit, cxa_finalize_p cxa_finalize) | |
168 { | |
169 struct atexit_data aed = { 0, cxa_atexit }; | |
170 | |
171 /* We re-use &aed as the 'dso' parameter, since it's a unique address. */ | |
172 if (cxa_atexit (cxa_atexit_check_1, &aed, &aed) != 0) | |
173 return -1; | |
174 cxa_finalize (&aed); | |
175 if (aed.result == 0) | |
176 { | |
177 /* Call __cxa_finalize again to make sure that cxa_atexit_check_2 | |
178 is removed from the list before AED goes out of scope. */ | |
179 cxa_finalize (&aed); | |
180 aed.result = 0; | |
181 } | |
182 return aed.result; | |
183 } | |
184 | |
185 #ifdef __ppc__ | |
186 /* This comes from Csu. It works only before 10.4. The prototype has | |
187 been altered a bit to avoid casting. */ | |
188 extern int _dyld_func_lookup(const char *dyld_func_name, | |
189 void *address) __attribute__((visibility("hidden"))); | |
190 | |
191 static void our_atexit (void); | |
192 | |
193 /* We're running on 10.3.9. Find the address of the system atexit() | |
194 function. So easy to say, so hard to do. */ | |
195 static atexit_p | |
196 find_atexit_10_3 (void) | |
197 { | |
198 unsigned int (*dyld_image_count_fn)(void); | |
199 const char *(*dyld_get_image_name_fn)(unsigned int image_index); | |
200 const void *(*dyld_get_image_header_fn)(unsigned int image_index); | |
201 const void *(*NSLookupSymbolInImage_fn)(const void *image, | |
202 const char *symbolName, | |
203 unsigned int options); | |
204 void *(*NSAddressOfSymbol_fn)(const void *symbol); | |
205 unsigned i, count; | |
206 | |
207 /* Find some dyld functions. */ | |
208 _dyld_func_lookup("__dyld_image_count", &dyld_image_count_fn); | |
209 _dyld_func_lookup("__dyld_get_image_name", &dyld_get_image_name_fn); | |
210 _dyld_func_lookup("__dyld_get_image_header", &dyld_get_image_header_fn); | |
211 _dyld_func_lookup("__dyld_NSLookupSymbolInImage", &NSLookupSymbolInImage_fn); | |
212 _dyld_func_lookup("__dyld_NSAddressOfSymbol", &NSAddressOfSymbol_fn); | |
213 | |
214 /* If any of these don't exist, that's an error. */ | |
215 if (! dyld_image_count_fn || ! dyld_get_image_name_fn | |
216 || ! dyld_get_image_header_fn || ! NSLookupSymbolInImage_fn | |
217 || ! NSAddressOfSymbol_fn) | |
218 return NULL; | |
219 | |
220 count = dyld_image_count_fn (); | |
221 for (i = 0; i < count; i++) | |
222 { | |
223 const char * path = dyld_get_image_name_fn (i); | |
224 const void * image; | |
225 const void * symbol; | |
226 | |
227 if (strcmp (path, "/usr/lib/libSystem.B.dylib") != 0) | |
228 continue; | |
229 image = dyld_get_image_header_fn (i); | |
230 if (! image) | |
231 return NULL; | |
232 /* '4' is NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR. */ | |
233 symbol = NSLookupSymbolInImage_fn (image, "_atexit", 4); | |
234 if (! symbol) | |
235 return NULL; | |
236 return NSAddressOfSymbol_fn (symbol); | |
237 } | |
238 return NULL; | |
239 } | |
240 #endif | |
241 | |
242 /* Create (if necessary), find, lock, fill in, and return our globals. | |
243 Return NULL on error, in which case the globals will not be locked. | |
244 The caller should call keymgr_set_and_unlock. */ | |
245 static struct keymgr_atexit_list * | |
246 get_globals (void) | |
247 { | |
248 struct keymgr_atexit_list * r; | |
249 | |
250 #ifdef __ppc__ | |
251 /* 10.3.9 doesn't have _keymgr_get_and_lock_processwide_ptr_2 so the | |
252 PPC side can't use it. On 10.4 this just means the error gets | |
253 reported a little later when | |
254 _keymgr_set_and_unlock_processwide_ptr finds that the key was | |
255 never locked. */ | |
256 r = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); | |
257 #else | |
258 void * rr; | |
259 if (_keymgr_get_and_lock_processwide_ptr_2 (KEYMGR_ATEXIT_LIST, &rr)) | |
260 return NULL; | |
261 r = rr; | |
262 #endif | |
263 | |
264 if (r == NULL) | |
265 { | |
266 r = calloc (sizeof (struct keymgr_atexit_list), 1); | |
267 if (! r) | |
268 return NULL; | |
269 } | |
270 | |
271 if (r->atexit_status == atexit_status_unknown) | |
272 { | |
273 void *handle; | |
274 | |
275 handle = dlopen ("/usr/lib/libSystem.B.dylib", RTLD_NOLOAD); | |
276 if (!handle) | |
277 { | |
278 #ifdef __ppc__ | |
279 r->atexit_status = atexit_status_missing; | |
280 r->atexit_f = find_atexit_10_3 (); | |
281 if (! r->atexit_f) | |
282 goto error; | |
283 if (r->atexit_f (our_atexit)) | |
284 goto error; | |
285 #else | |
286 goto error; | |
287 #endif | |
288 } | |
289 else | |
290 { | |
291 int chk_result; | |
292 | |
293 r->cxa_atexit_f = (cxa_atexit_p)dlsym (handle, "__cxa_atexit"); | |
294 r->cxa_finalize_f = (cxa_finalize_p)dlsym (handle, "__cxa_finalize"); | |
295 if (! r->cxa_atexit_f || ! r->cxa_finalize_f) | |
296 goto error; | |
297 | |
298 chk_result = check_cxa_atexit (r->cxa_atexit_f, r->cxa_finalize_f); | |
299 if (chk_result == -1) | |
300 goto error; | |
301 else if (chk_result == 0) | |
302 r->atexit_status = atexit_status_broken; | |
303 else | |
304 { | |
305 r->atexit_f = (atexit_p)dlsym (handle, "atexit"); | |
306 if (! r->atexit_f) | |
307 goto error; | |
308 r->atexit_status = atexit_status_working; | |
309 } | |
310 } | |
311 } | |
312 | |
313 return r; | |
314 | |
315 error: | |
316 _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, r); | |
317 return NULL; | |
318 } | |
319 | |
320 /* Add TO_ADD to ATEXIT_LIST. ATEXIT_LIST may be NULL but is | |
321 always the result of calling _keymgr_get_and_lock_processwide_ptr and | |
322 so KEYMGR_ATEXIT_LIST is known to be locked; this routine is responsible | |
323 for unlocking it. */ | |
324 | |
325 static int | |
326 add_routine (struct keymgr_atexit_list * g, | |
327 const struct one_atexit_routine * to_add) | |
328 { | |
329 struct atexit_routine_list * s | |
330 = malloc (sizeof (struct atexit_routine_list)); | |
331 int result; | |
332 | |
333 if (!s) | |
334 { | |
335 _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); | |
336 return -1; | |
337 } | |
338 s->r = *to_add; | |
339 s->next = g->l; | |
340 g->l = s; | |
341 result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); | |
342 return CHECK_KEYMGR_ERROR (result) == 0 ? 0 : -1; | |
343 } | |
344 | |
345 /* This runs the routines in G->L up to STOP. */ | |
346 static struct keymgr_atexit_list * | |
347 run_routines (struct keymgr_atexit_list *g, | |
348 struct atexit_routine_list *stop) | |
349 { | |
350 for (;;) | |
351 { | |
352 struct atexit_routine_list * cur = g->l; | |
353 if (! cur || cur == stop) | |
354 break; | |
355 g->l = cur->next; | |
356 _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); | |
357 | |
358 switch (cur->r.has_arg) { | |
359 case 0: case 2: case 4: | |
360 cur->r.callback.ac (); | |
361 break; | |
362 case 1: case 3: case 5: | |
363 cur->r.callback.cac (cur->r.arg); | |
364 break; | |
365 default: | |
366 /* Don't understand, so don't call it. */ | |
367 break; | |
368 } | |
369 free (cur); | |
370 | |
371 g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); | |
372 if (! g) | |
373 break; | |
374 } | |
375 return g; | |
376 } | |
377 | |
378 /* Call the routine described by ROUTINE_PARAM and then call any | |
379 routines added to KEYMGR_ATEXIT_LIST while that routine was | |
380 running, all with in_cxa_finalize set. */ | |
381 | |
382 static void | |
383 cxa_atexit_wrapper (void* routine_param) | |
384 { | |
385 struct one_atexit_routine * routine = routine_param; | |
386 struct keymgr_atexit_list *g; | |
387 struct atexit_routine_list * base = NULL; | |
388 char prev_running = 0; | |
389 | |
390 g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); | |
391 if (g) | |
392 { | |
393 prev_running = g->running_routines; | |
394 g->running_routines = 1; | |
395 base = g->l; | |
396 _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); | |
397 } | |
398 | |
399 if (routine->has_arg) | |
400 routine->callback.cac (routine->arg); | |
401 else | |
402 routine->callback.ac (); | |
403 | |
404 if (g) | |
405 g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); | |
406 if (g) | |
407 g = run_routines (g, base); | |
408 if (g) | |
409 { | |
410 g->running_routines = prev_running; | |
411 _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); | |
412 } | |
413 } | |
414 | |
415 #ifdef __ppc__ | |
416 /* This code is used while running on 10.3.9, when __cxa_atexit doesn't | |
417 exist in the system library. 10.3.9 only supported regular PowerPC, | |
418 so this code isn't necessary on x86 or ppc64. */ | |
419 | |
420 /* This routine is called from the system atexit(); it runs everything | |
421 registered on the KEYMGR_ATEXIT_LIST. */ | |
422 | |
423 static void | |
424 our_atexit (void) | |
425 { | |
426 struct keymgr_atexit_list *g; | |
427 char prev_running; | |
428 | |
429 g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); | |
430 if (! g || g->version != 0 || g->atexit_status != atexit_status_missing) | |
431 return; | |
432 | |
433 prev_running = g->running_routines; | |
434 g->running_routines = 1; | |
435 g = run_routines (g, NULL); | |
436 if (! g) | |
437 return; | |
438 g->running_routines = prev_running; | |
439 _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); | |
440 } | |
441 #endif | |
442 | |
443 /* This is our wrapper around atexit and __cxa_atexit. It will return | |
444 nonzero if an error occurs, and otherwise: | |
445 - if in_cxa_finalize is set, or running on 10.3.9, add R to | |
446 KEYMGR_ATEXIT_LIST; or | |
447 - call the system __cxa_atexit to add cxa_atexit_wrapper with an argument | |
448 that indicates how cxa_atexit_wrapper should call R. */ | |
449 | |
450 static int | |
451 atexit_common (const struct one_atexit_routine *r, const void *dso) | |
452 { | |
453 struct keymgr_atexit_list *g = get_globals (); | |
454 | |
455 if (! g) | |
456 return -1; | |
457 | |
458 if (g->running_routines || g->atexit_status == atexit_status_missing) | |
459 return add_routine (g, r); | |
460 | |
461 if (g->atexit_status >= atexit_status_working) | |
462 { | |
463 int result; | |
464 if (r->has_arg) | |
465 { | |
466 cxa_atexit_p cxa_atexit = g->cxa_atexit_f; | |
467 result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, | |
468 g); | |
469 if (CHECK_KEYMGR_ERROR (result)) | |
470 return -1; | |
471 return cxa_atexit (r->callback.cac, r->arg, dso); | |
472 } | |
473 else | |
474 { | |
475 atexit_p atexit_f = g->atexit_f; | |
476 result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, | |
477 g); | |
478 if (CHECK_KEYMGR_ERROR (result)) | |
479 return -1; | |
480 return atexit_f (r->callback.ac); | |
481 } | |
482 } | |
483 else | |
484 { | |
485 cxa_atexit_p cxa_atexit = g->cxa_atexit_f; | |
486 struct one_atexit_routine *alloced; | |
487 int result; | |
488 | |
489 result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); | |
490 if (CHECK_KEYMGR_ERROR (result)) | |
491 return -1; | |
492 | |
493 alloced = malloc (sizeof (struct one_atexit_routine)); | |
494 if (! alloced) | |
495 return -1; | |
496 *alloced = *r; | |
497 return cxa_atexit (cxa_atexit_wrapper, alloced, dso); | |
498 } | |
499 } | |
500 | |
501 /* These are the actual replacement routines; they just funnel into | |
502 atexit_common. */ | |
503 | |
504 int __cxa_atexit (cxa_atexit_callback func, void* arg, | |
505 const void* dso) __attribute__((visibility("hidden"))); | |
506 | |
507 int | |
508 __cxa_atexit (cxa_atexit_callback func, void* arg, const void* dso) | |
509 { | |
510 struct one_atexit_routine r; | |
511 r.callback.cac = func; | |
512 r.has_arg = 1; | |
513 r.arg = arg; | |
514 return atexit_common (&r, dso); | |
515 } | |
516 | |
517 int atexit (atexit_callback func) __attribute__((visibility("hidden"))); | |
518 | |
519 /* Use __dso_handle to allow even bundles that call atexit() to be unloaded | |
520 on 10.4. */ | |
521 extern void __dso_handle; | |
522 | |
523 int | |
524 atexit (atexit_callback func) | |
525 { | |
526 struct one_atexit_routine r; | |
527 r.callback.ac = func; | |
528 r.has_arg = 0; | |
529 return atexit_common (&r, &__dso_handle); | |
530 } | |
531 | |
532 #endif /* __PIC__ */ |