1169689Skan/* __cxa_atexit backwards-compatibility support for Darwin.
2169689Skan   Copyright (C) 2006 Free Software Foundation, Inc.
3169689Skan
4169689SkanThis file is part of GCC.
5169689Skan
6169689SkanGCC is free software; you can redistribute it and/or modify it under
7169689Skanthe terms of the GNU General Public License as published by the Free
8169689SkanSoftware Foundation; either version 2, or (at your option) any later
9169689Skanversion.
10169689Skan
11169689SkanIn addition to the permissions in the GNU General Public License, the
12169689SkanFree Software Foundation gives you unlimited permission to link the
13169689Skancompiled version of this file into combinations with other programs,
14169689Skanand to distribute those combinations without any restriction coming
15169689Skanfrom the use of this file.  (The General Public License restrictions
16169689Skando apply in other respects; for example, they cover modification of
17169689Skanthe file, and distribution when not linked into a combine
18169689Skanexecutable.)
19169689Skan
20169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
21169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
22169689SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23169689Skanfor more details.
24169689Skan
25169689SkanYou should have received a copy of the GNU General Public License
26169689Skanalong with GCC; see the file COPYING.  If not, write to the Free
27169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
28169689Skan02110-1301, USA.  */
29169689Skan
30169689Skan/* Don't do anything if we are compiling for a kext multilib. */
31169689Skan#ifdef __PIC__
32169689Skan
33169689Skan/* It is incorrect to include config.h here, because this file is being
34169689Skan   compiled for the target, and hence definitions concerning only the host
35169689Skan   do not apply.  */
36169689Skan
37169689Skan#include "tconfig.h"
38169689Skan#include "tsystem.h"
39169689Skan
40169689Skan#include <dlfcn.h>
41169689Skan#include <stdbool.h>
42169689Skan#include <stdlib.h>
43169689Skan#include <string.h>
44169689Skan
45169689Skan/* This file works around two different problems.
46169689Skan
47169689Skan   The first problem is that there is no __cxa_atexit on Mac OS versions
48169689Skan   before 10.4.  It fixes this by providing a complete atexit and
49169689Skan   __cxa_atexit emulation called from the regular atexit.
50169689Skan
51169689Skan   The second problem is that on all shipping versions of Mac OS,
52169689Skan   __cxa_finalize and exit() don't work right: they don't run routines
53169689Skan   that were registered while other atexit routines are running.  This
54169689Skan   is worked around by wrapping each atexit/__cxa_atexit routine with
55169689Skan   our own routine which ensures that any __cxa_atexit calls while it
56169689Skan   is running are honoured.
57169689Skan
58169689Skan   There are still problems which this does not solve.  Before 10.4,
59169689Skan   shared objects linked with previous compilers won't have their
60169689Skan   atexit calls properly interleaved with code compiled with newer
61169689Skan   compilers.  Also, atexit routines registered from shared objects
62169689Skan   linked with previous compilers won't get the bug fix.  */
63169689Skan
64169689Skantypedef int (*cxa_atexit_p)(void (*func) (void*), void* arg, const void* dso);
65169689Skantypedef void (*cxa_finalize_p)(const void *dso);
66169689Skantypedef int (*atexit_p)(void (*func)(void));
67169689Skan
68169689Skan/* These are from "keymgr.h".  */
69169689Skanextern void *_keymgr_get_and_lock_processwide_ptr (unsigned key);
70169689Skanextern int _keymgr_get_and_lock_processwide_ptr_2 (unsigned, void **);
71169689Skanextern int _keymgr_set_and_unlock_processwide_ptr (unsigned key, void *ptr);
72169689Skan
73169689Skanextern void *__keymgr_global[];
74169689Skantypedef struct _Sinfo_Node {
75169689Skan        unsigned int size ;             /*size of this node*/
76169689Skan        unsigned short major_version ;  /*API major version.*/
77169689Skan        unsigned short minor_version ;  /*API minor version.*/
78169689Skan        } _Tinfo_Node ;
79169689Skan
80169689Skan#ifdef __ppc__
81169689Skan#define CHECK_KEYMGR_ERROR(e) \
82169689Skan  (((_Tinfo_Node *)__keymgr_global[2])->major_version >= 4 ? (e) : 0)
83169689Skan#else
84169689Skan#define CHECK_KEYMGR_ERROR(e) (e)
85169689Skan#endif
86169689Skan
87169689Skan/* Our globals are stored under this keymgr index.  */
88169689Skan#define KEYMGR_ATEXIT_LIST	14
89169689Skan
90169689Skan/* The different kinds of callback routines.  */
91169689Skantypedef void (*atexit_callback)(void);
92169689Skantypedef void (*cxa_atexit_callback)(void *);
93169689Skan
94169689Skan/* This structure holds a routine to call.  There may be extra fields
95169689Skan   at the end of the structure that this code doesn't know about.  */
96169689Skanstruct one_atexit_routine
97169689Skan{
98169689Skan  union {
99169689Skan    atexit_callback ac;
100169689Skan    cxa_atexit_callback cac;
101169689Skan  } callback;
102169689Skan  /* has_arg is 0/2/4 if 'ac' is live, 1/3/5 if 'cac' is live.
103169689Skan     Higher numbers indicate a later version of the structure that this
104169689Skan     code doesn't understand and will ignore.  */
105169689Skan  int has_arg;
106169689Skan  void * arg;
107169689Skan};
108169689Skan
109169689Skanstruct atexit_routine_list
110169689Skan{
111169689Skan  struct atexit_routine_list * next;
112169689Skan  struct one_atexit_routine r;
113169689Skan};
114169689Skan
115169689Skan/* The various possibilities for status of atexit().  */
116169689Skanenum atexit_status {
117169689Skan  atexit_status_unknown = 0,
118169689Skan  atexit_status_missing = 1,
119169689Skan  atexit_status_broken = 2,
120169689Skan  atexit_status_working = 16
121169689Skan};
122169689Skan
123169689Skanstruct keymgr_atexit_list
124169689Skan{
125169689Skan  /* Version of this list.  This code knows only about version 0.
126169689Skan     If the version is higher than 0, this code may add new atexit routines
127169689Skan     but should not attempt to run the list.  */
128169689Skan  short version;
129169689Skan  /* 1 if an atexit routine is currently being run by this code, 0
130169689Skan     otherwise.  */
131169689Skan  char running_routines;
132169689Skan  /* Holds a value from 'enum atexit_status'.  */
133169689Skan  unsigned char atexit_status;
134169689Skan  /* The list of atexit and cxa_atexit routines registered.  If
135169689Skan   atexit_status_missing it contains all routines registered while
136169689Skan   linked with this code.  If atexit_status_broken it contains all
137169689Skan   routines registered during cxa_finalize while linked with this
138169689Skan   code.  */
139169689Skan  struct atexit_routine_list *l;
140169689Skan  /* &__cxa_atexit; set if atexit_status >= atexit_status_broken.  */
141169689Skan  cxa_atexit_p cxa_atexit_f;
142169689Skan  /* &__cxa_finalize; set if atexit_status >= atexit_status_broken.  */
143169689Skan  cxa_finalize_p cxa_finalize_f;
144169689Skan  /* &atexit; set if atexit_status >= atexit_status_working
145169689Skan     or atexit_status == atexit_status_missing.  */
146169689Skan  atexit_p atexit_f;
147169689Skan};
148169689Skan
149169689Skan/* Return 0 if __cxa_atexit has the bug it has in Mac OS 10.4: it
150169689Skan   fails to call routines registered while an atexit routine is
151169689Skan   running.  Return 1 if it works properly, and -1 if an error occurred.  */
152169689Skan
153169689Skanstruct atexit_data
154169689Skan{
155169689Skan  int result;
156169689Skan  cxa_atexit_p cxa_atexit;
157169689Skan};
158169689Skan
159169689Skanstatic void cxa_atexit_check_2 (void *arg)
160169689Skan{
161169689Skan  ((struct atexit_data *)arg)->result = 1;
162169689Skan}
163169689Skan
164169689Skanstatic void cxa_atexit_check_1 (void *arg)
165169689Skan{
166169689Skan  struct atexit_data * aed = arg;
167169689Skan  if (aed->cxa_atexit (cxa_atexit_check_2, arg, arg) != 0)
168169689Skan    aed->result = -1;
169169689Skan}
170169689Skan
171169689Skanstatic int
172169689Skancheck_cxa_atexit (cxa_atexit_p cxa_atexit, cxa_finalize_p cxa_finalize)
173169689Skan{
174169689Skan  struct atexit_data aed = { 0, cxa_atexit };
175169689Skan
176169689Skan  /* We re-use &aed as the 'dso' parameter, since it's a unique address.  */
177169689Skan  if (cxa_atexit (cxa_atexit_check_1, &aed, &aed) != 0)
178169689Skan    return -1;
179169689Skan  cxa_finalize (&aed);
180169689Skan  if (aed.result == 0)
181169689Skan    {
182169689Skan      /* Call __cxa_finalize again to make sure that cxa_atexit_check_2
183169689Skan	 is removed from the list before AED goes out of scope.  */
184169689Skan      cxa_finalize (&aed);
185169689Skan      aed.result = 0;
186169689Skan    }
187169689Skan  return aed.result;
188169689Skan}
189169689Skan
190169689Skan#ifdef __ppc__
191169689Skan/* This comes from Csu.  It works only before 10.4.  The prototype has
192169689Skan   been altered a bit to avoid casting.  */
193169689Skanextern int _dyld_func_lookup(const char *dyld_func_name,
194169689Skan     void *address) __attribute__((visibility("hidden")));
195169689Skan
196169689Skanstatic void our_atexit (void);
197169689Skan
198169689Skan/* We're running on 10.3.9.  Find the address of the system atexit()
199169689Skan   function.  So easy to say, so hard to do.  */
200169689Skanstatic atexit_p
201169689Skanfind_atexit_10_3 (void)
202169689Skan{
203169689Skan  unsigned int (*dyld_image_count_fn)(void);
204169689Skan  const char *(*dyld_get_image_name_fn)(unsigned int image_index);
205169689Skan  const void *(*dyld_get_image_header_fn)(unsigned int image_index);
206169689Skan  const void *(*NSLookupSymbolInImage_fn)(const void *image,
207169689Skan					  const char *symbolName,
208169689Skan					  unsigned int options);
209169689Skan  void *(*NSAddressOfSymbol_fn)(const void *symbol);
210169689Skan  unsigned i, count;
211169689Skan
212169689Skan  /* Find some dyld functions.  */
213169689Skan  _dyld_func_lookup("__dyld_image_count", &dyld_image_count_fn);
214169689Skan  _dyld_func_lookup("__dyld_get_image_name", &dyld_get_image_name_fn);
215169689Skan  _dyld_func_lookup("__dyld_get_image_header", &dyld_get_image_header_fn);
216169689Skan  _dyld_func_lookup("__dyld_NSLookupSymbolInImage", &NSLookupSymbolInImage_fn);
217169689Skan  _dyld_func_lookup("__dyld_NSAddressOfSymbol", &NSAddressOfSymbol_fn);
218169689Skan
219169689Skan  /* If any of these don't exist, that's an error.  */
220169689Skan  if (! dyld_image_count_fn || ! dyld_get_image_name_fn
221169689Skan      || ! dyld_get_image_header_fn || ! NSLookupSymbolInImage_fn
222169689Skan      || ! NSAddressOfSymbol_fn)
223169689Skan    return NULL;
224169689Skan
225169689Skan  count = dyld_image_count_fn ();
226169689Skan  for (i = 0; i < count; i++)
227169689Skan    {
228169689Skan      const char * path = dyld_get_image_name_fn (i);
229169689Skan      const void * image;
230169689Skan      const void * symbol;
231169689Skan
232169689Skan      if (strcmp (path, "/usr/lib/libSystem.B.dylib") != 0)
233169689Skan	continue;
234169689Skan      image = dyld_get_image_header_fn (i);
235169689Skan      if (! image)
236169689Skan	return NULL;
237169689Skan      /* '4' is NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR.  */
238169689Skan      symbol = NSLookupSymbolInImage_fn (image, "_atexit", 4);
239169689Skan      if (! symbol)
240169689Skan	return NULL;
241169689Skan      return NSAddressOfSymbol_fn (symbol);
242169689Skan    }
243169689Skan  return NULL;
244169689Skan}
245169689Skan#endif
246169689Skan
247169689Skan/* Create (if necessary), find, lock, fill in, and return our globals.
248169689Skan   Return NULL on error, in which case the globals will not be locked.
249169689Skan   The caller should call keymgr_set_and_unlock.  */
250169689Skanstatic struct keymgr_atexit_list *
251169689Skanget_globals (void)
252169689Skan{
253169689Skan  struct keymgr_atexit_list * r;
254169689Skan
255169689Skan#ifdef __ppc__
256169689Skan  /* 10.3.9 doesn't have _keymgr_get_and_lock_processwide_ptr_2 so the
257169689Skan     PPC side can't use it.  On 10.4 this just means the error gets
258169689Skan     reported a little later when
259169689Skan     _keymgr_set_and_unlock_processwide_ptr finds that the key was
260169689Skan     never locked.  */
261169689Skan  r = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
262169689Skan#else
263169689Skan  void * rr;
264169689Skan  if (_keymgr_get_and_lock_processwide_ptr_2 (KEYMGR_ATEXIT_LIST, &rr))
265169689Skan    return NULL;
266169689Skan  r = rr;
267169689Skan#endif
268169689Skan
269169689Skan  if (r == NULL)
270169689Skan    {
271169689Skan      r = calloc (sizeof (struct keymgr_atexit_list), 1);
272169689Skan      if (! r)
273169689Skan	return NULL;
274169689Skan    }
275169689Skan
276169689Skan  if (r->atexit_status == atexit_status_unknown)
277169689Skan    {
278169689Skan      void *handle;
279169689Skan
280169689Skan      handle = dlopen ("/usr/lib/libSystem.B.dylib", RTLD_NOLOAD);
281169689Skan      if (!handle)
282169689Skan	{
283169689Skan#ifdef __ppc__
284169689Skan	  r->atexit_status = atexit_status_missing;
285169689Skan	  r->atexit_f = find_atexit_10_3 ();
286169689Skan	  if (! r->atexit_f)
287169689Skan	    goto error;
288169689Skan	  if (r->atexit_f (our_atexit))
289169689Skan	    goto error;
290169689Skan#else
291169689Skan	  goto error;
292169689Skan#endif
293169689Skan	}
294169689Skan      else
295169689Skan	{
296169689Skan	  int chk_result;
297169689Skan
298169689Skan	  r->cxa_atexit_f = (cxa_atexit_p)dlsym (handle, "__cxa_atexit");
299169689Skan	  r->cxa_finalize_f = (cxa_finalize_p)dlsym (handle, "__cxa_finalize");
300169689Skan	  if (! r->cxa_atexit_f || ! r->cxa_finalize_f)
301169689Skan	    goto error;
302169689Skan
303169689Skan	  chk_result = check_cxa_atexit (r->cxa_atexit_f, r->cxa_finalize_f);
304169689Skan	  if (chk_result == -1)
305169689Skan	    goto error;
306169689Skan	  else if (chk_result == 0)
307169689Skan	    r->atexit_status = atexit_status_broken;
308169689Skan	  else
309169689Skan	    {
310169689Skan	      r->atexit_f = (atexit_p)dlsym (handle, "atexit");
311169689Skan	      if (! r->atexit_f)
312169689Skan		goto error;
313169689Skan	      r->atexit_status = atexit_status_working;
314169689Skan	    }
315169689Skan	}
316169689Skan    }
317169689Skan
318169689Skan  return r;
319169689Skan
320169689Skan error:
321169689Skan  _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, r);
322169689Skan  return NULL;
323169689Skan}
324169689Skan
325169689Skan/* Add TO_ADD to ATEXIT_LIST.  ATEXIT_LIST may be NULL but is
326169689Skan   always the result of calling _keymgr_get_and_lock_processwide_ptr and
327169689Skan   so KEYMGR_ATEXIT_LIST is known to be locked; this routine is responsible
328169689Skan   for unlocking it.  */
329169689Skan
330169689Skanstatic int
331169689Skanadd_routine (struct keymgr_atexit_list * g,
332169689Skan	     const struct one_atexit_routine * to_add)
333169689Skan{
334169689Skan  struct atexit_routine_list * s
335169689Skan    = malloc (sizeof (struct atexit_routine_list));
336169689Skan  int result;
337169689Skan
338169689Skan  if (!s)
339169689Skan    {
340169689Skan      _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
341169689Skan      return -1;
342169689Skan    }
343169689Skan  s->r = *to_add;
344169689Skan  s->next = g->l;
345169689Skan  g->l = s;
346169689Skan  result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
347169689Skan  return CHECK_KEYMGR_ERROR (result) == 0 ? 0 : -1;
348169689Skan}
349169689Skan
350169689Skan/* This runs the routines in G->L up to STOP.  */
351169689Skanstatic struct keymgr_atexit_list *
352169689Skanrun_routines (struct keymgr_atexit_list *g,
353169689Skan	      struct atexit_routine_list *stop)
354169689Skan{
355169689Skan  for (;;)
356169689Skan    {
357169689Skan      struct atexit_routine_list * cur = g->l;
358169689Skan      if (! cur || cur == stop)
359169689Skan	break;
360169689Skan      g->l = cur->next;
361169689Skan      _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
362169689Skan
363169689Skan      switch (cur->r.has_arg) {
364169689Skan      case 0: case 2: case 4:
365169689Skan	cur->r.callback.ac ();
366169689Skan	break;
367169689Skan      case 1: case 3: case 5:
368169689Skan	cur->r.callback.cac (cur->r.arg);
369169689Skan	break;
370169689Skan      default:
371169689Skan	/* Don't understand, so don't call it.  */
372169689Skan	break;
373169689Skan      }
374169689Skan      free (cur);
375169689Skan
376169689Skan      g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
377169689Skan      if (! g)
378169689Skan	break;
379169689Skan    }
380169689Skan  return g;
381169689Skan}
382169689Skan
383169689Skan/* Call the routine described by ROUTINE_PARAM and then call any
384169689Skan   routines added to KEYMGR_ATEXIT_LIST while that routine was
385169689Skan   running, all with in_cxa_finalize set.  */
386169689Skan
387169689Skanstatic void
388169689Skancxa_atexit_wrapper (void* routine_param)
389169689Skan{
390169689Skan  struct one_atexit_routine * routine = routine_param;
391169689Skan  struct keymgr_atexit_list *g;
392169689Skan  struct atexit_routine_list * base = NULL;
393169689Skan  char prev_running = 0;
394169689Skan
395169689Skan  g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
396169689Skan  if (g)
397169689Skan    {
398169689Skan      prev_running = g->running_routines;
399169689Skan      g->running_routines = 1;
400169689Skan      base = g->l;
401169689Skan      _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
402169689Skan    }
403169689Skan
404169689Skan  if (routine->has_arg)
405169689Skan    routine->callback.cac (routine->arg);
406169689Skan  else
407169689Skan    routine->callback.ac ();
408169689Skan
409169689Skan  if (g)
410169689Skan    g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
411169689Skan  if (g)
412169689Skan    g = run_routines (g, base);
413169689Skan  if (g)
414169689Skan    {
415169689Skan      g->running_routines = prev_running;
416169689Skan      _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
417169689Skan    }
418169689Skan}
419169689Skan
420169689Skan#ifdef __ppc__
421169689Skan/* This code is used while running on 10.3.9, when __cxa_atexit doesn't
422169689Skan   exist in the system library.  10.3.9 only supported regular PowerPC,
423169689Skan   so this code isn't necessary on x86 or ppc64.  */
424169689Skan
425169689Skan/* This routine is called from the system atexit(); it runs everything
426169689Skan   registered on the KEYMGR_ATEXIT_LIST.  */
427169689Skan
428169689Skanstatic void
429169689Skanour_atexit (void)
430169689Skan{
431169689Skan  struct keymgr_atexit_list *g;
432169689Skan  char prev_running;
433169689Skan
434169689Skan  g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
435169689Skan  if (! g || g->version != 0 || g->atexit_status != atexit_status_missing)
436169689Skan    return;
437169689Skan
438169689Skan  prev_running = g->running_routines;
439169689Skan  g->running_routines = 1;
440169689Skan  g = run_routines (g, NULL);
441169689Skan  if (! g)
442169689Skan    return;
443169689Skan  g->running_routines = prev_running;
444169689Skan  _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
445169689Skan}
446169689Skan#endif
447169689Skan
448169689Skan/* This is our wrapper around atexit and __cxa_atexit.  It will return
449169689Skan   nonzero if an error occurs, and otherwise:
450169689Skan   - if in_cxa_finalize is set, or running on 10.3.9, add R to
451169689Skan     KEYMGR_ATEXIT_LIST; or
452169689Skan   - call the system __cxa_atexit to add cxa_atexit_wrapper with an argument
453169689Skan     that indicates how cxa_atexit_wrapper should call R.  */
454169689Skan
455169689Skanstatic int
456169689Skanatexit_common (const struct one_atexit_routine *r, const void *dso)
457169689Skan{
458169689Skan  struct keymgr_atexit_list *g = get_globals ();
459169689Skan
460169689Skan  if (! g)
461169689Skan    return -1;
462169689Skan
463169689Skan  if (g->running_routines || g->atexit_status == atexit_status_missing)
464169689Skan    return add_routine (g, r);
465169689Skan
466169689Skan  if (g->atexit_status >= atexit_status_working)
467169689Skan    {
468169689Skan      int result;
469169689Skan      if (r->has_arg)
470169689Skan	{
471169689Skan	  cxa_atexit_p cxa_atexit = g->cxa_atexit_f;
472169689Skan	  result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST,
473169689Skan							   g);
474169689Skan	  if (CHECK_KEYMGR_ERROR (result))
475169689Skan	    return -1;
476169689Skan	  return cxa_atexit (r->callback.cac, r->arg, dso);
477169689Skan	}
478169689Skan      else
479169689Skan	{
480169689Skan	  atexit_p atexit_f = g->atexit_f;
481169689Skan	  result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST,
482169689Skan							   g);
483169689Skan	  if (CHECK_KEYMGR_ERROR (result))
484169689Skan	    return -1;
485169689Skan	  return atexit_f (r->callback.ac);
486169689Skan	}
487169689Skan    }
488169689Skan  else
489169689Skan    {
490169689Skan      cxa_atexit_p cxa_atexit = g->cxa_atexit_f;
491169689Skan      struct one_atexit_routine *alloced;
492169689Skan      int result;
493169689Skan
494169689Skan      result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
495169689Skan      if (CHECK_KEYMGR_ERROR (result))
496169689Skan	return -1;
497169689Skan
498169689Skan      alloced = malloc (sizeof (struct one_atexit_routine));
499169689Skan      if (! alloced)
500169689Skan	return -1;
501169689Skan      *alloced = *r;
502169689Skan      return cxa_atexit (cxa_atexit_wrapper, alloced, dso);
503169689Skan    }
504169689Skan}
505169689Skan
506169689Skan/* These are the actual replacement routines; they just funnel into
507169689Skan   atexit_common.  */
508169689Skan
509169689Skanint __cxa_atexit (cxa_atexit_callback func, void* arg,
510169689Skan		  const void* dso) __attribute__((visibility("hidden")));
511169689Skan
512169689Skanint
513169689Skan__cxa_atexit (cxa_atexit_callback func, void* arg, const void* dso)
514169689Skan{
515169689Skan  struct one_atexit_routine r;
516169689Skan  r.callback.cac = func;
517169689Skan  r.has_arg = 1;
518169689Skan  r.arg = arg;
519169689Skan  return atexit_common (&r, dso);
520169689Skan}
521169689Skan
522169689Skanint atexit (atexit_callback func) __attribute__((visibility("hidden")));
523169689Skan
524169689Skan/* Use __dso_handle to allow even bundles that call atexit() to be unloaded
525169689Skan   on 10.4.  */
526169689Skanextern void __dso_handle;
527169689Skan
528169689Skanint
529169689Skanatexit (atexit_callback func)
530169689Skan{
531169689Skan  struct one_atexit_routine r;
532169689Skan  r.callback.ac = func;
533169689Skan  r.has_arg = 0;
534169689Skan  return atexit_common (&r, &__dso_handle);
535169689Skan}
536169689Skan
537169689Skan#endif /* __PIC__ */
538