summary refs log tree commit diff
path: root/sysdeps/mips/elf/start.S
blob: 0db3a04a7d5889e75bbff63d4e12c0b15bc88365 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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