1/* crt1.s for Solaris 2, x86
2
3   Copyright (C) 1993-2017 Free Software Foundation, Inc.
4   Written By Fred Fish, Nov 1992
5
6This file is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 3, or (at your option) any
9later version.
10
11This file is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14General Public License for more details.
15
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23<http://www.gnu.org/licenses/>.  */
24
25
26/* This file takes control of the process from the kernel, as specified
27   in section 3 of the System V Application Binary Interface, Intel386
28   Processor Supplement.  It has been constructed from information obtained
29   from the ABI, information obtained from single stepping existing
30   Solaris executables through their startup code with gdb, and from
31   information obtained by single stepping executables on other i386 SVR4
32   implementations.  This file is the first thing linked into any
33   executable.  */
34
35#ifndef GCRT1
36	.ident	"GNU C crt1.s"
37#define CLEANUP	_cleanup
38#else
39/* This is a modified crt1.s by J.W.Hawtin <oolon@ankh.org> 15/8/96,
40   to allow program profiling, by calling monstartup on entry and _mcleanup
41   on exit.  */
42	.ident	"GNU C gcrt1.s"
43#define CLEANUP _mcleanup
44#endif
45	.weak	_cleanup
46	.weak	_DYNAMIC
47	.text
48
49/* Start creating the initial frame by pushing a NULL value for the return
50   address of the initial frame, and mark the end of the stack frame chain
51   (the innermost stack frame) with a NULL value, per page 3-32 of the ABI.
52   Initialize the first stack frame pointer in %ebp (the contents of which
53   are unspecified at process initialization).  */
54
55	.globl	_start
56_start:
57	pushl	$0x0
58	pushl	$0x0
59	movl	%esp,%ebp
60
61/* As specified per page 3-32 of the ABI, %edx contains a function
62   pointer that should be registered with atexit(), for proper
63   shared object termination.  Just push it onto the stack for now
64   to preserve it.  We want to register _cleanup() first.  */
65
66	pushl	%edx
67
68/* Check to see if there is an _cleanup() function linked in, and if
69   so, register it with atexit() as the last thing to be run by
70   atexit().  */
71
72	movl	$CLEANUP,%eax
73	testl	%eax,%eax
74	je	.L1
75	pushl	$CLEANUP
76	call	atexit
77	addl	$0x4,%esp
78.L1:
79
80/* Now check to see if we have an _DYNAMIC table, and if so then
81   we need to register the function pointer previously in %edx, but
82   now conveniently saved on the stack as the argument to pass to
83   atexit().  */
84
85	movl	$_DYNAMIC,%eax
86	testl	%eax,%eax
87	je	.L2
88	call	atexit
89.L2:
90
91/* Register _fini() with atexit().  We will take care of calling _init()
92   directly.  */
93
94	pushl	$_fini
95	call	atexit
96
97#ifdef GCRT1
98/* Start profiling.  */
99
100        pushl %ebp
101        movl %esp,%ebp
102        pushl $_etext
103        pushl $_start
104        call monstartup
105        addl $8,%esp
106	popl %ebp
107#endif
108
109/* Compute the address of the environment vector on the stack and load
110   it into the global variable _environ.  Currently argc is at 8 off
111   the frame pointer.  Fetch the argument count into %eax, scale by the
112   size of each arg (4 bytes) and compute the address of the environment
113   vector which is 16 bytes (the two zero words we pushed, plus argc,
114   plus the null word terminating the arg vector) further up the stack,
115   off the frame pointer (whew!).  */
116
117	movl	8(%ebp),%eax
118	leal	16(%ebp,%eax,4),%edx
119	movl	%edx,_environ
120
121/* Push the environment vector pointer, the argument vector pointer,
122   and the argument count on to the stack to set up the arguments
123   for _init(), _fpstart(), and main().  Note that the environment
124   vector pointer and the arg count were previously loaded into
125   %edx and %eax respectively.  The only new value we need to compute
126   is the argument vector pointer, which is at a fixed address off
127   the initial frame pointer.  */
128
129/* Make sure the stack is properly aligned.  */
130	andl $0xfffffff0,%esp
131	subl $4,%esp
132
133	pushl	%edx
134	leal	12(%ebp),%edx
135	pushl	%edx
136	pushl	%eax
137
138/* Call _init(argc, argv, environ), _fpstart(argc, argv, environ), and
139   main(argc, argv, environ).  */
140
141	call	_init
142	call	__fpstart
143	call	main
144
145/* Pop the argc, argv, and environ arguments off the stack, push the
146   value returned from main(), and call exit().  */
147
148	addl	$12,%esp
149	pushl	%eax
150	call	exit
151
152/* An inline equivalent of _exit, as specified in Figure 3-26 of the ABI.  */
153
154	pushl	$0x0
155	movl	$0x1,%eax
156	lcall	$7,$0
157
158/* If all else fails, just try a halt!  */
159
160	hlt
161	.type	_start,@function
162	.size	_start,.-_start
163
164#ifndef GCRT1
165/* A dummy profiling support routine for non-profiling executables,
166   in case we link in some objects that have been compiled for profiling.  */
167
168	.weak	_mcount
169_mcount:
170	ret
171	.type	_mcount,@function
172	.size	_mcount,.-_mcount
173#endif
174