1/*
2 * Copyright (c) 1999-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
7 * Reserved.  This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License").  You may not use this file
10 * except in compliance with the License.  Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <Availability.h>
26
27#if __ppc__ && __DYNAMIC__
28//
29// Force stub section next to __text section to minimize chance that
30// a bl to a stub will be out of range.
31//
32	.text
33	.symbol_stub
34	.picsymbol_stub
35#endif
36
37/*
38 * C runtime startup for ppc, ppc64, i386, x86_64
39 *
40 * Kernel sets up stack frame to look like:
41 *
42 *	       :
43 *	| STRING AREA |
44 *	+-------------+
45 *	|      0      |
46 *	+-------------+
47 *	|  exec_path  | extra "apple" parameters start after NULL terminating env array
48 *	+-------------+
49 *	|      0      |
50 *	+-------------+
51 *	|    env[n]   |
52 *	+-------------+
53 *	       :
54 *	       :
55 *	+-------------+
56 *	|    env[0]   |
57 *	+-------------+
58 *	|      0      |
59 *	+-------------+
60 *	| arg[argc-1] |
61 *	+-------------+
62 *	       :
63 *	       :
64 *	+-------------+
65 *	|    arg[0]   |
66 *	+-------------+
67 *	|     argc    | argc is always 4 bytes long, even in 64-bit architectures
68 *	+-------------+ <- sp
69 *
70 *	Where arg[i] and env[i] point into the STRING AREA
71 */
72
73	.text
74	.globl start
75	.align 2
76
77#if __ppc__
78start:	mr      r26,r1              ; save original stack pointer into r26
79	subi	r1,r1,4		    ; make space for linkage
80	clrrwi	r1,r1,5             ; align to 32 bytes (good enough for 32- and 64-bit APIs)
81	li      r0,0                ; load 0 into r0
82	stw     r0,0(r1)            ; terminate initial stack frame
83	stwu	r1,-64(r1)	    ; allocate minimal stack frame
84	lwz     r3,0(r26)           ; get argc into r3
85	addi    r4,r26,4	    ; get argv into r4
86	addi	r27,r3,1            ; calculate argc + 1 into r27
87	slwi	r27,r27,2	    ; calculate (argc + 1) * sizeof(char *) into r27
88	add     r5,r4,r27           ; get address of env[0] into r5
89#if OLD_LIBSYSTEM_SUPPORT
90	bl	__start		    ; 24-bt branch to __start.  ld64 will make a branch island if needed
91	trap                        ; should never return
92#else
93	mr	r6,r5
94Lapple:	lwz	r0,0(r6)	    ; look for NULL ending env[] array
95	addi	r6,r6,4
96	cmpwi	r0,0
97	bne	Lapple		    ; once found, next pointer is "apple" parameter now in r6
98	bl	_main
99	b	_exit		    ; pass result from main() to exit()
100#endif
101#endif // __ppc__
102
103
104#if __ppc64__
105start:	mr      r26,r1              ; save original stack pointer into r26
106	subi	r1,r1,8		    ; make space for linkage
107	clrrdi	r1,r1,5             ; align to 32 bytes (good enough for 32- and 64-bit APIs)
108	li      r0,0                ; load 0 into r0
109	std     r0,0(r1)            ; terminate initial stack frame
110	stdu	r1,-128(r1)	    ; allocate minimal stack frame
111	lwz     r3,0(r26)           ; get argc into r3
112	addi    r4,r26,8	    ; get argv into r4
113	addi	r27,r3,1            ; calculate argc + 1 into r27
114	sldi	r27,r27,3	    ; calculate (argc + 1) * sizeof(char *) into r27
115	add     r5,r4,r27           ; get address of env[0] into r5
116#if OLD_LIBSYSTEM_SUPPORT
117	bl	__start		    ; 24-bt branch to __start.  ld64 will make a branch island if needed
118	trap                        ; should never return
119#else
120	mr	r6,r5
121Lapple:	ld	r0,0(r6)	    ; look for NULL ending env[] array
122	addi	r6,r6,8
123	cmpdi	r0,0
124	bne	Lapple		    ; once found, next pointer is "apple" parameter now in r6
125	bl	_main
126	b	_exit		    ; pass result from main() to exit()
127#endif
128#endif	// __ppc64__
129
130
131#if __i386__
132start:	pushl	$0		    # push a zero for debugger end of frames marker
133	movl	%esp,%ebp	    # pointer to base of kernel frame
134	andl    $-16,%esp	    # force SSE alignment
135	subl    $16,%esp	    # room for new argc, argv, & envp, SSE aligned
136	movl	4(%ebp),%ebx	    # pickup argc in %ebx
137	movl	%ebx,0(%esp)	    # argc to reserved stack word
138	lea	8(%ebp),%ecx	    # addr of arg[0], argv, into %ecx
139	movl	%ecx,4(%esp)	    # argv to reserved stack word
140	addl	$1,%ebx		    # argc + 1 for zero word
141	sall	$2,%ebx		    # * sizeof(char *)
142	addl	%ecx,%ebx	    # addr of env[0], envp, into %ebx
143	movl	%ebx,8(%esp)	    # envp to reserved stack word
144#if OLD_LIBSYSTEM_SUPPORT
145	call	__start		    # call _start(argc, argv, envp)
146	hlt			    # should never return
147#else
148Lapple:	movl	(%ebx),%eax	    # look for NULL ending env[] array
149	add	$4,%ebx
150	testl	%eax,%eax
151	jne	Lapple		    # once found, next pointer is "apple" parameter now in %ebx
152	movl	%ebx,12(%esp)	    # apple to reserved stack word
153	call	_main
154	movl	%eax, 0(%esp)	    # pass result from main() to exit()
155	call	_exit		    # need to use call to keep stack aligned
156	hlt
157#endif
158#endif // __i386__
159
160
161
162#if __x86_64__
163start:	pushq	$0		    # push a zero for debugger end of frames marker
164	movq	%rsp,%rbp	    # pointer to base of kernel frame
165	andq    $-16,%rsp	    # force SSE alignment
166	movq	8(%rbp),%rdi	    # put argc in %rdi
167	leaq	16(%rbp),%rsi	    # addr of arg[0], argv, into %rsi
168	movl	%edi,%edx	    # copy argc into %rdx
169	addl	$1,%edx		    # argc + 1 for zero word
170	sall	$3,%edx		    # * sizeof(char *)
171	addq	%rsi,%rdx	    # addr of env[0], envp, into %rdx
172#if OLD_LIBSYSTEM_SUPPORT
173	call	__start		    # call _start(argc, argv, envp)
174	hlt			    # should never return
175#else
176	movq	%rdx,%rcx
177	jmp	Lapple2
178Lapple:	add	$8,%rcx
179Lapple2:cmpq	$0,(%rcx)	    # look for NULL ending env[] array
180	jne	Lapple
181	add	$8,%rcx		    # once found, next pointer is "apple" parameter now in %rcx
182	call	_main
183	movl	%eax,%edi	    # pass result from main() to exit()
184	call	_exit		    # need to use call to keep stack aligned
185	hlt
186#endif
187#endif // __x86_64__
188
189#ifdef __arm__
190start:
191	ldr	r0, [sp]		// get argc into r0
192	add	r1, sp, #4		// get argv into r1
193	add	r4, r0, #1		// calculate argc + 1 into r4
194	add	r2, r1, r4, lsl #2	// get address of env[0] into r2
195	bic	sp, sp, #7		// force eight-byte alignment
196#if OLD_LIBSYSTEM_SUPPORT
197	bl	__start
198	.long	0xe1200070		// should never return
199#else
200	mov	r3, r2
201Lapple:
202	ldr	r4, [r3], #4		// look for NULL ending env[] array
203	cmp	r4, #0
204	bne	Lapple
205					// "apple" param now in r3
206#if __STATIC__ || ((__IPHONE_OS_VERSION_MIN_REQUIRED >= 30100) && !__ARM_ARCH_4T__)
207	bl	_main
208	b	_exit
209#else
210// use -mlong-branch style call sites so that main executable can be >32MB
211	ldr	ip, L4
212L2:	add	ip, pc, ip
213	ldr	ip, [ip, #0]
214#if __ARM_ARCH_4T__
215	mov lr, pc		// blx not supported, so simulate it in two steps
216	bx  ip
217#else
218	blx	ip			// call main()
219#endif
220
221	ldr	ip, L5
222L3:	add	ip, pc, ip
223	ldr	ip, [ip, #0]
224	bx	ip			// jmp exit()
225
226L4:	.long	L_main$non_lazy_ptr-(L2+8)
227L5:	.long	L_exit$non_lazy_ptr-(L3+8)
228
229	.non_lazy_symbol_pointer
230L_main$non_lazy_ptr:
231	.indirect_symbol _main
232	.long	0
233L_exit$non_lazy_ptr:
234	.indirect_symbol _exit
235	.long	0
236#endif
237
238
239#endif
240#endif /* __arm__ */
241
242
243#if __arm64__
244
245start:
246	mov     x5, sp
247	ldr     x0, [x5]            ; get argc into x0 (kernel passes 32-bit int argc as 64-bits on stack to keep alignment)
248	add     x1, x5, #8          ; get argv into x1
249	add     x4, x0, #1          ; argc + 1
250	add     x2, x1, x4, lsl #3  ; &env[0] = (argc+1)*8
251	and     sp, x5, #~15        ; force 16-byte alignment of stack
252	mov     x3, x2
253L1: ldr     x4, [x3], #8
254	cmp     x4, #0              ; look for NULL ending env[] array
255	b.ne     L1
256	bl      _main               ; main(x0=argc, x1=argv, x2=envp, x3=apple)
257	b       _exit
258
259#endif /* __arm64__ */
260
261
262// This code has be written to allow dead code stripping
263	.subsections_via_symbols
264