147882Sbostic /*- 248802Sdonn * Copyright (c) 1991 The Regents of the University of California. 347882Sbostic * All rights reserved. 447882Sbostic * 549275Sbostic * %sccs.include.redist.c% 644279Sbostic */ 744279Sbostic 848802Sdonn #ifndef lint 9*54908Smckusick static char sccsid[] = "@(#)crt0.c 5.7 (Berkeley) 07/10/92"; 1048802Sdonn #endif /* not lint */ 1144279Sbostic 1244279Sbostic /* 1344279Sbostic * C start up routine. 1444279Sbostic * Robert Henry, UCB, 20 Oct 81 1544279Sbostic * 1644279Sbostic * We make the following (true) assumptions: 1744279Sbostic * 1) when the kernel calls start, it does a jump to location 2, 1844279Sbostic * and thus avoids the register save mask. We are NOT called 1944279Sbostic * with a calls! see sys1.c:setregs(). 2044279Sbostic * 2) The only register variable that we can trust is sp, 2144279Sbostic * which points to the base of the kernel calling frame. 2244279Sbostic * Do NOT believe the documentation in exec(2) regarding the 2344279Sbostic * values of fp and ap. 2444279Sbostic * 3) We can allocate as many register variables as we want, 2544279Sbostic * and don't have to save them for anybody. 2644279Sbostic * 4) Because of the ways that asm's work, we can't have 2744279Sbostic * any automatic variables allocated on the stack, because 2844279Sbostic * we must catch the value of sp before any automatics are 2944279Sbostic * allocated. 3044279Sbostic */ 3144279Sbostic 3244279Sbostic char **environ = (char **)0; 3344279Sbostic static int fd; 3444279Sbostic 3548802Sdonn extern unsigned char etext; 3648802Sdonn extern unsigned char eprol asm ("eprol"); 3748802Sdonn extern start() asm("start"); 3844279Sbostic 3948802Sdonn asm(".text; orb #0,d0"); /* 32 bits of zero at location 0 */ 4044279Sbostic 4144279Sbostic start() 4244279Sbostic { 4344279Sbostic struct kframe { 4444279Sbostic int kargc; 4544279Sbostic char *kargv[1]; /* size depends on kargc */ 4644279Sbostic char kargstr[1]; /* size varies */ 4744279Sbostic char kenvstr[1]; /* size varies */ 4844279Sbostic }; 4944279Sbostic /* 5044279Sbostic * ALL REGISTER VARIABLES!!! 5144279Sbostic */ 5248802Sdonn register struct kframe *kfp; /* r10 */ 5344279Sbostic register char **targv; 5444279Sbostic register char **argv; 5544279Sbostic extern int errno; 5650404Smckusick extern void _mcleanup(); 5744279Sbostic 5844279Sbostic #ifdef lint 5944279Sbostic kfp = 0; 6044279Sbostic initcode = initcode = 0; 6144279Sbostic #else not lint 6244279Sbostic asm("lea a6@(4),%0" : "=r" (kfp)); /* catch it quick */ 6344279Sbostic #endif not lint 6444279Sbostic for (argv = targv = &kfp->kargv[0]; *targv++; /* void */) 6544279Sbostic /* void */ ; 6644279Sbostic if (targv >= (char **)(*argv)) 6744279Sbostic --targv; 6844279Sbostic environ = targv; 6944279Sbostic asm("eprol:"); 7044279Sbostic 7144279Sbostic #ifdef paranoid 7244279Sbostic /* 7344279Sbostic * The standard I/O library assumes that file descriptors 0, 1, and 2 7444279Sbostic * are open. If one of these descriptors is closed prior to the start 7544279Sbostic * of the process, I/O gets very confused. To avoid this problem, we 7644279Sbostic * insure that the first three file descriptors are open before calling 7744279Sbostic * main(). Normally this is undefined, as it adds two unnecessary 7844279Sbostic * system calls. 7944279Sbostic */ 8044279Sbostic do { 8144279Sbostic fd = open("/dev/null", 2); 8244279Sbostic } while (fd >= 0 && fd < 3); 8344279Sbostic close(fd); 8444279Sbostic #endif paranoid 8544279Sbostic 8644279Sbostic #ifdef MCRT0 8750404Smckusick atexit(_mcleanup); 8844279Sbostic monstartup(&eprol, &etext); 8944279Sbostic #endif MCRT0 9044279Sbostic errno = 0; 9144279Sbostic exit(main(kfp->kargc, argv, environ)); 9244279Sbostic } 9344279Sbostic 9444279Sbostic #ifdef CRT0 9544279Sbostic /* 96*54908Smckusick * null moncontrol, just in case some routine is compiled for profiling 9744279Sbostic */ 9844279Sbostic moncontrol(val) 9944279Sbostic int val; 10044279Sbostic { 10144279Sbostic 10244279Sbostic } 103*54908Smckusick #endif /* CRT0 */ 104