150397Sobrien! gcrt1.s for Solaris 2, x86
250397Sobrien
350397Sobrien!   Copyright (C) 1993 Free Software Foundation, Inc.
450397Sobrien!   Written By Fred Fish, Nov 1992
550397Sobrien! 
650397Sobrien! This file is free software; you can redistribute it and/or modify it
750397Sobrien! under the terms of the GNU General Public License as published by the
850397Sobrien! Free Software Foundation; either version 2, or (at your option) any
950397Sobrien! later version.
1050397Sobrien! 
1150397Sobrien! In addition to the permissions in the GNU General Public License, the
1250397Sobrien! Free Software Foundation gives you unlimited permission to link the
1350397Sobrien! compiled version of this file with other programs, and to distribute
1450397Sobrien! those programs without any restriction coming from the use of this
1550397Sobrien! file.  (The General Public License restrictions do apply in other
1650397Sobrien! respects; for example, they cover modification of the file, and
1750397Sobrien! distribution when not linked into another program.)
1850397Sobrien! 
1950397Sobrien! This file is distributed in the hope that it will be useful, but
2050397Sobrien! WITHOUT ANY WARRANTY; without even the implied warranty of
2150397Sobrien! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2250397Sobrien! General Public License for more details.
2350397Sobrien! 
2450397Sobrien! You should have received a copy of the GNU General Public License
2550397Sobrien! along with this program; see the file COPYING.  If not, write to
26169689Skan! the Free Software Foundation, 51 Franklin Street, Fifth Floor,
27169689Skan! Boston, MA 02110-1301, USA.
2850397Sobrien! 
2950397Sobrien!    As a special exception, if you link this library with files
3050397Sobrien!    compiled with GCC to produce an executable, this does not cause
3150397Sobrien!    the resulting executable to be covered by the GNU General Public License.
3250397Sobrien!    This exception does not however invalidate any other reasons why
3350397Sobrien!    the executable file might be covered by the GNU General Public License.
3450397Sobrien! 
3550397Sobrien
3650397Sobrien! This file takes control of the process from the kernel, as specified
3750397Sobrien! in section 3 of the System V Application Binary Interface, Intel386
3850397Sobrien! Processor Supplement.  It has been constructed from information obtained
3950397Sobrien! from the ABI, information obtained from single stepping existing
4050397Sobrien! Solaris executables through their startup code with gdb, and from
4150397Sobrien! information obtained by single stepping executables on other i386 SVR4
4250397Sobrien! implementations.  This file is the first thing linked into any executable.
4350397Sobrien
4450397Sobrien! This is a modified crt1.s by J.W.Hawtin <oolon@ankh.org> 15/8/96, 
4550397Sobrien! to allow program profiling, by calling monstartup on entry and _mcleanup 
4650397Sobrien! on exit
4750397Sobrien
4850397Sobrien	.file	"gcrt1.s"
4950397Sobrien	.ident	"GNU C gcrt1.s"
5050397Sobrien	.weak	_DYNAMIC
5150397Sobrien	.text
5250397Sobrien
5350397Sobrien! Start creating the initial frame by pushing a NULL value for the return
5450397Sobrien! address of the initial frame, and mark the end of the stack frame chain
5550397Sobrien! (the innermost stack frame) with a NULL value, per page 3-32 of the ABI.
5650397Sobrien! Initialize the first stack frame pointer in %ebp (the contents of which
5750397Sobrien! are unspecified at process initialization).
5850397Sobrien
5950397Sobrien	.globl	_start
6050397Sobrien_start:
6150397Sobrien	pushl	$0x0
6250397Sobrien	pushl	$0x0
6350397Sobrien	movl	%esp,%ebp
6450397Sobrien
6550397Sobrien! As specified per page 3-32 of the ABI, %edx contains a function 
6650397Sobrien! pointer that should be registered with atexit(), for proper
6750397Sobrien! shared object termination.  Just push it onto the stack for now
6850397Sobrien! to preserve it.  We want to register _cleanup() first.
6950397Sobrien
7050397Sobrien	pushl	%edx
7150397Sobrien
7250397Sobrien! Check to see if there is an _cleanup() function linked in, and if
7350397Sobrien! so, register it with atexit() as the last thing to be run by
7450397Sobrien! atexit().
7550397Sobrien
7650397Sobrien	movl	$_mcleanup,%eax
7750397Sobrien	testl	%eax,%eax
7850397Sobrien	je	.L1
7950397Sobrien	pushl	$_mcleanup
8050397Sobrien	call	atexit
8150397Sobrien	addl	$0x4,%esp
8250397Sobrien.L1:
8350397Sobrien
8450397Sobrien! Now check to see if we have an _DYNAMIC table, and if so then
8550397Sobrien! we need to register the function pointer previously in %edx, but
8650397Sobrien! now conveniently saved on the stack as the argument to pass to
8750397Sobrien! atexit().
8850397Sobrien
8950397Sobrien	movl	$_DYNAMIC,%eax
9050397Sobrien	testl	%eax,%eax
9150397Sobrien	je	.L2
9250397Sobrien	call	atexit
9350397Sobrien.L2:
9450397Sobrien
9550397Sobrien! Register _fini() with atexit().  We will take care of calling _init()
9650397Sobrien! directly.
9750397Sobrien
9850397Sobrien	pushl	$_fini
9950397Sobrien	call	atexit
10050397Sobrien
10150397Sobrien! Start profiling
10250397Sobrien
10350397Sobrien        pushl %ebp
10450397Sobrien        movl %esp,%ebp
10550397Sobrien        pushl $_etext
10650397Sobrien        pushl $_start
10750397Sobrien        call monstartup
10850397Sobrien        addl $8,%esp
10950397Sobrien	popl %ebp
11050397Sobrien
11150397Sobrien! Compute the address of the environment vector on the stack and load
11250397Sobrien! it into the global variable _environ.  Currently argc is at 8 off
11350397Sobrien! the frame pointer.  Fetch the argument count into %eax, scale by the
11450397Sobrien! size of each arg (4 bytes) and compute the address of the environment
11550397Sobrien! vector which is 16 bytes (the two zero words we pushed, plus argc,
11650397Sobrien! plus the null word terminating the arg vector) further up the stack,
11750397Sobrien! off the frame pointer (whew!).
11850397Sobrien
11950397Sobrien	movl	8(%ebp),%eax
12050397Sobrien	leal	16(%ebp,%eax,4),%edx
12150397Sobrien	movl	%edx,_environ
12250397Sobrien
12350397Sobrien! Push the environment vector pointer, the argument vector pointer,
12450397Sobrien! and the argument count on to the stack to set up the arguments
12550397Sobrien! for _init(), _fpstart(), and main().  Note that the environment
12650397Sobrien! vector pointer and the arg count were previously loaded into
12750397Sobrien! %edx and %eax respectively.  The only new value we need to compute
12850397Sobrien! is the argument vector pointer, which is at a fixed address off
12950397Sobrien! the initial frame pointer.
13050397Sobrien
13190075Sobrien!
13290075Sobrien! Make sure the stack is properly aligned.
13390075Sobrien!
13490075Sobrien	andl $0xfffffff0,%esp
13590075Sobrien	subl $4,%esp
13690075Sobrien
13750397Sobrien	pushl	%edx
13850397Sobrien	leal	12(%ebp),%edx
13950397Sobrien	pushl	%edx
14050397Sobrien	pushl	%eax
14150397Sobrien
14250397Sobrien! Call _init(argc, argv, environ), _fpstart(argc, argv, environ), and
14350397Sobrien! main(argc, argv, environ).
14450397Sobrien
14550397Sobrien	call	_init
14650397Sobrien	call	__fpstart
14750397Sobrien	call	main
14850397Sobrien
14950397Sobrien! Pop the argc, argv, and environ arguments off the stack, push the
15050397Sobrien! value returned from main(), and call exit().
15150397Sobrien
15250397Sobrien	addl	$12,%esp
15350397Sobrien	pushl	%eax
15450397Sobrien	call	exit
15550397Sobrien
15650397Sobrien! An inline equivalent of _exit, as specified in Figure 3-26 of the ABI.
15750397Sobrien
15850397Sobrien	pushl	$0x0
15950397Sobrien	movl	$0x1,%eax
16050397Sobrien	lcall	$7,$0
16150397Sobrien
16250397Sobrien! If all else fails, just try a halt!
16350397Sobrien
16450397Sobrien	hlt
16550397Sobrien	.type	_start,@function
16650397Sobrien	.size	_start,.-_start
167