MIPS specific ELF startup code
authorUlrich Drepper <drepper@redhat.com>
Sat, 21 Jun 1997 02:01:37 +0000 (02:01 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sat, 21 Jun 1997 02:01:37 +0000 (02:01 +0000)
sysdeps/mips/elf/start.S [new file with mode: 0644]

diff --git a/sysdeps/mips/elf/start.S b/sysdeps/mips/elf/start.S
new file mode 100644 (file)
index 0000000..0db3a04
--- /dev/null
@@ -0,0 +1,181 @@
+/* Startup code compliant to the ELF Mips ABI.
+Copyright (C) 1995 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.  */
+
+/* This is the canonical entry point, usually the first thing in the text
+   segment.  The SVR4/Mips ABI (pages 3-31, 3-32) says that when the entry
+   point runs, most registers' values are unspecified, except for:
+
+   v1 ($2)     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.
+
+   sp ($29)    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
+   ra ($31)    The return address register is set to zero so that programs
+               that search backword through stack frames recognize the last
+               stack frame.
+*/
+
+#ifdef PIC
+/* A macro to (re)initialize gp. We can get the run time address of 0f in
+   ra ($31) by blezal instruction. In this early phase, we can't save gp
+   in stack and .cprestore doesn't work properly. So we set gp by using
+   this macro. */
+#define SET_GP \
+       .set noreorder; \
+       bltzal $0,0f;   \
+       nop;            \
+0:     .cpload $31;    \
+       .set reorder;
+#endif
+
+       .text   
+       .globl _start
+_start:
+#ifdef PIC
+       SET_GP
+#endif
+       move $31, $0
+
+       /* $2 contains the address of the shared library termination
+          function, which we will register with `atexit' to be called by
+          `exit'.  I suspect that on some systems, and when statically
+          linked, this will not be set by anything to any function
+          pointer; hopefully it will be zero so we don't try to call
+          random pointers.  */
+       beq $2, $0, nofini
+       move $4, $2
+       jal atexit
+#ifdef PIC
+       SET_GP
+#endif
+nofini:
+
+       /* Do essential libc initialization.  In statically linked
+          programs under the GNU Hurd, this is what sets up the
+          arguments on the stack for the code below. Since the argument
+          registers (a0 - a3) saved to the first 4 stack entries by
+          the prologue of __libc_init_first, we preload them to
+          prevent clobbering the stack tops. In Hurd case, stack pointer
+          ($29) may be VM_MAX_ADDRESS here. If so, we must modify it.  */
+#if (__mips64)
+       dli $4, 0x10000000000
+       bne $29, $4, 1f
+       dsubu $29, 32
+       sd $0, 0($29)
+       sd $0, 8($29)
+       sd $0, 16($29)
+       sd $0, 24($29)
+1:
+       ld $4, 0($29)
+       ld $5, 8($29)
+       ld $6, 16($29)
+       ld $7, 24($29)
+#else  /* __mips64 */
+       li $4, 0x80000000
+       bne $29, $4, 1f
+       subu $29, 16
+       sw $0, 0($29)
+       sw $0, 4($29)
+       sw $0, 8($29)
+       sw $0, 12($29)
+1:
+       lw $4, 0($29)
+       lw $5, 4($29)
+       lw $6, 8($29)
+       lw $7, 12($29)
+#endif  /* __mips64 */
+
+       jal __libc_init_first
+#ifdef PIC
+       SET_GP
+#endif
+#if (__mips64)
+       ld $4, 0($29)
+       ld $5, 8($29)
+       ld $6, 16($29)
+       ld $7, 24($29)
+#else  /* __mips64 */
+       lw $4, 0($29)
+       lw $5, 4($29)
+       lw $6, 8($29)
+       lw $7, 12($29)
+#endif  /* __mips64 */
+       
+       /* Call `_init', which is the entry point to our own `.init'
+          section; and register with `atexit' to have `exit' call
+          `_fini', which is the entry point to our own `.fini' section.  */
+       jal _init
+#ifdef PIC
+       SET_GP
+#endif
+#if (__mips64)
+       dla $4, _fini
+#else  /* __mips64 */
+       la $4, _fini
+#endif  /* __mips64 */
+
+       jal atexit
+#ifdef PIC
+       SET_GP
+#endif
+
+       /* Extract the arguments and environment as encoded on the stack
+          and set up the arguments for `main': argc, argv, envp.  */
+#if (__mips64)
+       ld $4, 0($29)           /* argc */
+       daddu $5, $29, 8        /* argv */
+       dsll $6, $4, 3
+       daddu $6, $6, 8
+       daddu $6, $5, $6        /* envp = &argv[argc + 1] */
+#else  /* __mips64 */
+       lw $4, 0($29)           /* argc */
+       addu $5, $29, 4         /* argv */
+       sll $6, $4, 2
+       addu $6, $6, 4
+       addu $6, $5, $6         /* envp = &argv[argc + 1] */
+#endif  /* __mips64 */
+
+       /* Call the user's main function, and exit with its value.  */
+       jal main
+#ifdef PIC
+       SET_GP
+#endif
+       move $4, $2
+       jal exit                /* This should never return.  */
+hlt:   b hlt                   /* Crash if somehow it does return.  */
+
+/* Define a symbol for the first piece of initialized data.  */
+       .data
+       .globl __data_start
+__data_start:
+#if (__mips64)
+       .dword 0
+#else  /* __mips64 */
+       .word 0
+#endif  /* __mips64 */
+       .weak data_start
+       data_start = __data_start