1 /*
2 Copyright (c) 2004 Paul Brook <paul@codesourcery.com>
3 
4 Common routine to implement atexit-like functionality.
5 
6 This is also the key function to be configured as lite exit, a size-reduced
7 implementation of exit that doesn't invoke clean-up functions such as _fini
8 or global destructors.
9 
10 Default (without lite exit) call graph is like:
11 start -> atexit -> __register_exitproc
12 start -> __libc_init_array -> __cxa_atexit -> __register_exitproc
13 on_exit -> __register_exitproc
14 start -> exit -> __call_exitprocs
15 
16 Here an -> means arrow tail invokes arrow head. All invocations here
17 are non-weak reference in current newlib.
18 
19 Lite exit makes some of above calls as weak reference, so that size expansive
20 functions __register_exitproc and __call_exitprocs may not be linked. These
21 calls are:
22 start w-> atexit
23 cxa_atexit w-> __register_exitproc
24 exit w-> __call_exitprocs
25 
26 Lite exit also makes sure that __call_exitprocs will be referenced as non-weak
27 whenever __register_exitproc is referenced as non-weak.
28 
29 Thus with lite exit libs, a program not explicitly calling atexit or on_exit
30 will escape from the burden of cleaning up code. A program with atexit or on_exit
31 will work consistently to normal libs.
32 
33 Lite exit is enabled with --enable-lite-exit, and is controlled with macro
34 LITE_EXIT.
35  */
36 /*
37  * COmmon routine to call call registered atexit-like routines.
38  */
39 
40 
41 #include <stdlib.h>
42 #include <sys/lock.h>
43 #include "atexit.h"
44 
45 /* Make this a weak reference to avoid pulling in free.  */
46 #ifndef MALLOC_PROVIDED
47 void free(void *) _ATTRIBUTE((__weak__));
48 #endif
49 
50 #ifdef _WANT_REGISTER_FINI
51 
52 /* If "__libc_fini" is defined, finalizers (either
53    "__libc_fini_array", or "_fini", as appropriate) will be run after
54    all user-specified atexit handlers.  For example, you can define
55    "__libc_fini" to "_fini" in your linker script if you want the C
56    library, rather than startup code, to register finalizers.  If you
57    do that, then your startup code need not contain references to
58    "atexit" or "exit".  As a result, only applications that reference
59    "exit" explicitly will pull in finalization code.
60 
61    The choice of whether to register finalizers from libc or from
62    startup code is deferred to link-time, rather than being a
63    configure-time option, so that the same C library binary can be
64    used with multiple BSPs, some of which register finalizers from
65    startup code, while others defer to the C library.  */
66 extern char __libc_fini __attribute__((weak));
67 
68 /* Register the application finalization function with atexit.  These
69    finalizers should run last.  Therefore, we want to call atexit as
70    soon as possible.  */
71 static void
72 register_fini(void) __attribute__((constructor (0)));
73 
74 static void
register_fini(void)75 register_fini(void)
76 {
77   if (&__libc_fini) {
78 #ifdef _HAVE_INITFINI_ARRAY
79     extern void __libc_fini_array (void);
80     atexit (__libc_fini_array);
81 #else
82     extern void _fini (void);
83     atexit (_fini);
84 #endif
85   }
86 }
87 
88 #endif /* _WANT_REGISTER_FINI  */
89 
90 /*
91  * Call registered exit handlers.  If D is null then all handlers are called,
92  * otherwise only the handlers from that DSO are called.
93  */
94 
95 void
__call_exitprocs(int code,void * d)96 __call_exitprocs (int code, void *d)
97 {
98   register struct _atexit *p;
99   struct _atexit **lastp;
100   register struct _on_exit_args * args;
101   register int n;
102   int i;
103   void (*fn) (void);
104 
105 
106   __LIBC_LOCK();
107 
108  restart:
109 
110   p = _atexit;
111   lastp = &_atexit;
112   while (p)
113     {
114       args = &p->_on_exit_args;
115       for (n = p->_ind - 1; n >= 0; n--)
116 	{
117 	  int ind;
118 
119 	  i = 1 << n;
120 
121 	  /* Skip functions not from this dso.  */
122 	  if (d && (!args || args->_dso_handle[n] != d))
123 	    continue;
124 
125 	  /* Remove the function now to protect against the
126 	     function calling exit recursively.  */
127 	  fn = p->_fns[n];
128 	  if (n == p->_ind - 1)
129 	    p->_ind--;
130 	  else
131 	    p->_fns[n] = NULL;
132 
133 	  /* Skip functions that have already been called.  */
134 	  if (!fn)
135 	    continue;
136 
137 	  ind = p->_ind;
138 
139 	  /* Call the function.  */
140 	  if (!args || (args->_fntypes & i) == 0)
141 	    fn ();
142 	  else if ((args->_is_cxa & i) == 0)
143 	    (*((void (*)(int, void *)) fn))(code, args->_fnargs[n]);
144 	  else
145 	    (*((void (*)(void *)) fn))(args->_fnargs[n]);
146 
147 	  /* The function we called call atexit and registered another
148 	     function (or functions).  Call these new functions before
149 	     continuing with the already registered functions.  */
150 	  if (ind != p->_ind || *lastp != p)
151 	    goto restart;
152 	}
153 
154 #if !defined (_ATEXIT_DYNAMIC_ALLOC) || !defined (MALLOC_PROVIDED)
155       break;
156 #else
157       /* Move to the next block.  Free empty blocks except the last one,
158 	 which is part of _GLOBAL_REENT.  */
159       if (p->_ind == 0 && p->_next)
160 	{
161 	  /* Remove empty block from the list.  */
162 	  *lastp = p->_next;
163 	  free (p);
164 	  p = *lastp;
165 	}
166       else
167 	{
168 	  lastp = &p->_next;
169 	  p = p->_next;
170 	}
171 #endif
172     }
173     __LIBC_UNLOCK();
174 }
175