1/*	$NetBSD: rtld_start.S,v 1.1 2002/07/10 15:12:40 fredette Exp $	*/
2
3/*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Fredette.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *        This product includes software developed by the NetBSD
21 *        Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 *    contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#include <machine/asm.h>
40#define _LOCORE /* XXX fredette we MUST get rid of this */
41#include <machine/frame.h>
42#undef _LOCORE
43
44	.import _GLOBAL_OFFSET_TABLE_
45	.import _GOT_END_
46
47ENTRY($rtld_start,32)
48
49	/* Start stack calling convention. */
50	copy	%r3, %r1
51	copy	%sp, %r3
52	stw,ma	%r1, HPPA_FRAME_SIZE(%sp)
53
54	/*
55	 * Save our single argument, the ps_strings pointer.
56	 * We'll need this twice later: once to call _rtld,
57	 * and again to transfer to the program's entry point.
58	 */
59        stw     %arg0, HPPA_FRAME_ARG(0)(%r3)
60
61	/*
62	 * We can't move to C until we relocate at least the
63	 * Global Offset Table.  Even finding the GOT is tricky
64	 * without inadvertently causing the linker to make
65	 * relocations for this part of the text segment.
66	 */
67
68	/*
69	 * The only way I know to get an external symbol value
70	 * for which the linker won't also emit a relocation is
71	 * to assemble a branch to that symbol, and then decode
72	 * the PC-relative offset that it contains.  Since we
73	 * can discover the absolute address of the branch
74	 * instruction, we can add the two together to arrive
75	 * at the symbol's absolute address.
76	 *
77	 * The LOAD_ADDR macro hides all of this.  The most
78	 * difficult part is implementing the
79	 *
80	 * lshift(sign_ext(assemble_17(w1,w2,w),17),2)
81	 *
82	 * pseudoinstruction from the b,l description.
83	 */
84#define	LOAD_ADDR(sym,reg)						!\
85	bl	4,t1		/* branch to the ldw below, */		!\
86				/*  storing absolute address of	*/	!\
87				/*  fake branch in t1 */		!\
88	depi	0, 31, 2, t1	/* mask off privilege bits */		!\
89	b	sym		/* fake branch, never executed */	!\
90	ldw	0(t1), t2	/* load the fake branch	*/		!\
91	ldo	8(t1), t1	/* branch target = pc + 8 + disp */	!\
92	extrs	t2, 31, 1, t3	/* extract w */				!\
93	zdep	t3, 13, 16, reg	/* deposit w */				!\
94	extru	t2, 15, 5, t3	/* extract w1 */			!\
95	dep	t3, 18, 5, reg	/* deposit w1 */			!\
96	extru	t2, 29, 1, t3	/* extract w2{10} */			!\
97	dep	t3, 19, 1, reg	/* deposit w2{10} */			!\
98	extru	t2, 28, 10, t3	/* extract w2{0..9} */			!\
99	dep	t3, 29, 10, reg	/* deposit w2{0..9} */			!\
100	add	t1, reg, reg	/* make final absolute address */
101
102	/*
103	 * Load the absolute address of the beginning of the
104	 * GOT into %r19, the shared library linkage table
105	 * register, leaving it ready-to-use by the dynamic
106	 * linker C code.
107	 */
108	LOAD_ADDR(_GLOBAL_OFFSET_TABLE_, %r19)
109
110	/*
111	 * The linker sets the first entry in the GOT to the
112	 * unrelocated address of _DYNAMIC.  Subtract this
113	 * from the absolute address of _DYNAMIC to get our
114	 * relocbase.
115	 */
116	LOAD_ADDR(_DYNAMIC, %arg0)	; %arg0 = &_DYNAMIC
117	ldw	0(%r19), %arg1
118	sub	%arg0, %arg1, %arg1	; %arg1 = relocbase
119
120	/*
121	 * Our special linker script sets _GOT_END_ to the
122	 * end of the GOT.
123	 */
124	LOAD_ADDR(_GOT_END_, %arg3)	; %arg3 = _GOT_END_
125
126	/*
127	 * Relocate the GOT.
128	 */
129	bl	_rtld_bootstrap_hppa_got, %rp
130	copy	%r19, %arg2		; %arg2 = _GLOBAL_OFFSET_TABLE_
131
132	/*
133	 * Recover the ps_strings pointer, and take out the
134	 * ps_argvstr member.
135	 */
136	ldw	HPPA_FRAME_ARG(0)(%r3), %arg0	; ps_strings
137	ldw	0(%arg0), %arg0		; ps_argvstr member first in struct
138
139	/*
140	 * ps_argvstr - 4 would get us a pointer to argc,
141	 * comparable to the initial stack pointer on
142	 * architectures where the stack grows down.
143	 * Subtracting an additional eight creates the
144	 * storage for obj and cleanup that _rtld needs.
145	 */
146	ldo	-12(%arg0), %arg0
147
148	/* Call _rtld, saving our pointer to that storage. */
149	bl	_rtld, %rp
150	stw	%arg0, HPPA_FRAME_ARG(1)(%r3)
151
152	/* Prepare the arguments for the entry point. */
153	ldw	HPPA_FRAME_ARG(1)(%r3), %r1
154	ldw	HPPA_FRAME_ARG(0)(%r3), %arg0	; ps_strings
155	ldw	0(%r1), %arg1			; cleanup
156	ldw	4(%r1), %arg2			; obj
157
158	/* End stack calling convention. */
159	ldo	HPPA_FRAME_SIZE(%r3), %sp
160	ldw,mb	-HPPA_FRAME_SIZE(%sp), %r3
161
162	/* Go for it. */
163	bv	%r0(%ret0)
164	copy	%r0, %rp
165EXIT($rtld_start)
166
167/*
168 * This does our setup for an object's GOT.  %arg0 is the
169 * Obj_Entry * for the object, and %arg1 is its GOT pointer.
170 */
171LEAF_ENTRY(__rtld_setup_hppa_pltgot)
172
173	/*
174	 * The second entry of the GOT is reserved for
175	 * the dynamic linker.  We put the Obj_Entry *
176	 * for the object in there.
177	 */
178	stw	%arg0, 4(%arg1)
179
180	/*
181	 * Fill the fixup_func and fixup_ltp members of
182	 * the PLT stub.  This stub is inserted by the
183	 * linker immediately before the GOT.  We use
184	 * this stub to enter our binder.
185	 */
186	LOAD_ADDR(_rtld_bind_start, %arg0)
187	stw	%arg0, -8(%arg1)
188	bv	%r0(%rp)
189	stw	%r19, -4(%arg1)
190EXIT(__rtld_hppa_setup_pltgot)
191
192/*
193 * In order to support lazy binding, this implementation of
194 * _rtld_bind_start is very closely tied to the shared-library
195 * call stub and the PLT stub, both inserted by the linker.
196 */
197ENTRY(_rtld_bind_start,32)
198
199	/* Start stack calling convention.  */
200	copy	%r3, %r1
201	copy	%sp, %r3
202	stw,ma	%r1, HPPA_FRAME_SIZE*2(%sp)
203
204	/*
205	 * We have to save all calling convention registers
206	 * that are set by the caller, because we have to
207	 * restore them before transferring to the bound
208	 * function.  Note that this includes %ret0 and %ret1,
209	 * because they can have meaning on entry to a function.
210	 */
211	stw	%rp, HPPA_FRAME_CRP(%r3)
212	stw	%arg0, HPPA_FRAME_ARG(0)(%r3)
213	stw	%arg1, HPPA_FRAME_ARG(1)(%r3)
214	stw	%arg2, HPPA_FRAME_ARG(2)(%r3)
215	stw	%arg3, HPPA_FRAME_ARG(3)(%r3)
216	/* 0(%r3) is filled with the saved %r3 above */
217	stw	%ret0, 4(%r3)
218	stw	%ret1, 8(%r3)
219
220	/*
221	 * The linker PLT stub loads %r20 with (GOT - 8) for
222	 * the object that needs binding done.  The second entry
223	 * of the GOT is reserved for the dynamic linker's use,
224	 * and we previously stashed the object's Obj_Entry *
225	 * there.
226	 */
227	ldw	12(%r20), %arg0
228
229	/*
230	 * The linker shared-library call stub loads %r19 from
231	 * the shared linkage member of the PLT entry.  We
232	 * previously stashed the reloff of the relocation there.
233	 */
234	copy	%r19, %arg1
235
236	/*
237	 * The linker PLT stub loads %r21 with the fixup_ltp
238	 * word in itself.  We previously stashed our %r19
239	 * value there.
240	 */
241	bl	_rtld_bind, %rp
242	copy	%r21, %r19
243
244	/*
245	 * Our hppa version of _rtld_relocate_plt_object
246	 * returns to us the address of the PLT entry that
247	 * it fixed up.  Load the function address and
248	 * shared linkage for the newly bound function.
249	 */
250	ldw	0(%ret0), %r21
251	ldw	4(%ret0), %r19
252
253	/* Restore registers saved above. */
254	ldw	HPPA_FRAME_CRP(%r3), %rp
255	ldw	HPPA_FRAME_ARG(0)(%r3), %arg0
256	ldw	HPPA_FRAME_ARG(1)(%r3), %arg1
257	ldw	HPPA_FRAME_ARG(2)(%r3), %arg2
258	ldw	HPPA_FRAME_ARG(3)(%r3), %arg3
259	ldw	4(%r3), %ret0
260	ldw	8(%r3), %ret1
261
262	/* End stack calling convention. */
263	ldo	HPPA_FRAME_SIZE(%r3), %sp
264	ldw,mb	-HPPA_FRAME_SIZE(%sp), %r3
265
266	/* Transfer to the function. */
267	bv	%r0(%r21)
268	nop
269EXIT(_rtld_bind_start)
270