diff options
Diffstat (limited to 'libc')
-rw-r--r-- | libc/sysdeps/linux/i386/crt1.S | 202 |
1 files changed, 106 insertions, 96 deletions
diff --git a/libc/sysdeps/linux/i386/crt1.S b/libc/sysdeps/linux/i386/crt1.S index 7eee8aea9..fa9174f3e 100644 --- a/libc/sysdeps/linux/i386/crt1.S +++ b/libc/sysdeps/linux/i386/crt1.S @@ -1,121 +1,132 @@ -/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - - -/* Based on the code from GNU libc, but hacked up by John Beppu and Erik Andersen */ -/* adapted by PaX Team for ET_DYN/PIE binaries */ - -/* - When we enter this piece of code, the program stack looks like this: - argc argument counter (integer) - argv[0] program name (pointer) - argv[1...N] program args (pointers) - argv[argc-1] end of args (integer) - NULL - env[0...N] environment variables (pointers) - NULL +/* Startup code compliant to the ELF i386 ABI. + Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This is the canonical entry point, usually the first thing in the text + segment. The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry + point runs, most registers' values are unspecified, except for: + + %edx Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + %esp The stack contains the arguments and environment: + 0(%esp) argc + 4(%esp) argv[0] + ... + (4*argc)(%esp) NULL + (4*(argc+1))(%esp) envp[0] + ... + NULL */ -#include <features.h> - -.text - .align 4 - - .global _start - .type _start,%function + .text + .globl _start + .type _start,@function .type _init,%function .type _fini,%function .type main,%function .type __uClibc_start_main,%function - _start: - /* locate the start of the environment variables */ - popl %ecx /* Store argc into %ecx */ - movl %esp,%ebx /* Store argv into ebx */ - movl %esp,%eax /* Store argv into eax as well*/ - movl %edx,%esi /* Store edx(FINI ptr) in %esi */ - movl %ecx,%edx /* Stick argc into %edx so we can do some math in a sec */ - leal 4(%eax,%edx,4),%eax - - /* [ register layout ] - - sizeof(char*) == 4 - %ecx = argc ; 0(esp) - %ebx = argv ; 4(esp) - %eax = env ; argv + (argc * 4) + 4 - */ - xorl %ebp,%ebp /* NULL */ - /* - Before pushing the arguments align the stack to a 16-byte + /* Clear the frame pointer. The ABI suggests this be done, to mark + the outermost frame obviously. */ + xorl %ebp, %ebp + + /* Extract the arguments as encoded on the stack and set up + the arguments for `main': argc, argv. envp will be determined + later in __libc_start_main. */ + popl %esi /* Pop the argument count. */ + movl %esp, %ecx /* argv starts just at the current stack top.*/ + + /* Before pushing the arguments align the stack to a 16-byte (SSE needs 16-byte alignment) boundary to avoid penalties from misaligned accesses. Thanks to Edward Seidl <seidl@janed.com> - for pointing this out. - */ + for pointing this out. */ andl $0xfffffff0, %esp - /* Push NULL to make sure stack ptr - is 16 byte aligned when calling __uClibc_start_main */ - pushl %ebp - - /* Set up an invalid (NULL return address, NULL frame pointer) - callers stack frame so anybody unrolling the stack knows where - to stop */ - pushl %ebp /* callers %cs */ - pushl %ebp /* callers %eip (return address) */ - pushl %ebp /* callers %ebp (frame pointer) */ - movl %esp,%ebp /* mark callers stack frame as invalid */ + pushl %eax /* Push garbage because we allocate + 28 more bytes. */ + + /* Provide the highest stack address to the user code (for stacks + which grow downwards). */ + pushl %esp + + pushl %edx /* Push address of the shared library + termination function. */ #if defined L_Scrt1 - call .L0 -.L0: - pop %edx - addl $_GLOBAL_OFFSET_TABLE_+[.-.L0],%edx -#endif - pushl %esp /* push stack ptr */ - pushl %esi /* Push FINI pointer */ + /* Load PIC register. */ + call 1f + addl $_GLOBAL_OFFSET_TABLE_, %ebx + + /* Push address of our own entry points to .fini and .init. */ + leal _fini@GOTOFF(%ebx), %eax + pushl %eax + leal _init@GOTOFF(%ebx), %eax + pushl %eax - /* Push apps .init, .fini and main arguments to __uClibc_start_main() on the stack */ -#ifdef L_Scrt1 - pushl _fini@GOT(%edx) - pushl _init@GOT(%edx) + pushl %ecx /* Push second argument: argv. */ + pushl %esi /* Push first argument: argc. */ + + pushl main@GOT(%ebx) + + /* Call the user's main function, and exit with its value. + But let the libc call main. */ + call __uClibc_start_main@PLT #else + /* Push address of our own entry points to .fini and .init. */ pushl $_fini pushl $_init -#endif - /* Push envp, argc, and argc arguments to __uClibc_start_main() on the stack */ - pushl %eax /* Environment pointer */ - pushl %ebx /* Argument pointer */ - pushl %ecx /* And the argument count */ + pushl %ecx /* Push second argument: argv. */ + pushl %esi /* Push first argument: argc. */ - /* Ok, now run uClibc's main() -- shouldn't return */ -#ifdef L_Scrt1 - pushl main@GOT(%edx) - call *__uClibc_start_main@GOT(%edx) -#else pushl $main + + /* Call the user's main function, and exit with its value. + But let the libc call main. */ call __uClibc_start_main #endif - /* Crash if somehow `exit' returns anyways. */ - hlt -.size _start,.-_start - + hlt /* Crash if somehow `exit' does return. */ +#if defined L_Scrt1 +1: movl (%esp), %ebx + ret +#endif /* Define a symbol for the first piece of initialized data. */ .data .globl __data_start @@ -123,4 +134,3 @@ __data_start: .long 0 .weak data_start data_start = __data_start - |