rtld: Add support for preinit, init, and fini arrays
[dragonfly.git] / lib / csu / x86_64 / crt1.c
1 /* LINTLIBRARY */
2 /*-
3  * Copyright 1996-1998 John D. Polstra.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: src/lib/csu/amd64/crt1.c,v 1.13 2003/04/30 19:27:07 peter Exp $
27  */
28
29 #ifndef lint
30 #ifndef __GNUC__
31 #error "GCC is needed to compile this file"
32 #endif
33 #endif /* lint */
34
35 #include <machine/tls.h>
36 #include <stdlib.h>
37
38 #include "libc_private.h"
39 #include "crtbrand.c"
40
41 extern int _DYNAMIC;
42 #pragma weak _DYNAMIC
43
44 typedef void (*fptr)(void);
45
46 extern void _fini(void);
47 extern void _init(void);
48 extern int main(int, char **, char **);
49 extern void _start(char **, void (*)(void));
50
51 extern void (*__preinit_array_start []) (int, char **, char **) __dso_hidden;
52 extern void (*__preinit_array_end   []) (int, char **, char **) __dso_hidden;
53 extern void (*__init_array_start    []) (int, char **, char **) __dso_hidden;
54 extern void (*__init_array_end      []) (int, char **, char **) __dso_hidden;
55 extern void (*__fini_array_start    []) (void) __dso_hidden;
56 extern void (*__fini_array_end      []) (void) __dso_hidden;
57
58 #ifdef GCRT
59 extern void _mcleanup(void);
60 extern void monstartup(void *, void *);
61 extern int eprol;
62 extern int etext;
63 #endif
64
65 char **environ;
66 const char *__progname = "";
67
68 /* The entry function. */
69 void
70 _start(char **ap, void (*cleanup)(void))
71 {
72         int argc;
73         char **argv;
74         char **env;
75         const char *s;
76         size_t n, array_size;
77
78         argc = *(long *)(void *)ap;
79         argv = ap + 1;
80         env = ap + 2 + argc;
81         environ = env;
82         if (argc > 0 && argv[0] != NULL) {
83                 __progname = argv[0];
84                 for (s = __progname; *s != '\0'; s++)
85                         if (*s == '/')
86                                 __progname = s + 1;
87         }
88
89         /*
90          * Setup the initial TLS space.  The RTLD does not set up our TLS
91          * (it can't, it doesn't know how our errno is declared).  It simply
92          * does all the groundwork required so that we can call
93          * _rtld_allocate_tls().
94          */
95         _init_tls();
96         _rtld_call_init();
97
98         if (&_DYNAMIC != NULL)
99                 atexit(cleanup);
100
101 #ifdef GCRT
102         atexit(_mcleanup);
103 #endif
104         /*
105          * The fini_array needs to be executed in the opposite order of its
106          * definition.  However, atexit works like a LIFO stack, so by
107          * pushing functions in array order, they will be executed in the
108          * reverse order as required.
109          */
110         atexit(_fini);
111         array_size = __fini_array_end - __fini_array_start;
112         for (n = 0; n < array_size; n++)
113                 atexit(*__fini_array_start [n]);
114 #ifdef GCRT
115         monstartup(&eprol, &etext);
116 #endif
117         if (&_DYNAMIC == NULL) {
118                 /*
119                  * For static executables preinit happens right before init.
120                  * Dynamic executable preinit arrays are handled by rtld
121                  * before any DSOs are initialized.
122                  */
123                 array_size = __preinit_array_end - __preinit_array_start;
124                 for (n = 0; n < array_size; n++)
125                         (*__preinit_array_start [n])(argc, argv, env);
126         }
127         _init();
128         array_size = __init_array_end - __init_array_start;
129         for (n = 0; n < array_size; n++)
130                 (*__init_array_start [n])(argc, argv, env);
131         exit( main(argc, argv, env) );
132 }
133
134 #ifdef GCRT
135 __asm__(".text");
136 __asm__("eprol:");
137 __asm__(".previous");
138 #endif