1 /* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */ 2 3 /*- 4 * Copyright (C) 1998 Tsubai Masanari 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <stdarg.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <machine/cpu.h> 37 38 #include "debug.h" 39 #include "rtld.h" 40 41 caddr_t _rtld_bind_powerpc __P((Obj_Entry *, Elf_Word)); 42 void _rtld_powerpc_pltcall __P((Elf_Word)); 43 void _rtld_powerpc_pltresolve __P((Elf_Word, Elf_Word)); 44 45 #define ha(x) ((((u_int32_t)(x) & 0x8000) ? \ 46 ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16) 47 #define l(x) ((u_int32_t)(x) & 0xffff) 48 49 /* 50 * Bind a pltgot slot indexed by reloff. 51 */ 52 caddr_t 53 _rtld_bind_powerpc(obj, reloff) 54 Obj_Entry *obj; 55 Elf_Word reloff; 56 { 57 const Elf_Rela *rela; 58 caddr_t addr; 59 60 if (reloff < 0 || reloff >= 0x8000) { 61 dbg(("_rtld_bind_powerpc: broken reloff %x", reloff)); 62 _rtld_die(); 63 } 64 65 rela = obj->pltrela + reloff; 66 67 if (_rtld_relocate_plt_object(obj, rela, &addr, true, true) < 0) 68 _rtld_die(); 69 70 return addr; 71 } 72 73 /* 74 * Make a pltgot slot. 75 * Initial value is "pltresolve" unless bind_now is true. 76 */ 77 int 78 _rtld_relocate_plt_object( 79 Obj_Entry *obj, 80 const Elf_Rela *rela, 81 caddr_t *addrp, 82 bool bind_now, 83 bool dodebug) 84 { 85 Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); 86 int distance; 87 88 if (bind_now) { 89 const Elf_Sym *def; 90 const Obj_Entry *defobj; 91 Elf_Addr value; 92 93 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 94 95 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, 96 &defobj, true); 97 if (def == NULL) 98 return (-1); 99 100 value = (Elf_Addr)(defobj->relocbase + def->st_value); 101 distance = value - (Elf_Addr)where; 102 103 if (abs(distance) < 32*1024*1024) { /* inside 32MB? */ 104 /* b value # branch directly */ 105 *where = 0x48000000 | (distance & 0x03fffffc); 106 __syncicache(where, 4); 107 } else { 108 Elf_Addr *pltcall, *jmptab; 109 int N = obj->pltrelalim - obj->pltrela; 110 int reloff = rela - obj->pltrela; 111 112 if (reloff < 0 || reloff >= 0x8000) 113 return (-1); 114 115 pltcall = obj->pltgot; 116 117 jmptab = pltcall + 18 + N * 2; 118 jmptab[reloff] = value; 119 120 distance = (Elf_Addr)pltcall - (Elf_Addr)(where + 1); 121 122 /* li r11,reloff */ 123 /* b pltcall # use pltcall routine */ 124 where[0] = 0x39600000 | reloff; 125 where[1] = 0x48000000 | (distance & 0x03fffffc); 126 __syncicache(where, 8); 127 } 128 129 if (addrp != NULL) 130 *addrp = (caddr_t)value; 131 132 return (0); 133 } else { 134 Elf_Addr *pltresolve; 135 int reloff = rela - obj->pltrela; 136 137 if (reloff < 0 || reloff >= 0x8000) 138 return (-1); 139 140 pltresolve = obj->pltgot + 8; 141 142 distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1); 143 144 /* li r11,reloff */ 145 /* b pltresolve */ 146 where[0] = 0x39600000 | reloff; 147 where[1] = 0x48000000 | (distance & 0x03fffffc); 148 /* __syncicache(where, 8); */ 149 } 150 151 return 0; 152 } 153 154 /* 155 * Setup the plt glue routines. 156 */ 157 #define PLTCALL_SIZE 20 158 #define PLTRESOLVE_SIZE 24 159 160 void 161 _rtld_setup_powerpc_plt(obj) 162 const Obj_Entry * obj; 163 { 164 Elf_Word *pltcall, *pltresolve; 165 Elf_Word *jmptab; 166 int N = obj->pltrelalim - obj->pltrela; 167 168 pltcall = obj->pltgot; 169 170 memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE); 171 jmptab = pltcall + 18 + N * 2; 172 pltcall[1] |= ha(jmptab); 173 pltcall[2] |= l(jmptab); 174 175 pltresolve = obj->pltgot + 8; 176 177 memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE); 178 pltresolve[0] |= ha(_rtld_bind_start); 179 pltresolve[1] |= l(_rtld_bind_start); 180 pltresolve[3] |= ha(obj); 181 pltresolve[4] |= l(obj); 182 183 __syncicache(pltcall, 72 + N * 8); 184 } 185