OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [config/] [darwin-crt3.c] - Blame information for rev 328

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 282 jeremybenn
/* __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__ */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.