rtld_start.S revision 1.1 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
47 ENTRY($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
165 EXIT($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 */
171 LEAF_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)
190 EXIT(__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 */
197 ENTRY(_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
269 EXIT(_rtld_bind_start)
270