summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/avr32/crt1.S
blob: e2a82a5283843c2bb17163dfa178f3a52c02b7a3 (plain)
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
/*
 * Copyright (C) 2004-2007 Atmel Corporation
 *
 * This file is subject to the terms and conditions of the GNU Lesser General
 * Public License.  See the file "COPYING.LIB" in the main directory of this
 * archive for more details.
 *
 * When we enter _start, the stack looks like this:
 *	argc		argument counter
 *	argv[0]		pointer to program name
 *	argv[1..argc-1]	pointers to program args
 *	NULL
 *	env[0..N]	pointers to environment variables
 *	NULL
 *
 * r12 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.
 *
 * We're going to call the following function:
 * __uClibc_main(int (*main)(int, char **, char **), int argc,
 *		 char **argv, void (*app_init)(void), void (*app_fini)(void),
 *		 void (*rtld_fini)(void), void *stack_end)
 *
 * So we need to set up things as follows:
 *	r12 = address of main
 *	r11 = argc
 *	r10 = &argv[0]
 *	r9  = address of _init
 *	r8  = address of _fini
 *	sp[0] = whatever we got passed in r12
 */

#include <features.h>

	.text
	.global _start
	.type	_start, @function
_start:
	/* Clear the frame pointer and link register since this is the outermost frame.  */
	mov	r7, 0
	mov	lr, 0

	ld.w	r11, sp++		/* argc		*/
	mov	r10, sp			/* &argv[0]	*/

	st.w	--sp, r10		/* stack_end */
	st.w	--sp, r12		/* rtld_fini */

#ifdef __PIC__
	lddpc	r6, .L_GOT
.L_RGOT:
	rsub	r6, pc
	lda.w	r9, _init
	lda.w	r8, _fini
	lda.w	r12, main

	/* Ok, now run uClibc's main() -- should not return */
	call	__uClibc_main

	.align	2
.L_GOT:
	.long	.L_RGOT - _GLOBAL_OFFSET_TABLE_
#else
	lddpc	r9, __init_addr		/* app_init */
	lddpc	r8, __fini_addr		/* app_fini */
	lddpc	r12, __main_addr	/* main */

	/* Ok, now run uClibc's main() -- should not return */
	lddpc	pc, ___uClibc_main_addr

	.align	2
__init_addr:
	.long	_init
__fini_addr:
	.long	_fini
__main_addr:
	.long	main
___uClibc_main_addr:
	.long	__uClibc_main
#endif

	/*
	 * The LSB says we need this.
	 */
	.section ".note.ABI-tag", "a"
	.align	4
	.long	2f - 1f		/* namesz */
	.long	4f - 3f		/* descsz */
	.long	1		/* type   */
1:	.asciz	"GNU"		/* name */
2:	.align	4
3:	.long	0		/* Linux executable */
	.long	2,6,0		/* Earliest compatible kernel */
4:	.align	4