1/* $NetBSD: rtld_start.S,v 1.23 2014/08/17 16:14:19 matt Exp $ */ 2 3/* 4 * Copyright 1996 Matt Thomas <matt@3am-software.com> 5 * Portions copyright 2002, 2003 Charles M. Hannum <root@ihack.net> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include <machine/asm.h> 32 33/* R9 contains the address of PS_STRINGS and since its caller saved, 34 * we can just use it. R6 has a backup copy of the stack pointer which 35 * we can use as well. 36 */ 37ENTRY(_rtld_start, 0) 38 /* Allocate space on the stack for the cleanup and obj_main 39 * entries that _rtld() will provide for us. 40 */ 41 clrl %fp 42 subl2 $8,%sp 43 44 movab _DYNAMIC,%r0 45 subl3 _GLOBAL_OFFSET_TABLE_,%r0,%r10 46 pushl %r10 /* relocbase */ 47 pushl %r0 /* &_DYNAMIC */ 48 calls $2,_rtld_relocate_nonplt_self 49 50 pushl %r10 /* relocbase */ 51 pushal 4(%sp) /* sp */ 52 calls $2,_rtld /* entry = _rtld(sp, relocbase) */ 53 54 movq (%sp)+,%r7 /* grab cleanup and obj_main into %r7/%r8 */ 55 jmp 2(%r0) /* jump to entry point + 2 */ 56END(_rtld_start) 57 58/* 59 * Lazy binding entry point, called via PLT via JMP into pltgot[1]. 60 * SP+4: address to relocation offset 61 * SP+0: obj entry points 62 */ 63ALTENTRY(_rtld_bind_start) 64 pushl %r1 /* need to preserve r1 */ 65 movq -8(%fp),%r0 /* get addresses of plt.got & reloc index */ 66 pushl (%r1) /* push relocation offset */ 67 pushl %r0 /* push address of obj entry */ 68 calls $2,_rtld_bind 69 70 /* 71 * This code checks to see if we got called via a call{s,g} $n,*pcrel32 72 * This is by far the most common case (a call indirectly via the PLT). 73 */ 74 subl3 $7,16(%fp),%r1 /* return address */ 75 bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */ 76 cmpb $0xfa,%r2 /* is it calls/callg */ 77 jneq 20f /* no it isn't */ 78 cmpb $0xff,2(%r1) /* and deferred 32-bit PC displacement? */ 79 jneq 20f /* no it isn't */ 80 81 /* 82 * This makes sure the longword with the PLT's address has been updated 83 * to point to the routine's address. If it hasn't, then returning 84 * would put us in an infinite loop. Instead we punt and fake up a 85 * callframe. 86 */ 87 movl 3(%r1),%r3 /* get displacement */ 88 addl2 16(%fp),%r3 /* add ending location */ 89 cmpl (%r3),%r0 /* does it contain the routine address? */ 90#ifdef DEBUG 91 jneq 30f /* no it doesn't, die */ 92#else 93 jneq 20f /* no it doesn't, go fake a new callframe */ 94#endif 95 9611: movl %r1,16(%fp) /* backup to the calls/callg */ 97 jbc $29,4(%fp),12f /* skip if this was a callg */ 98 clrl (%ap) /* clear argument count */ 9912: movl (%sp)+,%r1 /* restore r1 */ 100 ret /* return and redo the call */ 101 102#if 1 10320: 104 /* 105 * Since the calling standard says only r6-r11 should be saved, 106 * that simplies things for us. That means we can use r0-r5 as 107 * temporaries without worrying about preserving them. This means 108 * can hold the current fixed callframe in r2-r5 as we build the 109 * callframe without having to worry about overwriting the existing 110 * callframe. 111 */ 112 extzv $0,$12,(%r0),%r1/* get routine's save mask */ 113 bitw $0x3f,%r1 /* does the routine use r0-r5? */ 114 jneq 30f /* yes, that sucks */ 115 jbc $29,4(%fp),27f /* handle callg */ 116 movq 4(%fp),%r2 /* fetch callframe status & saved AP */ 117 movq 12(%fp),%r4 /* fetch callframe saved FP & PC */ 118 insv %r1,$16,$12,%r2 /* update save mask */ 119 movl (%sp)+,%fp /* use fp to keep saved r1 */ 120 movl %ap,%sp /* reset stack to top of callframe */ 12122: pushr %r1 /* push registers */ 122 movq %r4,-(%sp) /* push callframe saved FP & PC */ 123 movq %r2,-(%sp) /* push callframe status & saved AP */ 124 pushl $0 /* push condition handler */ 125 movl %fp,%r1 /* restore r1 */ 126 movl %sp,%fp /* sp == fp now */ 127#if 1 128 jmp 2(%r0) /* jump past entry mask */ 129#else 130 /* 131 * More correct but IV/DV are never set so ignore doing this for now. 132 */ 133 movpsl -(%sp) /* push PSL */ 134 clrb (%sp) /* clear user flags */ 135 jbc $14,(%r0),24f /* IV need to be set? */ 136 bisb2 $0x20,(%sp) /* yes, set it. */ 13724: jbc $15,(%r0),25f /* DV need to be set? */ 138 bisb2 $0x80,(%sp) /* yes, set it. */ 13925: pushab 2(%r0) /* push address of first instruction */ 140 rei /* and go to it (updating PSW) */ 141#endif 142 143 /* 144 * Count how many registers are being used for callg. 145 */ 14627: movl $0x32212110,%r3 /* bit counts */ 147 extzv $6,$3,%r1,%r2 /* extract bits 6-8 */ 148 ashl $2,%r2,%r2 /* shift by 2 */ 149 extzv %r2,$4,%r3,%r4 /* extract count */ 150 extzv $9,$3,%r1,%r2 /* extract bits 9-11 */ 151 ashl $2,%r2,%r2 /* shift by 2 */ 152 extzv %r2,$4,%r3,%r5 /* extract count */ 153 movq 4(%fp),%r2 /* fetch callframe status & saved AP */ 154 insv %r1,$16,$12,%r2 /* update save mask */ 155 addl3 %r4,%r5,%r1 /* add counts and discard them */ 156 movq 12(%fp),%r4 /* fetch callframe saved FP & PC */ 157 moval 20(%fp)[%r1],%sp/* pop callframe */ 158 extzv $16,$12,%r2,%r1 /* get save mask back */ 159 jbr 22b /* now build the new callframe */ 160 16130: 162 calls $0,_C_LABEL(_rtld_die) 163#else 164 /* 165 * Check to see if called via call? $n,w^off(reg) 166 */ 16720: addl2 $2,%r1 /* 16-bit displacement */ 168 bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */ 169 cmpb $0xfa,%r2 /* is it calls/callg */ 170 jneq 30f /* no it isn't */ 171 bicb3 $0x1f,2(%r1),%r3/* extract addressing mode */ 172 cmpb $0xc0,%r3 /* 16-bit displacement? */ 173 jeql 11b /* yes, redo the call */ 174 halt 175 176 /* 177 * Check to see if called via call? $n,b^off(reg) 178 */ 17930: incl %r1 /* 8-bit displacement */ 180 bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */ 181 cmpb $0xfa,%r2 /* is it calls/callg */ 182 jneq 40f /* no it isn't */ 183 bicb3 $0x1f,2(%r1),%r3/* extract addressing mode */ 184 cmpb $0xa0,%r3 /* 8-bit displacement? */ 185 jeql 11b /* yes, redo the call */ 186 halt 187 188 /* 189 * Check to see if called via call? $n,(reg) 190 */ 19140: incl %r1 /* no displacement */ 192 bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */ 193 cmpb $0xfa,%r2 /* is it calls/callg */ 194 jeql 41f /* yes it is */ 195 halt /* no, die die die */ 19641: bicb3 $0x0f,2(%r1),%r2/* extract addressing mode */ 197 bicb3 $0xf0,2(%r1),%r3/* extract register */ 198 extzv $0,$12,6(%fp),%r4/* extract saved mask */ 199 cmpb $0x60,%r2 /* register deferred? */ 200 jeql 42f /* yes, deal with it */ 201 cmpb $0x90,%r2 /* autoincrement deferred? */ 202 jeql 70f /* yes, deal with it */ 203 halt /* no, die die die */ 204 20542: cmpw %r4,$0xffc /* did we save r2-r11? */ 206 jneq 50f /* no, deal with it */ 207 jbc %r3,%r4,43f /* is the register in the saved mask? */ 208 209 /* 210 * We saved r2-r11, so it's easy to replace the saved register with 211 * the right value by indexing into saved register (offset by 8). 212 */ 213 movl %r0,(20-8)(%fp)[%r3] /* replace address in saved registers */ 214 jbr 11b /* go back and redo call */ 215 /* 216 * Must have been called via r0 or r1 which are saved locally. 217 * So move the routine address in the appropriate slot on the stack. 218 */ 21943: movl %r0,(%sp)[%r3] 220 jbr 11b /* go back and redo call */ 221 22250: jbs %r3,%r4,60f /* is the register in the saved mask? */ 223 jbs %r3,$0x3f,43b /* is it r0-r5? */ 224 /* 225 * The register used for the call was not saved so we need to move 226 * the new function address into it so the re-call will use the new 227 * address. 228 */ 229 pushl %r0 /* save function address on the stack */ 230 ashl %r5,$1,%r0 /* create a bitmask for the register */ 231 popr %r0 /* pop it off the stack. */ 232 jbr 11b /* and redo the call */ 233 23460: clrl %r2 /* starting offset into saved registers */ 235 clrl %r5 /* start with register 0 */ 236 23761: cmpl %r2,%r3 /* is the register to save? */ 238 jneq 62f /* no, advance to next */ 239 movl %r0,20(%fp)[%r5]/* yes, save return address in saved reg */ 240 jbr 11b /* and return the call */ 24162: jbc %r5,%r4,63f /* is this register saved? */ 242 incl %r5 /* yes, account for it */ 24363: incl %r2 /* increment register number */ 244 jbr 61b /* and loop */ 245 24670: cmpb %r3,$12 247 blss 71f 248 halt 249 25071: cmpw %r4,$0xffc /* did we save r2-r11? */ 251 jneq 72f /* no, deal with it */ 252 subl2 $4,(20-8)(%fp)[%r3] /* backup incremented register */ 253 jbr 11b /* and redo the call. 254 25572: jbs %r3,%r4,80f 256 jbs %r3,%3f,74f 257 ashl %r5,$1,%r0 /* create a bitmask for the register */ 258 pushr %r0 /* pop it off the stack. */ 259 subl2 $4,(%sp) /* backup incremented register */ 260 popr %r0 /* pop it off the stack. */ 261 jbr 11b /* and redo the call. 262 26373: subl2 %4,(%sp)[%r3] /* backup incremented register */ 264 jbr 11b /* and redo the call. 265 26680: clrl %r2 /* starting offset into saved registers */ 267 clrl %r5 /* start with register 0 */ 268 26981: cmpl %r2,%r3 /* is the register to save? */ 270 jneq 82f /* no, advance to next */ 271 subl $4,20(%fp)[%r5] /* yes, backup incremented register */ 272 jbr 11b /* and return the call */ 27382: jbc %r5,%r4,83f /* is this register saved? */ 274 incl %r5 /* yes, account for it */ 27583: incl %r2 /* increment register number */ 276 jbr 81b /* and loop */ 277#endif 278END(_rtld_bind_start) 279