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