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