1/* C code startup routine.
2   Copyright (C) 1985, 1986, 1992, 2001, 2002, 2003, 2004,
3                 2005, 2006, 2007 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING.  If not, write to
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA.  */
21
22
23/* The standard Vax 4.2 Unix crt0.c cannot be used for Emacs
24   because it makes `environ' an initialized variable.
25   It is easiest to have a special crt0.c on all machines
26   though I don't know whether other machines actually need it.  */
27
28/* On the vax and 68000, in BSD4.2 and USG5.2,
29   this is the data format on startup:
30  (vax) ap and fp are unpredictable as far as I know; don't use them.
31  sp ->  word containing argc
32         word pointing to first arg string
33	 [word pointing to next arg string]... 0 or more times
34	 0
35Optionally:
36	 [word pointing to environment variable]... 1 or more times
37	 ...
38	 0
39And always:
40	 first arg string
41	 [next arg string]... 0 or more times
42*/
43
44/* On the 16000, at least in the one 4.2 system I know about,
45  the initial data format is
46  sp ->  word containing argc
47         word containing argp
48         word pointing to first arg string, and so on as above
49*/
50
51#ifdef emacs
52#include <config.h>
53#endif
54
55/*		********  WARNING ********
56    Do not insert any data definitions before data_start!
57    Since this is the first file linked, the address of the following
58    variable should correspond to the start of initialized data space.
59    On some systems this is a constant that is independent of the text
60    size for shared executables.  On others, it is a function of the
61    text size. In short, this seems to be the most portable way to
62    discover the start of initialized data space dynamically at runtime,
63    for either shared or unshared executables, on either swapping or
64    virtual systems.  It only requires that the linker allocate objects
65    in the order encountered, a reasonable model for most Unix systems.
66    Similarly, note that the address of _start() should be the start
67    of text space.   Fred Fish, UniSoft Systems Inc.  */
68
69int data_start = 0;
70
71#ifdef NEED_ERRNO
72int errno;
73#endif
74
75#ifndef DONT_NEED_ENVIRON
76char **environ;
77#endif
78
79#ifndef static
80/* On systems where the static storage class is usable, this function
81   should be declared as static.  Otherwise, the static keyword has
82   been defined to be something else, and code for those systems must
83   take care of this declaration appropriately.  */
84static start1 ();
85#endif
86
87#ifdef APOLLO
88extern	char   *malloc(), *realloc(), *(*_libc_malloc) (), *(*_libc_realloc)();
89extern	void	free(),	(*_libc_free) (); extern int main();
90std_$call void  unix_$main();
91
92_start()
93{
94	_libc_malloc = malloc;
95	_libc_realloc = realloc;
96	_libc_free = free;
97	unix_$main(main);	/* no return */
98}
99#endif /* APOLLO */
100
101#if defined(orion) || defined(pyramid) || defined(celerity) || defined(ALLIANT) || defined(clipper) || defined(sps7)
102
103#if defined(sps7) && defined(V3x)
104        asm("	section	10");
105        asm("	ds.b	0xb0");
106#endif
107
108#ifdef ALLIANT
109/* _start must initialize _curbrk and _minbrk on the first startup;
110   when starting up after dumping, it must initialize them to what they were
111   before the dumping, since they are in the shared library and
112   are not dumped.  See ADJUST_EXEC_HEADER in m-alliant.h.  */
113extern unsigned char *_curbrk, *_minbrk;
114extern unsigned char end;
115unsigned char *_setbrk = &end;
116#ifdef ALLIANT_2800
117unsigned char *_end = &end;
118#endif
119#endif
120
121#ifndef DUMMIES
122#define DUMMIES
123#endif
124
125_start (DUMMIES argc, argv, envp)
126     int argc;
127     char **argv, **envp;
128{
129#ifdef ALLIANT
130#ifdef ALLIANT_2800
131  _curbrk = _end;
132  _minbrk = _end;
133#else
134  _curbrk = _setbrk;
135  _minbrk = _setbrk;
136#endif
137#endif
138
139  environ = envp;
140
141  exit (main (argc, argv, envp));
142}
143
144#endif /* orion or pyramid or celerity or alliant or clipper */
145
146#if defined (ns16000) && !defined (sequent) && !defined (UMAX) && !defined (CRT0_DUMMIES)
147
148_start ()
149{
150/* On 16000, _start pushes fp onto stack */
151  start1 ();
152}
153
154/* ignore takes care of skipping the fp value pushed in start.  */
155static
156start1 (ignore, argc, argv)
157     int ignore;
158     int argc;
159     register char **argv;
160{
161  environ = argv + argc + 1;
162
163  if (environ == *argv)
164    environ--;
165  exit (main (argc, argv, environ));
166}
167#endif /* ns16000, not sequent and not UMAX, and not the CRT0_DUMMIES method */
168
169#ifdef UMAX
170_start()
171{
172	asm("	exit []			# undo enter");
173	asm("	.set	exitsc,1");
174	asm("	.set	sigcatchall,0x400");
175
176	asm("	.globl	_exit");
177	asm("	.globl	start");
178	asm("	.globl	__start");
179	asm("	.globl	_main");
180	asm("	.globl	_environ");
181	asm("	.globl	_sigvec");
182	asm("	.globl	sigentry");
183
184	asm("start:");
185	asm("	br	.xstart");
186	asm("	.org	0x20");
187	asm("	.double	p_glbl,0,0xf00000,0");
188	asm("	.org	0x30");
189	asm(".xstart:");
190	asm("	adjspb	$8");
191	asm("	movd	8(sp),0(sp)	# argc");
192	asm("	addr	12(sp),r0");
193	asm("	movd	r0,4(sp)	# argv");
194	asm("L1:");
195	asm("	movd	r0,r1");
196	asm("	addqd	$4,r0");
197	asm("	cmpqd	$0,0(r1)	# null args term ?");
198	asm("	bne	L1");
199	asm("	cmpd	r0,0(4(sp))	# end of 'env' or 'argv' ?");
200	asm("	blt	L2");
201	asm("	addqd	$-4,r0		# envp's are in list");
202	asm("L2:");
203	asm("	movd	r0,8(sp)	# env");
204	asm("	movd	r0,@_environ	# indir is 0 if no env ; not 0 if env");
205	asm("	movqd	$0,tos		# setup intermediate signal handler");
206	asm("	addr	@sv,tos");
207	asm("	movzwd	$sigcatchall,tos");
208	asm("	jsr	@_sigvec");
209	asm("	adjspb	$-12");
210	asm("	jsr	@_main");
211	asm("	adjspb	$-12");
212	asm("	movd	r0,tos");
213	asm("	jsr	@_exit");
214	asm("	adjspb	$-4");
215	asm("	addr	@exitsc,r0");
216	asm("	svc");
217	asm("	.align	4		# sigvec arg");
218	asm("sv:");
219	asm("	.double	sigentry");
220	asm("	.double	0");
221	asm("	.double	0");
222
223	asm("	.comm	p_glbl,1");
224}
225#endif /* UMAX */
226
227#ifdef CRT0_DUMMIES
228
229/* Define symbol "start": here; some systems want that symbol.  */
230#ifdef DOT_GLOBAL_START
231asm("	.text		");
232asm("	.globl start	");
233asm("	start:		");
234#endif /* DOT_GLOBAL_START */
235
236#ifdef NODOT_GLOBAL_START
237asm("	text		");
238asm("	global start	");
239asm("	start:		");
240#endif /* NODOT_GLOBAL_START */
241
242#ifdef m68000
243
244/* GCC 2.1, when optimization is turned off, seems to want to push a
245   word of garbage on the stack, which screws up the CRT0_DUMMIES
246   hack.  So we hand-code _start in assembly language.  */
247asm(".text			");
248asm("	.even			");
249asm(".globl __start		");
250asm("__start:			");
251asm("	link a6,#0		");
252asm("	jbsr _start1		");
253asm("	unlk a6			");
254asm("	rts			");
255
256#else /* not m68000 */
257
258_start ()
259{
260/* On vax, nothing is pushed here  */
261/* On sequent, bogus fp is pushed here  */
262  start1 ();
263}
264
265#endif /* possibly m68000 */
266
267static
268start1 (CRT0_DUMMIES argc, xargv)
269     int argc;
270     char *xargv;
271{
272  register char **argv = &xargv;
273  environ = argv + argc + 1;
274
275  if ((char *)environ == xargv)
276    environ--;
277  exit (main (argc, argv, environ));
278
279  /* Refer to `start1' so GCC will not think it is never called
280     and optimize it out.  */
281  (void) &start1;
282}
283#else /* not CRT0_DUMMIES */
284
285/* "m68k" and "m68000" both stand for m68000 processors,
286   but with different program-entry conventions.
287   This is a kludge.  Now that the CRT0_DUMMIES mechanism above exists,
288   most of these machines could use the vax code above
289   with some suitable definition of CRT0_DUMMIES.
290   Then the symbol m68k could be flushed.
291   But I don't want to risk breaking these machines
292   in a version 17 patch release, so that change is being put off.  */
293
294#ifdef m68k			/* Can't do it all from C */
295	asm ("	global	_start");
296	asm ("	text");
297	asm ("_start:");
298#ifndef NU
299#ifdef STRIDE
300	asm ("	comm	havefpu%,2");
301#else /* m68k, not STRIDE */
302	asm ("  comm	splimit%,4");
303#endif /* STRIDE */
304	asm ("	global	exit");
305	asm ("	text");
306#ifdef STRIDE
307	asm ("	trap	&3");
308	asm ("	mov.w	%d0,havefpu%");
309#else /* m68k, not STRIDE */
310  	asm ("	mov.l	%d0,splimit%");
311#endif /* STRIDE */
312#endif /* not NU */
313	asm ("	jsr	start1");
314	asm ("	mov.l	%d0,(%sp)");
315	asm ("	jsr	exit");
316	asm ("	mov.l	&1,%d0");	/* d0 = 1 => exit */
317	asm ("	trap	&0");
318#else /* m68000, not m68k */
319
320#ifdef m68000
321
322#ifdef ISI68K
323/* Added by ESM Sun May 24 12:44:02 1987 to get new ISI library to work */
324/* Edited by Ray Mon May 15 15:59:56 EST 1989 so we can compile with gcc */
325#if defined(BSD4_3) && !defined(__GNUC__)
326static foo () {
327#endif
328	asm ("	.globl  is68020");
329	asm ("is68020:");
330#ifndef BSD4_3
331	asm ("	.long   0x00000000");
332	asm ("	.long   0xffffffff");
333/* End of stuff added by ESM */
334#endif
335	asm ("	.text");
336	asm ("	.globl	__start");
337	asm ("__start:");
338	asm ("	.word 0");
339	asm ("	link	a6,#0");
340	asm ("	jbsr	_start1");
341	asm ("	unlk	a6");
342	asm ("	rts");
343#if defined(BSD4_3) && !defined(__GNUC__)
344      }
345#endif
346#else /* not ISI68K */
347
348_start ()
349{
350#ifdef sun
351  finitfp_();
352#endif
353/* On 68000, _start pushes a6 onto stack  */
354  start1 ();
355}
356#endif /* not ISI68k */
357#endif /* m68000 */
358#endif /* m68k */
359
360#if defined(m68k) || defined(m68000)
361/* ignore takes care of skipping the a6 value pushed in start.  */
362static
363#if defined(m68k)
364start1 (argc, xargv)
365#else
366start1 (ignore, argc, xargv)
367#endif
368     int argc;
369     char *xargv;
370{
371  register char **argv = &xargv;
372  environ = argv + argc + 1;
373
374  if ((char *)environ == xargv)
375    environ--;
376#ifdef sun_68881
377  asm("    jsr     f68881_used");
378#endif
379#ifdef sun_fpa
380  asm("    jsr     ffpa_used");
381#endif
382#ifdef sun_soft
383  asm("    jsr     start_float");
384#endif
385  exit (main (argc, argv, environ));
386}
387
388#endif /* m68k or m68000 */
389
390#endif /* not CRT0_DUMMIES */
391
392#ifdef hp9000s300
393int argc_value;
394char **argv_value;
395#ifdef OLD_HP_ASSEMBLER
396	asm("   text");
397	asm("	globl __start");
398	asm("	globl _exit");
399	asm("	globl _main");
400	asm("__start");
401	asm("	dc.l	0");
402	asm("	subq.w	#0x1,d0");
403	asm("	move.w	d0,float_soft");
404	asm("	move.l	0x4(a7),d0");
405	asm("	beq.s	skip_1");
406	asm("	move.l	d0,a0");
407	asm("	clr.l	-0x4(a0)");
408	asm("skip_1");
409	asm("	move.l	a7,a0");
410	asm("	subq.l	#0x8,a7");
411	asm("	move.l	(a0),(a7)");
412	asm("	move.l	(a0),_argc_value");
413	asm("	addq.l	#0x4,a0");
414	asm("	move.l	a0,0x4(a7)");
415	asm("	move.l	a0,_argv_value");
416	asm("incr_loop");
417	asm("	tst.l	(a0)+");
418	asm("	bne.s	incr_loop");
419	asm("	move.l	0x4(a7),a1");
420	asm("	cmp.l	(a1),a0");
421	asm("	blt.s	skip_2");
422	asm("	subq.l	#0x4,a0");
423	asm("skip_2");
424	asm("	move.l	a0,0x8(a7)");
425	asm("	move.l	a0,_environ");
426	asm("	jsr	_main");
427	asm("	addq.l	#0x8,a7");
428	asm("	move.l	d0,-(a7)");
429	asm("	jsr	_exit");
430	asm("	move.w	#0x1,d0");
431	asm("	trap	#0x0");
432	asm("	comm	float_soft,4");
433/* float_soft is allocated in this way because C would
434   put an underscore character in its name otherwise. */
435
436#else /* new hp assembler */
437
438	asm("	text");
439        asm("   global  float_loc");
440        asm("   set     float_loc,0xFFFFB000");
441 	asm("	global	fpa_loc");
442	asm("	set	fpa_loc,0xfff08000");
443	asm("	global	__start");
444	asm("	global	_exit");
445	asm("	global	_main");
446	asm("__start:");
447	asm("	byte	0,0,0,0");
448	asm("	subq.w	&1,%d0");
449	asm("	mov.w	%d0,float_soft");
450	asm("	mov.w	%d1,flag_68881");
451#ifndef HPUX_68010
452	asm("	beq.b	skip_float");
453	asm("	fmov.l	&0x7400,%fpcr");
454/*	asm("	fmov.l	&0x7480,%fpcr"); */
455#endif /* HPUX_68010 */
456	asm("skip_float:");
457	asm("	mov.l	%a0,%d0");
458	asm("	add.l	%d0,%d0");
459	asm("	subx.w	%d1,%d1");
460	asm("	mov.w	%d1,flag_68010");
461	asm("	add.l	%d0,%d0");
462	asm("	subx.w	%d1,%d1");
463	asm("	mov.w	%d1,flag_fpa");
464	asm("	tst.l	%d2");
465	asm("	ble.b	skip_3");
466	asm("	lsl	flag_68881");
467	asm("	lsl	flag_fpa");
468	asm("skip_3:");
469	asm("	mov.l	4(%a7),%d0");
470	asm("	beq.b	skip_1");
471	asm("	mov.l	%d0,%a0");
472	asm("	clr.l	-4(%a0)");
473	asm("skip_1:");
474	asm("	mov.l	%a7,%a0");
475	asm("	subq.l	&8,%a7");
476	asm("	mov.l	(%a0),(%a7)");
477	asm("	mov.l	(%a0),_argc_value");
478	asm("	addq.l	&4,%a0");
479	asm("	mov.l	%a0,4(%a7)");
480	asm("	mov.l	%a0,_argv_value");
481	asm("incr_loop:");
482	asm("	tst.l	(%a0)+");
483	asm("	bne.b	incr_loop");
484	asm("	mov.l	4(%a7),%a1");
485	asm("	cmp.l	%a0,(%a1)");
486	asm("	blt.b	skip_2");
487	asm("	subq.l	&4,%a0");
488	asm("skip_2:");
489	asm("	mov.l	%a0,8(%a7)");
490	asm("	mov.l	%a0,_environ");
491	asm("	jsr	_main");
492	asm("	addq.l	&8,%a7");
493	asm("	mov.l	%d0,-(%a7)");
494	asm("	jsr	_exit");
495	asm("	mov.w	&1,%d0");
496	asm("	trap	&0");
497	asm("	comm	float_soft, 4");
498	asm("	comm	flag_68881, 4");
499	asm("	comm	flag_68010, 4");
500	asm("	comm	flag_68040, 4");
501	asm("	comm	flag_fpa, 4");
502
503#endif /* new hp assembler */
504#endif /* hp9000s300 */
505
506#ifdef GOULD
507
508/* startup code has to be in near text rather
509   than fartext as allocated by the C compiler. */
510	asm("	.text");
511	asm("	.align	2");
512	asm("	.globl	__start");
513	asm("	.text");
514	asm("__start:");
515/* setup base register b1 (function base). */
516	asm("	.using	b1,.");
517	asm("	tpcbr	b1");
518/* setup base registers b3 through b7 (data references). */
519	asm("	file	basevals,b3");
520/* setup base register b2 (stack pointer); it should be
521   aligned on a 8-word boundary; but because it is pointing
522   to argc, its value should be remembered (in r5). */
523	asm("	movw	b2,r4");
524	asm("	movw	b2,r5");
525	asm("	andw	#~0x1f,r4");
526	asm("	movw	r4,b2");
527/* allocate stack frame to do some work. */
528	asm("	subea	16w,b2");
529/* initialize signal catching for UTX/32 1.2; this is
530   necessary to make restart from saved image work. */
531	asm("	movea	sigcatch,r1");
532	asm("	movw	r1,8w[b2]");
533	asm("	svc	#1,#150");
534/* setup address of argc for start1. */
535	asm("	movw	r5,8w[b2]");
536	asm("   func	#1,_start1");
537	asm("	halt");
538/* space for ld to store base register initial values. */
539	asm("	.align	5");
540	asm("basevals:");
541	asm("	.word	__base3,__base4,__base5,__base6,__base7");
542
543static
544start1 (xargc)
545     int *xargc;
546{
547  register int	argc;
548  register char **argv;
549
550  argc = *xargc;
551  argv = (char **)(xargc) + 1;
552  environ = argv + argc + 1;
553
554  if (environ == argv)
555    environ--;
556  exit (main (argc, argv, environ));
557
558}
559
560#endif /* GOULD */
561
562#ifdef elxsi
563#include <elxsi/argvcache.h>
564
565extern char **environ;
566extern int	errno;
567extern void	_init_doscan(), _init_iob();
568extern char	end[];
569char		*_init_brk = end;
570
571_start()
572{
573  environ = exec_cache.ac_envp;
574  brk (_init_brk);
575  errno = 0;
576  _init_doscan ();
577  _init_iob ();
578  _exit (exit (main (exec_cache.ac_argc,
579		     exec_cache.ac_argv,
580		     exec_cache.ac_envp)));
581}
582#endif /* elxsi */
583
584
585#ifdef sparc
586asm (".global __start");
587asm (".text");
588asm ("__start:");
589asm ("	mov	0, %fp");
590asm ("	ld	[%sp + 64], %o0");
591asm ("	add	%sp, 68, %o1");
592asm ("	sll	%o0, 2,	%o2");
593asm ("	add	%o2, 4,	%o2");
594asm ("	add	%o1, %o2, %o2");
595asm ("	sethi	%hi(_environ), %o3");
596asm ("	st	%o2, [%o3+%lo(_environ)]");
597asm ("	andn	%sp, 7,	%sp");
598asm ("	call	_main");
599asm ("	sub	%sp, 24, %sp");
600asm ("	call	__exit");
601asm ("	nop");
602
603#endif /* sparc */
604
605#if __FreeBSD__ == 2
606char *__progname;
607#endif
608#ifdef __bsdi__
609#include <sys/param.h> /* for version number */
610#if defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199501)
611char *__progname;
612#endif
613#endif /* __bsdi__ */
614
615/* arch-tag: 4025c2fb-d6b1-4d29-b1b6-8100b6bd1e74
616   (do not change this comment) */
617