about summary refs log tree commit diff
path: root/sysdeps/mips/elf/start.S
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mips/elf/start.S')
-rw-r--r--sysdeps/mips/elf/start.S181
1 files changed, 181 insertions, 0 deletions
diff --git a/sysdeps/mips/elf/start.S b/sysdeps/mips/elf/start.S
new file mode 100644
index 0000000000..0db3a04a7d
--- /dev/null
+++ b/sysdeps/mips/elf/start.S
@@ -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