Commit | Line | Data |
---|---|---|
90c075bb PR |
1 | /* |
2 | * Copyright (c) 1993 Paul Kranenburg | |
15637ed4 RG |
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: | |
90c075bb PR |
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 withough 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. | |
15637ed4 | 29 | * |
5e358090 | 30 | * $Id: crt0.c,v 1.6 1993/11/09 04:26:11 paul Exp $ |
15637ed4 RG |
31 | */ |
32 | ||
90c075bb | 33 | |
15637ed4 | 34 | #if defined(LIBC_SCCS) && !defined(lint) |
90c075bb | 35 | static char sccsid[] = "%W% (Erasmus) %G%"; |
15637ed4 RG |
36 | #endif /* LIBC_SCCS and not lint */ |
37 | ||
90c075bb PR |
38 | extern void exit(); |
39 | int _callmain(); | |
15637ed4 | 40 | |
90c075bb PR |
41 | #include <sys/param.h> |
42 | ||
43 | #ifdef DYNAMIC | |
44 | #include <sys/types.h> | |
45 | #include <sys/syscall.h> | |
46 | #include <a.out.h> | |
47 | #ifndef N_GETMAGIC | |
48 | #define N_GETMAGIC(x) ((x).a_magic) | |
49 | #endif | |
50 | #ifndef N_BSSADDR | |
51 | #define N_BSSADDR(x) (N_DATADDR(x)+(x).a_data) | |
52 | #endif | |
53 | #include <sys/mman.h> | |
54 | #ifdef sun | |
55 | #define MAP_COPY MAP_PRIVATE | |
56 | #define MAP_FILE 0 | |
57 | #define MAP_ANON 0 | |
58 | #endif | |
59 | #include <link.h> | |
60 | ||
61 | extern struct link_dynamic _DYNAMIC; | |
62 | static void __do_dynamic_link (); | |
63 | static char *_getenv(); | |
64 | static int _strncmp(); | |
65 | ||
66 | #ifdef sparc | |
67 | static __call(); | |
68 | #endif | |
15637ed4 | 69 | |
90c075bb PR |
70 | #ifdef sun |
71 | #define LDSO "/usr/lib/ld.so" | |
72 | #endif | |
73 | #ifdef BSD | |
74 | #define LDSO "/usr/libexec/ld.so" | |
75 | #endif | |
c90fc599 | 76 | |
90c075bb | 77 | #endif /* DYNAMIC */ |
15637ed4 | 78 | |
90c075bb PR |
79 | static char *_strrchr(); |
80 | ||
81 | char **environ; | |
82 | ||
83 | #ifdef BSD | |
15637ed4 RG |
84 | extern unsigned char etext; |
85 | extern unsigned char eprol asm ("eprol"); | |
86 | extern start() asm("start"); | |
87 | extern mcount() asm ("mcount"); | |
88 | ||
90c075bb PR |
89 | int errno; |
90 | static char empty[1]; | |
91 | char *__progname = empty; | |
92 | #endif | |
93 | ||
94 | /* | |
95 | * We need these system calls, but can't use library stubs | |
96 | */ | |
97 | #define _exit(v) __syscall(SYS_exit, (v)) | |
98 | #define open(name, f, m) __syscall(SYS_open, (name), (f), (m)) | |
99 | #define close(fd) __syscall(SYS_close, (fd)) | |
100 | #define read(fd, s, n) __syscall(SYS_read, (fd), (s), (n)) | |
101 | #define write(fd, s, n) __syscall(SYS_write, (fd), (s), (n)) | |
102 | #define dup(fd) __syscall(SYS_dup, (fd)) | |
103 | #define dup2(fd, fdnew) __syscall(SYS_dup2, (fd), (fdnew)) | |
104 | #ifdef sun | |
105 | #define mmap(addr, len, prot, flags, fd, off) \ | |
106 | __syscall(SYS_mmap, (addr), (len), (prot), _MAP_NEW|(flags), (fd), (off)) | |
107 | #else | |
108 | #define mmap(addr, len, prot, flags, fd, off) \ | |
109 | __syscall(SYS_mmap, (addr), (len), (prot), (flags), (fd), (off)) | |
110 | #endif | |
111 | ||
112 | #define _FATAL(str) \ | |
113 | write(2, str, sizeof(str)), \ | |
114 | _exit(1); | |
115 | ||
116 | ||
117 | #ifdef sparc | |
118 | asm (" .global start"); | |
119 | asm (" .text"); | |
120 | asm (" start:"); | |
121 | ||
122 | /* Set up `argc', `argv', and `envp' into local registers (from GNU Emacs). */ | |
123 | asm (" mov 0, %fp"); | |
124 | asm (" ld [%sp + 64], %l0"); /* argc */ | |
125 | asm (" add %sp, 68, %l1"); /* argv */ | |
126 | asm (" sll %l0, 2, %l2"); /**/ | |
127 | asm (" add %l2, 4, %l2"); /* envp = argv + (argc << 2) + 4 */ | |
128 | asm (" add %l1, %l2, %l2"); /**/ | |
129 | asm (" sethi %hi(_environ), %l3"); | |
130 | asm (" st %l2, [%l3+%lo(_environ)]"); /* *environ = l2 */ | |
131 | ||
132 | /* Finish diddling with stack. */ | |
133 | asm (" andn %sp, 7, %sp"); | |
134 | asm (" sub %sp, 24, %sp"); | |
135 | ||
136 | #ifdef DYNAMIC | |
137 | /* Resolve symbols in dynamic libraries */ | |
138 | asm (" call ___do_dynamic_link"); | |
139 | asm (" nop"); | |
140 | #endif | |
141 | ||
142 | /* From here, all symbols should have been resolved, so we can use libc */ | |
143 | #ifdef MCRT0 | |
144 | asm (" call ___do_mcrt"); | |
145 | asm (" nop"); | |
146 | #endif | |
147 | ||
148 | /* Stay Sun compatible (currently (SunOS 4.1.2) does nothing on sun4) */ | |
149 | asm (" call start_float"); | |
150 | asm (" nop"); | |
151 | ||
152 | /* Move `argc', `argv', and `envp' from locals to parameters for `main'. */ | |
153 | asm (" mov %l0,%o0"); | |
154 | asm (" mov %l1,%o1"); | |
155 | asm ("__callmain:"); /* Defined for the benefit of debuggers */ | |
156 | asm (" call _main"); | |
157 | asm (" mov %l2,%o2"); | |
158 | ||
159 | asm (" call _exit"); | |
160 | asm (" nop"); | |
161 | ||
162 | #ifdef MCRT0 | |
163 | static void | |
164 | __do_mcrt () | |
165 | { | |
166 | extern unsigned char eprol, etext; | |
167 | extern void _mcleanup(); | |
168 | ||
169 | on_exit(_mcleanup, 0); | |
170 | monstartup(&eprol, &etext); | |
171 | return; | |
172 | } | |
173 | #endif | |
174 | ||
175 | #endif /* sparc */ | |
176 | ||
177 | ||
178 | #ifdef i386 | |
15637ed4 RG |
179 | start() |
180 | { | |
181 | struct kframe { | |
182 | int kargc; | |
183 | char *kargv[1]; /* size depends on kargc */ | |
184 | char kargstr[1]; /* size varies */ | |
185 | char kenvstr[1]; /* size varies */ | |
186 | }; | |
187 | /* | |
188 | * ALL REGISTER VARIABLES!!! | |
189 | */ | |
190 | register struct kframe *kfp; | |
191 | register char **targv; | |
192 | register char **argv; | |
193 | extern void _mcleanup(); | |
90c075bb PR |
194 | #ifdef DYNAMIC |
195 | volatile caddr_t x; | |
196 | #endif | |
15637ed4 RG |
197 | |
198 | #ifdef lint | |
199 | kfp = 0; | |
200 | initcode = initcode = 0; | |
90c075bb | 201 | #else /* not lint */ |
15637ed4 RG |
202 | /* just above the saved frame pointer */ |
203 | asm ("lea 4(%%ebp), %0" : "=r" (kfp) ); | |
90c075bb | 204 | #endif /* not lint */ |
15637ed4 RG |
205 | for (argv = targv = &kfp->kargv[0]; *targv++; /* void */) |
206 | /* void */ ; | |
207 | if (targv >= (char **)(*argv)) | |
208 | --targv; | |
209 | environ = targv; | |
90c075bb PR |
210 | |
211 | #ifdef DYNAMIC | |
1781f4aa | 212 | /* ld(1) convention: if DYNAMIC = 0 then statically linked */ |
90c075bb PR |
213 | #ifdef stupid_gcc |
214 | if (&_DYNAMIC) | |
215 | __do_dynamic_link(); | |
216 | #else | |
217 | x = (caddr_t)&_DYNAMIC; | |
218 | if (x) | |
219 | __do_dynamic_link(); | |
220 | #endif | |
221 | #endif /* DYNAMIC */ | |
222 | ||
15637ed4 RG |
223 | asm("eprol:"); |
224 | ||
225 | #ifdef MCRT0 | |
226 | atexit(_mcleanup); | |
227 | monstartup(&eprol, &etext); | |
228 | #endif MCRT0 | |
90c075bb PR |
229 | #if 0 |
230 | errno = 0; | |
231 | #endif | |
232 | if (argv[0]) | |
233 | if ((__progname = _strrchr(argv[0], '/')) == NULL) | |
234 | __progname = argv[0]; | |
235 | else | |
236 | ++__progname; | |
237 | asm ("__callmain:"); /* Defined for the benefit of debuggers */ | |
15637ed4 RG |
238 | exit(main(kfp->kargc, argv, environ)); |
239 | } | |
90c075bb PR |
240 | #endif /* i386 */ |
241 | ||
242 | #ifdef DYNAMIC | |
243 | static void | |
244 | __do_dynamic_link () | |
245 | { | |
246 | struct crt_ldso crt; | |
247 | struct exec hdr; | |
248 | char *ldso; | |
249 | int dupzfd; | |
250 | void (*entry)(); | |
251 | ||
1781f4aa | 252 | #ifdef DEBUG |
90c075bb PR |
253 | /* Provision for alternate ld.so - security risk! */ |
254 | if (!(ldso = _getenv("LDSO"))) | |
1781f4aa | 255 | #endif |
90c075bb PR |
256 | ldso = LDSO; |
257 | ||
258 | crt.crt_ldfd = open(ldso, 0, 0); | |
259 | if (crt.crt_ldfd == -1) { | |
260 | _FATAL("No ld.so\n"); | |
261 | } | |
262 | ||
263 | /* Read LDSO exec header */ | |
264 | if (read(crt.crt_ldfd, &hdr, sizeof hdr) < sizeof hdr) { | |
265 | _FATAL("Failure reading ld.so\n"); | |
266 | } | |
5e358090 | 267 | if ((N_GETMAGIC_NET(hdr) != ZMAGIC) && (N_GETMAGIC(hdr) != QMAGIC)) { |
90c075bb PR |
268 | _FATAL("Bad magic: ld.so\n"); |
269 | } | |
270 | ||
271 | #ifdef sun | |
272 | /* Get bucket of zeroes */ | |
273 | crt.crt_dzfd = open("/dev/zero", 0, 0); | |
274 | if (crt.crt_dzfd == -1) { | |
275 | _FATAL("No /dev/zero\n"); | |
276 | } | |
277 | #endif | |
278 | #ifdef BSD | |
279 | /* We use MAP_ANON */ | |
280 | crt.crt_dzfd = -1; | |
281 | #endif | |
282 | ||
283 | #if defined(sun) && defined(DUPZFD) | |
284 | if ((dupzfd = dup(crt.crt_dzfd)) < 0) { | |
285 | _FATAL("Cannot dup /dev/zero\n"); | |
286 | } | |
287 | #endif | |
288 | ||
289 | /* Map in ld.so */ | |
5e358090 | 290 | crt.crt_ba = mmap(0, hdr.a_text, |
90c075bb PR |
291 | PROT_READ|PROT_EXEC, |
292 | MAP_FILE|MAP_COPY, | |
293 | crt.crt_ldfd, N_TXTOFF(hdr)); | |
294 | if (crt.crt_ba == -1) { | |
295 | _FATAL("Cannot map ld.so\n"); | |
296 | } | |
297 | ||
298 | #ifdef BSD | |
299 | /* !!! | |
300 | * This is gross, ld.so is a ZMAGIC a.out, but has `sizeof(hdr)' for | |
301 | * an entry point and not at PAGSIZ as the N_*ADDR macros assume. | |
302 | */ | |
303 | #undef N_DATADDR | |
304 | #undef N_BSSADDR | |
305 | #define N_DATADDR(x) ((x).a_text) | |
306 | #define N_BSSADDR(x) ((x).a_text + (x).a_data) | |
307 | #endif | |
308 | ||
309 | /* Map in data segment of ld.so writable */ | |
310 | if (mmap(crt.crt_ba+N_DATADDR(hdr), hdr.a_data, | |
5e358090 | 311 | PROT_READ|PROT_WRITE, |
90c075bb PR |
312 | MAP_FIXED|MAP_FILE|MAP_COPY, |
313 | crt.crt_ldfd, N_DATOFF(hdr)) == -1) { | |
314 | _FATAL("Cannot map ld.so\n"); | |
315 | } | |
316 | ||
317 | /* Map bss segment of ld.so zero */ | |
318 | if (hdr.a_bss && mmap(crt.crt_ba+N_BSSADDR(hdr), hdr.a_bss, | |
5e358090 | 319 | PROT_READ|PROT_WRITE, |
90c075bb PR |
320 | MAP_FIXED|MAP_ANON|MAP_COPY, |
321 | crt.crt_dzfd, 0) == -1) { | |
322 | _FATAL("Cannot map ld.so\n"); | |
323 | } | |
324 | ||
325 | crt.crt_dp = &_DYNAMIC; | |
326 | crt.crt_ep = environ; | |
327 | crt.crt_bp = (caddr_t)_callmain; | |
328 | ||
329 | #if defined(sparc) && defined(SUN_COMPAT) | |
330 | /* Call Sun's ld.so entry point: version 1, offset crt */ | |
331 | __call(CRT_VERSION_SUN, &crt, crt.crt_ba + sizeof hdr); | |
332 | #else | |
333 | entry = (void (*)())(crt.crt_ba + sizeof hdr); | |
334 | #ifdef SUN_COMPAT | |
335 | (*entry)(CRT_VERSION_SUN, &crt); | |
336 | #else | |
337 | (*entry)(CRT_VERSION_BSD, &crt); | |
338 | #endif | |
339 | #endif | |
340 | ||
341 | #if defined(sun) && defined(DUPZFD) | |
342 | if (dup2(dupzfd, crt.crt_dzfd) < 0) { | |
343 | _FATAL("Cannot dup2 /dev/zero\n"); | |
344 | } | |
345 | (void)close(dupzfd); | |
346 | #endif | |
347 | return; | |
348 | } | |
349 | ||
350 | #ifdef sparc | |
351 | static | |
352 | __call() | |
353 | { | |
354 | /* | |
355 | * adjust the C generated pointer to the crt struct to the | |
356 | * likings of ld.so, which is an offset relative to its %fp | |
357 | */ | |
358 | #if 0 | |
359 | asm("___call:"); | |
360 | asm("call %o2"); | |
361 | asm("sub %o1, %sp, %o1"); /* adjust parameter */ | |
362 | #else Hmmm... | |
363 | asm("mov %i0, %o0"); | |
364 | asm("mov %i1, %o1"); | |
365 | asm("call %i2"); | |
366 | asm("sub %o1, %sp, %o1"); | |
367 | /*NOTREACHED, control is transferred directly to our caller */ | |
368 | #endif | |
369 | } | |
370 | #endif | |
15637ed4 | 371 | |
15637ed4 | 372 | /* |
90c075bb | 373 | * Support routines |
15637ed4 | 374 | */ |
90c075bb PR |
375 | |
376 | static int | |
377 | _strncmp(s1, s2, n) | |
378 | register char *s1, *s2; | |
379 | register n; | |
15637ed4 RG |
380 | { |
381 | ||
90c075bb PR |
382 | if (n == 0) |
383 | return (0); | |
384 | do { | |
385 | if (*s1 != *s2++) | |
386 | return (*(unsigned char *)s1 - *(unsigned char *)--s2); | |
387 | if (*s1++ == 0) | |
388 | break; | |
389 | } while (--n != 0); | |
390 | return (0); | |
15637ed4 RG |
391 | } |
392 | ||
90c075bb PR |
393 | static char * |
394 | _getenv(name) | |
395 | register char *name; | |
396 | { | |
397 | extern char **environ; | |
398 | register int len; | |
399 | register char **P, *C; | |
400 | ||
401 | for (C = name, len = 0; *C && *C != '='; ++C, ++len); | |
402 | for (P = environ; *P; ++P) | |
403 | if (!_strncmp(*P, name, len)) | |
404 | if (*(C = *P + len) == '=') { | |
405 | return(++C); | |
406 | } | |
407 | return (char *)0; | |
408 | } | |
409 | ||
410 | #ifdef sparc | |
411 | /* System call entry */ | |
412 | asm("___syscall:"); | |
413 | asm("clr %g1"); | |
414 | asm("ta %g0"); | |
415 | asm("bgeu Lsyscallx"); /* good result ? */ | |
416 | asm("nop"); | |
417 | asm("mov -0x1, %o0"); /* Note: no `errno' */ | |
418 | asm("Lsyscallx:"); | |
419 | asm("jmp %o7 + 0x8"); | |
420 | asm("nop"); | |
421 | #endif /* sparc */ | |
422 | #ifdef i386 | |
423 | asm(" ___syscall:"); | |
424 | asm(" popl %ecx"); | |
425 | asm(" popl %eax"); | |
426 | asm(" pushl %ecx"); | |
427 | asm(" .byte 0x9a"); | |
428 | asm(" .long 0"); | |
429 | asm(" .word 7"); | |
430 | asm(" pushl %ecx"); | |
431 | asm(" jc 1f"); | |
432 | asm(" ret"); | |
433 | asm(" 1:"); | |
434 | asm(" movl $-1,%eax"); | |
435 | asm(" ret"); | |
436 | #endif /* i386 */ | |
437 | ||
438 | #endif /* DYNAMIC */ | |
439 | ||
440 | static char * | |
441 | _strrchr(p, ch) | |
442 | register char *p, ch; | |
443 | { | |
444 | register char *save; | |
445 | ||
446 | for (save = NULL;; ++p) { | |
447 | if (*p == ch) | |
448 | save = (char *)p; | |
449 | if (!*p) | |
450 | return(save); | |
451 | } | |
452 | /* NOTREACHED */ | |
453 | } | |
454 | ||
455 | #ifdef MCRT0 | |
456 | asm (" .text"); | |
457 | asm ("_eprol:"); | |
458 | #endif |