1/*	$NetBSD: crtbegin.S,v 1.1 2011/02/08 02:02:25 matt Exp $	*/
2/*-
3 * Copyright (c) 2011 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Matt Thomas of 3am Software Foundry.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <powerpc/asm.h>
32
33RCSID("$NetBSD: crtbegin.S,v 1.1 2011/02/08 02:02:25 matt Exp $")
34
35	.section	.ctors, "aw", @progbits
36	.p2align 2
37__CTOR_LIST__:
38	.long -1
39
40	.section	.dtors, "aw", @progbits
41	.p2align 2
42__DTOR_LIST__:
43	.long -1
44
45	.section	.eh_frame, "a", @progbits
46	.p2align 2
47__EH_FRAME_LIST__:
48
49	.section	.jcr, "aw", @progbits
50	.p2align 2
51__JCR_LIST__:
52
53	.section	".got2","aw", @progbits
54.LCTOC = . + 32768
55
56	.section	.data.rel, "aw", @progbits
57	.p2align 2
58	.type	__dso_handle, @object
59	.size	__dso_handle, 4
60	.globl	__dso_handle
61	.hidden	__dso_handle
62__dso_handle:
63#ifdef SHARED
64	.long	__dso_handle
65#else
66	.long	0
67#endif
68
69	.lcomm	__dwarf_eh_object,8*SZREG,SZREG
70	.lcomm	__initialized,1,1
71	.lcomm	__finished,1,1
72
73	.text
74	.weak	__cxa_finalize
75	.weak	__deregister_frame_info
76	.weak	__register_frame_info
77	.weak	_Jv_RegisterClasses
78
79/*
80 * All variables are local to this DSO so we can skip using GOT references
81 * and instead use PCREL references to access them.  We do this regardless
82 * of being PIC since it isn't any additional overhead to do so.
83 *
84 * We don't setup a TOC since all of ours calls are indirect so it isn't
85 * needed.
86 */
87
88__do_global_dtors_aux:
89	mflr	%r7				/* save return address */
90	bcl     20,31,1f			/* find out what address */
911:	mflr    %r3				/*   we are at */
92	mtlr	%r7				/* restore return address */
93
94	addis   %r4,%r3,__finished-1b@ha	/* PCREL ref (upper) */
95	lbzu	%r0,__finished-1b@l(%r4)	/* PCREL ref (lower) & load */
96	cmpwi	%r0,0				/* done this already? */
97	bnelr					/*   yep, return */
98
99	li	%r0, 1
100	stb	%r0, 0(%r4)			/* remember we've done this */
101
102	stw	%r7,(1*SZREG)(%r1)		/* save LR */
103	stwu	%r1,-(8*SZREG)(%r1)		/* alloc our stack frame */
104	stw	%r31,(7*SZREG)(%r1)		/* save some registers */
105	stw	%r30,(6*SZREG)(%r1)
106	stw	%r29,(5*SZREG)(%r1)
107	stw	%r28,(4*SZREG)(%r1)
108
109	mr	%r29,%r3			/* move this to a safe place */
110
111	/*
112	 * Get a reference to our TOC.
113	 */
114	addis   %r30,%r29,.LCTOC-1b@ha
115	addi    %r30,%r30,.LCTOC-1b@l
116
117	/*
118	 * Get a reference to the GOT.
119	 */
120	addis	%r31,%r29,_GLOBAL_OFFSET_TABLE_-1b@ha	/* pcrel (hi) */
121	addi	%r31,%r31,_GLOBAL_OFFSET_TABLE_-1b@l	/* pcrel (lo) */
122
123#ifdef SHARED
124	/*
125	 * if (__cxa_finalize)
126	 *     __cxa_finalize(&__dso_handle);
127	 */
128	lwz	%r0, __cxa_finalize@got(%r31)
129	cmpwi	%r0, 0
130	beq	2f
131
132	addis	%r3,%r29,__dso_handle-1b@ha	/* get &__dso_handle (pcrel) */
133	addi	%r3,%r3,__dso_handle-1b@l
134	mtctr	%r0				/* setup for indirect branch */
135	bctrl					/* and call the routine */
1362:
137#endif
138
139	addis	%r28,%r29,__DTOR_LIST__-1b@ha	/* get &__DTOR_LIST__ */
140	addi	%r28,%r28,__DTOR_LIST__-1b@l
141	/*
142	 * We know the first entry is -1 so skip it.  We use load with update
143	 * to advance the pointer along.
144	 */
1453:
146	lwzu	%r0, 4(%r28)			/* get entry */
147	cmpwi	%r0, 0				/* end of list? */
148	beq	4f				/*    yep. */
149	mtctr	%r0				/* setup for indirect branch */
150	bctrl					/* and call the routine */
151	b	3b				/* do it again */
152
1534:
154	/*
155	 * if (__deregister_frame_info)
156	 *     __deregister_frame_info(&__EH_FRAME_LIST__[0]);
157	 */
158	lwz	%r0,__deregister_frame_info@got(%r31)
159	cmpwi	%r0, 0				/* routine actually exist? */
160	beq	5f				/* nope, skip call */
161
162	addis	%r3,%r29,__EH_FRAME_LIST__-1b@ha
163	addi	%r3,%r3,__EH_FRAME_LIST__-1b@l
164	mtctr	%r0				/* setup for indirect branch */
165	bctrl					/* and call the routine */
1665:
167	lwz	%r28,(4*SZREG)(%r1)		/* restore registers */
168	lwz	%r29,(5*SZREG)(%r1)
169	lwz	%r30,(6*SZREG)(%r1)
170	lwz	%r31,(7*SZREG)(%r1)
171	addi	%r1,%r1,8*SZREG			/* adjust stack */
172	lwz	%r0,(1*SZREG)(%r1)		/* get return addr */
173	mtlr	%r0
174	blr					/* and return */
175
176__do_global_ctors_aux:
177	mflr	%r7				/* save return address */
178	bcl     20,31,1f			/* find out what address */
1791:	mflr    %r3				/*   we are at */
180	mtlr	%r7				/* restore return address */
181
182	addis   %r4,%r3,__initialized-1b@ha	/* pcrel (hi) */
183	lbzu	%r0,__initialized-1b@l(%r4)	/* pcrel (lo) load+update */
184	cmpwi	%r0,0				/* have we already done this? */
185	bnelr					/* yep, return */
186
187	li	%r0,1
188	stb	%r0,0(%r4)			/* remember we've been here */
189
190	stw	%r7,(1*SZREG)(%r1)		/* save LR */
191	stwu	%r1,-(8*SZREG)(%r1)		/* alloc our stack frame */
192	stw	%r31,(7*SZREG)(%r1)		/* save some registers */
193	stw	%r30,(6*SZREG)(%r1)
194	stw	%r29,(5*SZREG)(%r1)
195	stw	%r28,(4*SZREG)(%r1)
196
197	mr	%r29,%r3			/* move this to a safe place */
198
199	/*
200	 * Get a reference to our TOC.
201	 */
202	addis   %r30,%r29,.LCTOC-1b@ha
203	addi    %r30,%r30,.LCTOC-1b@l
204
205	/*
206	 * Get a reference to the GOT.
207	 */
208	addis	%r31,%r29,_GLOBAL_OFFSET_TABLE_-1b@ha	/* pcrel (hi) */
209	addi	%r31,%r31,_GLOBAL_OFFSET_TABLE_-1b@l	/* pcrel (lo) */
210
211	/*
212	 * if (__register_frame_info)
213	 *     __register_frame_info(&__EH_FRAME_LIST__[0], &__dwarf_eh_object)
214	 */
215	lwz	%r0, __register_frame_info@got(%r31)
216	cmpwi	%r0, 0
217	beq	2f
218
219	addis	%r3,%r29,__EH_FRAME_LIST__-1b@ha	/* pcrel (hi) */
220	addi	%r3,%r3,__EH_FRAME_LIST__-1b@l		/* pcrel (lo) */
221	addis	%r4,%r29,__dwarf_eh_object-1b@ha	/* pcrel (hi) */
222	addi	%r4,%r4,__dwarf_eh_object-1b@l		/* pcrel (lo) */
223	mtctr	%r0				/* setup for indirect branch */
224	bctrl					/* and call the routine */
225
2262:
227	/*
228	 * if (_Jv_RegisterClasses && __JCR_LIST__[0])
229	 *     _Jv_RegisterClasses(&__JCR_LIST__[0]);
230	 */
231	lwz	%r0, _Jv_RegisterClasses@got(%r31)
232	cmpwi	%r0, 0
233	beq	3f
234
235	mtctr	%r0				/* setup for indirect branch */
236	addis   %r3, %r29, __JCR_LIST__-1b@ha	/* pcrel (hi) */
237	addi    %r3, %r3, __JCR_LIST__-1b@l	/* pcrel (lo) */
238	lwz	%r4, 0(%r3)			/* load first entry */
239	cmpwi	%r4, 0				/* is the list empty? */
240	bnectrl					/* call the routine if not */
2413:
242
243	/*
244	 * Get end of list of CTOR list.
245	 */
246	addis   %r28,%r29,__CTOR_LIST_END__-1b@ha
247	addi    %r28,%r28,__CTOR_LIST_END__-1b@l
2484:
249	lwzu	%r0, -4(%r28)			/* get entry */
250	cmpwi	%r0, -1				/* first entry? */
251	beq	5f				/*   yes, we're done */
252	mtctr	%r0				/* setup for indirect branch */
253	bctrl					/* call the routine */
254	b	4b				/* do it again */
2555:
256	lwz	%r28,(4*SZREG)(%r1)		/* restore registers */
257	lwz	%r29,(5*SZREG)(%r1)
258	lwz	%r30,(6*SZREG)(%r1)
259	lwz	%r31,(7*SZREG)(%r1)
260	addi	%r1,%r1,8*SZREG			/* adjust stack */
261	lwz	%r0,(1*SZREG)(%r1)		/* get return addr */
262	mtlr	%r0
263	blr					/* and return */
264
265	.section	.init, "ax", @progbits
266	bl	__do_global_ctors_aux
267	.section	.fini, "ax", @progbits
268	bl	__do_global_dtors_aux
269