summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/avr32/crt1.S
blob: 0f0a2e87d2cc6db643a9d18bc801e7978a234544 (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
97
/*
 * 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
       .size   _start, . - _start

       /*
        * 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