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