147884Sbostic /*- 247884Sbostic * Copyright (c) 1982 The Regents of the University of California. 347884Sbostic * All rights reserved. 447884Sbostic * 549278Sbostic * %sccs.include.redist.c% 621414Sdist */ 75102Smckusick 849278Sbostic #ifndef lint 9*55307Smckusick static char sccsid[] = "@(#)crt0.c 5.11 (Berkeley) 07/16/92"; 1049278Sbostic #endif /* not lint */ 1121414Sdist 125102Smckusick /* 135102Smckusick * C start up routine. 145102Smckusick * Robert Henry, UCB, 20 Oct 81 155102Smckusick * 165102Smckusick * We make the following (true) assumptions: 175102Smckusick * 1) when the kernel calls start, it does a jump to location 2, 185102Smckusick * and thus avoids the register save mask. We are NOT called 195102Smckusick * with a calls! see sys1.c:setregs(). 205102Smckusick * 2) The only register variable that we can trust is sp, 215102Smckusick * which points to the base of the kernel calling frame. 225102Smckusick * Do NOT believe the documentation in exec(2) regarding the 235102Smckusick * values of fp and ap. 245102Smckusick */ 255102Smckusick 269438Smckusick char **environ = (char **)0; 2725247Smckusick static int fd; 285102Smckusick 299438Smckusick extern unsigned char etext; 3048971Sdonn extern unsigned char eprol asm ("eprol"); 3148971Sdonn extern start() asm("start"); 3248971Sdonn 3348971Sdonn /* 3448971Sdonn * Two kluges: store sp at entry in environ, and 3548971Sdonn * install 16 bits of 0 at location 0 (a zero register save mask). 3648971Sdonn * These two hacks remove limits on the use of local 3748971Sdonn * and register variables in start(). 3848971Sdonn */ 3948971Sdonn asm(".text; .word 0; movl sp,_environ; jbr start+2"); 4048971Sdonn 415102Smckusick start() 425102Smckusick { 435102Smckusick struct kframe { 445102Smckusick int kargc; 455102Smckusick char *kargv[1]; /* size depends on kargc */ 465102Smckusick char kargstr[1]; /* size varies */ 475102Smckusick char kenvstr[1]; /* size varies */ 485102Smckusick }; 4948971Sdonn register struct kframe *kfp; 505102Smckusick register char **targv; 515102Smckusick register char **argv; 5225247Smckusick extern int errno; 5350405Smckusick extern void _mcleanup(); 545102Smckusick 555102Smckusick #ifdef lint 565102Smckusick kfp = 0; 579438Smckusick initcode = initcode = 0; 585102Smckusick #else not lint 5948971Sdonn kfp = (struct kframe *) environ; 605102Smckusick #endif not lint 615102Smckusick for (argv = targv = &kfp->kargv[0]; *targv++; /* void */) 625102Smckusick /* void */ ; 635102Smckusick if (targv >= (char **)(*argv)) 645102Smckusick --targv; 655102Smckusick environ = targv; 669438Smckusick asm("eprol:"); 6725247Smckusick 6825247Smckusick #ifdef paranoid 6925247Smckusick /* 7025247Smckusick * The standard I/O library assumes that file descriptors 0, 1, and 2 7125247Smckusick * are open. If one of these descriptors is closed prior to the start 7225247Smckusick * of the process, I/O gets very confused. To avoid this problem, we 7325247Smckusick * insure that the first three file descriptors are open before calling 7425247Smckusick * main(). Normally this is undefined, as it adds two unnecessary 7525247Smckusick * system calls. 7625247Smckusick */ 7725247Smckusick do { 7825247Smckusick fd = open("/dev/null", 2); 7925247Smckusick } while (fd >= 0 && fd < 3); 8025247Smckusick close(fd); 8125247Smckusick #endif paranoid 8225247Smckusick 839438Smckusick #ifdef MCRT0 8450405Smckusick atexit(_mcleanup); 859438Smckusick monstartup(&eprol, &etext); 869438Smckusick #endif MCRT0 8725247Smckusick errno = 0; 885102Smckusick exit(main(kfp->kargc, argv, environ)); 895102Smckusick } 905102Smckusick 919438Smckusick #ifdef CRT0 925102Smckusick /* 93*55307Smckusick * null moncontrol, just in case some routine is compiled for profiling 945102Smckusick */ 9511795Speter moncontrol(val) 9611795Speter int val; 9711795Speter { 9811795Speter 9911795Speter } 1009438Smckusick #endif CRT0 101