Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / lib / csu / i386 / crt0.c
1 /*
2  * Copyright (c) 1993 Paul Kranenburg
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Paul Kranenburg.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * $FreeBSD: src/lib/csu/i386/crt0.c,v 1.36 1999/08/27 23:57:55 peter Exp $
31  * $DragonFly: src/lib/csu/i386/Attic/crt0.c,v 1.2 2003/06/17 04:26:41 dillon Exp $
32  */
33
34 #include <sys/param.h>
35
36 #include <stdlib.h>
37
38 #ifdef DYNAMIC
39 #include <sys/types.h>
40 #include <sys/syscall.h>
41 #include <a.out.h>
42 #include <string.h>
43 #include <sys/mman.h>
44 #include <link.h>
45
46 /* !!!
47  * This is gross, ld.so is a ZMAGIC a.out, but has `sizeof(hdr)' for
48  * an entry point and not at PAGSIZ as the N_*ADDR macros assume.
49  */
50 #undef N_DATADDR
51 #define N_DATADDR(x)    ((x).a_text)
52
53 #undef N_BSSADDR
54 #define N_BSSADDR(x)    ((x).a_text + (x).a_data)
55
56 #ifndef N_GETMAGIC
57 #define N_GETMAGIC(x)   ((x).a_magic)
58 #endif /* N_GETMAGIC */
59
60 #ifndef MAP_PRIVATE
61 #define MAP_PRIVATE     MAP_COPY
62 #endif /* MAP_PRIVATE */
63
64 #ifndef MAP_FILE
65 #define MAP_FILE        0
66 #endif /* MAP_FILE */
67
68 #ifndef MAP_ANON
69 #define MAP_ANON        0
70 #endif /* MAP_ANON */
71
72 #ifdef DEBUG 
73 /*
74  * We need these two because we are going to call them before the ld.so is
75  * finished (as a matter of fact before we know if it exists !) so we must
76  * provide these versions for them
77  */
78 static char             *_getenv();
79 static int              _strncmp();
80 #endif /* DEBUG */
81
82 #ifndef LDSO
83 #define LDSO            "/usr/libexec/ld.so"
84 #endif /* LDSO */
85
86 extern struct _dynamic  _DYNAMIC;
87 static void             __do_dynamic_link(char **argv);
88 #endif /* DYNAMIC */
89
90 int                     _callmain();
91 int                     errno;
92 static char             empty[1];
93 char                    *__progname = empty;
94 char                    **environ;
95
96 /* Globals used by dlopen() and related functions in libc */
97 struct ld_entry         *__ldso_entry;
98 int                     __ldso_version;
99
100 extern  unsigned char   etext;
101 extern  unsigned char   eprol asm ("eprol");
102 extern                  start() asm("start");
103 extern                  mcount() asm ("mcount");
104 extern  int             main(int argc, char **argv, char **envp);
105 int                     __syscall(int syscall,...);
106 #ifdef MCRT0
107 void                    monstartup(void *low, void *high);
108 #endif /* MCRT0 */
109
110
111 /*
112  * We need these system calls, but can't use library stubs because the are
113  * not accessible until we have done the ld.so stunt.
114  */
115
116 #define _exit(v) \
117         __syscall(SYS_exit, (int)(v))
118 #define _open(name, f, m) \
119         __syscall(SYS_open, (const char *)(name), (int)(f), (int)(m))
120 #define _read(fd, s, n) \
121         __syscall(SYS_read, (int)(fd), (void *)(s), (size_t)(n))
122 #define _write(fd, s, n) \
123         __syscall(SYS_write, (int)(fd), (const void *)(s), (size_t)(n))
124 #define _mmap(addr, len, prot, flags, fd, off)  \
125         (void *) __syscall(SYS_mmap, (void *)(addr), (size_t)(len), \
126                 (int)(prot), (int)(flags), (int)(fd), 0, (off_t)(off))
127
128 #define _PUTNMSG(str, len)      _write(2, (str), (len))
129 #define _PUTMSG(str)            _PUTNMSG((str), sizeof (str) - 1)
130 #define _FATAL(str)             ( _PUTMSG(str), _exit(1) )
131
132
133 int
134 start()
135 {
136         struct kframe {
137                 int     kargc;
138                 char    *kargv[1];      /* size depends on kargc */
139                 char    kargstr[1];     /* size varies */
140                 char    kenvstr[1];     /* size varies */
141         };
142         /*
143          *      ALL REGISTER VARIABLES!!!
144          */
145         register struct kframe *kfp;
146         register char **targv;
147         register char **argv;
148         extern void _mcleanup();
149 #ifdef DYNAMIC
150         volatile caddr_t x;
151 #endif
152
153 #ifdef lint
154         kfp = 0;
155 #else /* not lint */
156         /* just above the saved frame pointer */
157         asm ("lea 4(%%ebp), %0" : "=r" (kfp) );
158 #endif /* not lint */
159         for (argv = targv = &kfp->kargv[0]; *targv++; /* void */)
160                 /* void */ ;
161         if (targv >= (char **)(*argv))
162                 --targv;
163         environ = targv;
164
165         if (argv[0]) {
166                 register char *s;
167                 __progname = argv[0];
168                 for (s=__progname; *s != '\0'; s++)
169                         if (*s == '/')
170                                 __progname = s+1;
171         }
172
173 #ifdef DYNAMIC
174         /* ld(1) convention: if DYNAMIC = 0 then statically linked */
175         /* sometimes GCC is too smart/stupid for its own good */
176         x = (caddr_t)&_DYNAMIC;
177         if (x)
178                 __do_dynamic_link(argv);
179 #endif /* DYNAMIC */
180
181 asm("eprol:");
182
183 #ifdef MCRT0
184         atexit(_mcleanup);
185         monstartup(&eprol, &etext);
186 #endif /* MCRT0 */
187
188 asm ("__callmain:");            /* Defined for the benefit of debuggers */
189         exit(main(kfp->kargc, argv, environ));
190 }
191
192 #ifdef DYNAMIC
193 static void
194 __do_dynamic_link(argv)
195         char    **argv;
196 {
197         struct crt_ldso crt;
198         struct exec     hdr;
199         char            *ldso;
200         int             (*entry)();
201
202 #ifdef DEBUG
203         /* Provision for alternate ld.so - security risk! */
204         if (!(ldso = _getenv("LDSO")))
205 #endif
206                 ldso = LDSO;
207
208         crt.crt_ldfd = _open(ldso, 0, 0);
209         if (crt.crt_ldfd == -1) {
210                 _PUTMSG("Couldn't open ");
211                 _PUTMSG(LDSO);
212                 _FATAL(".\n");
213         }
214
215         /* Read LDSO exec header */
216         if (_read(crt.crt_ldfd, &hdr, sizeof hdr) < sizeof hdr) {
217                 _FATAL("Failure reading ld.so\n");
218         }
219         if ((N_GETMAGIC_NET(hdr) != ZMAGIC) && (N_GETMAGIC(hdr) != QMAGIC)) {
220                 _FATAL("Bad magic: ld.so\n");
221         }
222
223         /* We use MAP_ANON */
224         crt.crt_dzfd = -1;
225
226         /* Map in ld.so */
227         crt.crt_ba = (int)_mmap(0, hdr.a_text,
228                         PROT_READ|PROT_EXEC,
229                         MAP_FILE|MAP_PRIVATE,
230                         crt.crt_ldfd, N_TXTOFF(hdr));
231         if (crt.crt_ba == -1) {
232                 _FATAL("Cannot map ld.so (text)\n");
233         }
234
235         /* Map in data segment of ld.so writable */
236         if ((int)_mmap((caddr_t)(crt.crt_ba+N_DATADDR(hdr)), hdr.a_data,
237                         PROT_READ|PROT_WRITE,
238                         MAP_FIXED|MAP_FILE|MAP_PRIVATE,
239                         crt.crt_ldfd, N_DATOFF(hdr)) == -1) {
240                 _FATAL("Cannot map ld.so (data)\n");
241         }
242
243         /* Map bss segment of ld.so zero */
244         if (hdr.a_bss && (int)_mmap((caddr_t)(crt.crt_ba+N_BSSADDR(hdr)),
245                         hdr.a_bss,
246                         PROT_READ|PROT_WRITE,
247                         MAP_FIXED|MAP_ANON|MAP_PRIVATE,
248                         crt.crt_dzfd, 0) == -1) {
249                 _FATAL("Cannot map ld.so (bss)\n");
250         }
251
252         crt.crt_dp = &_DYNAMIC;
253         crt.crt_ep = environ;
254         crt.crt_bp = (caddr_t)_callmain;
255         crt.crt_prog = __progname;
256         crt.crt_ldso = ldso;
257         crt.crt_ldentry = NULL;
258         crt.crt_argv = argv;
259
260         entry = (int (*)())(crt.crt_ba + sizeof hdr);
261         __ldso_version = (*entry)(CRT_VERSION_BSD_5, &crt);
262         __ldso_entry = crt.crt_ldentry;
263         if (__ldso_version == -1 && __ldso_entry == NULL) {
264                 /* If version 5 not recognised, try version 4 */
265                 __ldso_version = (*entry)(CRT_VERSION_BSD_4, &crt);
266                 __ldso_entry = crt.crt_ldentry;
267                 if (__ldso_version == -1 && __ldso_entry == NULL) {
268                         /* if version 4 not recognised, try version 3 */
269                         __ldso_version = (*entry)(CRT_VERSION_BSD_3, &crt);
270                         __ldso_entry = _DYNAMIC.d_entry;
271                 }
272         }
273         if (__ldso_version == -1) {
274                 _PUTMSG("ld.so failed");
275                 if (__ldso_entry != NULL) {
276                         const char *msg = (__ldso_entry->dlerror)();
277                         if(msg != NULL) {
278                                 const char *endp;
279                                 _PUTMSG(": ");
280                                 for(endp = msg;  *endp != '\0';  ++endp)
281                                         ;       /* Find the end */
282                                 _PUTNMSG(msg, endp - msg);
283                         }
284                 }
285                 _FATAL("\n");
286         }
287
288
289         if (__ldso_version >= LDSO_VERSION_HAS_DLEXIT)
290                 atexit(__ldso_entry->dlexit);
291
292         return;
293 }
294
295 /*
296  * Support routines
297  */
298
299 #ifdef DEBUG
300 static int
301 _strncmp(s1, s2, n)
302         register char *s1, *s2;
303         register n;
304 {
305
306         if (n == 0)
307                 return (0);
308         do {
309                 if (*s1 != *s2++)
310                         return (*(unsigned char *)s1 - *(unsigned char *)--s2);
311                 if (*s1++ == 0)
312                         break;
313         } while (--n != 0);
314         return (0);
315 }
316
317 static char *
318 _getenv(name)
319         register char *name;
320 {
321         extern char **environ;
322         register int len;
323         register char **P, *C;
324
325         for (C = name, len = 0; *C && *C != '='; ++C, ++len);
326         for (P = environ; *P; ++P)
327                 if (!_strncmp(*P, name, len))
328                         if (*(C = *P + len) == '=') {
329                                 return(++C);
330                         }
331         return (char *)0;
332 }
333
334 #endif /* DEBUG */
335
336         asm("   ___syscall:");
337         asm("           popl %ecx");
338         asm("           popl %eax");
339         asm("           pushl %ecx");
340         asm("           .byte 0x9a");
341         asm("           .long 0");
342         asm("           .word 7");
343         asm("           pushl %ecx");
344         asm("           jc 1f");
345         asm("           ret");
346         asm("   1:");
347         asm("           movl    $-1,%eax");
348         asm("           ret");
349
350 #endif /* DYNAMIC */
351
352
353 /*
354  * Support routines
355  */
356
357 #ifdef MCRT0
358 asm ("  .text");
359 asm ("_eprol:");
360 #endif