1 1.66 christos /* $NetBSD: ppc_reloc.c,v 1.66 2024/11/30 01:04:05 christos Exp $ */ 2 1.1 tsubai 3 1.1 tsubai /*- 4 1.1 tsubai * Copyright (C) 1998 Tsubai Masanari 5 1.32 mycroft * Portions copyright 2002 Charles M. Hannum <root (at) ihack.net> 6 1.1 tsubai * All rights reserved. 7 1.1 tsubai * 8 1.1 tsubai * Redistribution and use in source and binary forms, with or without 9 1.1 tsubai * modification, are permitted provided that the following conditions 10 1.1 tsubai * are met: 11 1.1 tsubai * 1. Redistributions of source code must retain the above copyright 12 1.1 tsubai * notice, this list of conditions and the following disclaimer. 13 1.1 tsubai * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 tsubai * notice, this list of conditions and the following disclaimer in the 15 1.1 tsubai * documentation and/or other materials provided with the distribution. 16 1.1 tsubai * 3. The name of the author may not be used to endorse or promote products 17 1.1 tsubai * derived from this software without specific prior written permission. 18 1.1 tsubai * 19 1.1 tsubai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 1.1 tsubai * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 1.1 tsubai * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 1.1 tsubai * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 1.1 tsubai * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 1.1 tsubai * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 1.1 tsubai * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 1.1 tsubai * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 1.1 tsubai * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 1.1 tsubai * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 1.1 tsubai */ 30 1.1 tsubai 31 1.64 uwe /* 32 1.64 uwe * Power ELF relocations. 33 1.64 uwe * 34 1.64 uwe * Reference: 35 1.64 uwe * 36 1.64 uwe * Power Architecture(R) 32-bit 37 1.64 uwe * Application Binary Interface Supplement 1.0 - Linux(R) 38 1.64 uwe * http://web.archive.org/web/20120608163845/https://www.power.org/resources/downloads/Power-Arch-32-bit-ABI-supp-1.0-Linux.pdf 39 1.64 uwe * 40 1.64 uwe * 64-bit PowerPC ELF Application Binary Interface Supplement 1.9 41 1.64 uwe * https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf 42 1.64 uwe */ 43 1.64 uwe 44 1.37 skrll #include <sys/cdefs.h> 45 1.37 skrll #ifndef lint 46 1.66 christos __RCSID("$NetBSD: ppc_reloc.c,v 1.66 2024/11/30 01:04:05 christos Exp $"); 47 1.37 skrll #endif /* not lint */ 48 1.37 skrll 49 1.1 tsubai #include <stdarg.h> 50 1.1 tsubai #include <stdio.h> 51 1.1 tsubai #include <stdlib.h> 52 1.1 tsubai #include <string.h> 53 1.1 tsubai #include <sys/types.h> 54 1.1 tsubai #include <machine/cpu.h> 55 1.1 tsubai 56 1.1 tsubai #include "debug.h" 57 1.1 tsubai #include "rtld.h" 58 1.1 tsubai 59 1.66 christos #include <machine/lwp_private.h> 60 1.66 christos 61 1.35 skrll void _rtld_powerpc_pltcall(Elf_Word); 62 1.35 skrll void _rtld_powerpc_pltresolve(Elf_Word, Elf_Word); 63 1.1 tsubai 64 1.50 matt #define __u64(x) ((uint64_t)(x)) 65 1.50 matt #define __u32(x) ((uint32_t)(x)) 66 1.50 matt #define __ha48 __u64(0xffffffff8000) 67 1.50 matt #define __ha32 __u64(0xffff8000) 68 1.50 matt #define __ha16 __u32(0x8000) 69 1.52 matt #define __ha(x,n) ((((x) >> (n)) + (((x) & __ha##n) == __ha##n)) & 0xffff) 70 1.50 matt #define __hi(x,n) (((x) >> (n)) & 0xffff) 71 1.50 matt #ifdef __LP64 72 1.50 matt #define highesta(x) __ha(__u64(x), 48) 73 1.50 matt #define highest(x) __hi(__u64(x), 48) 74 1.50 matt #define higher(x) __ha(__u64(x), 32) 75 1.50 matt #define higher(x) __hi(__u64(x), 32) 76 1.50 matt #endif 77 1.50 matt #define ha(x) __ha(__u32(x), 16) 78 1.50 matt #define hi(x) __hi(__u32(x), 16) 79 1.50 matt #define lo(x) (__u32(x) & 0xffff) 80 1.50 matt 81 1.50 matt #ifdef _LP64 82 1.50 matt /* function descriptor for _rtld_bind_start */ 83 1.50 matt extern const uint64_t _rtld_bind_start[3]; 84 1.50 matt #else 85 1.46 matt void _rtld_bind_bssplt_start(void); 86 1.46 matt void _rtld_bind_secureplt_start(void); 87 1.50 matt #endif 88 1.51 matt Elf_Addr _rtld_bind(const Obj_Entry *, Elf_Word); 89 1.22 mycroft void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 90 1.46 matt static int _rtld_relocate_plt_object(const Obj_Entry *, 91 1.36 skrll const Elf_Rela *, int, Elf_Addr *); 92 1.1 tsubai 93 1.1 tsubai /* 94 1.50 matt * The PPC32 PLT format consists of three sections: 95 1.39 chs * (1) The "pltcall" and "pltresolve" glue code. This is always 18 words. 96 1.39 chs * (2) The code part of the PLT entries. There are 2 words per entry for 97 1.39 chs * up to 8192 entries, then 4 words per entry for any additional entries. 98 1.39 chs * (3) The data part of the PLT entries, comprising a jump table. 99 1.39 chs * This section is half the size of the second section (ie. 1 or 2 words 100 1.39 chs * per entry). 101 1.39 chs */ 102 1.39 chs 103 1.1 tsubai void 104 1.35 skrll _rtld_setup_pltgot(const Obj_Entry *obj) 105 1.1 tsubai { 106 1.50 matt #ifdef _LP64 107 1.50 matt /* 108 1.50 matt * For powerpc64, just copy the function descriptor to pltgot[0]. 109 1.50 matt */ 110 1.50 matt if (obj->pltgot != NULL) { 111 1.50 matt obj->pltgot[0] = (Elf_Addr) _rtld_bind_start[0]; 112 1.50 matt obj->pltgot[1] = (Elf_Addr) _rtld_bind_start[1]; 113 1.50 matt obj->pltgot[2] = (Elf_Addr) obj; 114 1.50 matt } 115 1.50 matt #else 116 1.39 chs /* 117 1.46 matt * Secure-PLT is much more sane. 118 1.39 chs */ 119 1.46 matt if (obj->gotptr != NULL) { 120 1.46 matt obj->gotptr[1] = (Elf_Addr) _rtld_bind_secureplt_start; 121 1.46 matt obj->gotptr[2] = (Elf_Addr) obj; 122 1.47 matt dbg(("obj %s secure-plt gotptr=%p start=%p obj=%p", 123 1.47 matt obj->path, obj->gotptr, 124 1.47 matt (void *) obj->gotptr[1], (void *) obj->gotptr[2])); 125 1.46 matt } else { 126 1.50 matt /* 127 1.50 matt * Setup the plt glue routines (for bss-plt). 128 1.50 matt */ 129 1.50 matt #define BSSPLTCALL_SIZE 20 130 1.50 matt #define BSSPLTRESOLVE_SIZE 24 131 1.50 matt 132 1.46 matt Elf_Word *pltcall, *pltresolve; 133 1.46 matt Elf_Word *jmptab; 134 1.46 matt int N = obj->pltrelalim - obj->pltrela; 135 1.46 matt 136 1.46 matt /* Entries beyond 8192 take twice as much space. */ 137 1.46 matt if (N > 8192) 138 1.46 matt N += N-8192; 139 1.46 matt 140 1.47 matt dbg(("obj %s bss-plt pltgot=%p jmptab=%u start=%p obj=%p", 141 1.47 matt obj->path, obj->pltgot, 18 + N * 2, 142 1.47 matt _rtld_bind_bssplt_start, obj)); 143 1.47 matt 144 1.46 matt pltcall = obj->pltgot; 145 1.46 matt jmptab = pltcall + 18 + N * 2; 146 1.46 matt 147 1.50 matt memcpy(pltcall, _rtld_powerpc_pltcall, BSSPLTCALL_SIZE); 148 1.46 matt pltcall[1] |= ha(jmptab); 149 1.50 matt pltcall[2] |= lo(jmptab); 150 1.46 matt 151 1.46 matt pltresolve = obj->pltgot + 8; 152 1.46 matt 153 1.50 matt memcpy(pltresolve, _rtld_powerpc_pltresolve, BSSPLTRESOLVE_SIZE); 154 1.46 matt pltresolve[0] |= ha(_rtld_bind_bssplt_start); 155 1.50 matt pltresolve[1] |= lo(_rtld_bind_bssplt_start); 156 1.46 matt pltresolve[3] |= ha(obj); 157 1.50 matt pltresolve[4] |= lo(obj); 158 1.46 matt 159 1.46 matt /* 160 1.46 matt * Invalidate the icache for only the code part of the PLT 161 1.46 matt * (and not the jump table at the end). 162 1.46 matt */ 163 1.46 matt __syncicache(pltcall, (char *)jmptab - (char *)pltcall); 164 1.46 matt } 165 1.50 matt #endif 166 1.13 mycroft } 167 1.13 mycroft 168 1.22 mycroft void 169 1.35 skrll _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 170 1.22 mycroft { 171 1.22 mycroft const Elf_Rela *rela = 0, *relalim; 172 1.22 mycroft Elf_Addr relasz = 0; 173 1.22 mycroft Elf_Addr *where; 174 1.22 mycroft 175 1.22 mycroft for (; dynp->d_tag != DT_NULL; dynp++) { 176 1.22 mycroft switch (dynp->d_tag) { 177 1.22 mycroft case DT_RELA: 178 1.22 mycroft rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr); 179 1.22 mycroft break; 180 1.22 mycroft case DT_RELASZ: 181 1.22 mycroft relasz = dynp->d_un.d_val; 182 1.22 mycroft break; 183 1.22 mycroft } 184 1.22 mycroft } 185 1.42 he relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz); 186 1.22 mycroft for (; rela < relalim; rela++) { 187 1.22 mycroft where = (Elf_Addr *)(relocbase + rela->r_offset); 188 1.22 mycroft *where = (Elf_Addr)(relocbase + rela->r_addend); 189 1.22 mycroft } 190 1.22 mycroft } 191 1.22 mycroft 192 1.13 mycroft int 193 1.45 joerg _rtld_relocate_nonplt_objects(Obj_Entry *obj) 194 1.13 mycroft { 195 1.14 mycroft const Elf_Rela *rela; 196 1.54 joerg const Elf_Sym *def = NULL; 197 1.54 joerg const Obj_Entry *defobj = NULL; 198 1.54 joerg unsigned long last_symnum = ULONG_MAX; 199 1.22 mycroft 200 1.14 mycroft for (rela = obj->rela; rela < obj->relalim; rela++) { 201 1.14 mycroft Elf_Addr *where; 202 1.14 mycroft Elf_Addr tmp; 203 1.15 mycroft unsigned long symnum; 204 1.14 mycroft 205 1.14 mycroft where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 206 1.58 christos symnum = ELF_R_SYM(rela->r_info); 207 1.54 joerg 208 1.54 joerg switch (ELF_R_TYPE(rela->r_info)) { 209 1.54 joerg #ifdef _LP64 210 1.54 joerg case R_TYPE(ADDR64): /* <address> S + A */ 211 1.54 joerg #else 212 1.54 joerg case R_TYPE(ADDR32): /* <address> S + A */ 213 1.61 macallan case R_TYPE(UADDR32): /* <address> S + A */ 214 1.54 joerg #endif 215 1.54 joerg case R_TYPE(GLOB_DAT): /* <address> S + A */ 216 1.59 uwe case R_TYPE(ADDR16_LO): 217 1.59 uwe case R_TYPE(ADDR16_HI): 218 1.59 uwe case R_TYPE(ADDR16_HA): 219 1.54 joerg case R_TYPE(DTPMOD): 220 1.54 joerg case R_TYPE(DTPREL): 221 1.54 joerg case R_TYPE(TPREL): 222 1.54 joerg if (last_symnum != symnum) { 223 1.54 joerg last_symnum = symnum; 224 1.54 joerg def = _rtld_find_symdef(symnum, obj, &defobj, 225 1.54 joerg false); 226 1.54 joerg if (def == NULL) 227 1.54 joerg return -1; 228 1.54 joerg } 229 1.54 joerg break; 230 1.54 joerg default: 231 1.54 joerg break; 232 1.54 joerg } 233 1.13 mycroft 234 1.14 mycroft switch (ELF_R_TYPE(rela->r_info)) { 235 1.26 mycroft #if 1 /* XXX Should not be necessary. */ 236 1.26 mycroft case R_TYPE(JMP_SLOT): 237 1.26 mycroft #endif 238 1.14 mycroft case R_TYPE(NONE): 239 1.14 mycroft break; 240 1.14 mycroft 241 1.50 matt #ifdef _LP64 242 1.50 matt case R_TYPE(ADDR64): /* <address> S + A */ 243 1.50 matt #else 244 1.50 matt case R_TYPE(ADDR32): /* <address> S + A */ 245 1.61 macallan case R_TYPE(UADDR32): /* <address> S + A */ 246 1.50 matt #endif 247 1.50 matt case R_TYPE(GLOB_DAT): /* <address> S + A */ 248 1.14 mycroft tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 249 1.14 mycroft rela->r_addend); 250 1.14 mycroft if (*where != tmp) 251 1.14 mycroft *where = tmp; 252 1.24 mycroft rdbg(("32/GLOB_DAT %s in %s --> %p in %s", 253 1.16 mycroft obj->strtab + obj->symtab[symnum].st_name, 254 1.16 mycroft obj->path, (void *)*where, defobj->path)); 255 1.14 mycroft break; 256 1.14 mycroft 257 1.59 uwe /* 258 1.59 uwe * Recent GNU ld does not resolve ADDR16_{LO,HI,HA} if 259 1.59 uwe * the reloc is in a writable section and the symbol 260 1.59 uwe * is not already referenced from text. 261 1.59 uwe */ 262 1.59 uwe case R_TYPE(ADDR16_LO): { 263 1.59 uwe tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 264 1.59 uwe rela->r_addend); 265 1.59 uwe 266 1.60 uwe uint16_t tmp16 = lo(tmp); 267 1.59 uwe 268 1.59 uwe uint16_t *where16 = (uint16_t *)where; 269 1.59 uwe if (*where16 != tmp16) 270 1.59 uwe *where16 = tmp16; 271 1.59 uwe rdbg(("ADDR16_LO %s in %s --> #lo(%p) = 0x%x in %s", 272 1.59 uwe obj->strtab + obj->symtab[symnum].st_name, 273 1.59 uwe obj->path, (void *)tmp, tmp16, defobj->path)); 274 1.59 uwe break; 275 1.59 uwe } 276 1.59 uwe 277 1.59 uwe case R_TYPE(ADDR16_HI): 278 1.59 uwe case R_TYPE(ADDR16_HA): { 279 1.59 uwe tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 280 1.59 uwe rela->r_addend); 281 1.59 uwe 282 1.60 uwe uint16_t tmp16 = hi(tmp); 283 1.59 uwe if (ELF_R_TYPE(rela->r_info) == R_TYPE(ADDR16_HA) 284 1.60 uwe && (tmp & __ha16)) 285 1.60 uwe ++tmp16; /* adjust to ha(tmp) */ 286 1.59 uwe 287 1.59 uwe uint16_t *where16 = (uint16_t *)where; 288 1.59 uwe if (*where16 != tmp16) 289 1.59 uwe *where16 = tmp16; 290 1.59 uwe rdbg(("ADDR16_H%c %s in %s --> #h%c(%p) = 0x%x in %s", 291 1.59 uwe (ELF_R_TYPE(rela->r_info) == R_TYPE(ADDR16_HI) 292 1.59 uwe ? 'I' : 'A'), 293 1.59 uwe obj->strtab + obj->symtab[symnum].st_name, 294 1.59 uwe obj->path, 295 1.59 uwe (ELF_R_TYPE(rela->r_info) == R_TYPE(ADDR16_HI) 296 1.59 uwe ? 'i' : 'a'), 297 1.59 uwe (void *)tmp, tmp16, defobj->path)); 298 1.59 uwe break; 299 1.59 uwe } 300 1.59 uwe 301 1.50 matt case R_TYPE(RELATIVE): /* <address> B + A */ 302 1.22 mycroft *where = (Elf_Addr)(obj->relocbase + rela->r_addend); 303 1.24 mycroft rdbg(("RELATIVE in %s --> %p", obj->path, 304 1.14 mycroft (void *)*where)); 305 1.14 mycroft break; 306 1.14 mycroft 307 1.14 mycroft case R_TYPE(COPY): 308 1.14 mycroft /* 309 1.14 mycroft * These are deferred until all other relocations have 310 1.14 mycroft * been done. All we do here is make sure that the 311 1.14 mycroft * COPY relocation is not in a shared library. They 312 1.14 mycroft * are allowed only in executable files. 313 1.14 mycroft */ 314 1.20 mycroft if (obj->isdynamic) { 315 1.14 mycroft _rtld_error( 316 1.13 mycroft "%s: Unexpected R_COPY relocation in shared library", 317 1.14 mycroft obj->path); 318 1.14 mycroft return -1; 319 1.14 mycroft } 320 1.24 mycroft rdbg(("COPY (avoid in main)")); 321 1.14 mycroft break; 322 1.14 mycroft 323 1.50 matt case R_TYPE(DTPMOD): 324 1.48 matt *where = (Elf_Addr)defobj->tlsindex; 325 1.48 matt rdbg(("DTPMOD32 %s in %s --> %p in %s", 326 1.48 matt obj->strtab + obj->symtab[symnum].st_name, 327 1.48 matt obj->path, (void *)*where, defobj->path)); 328 1.48 matt break; 329 1.48 matt 330 1.50 matt case R_TYPE(DTPREL): 331 1.48 matt *where = (Elf_Addr)(def->st_value + rela->r_addend 332 1.48 matt - TLS_DTV_OFFSET); 333 1.48 matt rdbg(("DTPREL32 %s in %s --> %p in %s", 334 1.48 matt obj->strtab + obj->symtab[symnum].st_name, 335 1.48 matt obj->path, (void *)*where, defobj->path)); 336 1.48 matt break; 337 1.48 matt 338 1.50 matt case R_TYPE(TPREL): 339 1.63 joerg if (!defobj->tls_static && 340 1.63 joerg _rtld_tls_offset_allocate(__UNCONST(defobj))) 341 1.48 matt return -1; 342 1.48 matt 343 1.48 matt *where = (Elf_Addr)(def->st_value + rela->r_addend 344 1.48 matt + defobj->tlsoffset - TLS_TP_OFFSET); 345 1.48 matt rdbg(("TPREL32 %s in %s --> %p in %s", 346 1.48 matt obj->strtab + obj->symtab[symnum].st_name, 347 1.48 matt obj->path, (void *)*where, defobj->path)); 348 1.48 matt break; 349 1.48 matt 350 1.56 joerg case R_TYPE(IRELATIVE): 351 1.56 joerg /* IFUNC relocations are handled in _rtld_call_ifunc */ 352 1.56 joerg if (obj->ifunc_remaining_nonplt == 0) { 353 1.56 joerg obj->ifunc_remaining_nonplt = 354 1.57 joerg obj->relalim - rela; 355 1.56 joerg } 356 1.56 joerg break; 357 1.56 joerg 358 1.14 mycroft default: 359 1.24 mycroft rdbg(("sym = %lu, type = %lu, offset = %p, " 360 1.14 mycroft "addend = %p, contents = %p, symbol = %s", 361 1.54 joerg (u_long)ELF_R_SYM(rela->r_info), 362 1.54 joerg (u_long)ELF_R_TYPE(rela->r_info), 363 1.14 mycroft (void *)rela->r_offset, (void *)rela->r_addend, 364 1.14 mycroft (void *)*where, 365 1.15 mycroft obj->strtab + obj->symtab[symnum].st_name)); 366 1.14 mycroft _rtld_error("%s: Unsupported relocation type %ld " 367 1.43 jmmv "in non-PLT relocations", 368 1.14 mycroft obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 369 1.13 mycroft return -1; 370 1.13 mycroft } 371 1.13 mycroft } 372 1.17 mycroft return 0; 373 1.17 mycroft } 374 1.17 mycroft 375 1.17 mycroft int 376 1.55 joerg _rtld_relocate_plt_lazy(Obj_Entry *obj) 377 1.17 mycroft { 378 1.51 matt #ifdef _LP64 379 1.51 matt /* 380 1.51 matt * For PowerPC64, the plt stubs handle an empty function descriptor 381 1.51 matt * so there's nothing to do. 382 1.51 matt */ 383 1.55 joerg /* XXX ifunc support */ 384 1.51 matt #else 385 1.46 matt Elf_Addr * const pltresolve = obj->pltgot + 8; 386 1.17 mycroft const Elf_Rela *rela; 387 1.17 mycroft 388 1.56 joerg for (rela = obj->pltrelalim; rela-- > obj->pltrela;) { 389 1.56 joerg size_t reloff = rela - obj->pltrela; 390 1.17 mycroft Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); 391 1.17 mycroft 392 1.58 christos assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT) || 393 1.55 joerg ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE)); 394 1.55 joerg 395 1.55 joerg if (ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE)) { 396 1.55 joerg /* No ifunc support for old-style insecure PLT. */ 397 1.55 joerg assert(obj->gotptr != NULL); 398 1.55 joerg obj->ifunc_remaining = obj->pltrelalim - rela; 399 1.55 joerg } 400 1.17 mycroft 401 1.46 matt if (obj->gotptr != NULL) { 402 1.46 matt /* 403 1.46 matt * For now, simply treat then as relative. 404 1.46 matt */ 405 1.46 matt *where += (Elf_Addr)obj->relocbase; 406 1.46 matt } else { 407 1.46 matt int distance; 408 1.46 matt 409 1.46 matt if (reloff < 32768) { 410 1.46 matt /* li r11,reloff */ 411 1.46 matt *where++ = 0x39600000 | reloff; 412 1.46 matt } else { 413 1.46 matt /* lis r11,ha(reloff) */ 414 1.50 matt /* addi r11,lo(reloff) */ 415 1.46 matt *where++ = 0x3d600000 | ha(reloff); 416 1.50 matt *where++ = 0x396b0000 | lo(reloff); 417 1.46 matt } 418 1.46 matt /* b pltresolve */ 419 1.46 matt distance = (Elf_Addr)pltresolve - (Elf_Addr)where; 420 1.46 matt *where++ = 0x48000000 | (distance & 0x03fffffc); 421 1.17 mycroft 422 1.46 matt /* 423 1.46 matt * Icache invalidation is not done for each entry here 424 1.46 matt * because we sync the entire code part of the PLT once 425 1.46 matt * in _rtld_setup_pltgot() after all the entries have been 426 1.46 matt * initialized. 427 1.46 matt */ 428 1.46 matt /* __syncicache(where - 3, 12); */ 429 1.28 mycroft } 430 1.17 mycroft } 431 1.51 matt #endif /* !_LP64 */ 432 1.17 mycroft 433 1.13 mycroft return 0; 434 1.27 mycroft } 435 1.27 mycroft 436 1.46 matt static int 437 1.36 skrll _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff, Elf_Addr *tp) 438 1.27 mycroft { 439 1.27 mycroft Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); 440 1.27 mycroft Elf_Addr value; 441 1.27 mycroft const Elf_Sym *def; 442 1.27 mycroft const Obj_Entry *defobj; 443 1.44 christos unsigned long info = rela->r_info; 444 1.27 mycroft 445 1.44 christos assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); 446 1.27 mycroft 447 1.44 christos def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); 448 1.44 christos if (__predict_false(def == NULL)) 449 1.36 skrll return -1; 450 1.44 christos if (__predict_false(def == &_rtld_sym_zero)) 451 1.44 christos return 0; 452 1.27 mycroft 453 1.53 joerg if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 454 1.53 joerg if (tp == NULL) 455 1.53 joerg return 0; 456 1.53 joerg value = _rtld_resolve_ifunc(defobj, def); 457 1.53 joerg } else { 458 1.53 joerg value = (Elf_Addr)(defobj->relocbase + def->st_value); 459 1.53 joerg } 460 1.65 riastrad rdbg(("bind now/fixup in %s --> new=%p", 461 1.29 mycroft defobj->strtab + def->st_name, (void *)value)); 462 1.27 mycroft 463 1.50 matt #ifdef _LP64 464 1.50 matt /* 465 1.51 matt * For PowerPC64 we simply replace the function descriptor in the 466 1.51 matt * PLTGOT with the one from source object. 467 1.50 matt */ 468 1.50 matt assert(where >= (Elf_Word *)obj->pltgot); 469 1.50 matt assert(where < (Elf_Word *)obj->pltgot + (obj->pltrelalim - obj->pltrela)); 470 1.51 matt const Elf_Addr * const fdesc = (Elf_Addr *) value; 471 1.51 matt where[0] = fdesc[0]; 472 1.51 matt where[1] = fdesc[1]; 473 1.51 matt where[2] = fdesc[2]; 474 1.50 matt #else 475 1.51 matt ptrdiff_t distance = value - (Elf_Addr)where; 476 1.46 matt if (obj->gotptr != NULL) { 477 1.46 matt /* 478 1.50 matt * For Secure-PLT we simply replace the entry in GOT with the 479 1.50 matt * address of the routine. 480 1.46 matt */ 481 1.46 matt assert(where >= (Elf_Word *)obj->pltgot); 482 1.46 matt assert(where < (Elf_Word *)obj->pltgot + (obj->pltrelalim - obj->pltrela)); 483 1.46 matt *where = value; 484 1.51 matt } else if (labs(distance) < 32*1024*1024) { /* inside 32MB? */ 485 1.27 mycroft /* b value # branch directly */ 486 1.27 mycroft *where = 0x48000000 | (distance & 0x03fffffc); 487 1.27 mycroft __syncicache(where, 4); 488 1.27 mycroft } else { 489 1.27 mycroft Elf_Addr *pltcall, *jmptab; 490 1.27 mycroft int N = obj->pltrelalim - obj->pltrela; 491 1.65 riastrad 492 1.28 mycroft /* Entries beyond 8192 take twice as much space. */ 493 1.28 mycroft if (N > 8192) 494 1.28 mycroft N += N-8192; 495 1.28 mycroft 496 1.27 mycroft pltcall = obj->pltgot; 497 1.28 mycroft jmptab = pltcall + 18 + N * 2; 498 1.65 riastrad 499 1.27 mycroft jmptab[reloff] = value; 500 1.27 mycroft 501 1.28 mycroft if (reloff < 32768) { 502 1.28 mycroft /* li r11,reloff */ 503 1.28 mycroft *where++ = 0x39600000 | reloff; 504 1.28 mycroft } else { 505 1.46 matt #ifdef notyet 506 1.46 matt /* lis r11,ha(value) */ 507 1.50 matt /* addi r11,lo(value) */ 508 1.46 matt /* mtctr r11 */ 509 1.46 matt /* bctr */ 510 1.46 matt *where++ = 0x3d600000 | ha(value); 511 1.50 matt *where++ = 0x396b0000 | lo(value); 512 1.46 matt *where++ = 0x7d6903a6; 513 1.46 matt *where++ = 0x4e800420; 514 1.46 matt #else 515 1.28 mycroft /* lis r11,ha(reloff) */ 516 1.50 matt /* addi r11,lo(reloff) */ 517 1.28 mycroft *where++ = 0x3d600000 | ha(reloff); 518 1.50 matt *where++ = 0x396b0000 | lo(reloff); 519 1.46 matt #endif 520 1.28 mycroft } 521 1.28 mycroft /* b pltcall */ 522 1.28 mycroft distance = (Elf_Addr)pltcall - (Elf_Addr)where; 523 1.28 mycroft *where++ = 0x48000000 | (distance & 0x03fffffc); 524 1.38 chs __syncicache(where - 3, 12); 525 1.27 mycroft } 526 1.50 matt #endif /* _LP64 */ 527 1.27 mycroft 528 1.36 skrll if (tp) 529 1.36 skrll *tp = value; 530 1.36 skrll return 0; 531 1.36 skrll } 532 1.36 skrll 533 1.51 matt Elf_Addr 534 1.36 skrll _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 535 1.36 skrll { 536 1.47 matt const Elf_Rela *rela = obj->pltrela + reloff; 537 1.36 skrll Elf_Addr new_value; 538 1.36 skrll int err; 539 1.36 skrll 540 1.40 mrg new_value = 0; /* XXX gcc */ 541 1.40 mrg 542 1.49 joerg _rtld_shared_enter(); 543 1.65 riastrad err = _rtld_relocate_plt_object(obj, rela, reloff, &new_value); 544 1.44 christos if (err) 545 1.36 skrll _rtld_die(); 546 1.49 joerg _rtld_shared_exit(); 547 1.36 skrll 548 1.51 matt #ifdef _LP64 549 1.51 matt return obj->glink; 550 1.51 matt #else 551 1.51 matt return new_value; 552 1.51 matt #endif 553 1.36 skrll } 554 1.36 skrll 555 1.36 skrll int 556 1.36 skrll _rtld_relocate_plt_objects(const Obj_Entry *obj) 557 1.36 skrll { 558 1.36 skrll const Elf_Rela *rela; 559 1.36 skrll int reloff; 560 1.65 riastrad 561 1.36 skrll for (rela = obj->pltrela, reloff = 0; rela < obj->pltrelalim; rela++, reloff++) { 562 1.36 skrll if (_rtld_relocate_plt_object(obj, rela, reloff, NULL) < 0) 563 1.36 skrll return -1; 564 1.36 skrll } 565 1.36 skrll return 0; 566 1.1 tsubai } 567