138816Sdfr/*- 248205Sjdp * Copyright 1996, 1997, 1998, 1999 John D. Polstra. 338816Sdfr * All rights reserved. 438816Sdfr * 538816Sdfr * Redistribution and use in source and binary forms, with or without 638816Sdfr * modification, are permitted provided that the following conditions 738816Sdfr * are met: 838816Sdfr * 1. Redistributions of source code must retain the above copyright 938816Sdfr * notice, this list of conditions and the following disclaimer. 1038816Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1138816Sdfr * notice, this list of conditions and the following disclaimer in the 1238816Sdfr * documentation and/or other materials provided with the distribution. 1338816Sdfr * 1438816Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1538816Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1638816Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1738816Sdfr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1838816Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1938816Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2038816Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2138816Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2238816Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2338816Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2438816Sdfr * 2550476Speter * $FreeBSD: stable/10/libexec/rtld-elf/i386/reloc.c 331206 2018-03-19 14:28:58Z marius $ 2638816Sdfr */ 2738816Sdfr 2838816Sdfr/* 2938816Sdfr * Dynamic linker for ELF. 3038816Sdfr * 3138816Sdfr * John Polstra <jdp@polstra.com>. 3238816Sdfr */ 3338816Sdfr 3438816Sdfr#include <sys/param.h> 3538816Sdfr#include <sys/mman.h> 36133063Sdfr#include <machine/segments.h> 37133063Sdfr#include <machine/sysarch.h> 3838816Sdfr 3938816Sdfr#include <dlfcn.h> 4038816Sdfr#include <err.h> 4138816Sdfr#include <errno.h> 4238816Sdfr#include <fcntl.h> 4338816Sdfr#include <stdarg.h> 4438816Sdfr#include <stdio.h> 4538816Sdfr#include <stdlib.h> 4638816Sdfr#include <string.h> 4738816Sdfr#include <unistd.h> 4838816Sdfr 4938816Sdfr#include "debug.h" 5038816Sdfr#include "rtld.h" 51281453Skib#include "rtld_tls.h" 5238816Sdfr 5338816Sdfr/* 5438816Sdfr * Process the special R_386_COPY relocations in the main program. These 5538816Sdfr * copy data from a shared object into a region in the main program's BSS 5638816Sdfr * segment. 5738816Sdfr * 5838816Sdfr * Returns 0 on success, -1 on failure. 5938816Sdfr */ 6038816Sdfrint 6138816Sdfrdo_copy_relocations(Obj_Entry *dstobj) 6238816Sdfr{ 6338816Sdfr const Elf_Rel *rellim; 6438816Sdfr const Elf_Rel *rel; 6538816Sdfr 6638816Sdfr assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ 6738816Sdfr 6838816Sdfr rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize); 6938816Sdfr for (rel = dstobj->rel; rel < rellim; rel++) { 7038816Sdfr if (ELF_R_TYPE(rel->r_info) == R_386_COPY) { 7138816Sdfr void *dstaddr; 7238816Sdfr const Elf_Sym *dstsym; 7338816Sdfr const char *name; 7438816Sdfr size_t size; 7538816Sdfr const void *srcaddr; 7638816Sdfr const Elf_Sym *srcsym; 77216695Skib const Obj_Entry *srcobj, *defobj; 78216695Skib SymLook req; 79216695Skib int res; 8038816Sdfr 8138816Sdfr dstaddr = (void *) (dstobj->relocbase + rel->r_offset); 8238816Sdfr dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); 8338816Sdfr name = dstobj->strtab + dstsym->st_name; 8438816Sdfr size = dstsym->st_size; 85216695Skib symlook_init(&req, name); 86216695Skib req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info)); 87233231Skib req.flags = SYMLOOK_EARLY; 8838816Sdfr 89296727Skib for (srcobj = globallist_next(dstobj); srcobj != NULL; 90296727Skib srcobj = globallist_next(srcobj)) { 91216695Skib res = symlook_obj(&req, srcobj); 92216695Skib if (res == 0) { 93216695Skib srcsym = req.sym_out; 94216695Skib defobj = req.defobj_out; 9538816Sdfr break; 96216695Skib } 97216695Skib } 9838816Sdfr 9938816Sdfr if (srcobj == NULL) { 10038816Sdfr _rtld_error("Undefined symbol \"%s\" referenced from COPY" 10138816Sdfr " relocation in %s", name, dstobj->path); 10238816Sdfr return -1; 10338816Sdfr } 10438816Sdfr 105216695Skib srcaddr = (const void *) (defobj->relocbase + srcsym->st_value); 10638816Sdfr memcpy(dstaddr, srcaddr, size); 10738816Sdfr } 10838816Sdfr } 10938816Sdfr 11038816Sdfr return 0; 11138816Sdfr} 11238816Sdfr 11345501Sjdp/* Initialize the special GOT entries. */ 11445501Sjdpvoid 11545501Sjdpinit_pltgot(Obj_Entry *obj) 11645501Sjdp{ 11745501Sjdp if (obj->pltgot != NULL) { 11845501Sjdp obj->pltgot[1] = (Elf_Addr) obj; 11945501Sjdp obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 12045501Sjdp } 12145501Sjdp} 12245501Sjdp 12338816Sdfr/* Process the non-PLT relocations. */ 12438816Sdfrint 125233231Skibreloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 126233231Skib RtldLockState *lockstate) 12738816Sdfr{ 12838816Sdfr const Elf_Rel *rellim; 12938816Sdfr const Elf_Rel *rel; 13076296Sjdp SymCache *cache; 131271469Skib const Elf_Sym *def; 132271469Skib const Obj_Entry *defobj; 133271469Skib Elf_Addr *where, symval, add; 134271469Skib int r; 13538816Sdfr 136271469Skib r = -1; 13798100Sdillon /* 13898100Sdillon * The dynamic loader may be called from a thread, we have 13998100Sdillon * limited amounts of stack available so we cannot use alloca(). 14098100Sdillon */ 141208256Srdivacky if (obj != obj_rtld) { 142271469Skib cache = calloc(obj->dynsymcount, sizeof(SymCache)); 143271469Skib /* No need to check for NULL here */ 144208256Srdivacky } else 145271469Skib cache = NULL; 14676296Sjdp 147271469Skib rellim = (const Elf_Rel *)((caddr_t) obj->rel + obj->relsize); 14838816Sdfr for (rel = obj->rel; rel < rellim; rel++) { 149271469Skib switch (ELF_R_TYPE(rel->r_info)) { 150271469Skib case R_386_32: 151271469Skib case R_386_PC32: 152271469Skib case R_386_GLOB_DAT: 153271469Skib case R_386_TLS_TPOFF: 154271469Skib case R_386_TLS_TPOFF32: 155271469Skib case R_386_TLS_DTPMOD32: 156271469Skib case R_386_TLS_DTPOFF32: 157271469Skib def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, 158271469Skib flags, cache, lockstate); 159271469Skib if (def == NULL) 160271469Skib goto done; 161271469Skib if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 162271469Skib switch (ELF_R_TYPE(rel->r_info)) { 163271469Skib case R_386_32: 164271469Skib case R_386_PC32: 165271469Skib case R_386_GLOB_DAT: 166271469Skib if ((flags & SYMLOOK_IFUNC) == 0) { 167271469Skib obj->non_plt_gnu_ifunc = true; 168271469Skib continue; 169271469Skib } 170271469Skib symval = (Elf_Addr)rtld_resolve_ifunc( 171271469Skib defobj, def); 172271469Skib break; 173271469Skib case R_386_TLS_TPOFF: 174271469Skib case R_386_TLS_TPOFF32: 175271469Skib case R_386_TLS_DTPMOD32: 176271469Skib case R_386_TLS_DTPOFF32: 177271469Skib _rtld_error("%s: IFUNC for TLS reloc", 178271469Skib obj->path); 179271469Skib goto done; 180271469Skib } 181271469Skib } else { 182271469Skib if ((flags & SYMLOOK_IFUNC) != 0) 183271469Skib continue; 184271469Skib symval = (Elf_Addr)defobj->relocbase + 185271469Skib def->st_value; 186271469Skib } 187271469Skib break; 188271469Skib default: 189271469Skib if ((flags & SYMLOOK_IFUNC) != 0) 190271469Skib continue; 191271469Skib break; 19238816Sdfr } 193271469Skib where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 19438816Sdfr 195271469Skib switch (ELF_R_TYPE(rel->r_info)) { 196271469Skib case R_386_NONE: 197271469Skib break; 198271469Skib case R_386_32: 199271469Skib *where += symval; 200271469Skib break; 201271469Skib case R_386_PC32: 202133063Sdfr /* 203271469Skib * I don't think the dynamic linker should ever 204271469Skib * see this type of relocation. But the 205271469Skib * binutils-2.6 tools sometimes generate it. 206133063Sdfr */ 207271469Skib *where += symval - (Elf_Addr)where; 208271469Skib break; 209271469Skib case R_386_COPY: 210271469Skib /* 211271469Skib * These are deferred until all other 212271469Skib * relocations have been done. All we do here 213271469Skib * is make sure that the COPY relocation is 214271469Skib * not in a shared library. They are allowed 215271469Skib * only in executable files. 216271469Skib */ 217271469Skib if (!obj->mainprog) { 218271469Skib _rtld_error("%s: Unexpected R_386_COPY " 219271469Skib "relocation in shared library", obj->path); 220271469Skib goto done; 221133063Sdfr } 222271469Skib break; 223271469Skib case R_386_GLOB_DAT: 224271469Skib *where = symval; 225271469Skib break; 226271469Skib case R_386_RELATIVE: 227271469Skib *where += (Elf_Addr)obj->relocbase; 228271469Skib break; 229271469Skib case R_386_TLS_TPOFF: 230271469Skib case R_386_TLS_TPOFF32: 231271469Skib /* 232271469Skib * We lazily allocate offsets for static TLS 233271469Skib * as we see the first relocation that 234271469Skib * references the TLS block. This allows us to 235271469Skib * support (small amounts of) static TLS in 236271469Skib * dynamically loaded modules. If we run out 237271469Skib * of space, we generate an error. 238271469Skib */ 239271469Skib if (!defobj->tls_done) { 240271469Skib if (!allocate_tls_offset((Obj_Entry*) defobj)) { 241271469Skib _rtld_error("%s: No space available " 242271469Skib "for static Thread Local Storage", 243271469Skib obj->path); 244271469Skib goto done; 245271469Skib } 246271469Skib } 247271469Skib add = (Elf_Addr)(def->st_value - defobj->tlsoffset); 248271469Skib if (ELF_R_TYPE(rel->r_info) == R_386_TLS_TPOFF) 249271469Skib *where += add; 250271469Skib else 251271469Skib *where -= add; 252271469Skib break; 253271469Skib case R_386_TLS_DTPMOD32: 254271469Skib *where += (Elf_Addr)defobj->tlsindex; 255271469Skib break; 256271469Skib case R_386_TLS_DTPOFF32: 257271469Skib *where += (Elf_Addr) def->st_value; 258271469Skib break; 259271469Skib default: 260271469Skib _rtld_error("%s: Unsupported relocation type %d" 261271469Skib " in non-PLT relocations\n", obj->path, 262271469Skib ELF_R_TYPE(rel->r_info)); 263133063Sdfr goto done; 264133063Sdfr } 26538816Sdfr } 26698103Sdillon r = 0; 26798103Sdillondone: 268271469Skib free(cache); 269233231Skib return (r); 27038816Sdfr} 27138816Sdfr 27238816Sdfr/* Process the PLT relocations. */ 27338816Sdfrint 27456780Sjdpreloc_plt(Obj_Entry *obj) 27538816Sdfr{ 27648205Sjdp const Elf_Rel *rellim; 27748205Sjdp const Elf_Rel *rel; 27838816Sdfr 27948205Sjdp rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); 28048205Sjdp for (rel = obj->pltrel; rel < rellim; rel++) { 281228435Skib Elf_Addr *where/*, val*/; 28238816Sdfr 283228435Skib switch (ELF_R_TYPE(rel->r_info)) { 284228435Skib case R_386_JMP_SLOT: 285228435Skib /* Relocate the GOT slot pointing into the PLT. */ 286228435Skib where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 287228435Skib *where += (Elf_Addr)obj->relocbase; 288228435Skib break; 28938816Sdfr 290228435Skib case R_386_IRELATIVE: 291228435Skib obj->irelative = true; 292228435Skib break; 293228435Skib 294228435Skib default: 295228435Skib _rtld_error("Unknown relocation type %x in PLT", 296228435Skib ELF_R_TYPE(rel->r_info)); 297228435Skib return (-1); 298228435Skib } 29956780Sjdp } 30056780Sjdp return 0; 30156780Sjdp} 30238816Sdfr 30356780Sjdp/* Relocate the jump slots in an object. */ 30456780Sjdpint 305233231Skibreloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 30656780Sjdp{ 30756780Sjdp const Elf_Rel *rellim; 30856780Sjdp const Elf_Rel *rel; 30948205Sjdp 31056780Sjdp if (obj->jmpslots_done) 31156780Sjdp return 0; 31256780Sjdp rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); 31356780Sjdp for (rel = obj->pltrel; rel < rellim; rel++) { 31485004Sdfr Elf_Addr *where, target; 31556780Sjdp const Elf_Sym *def; 31656780Sjdp const Obj_Entry *defobj; 31756780Sjdp 318228435Skib switch (ELF_R_TYPE(rel->r_info)) { 319228435Skib case R_386_JMP_SLOT: 320228435Skib where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 321233231Skib def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, 322233231Skib SYMLOOK_IN_PLT | flags, NULL, lockstate); 323228435Skib if (def == NULL) 324228435Skib return (-1); 325228435Skib if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 326228435Skib obj->gnu_ifunc = true; 327228435Skib continue; 328228435Skib } 329228435Skib target = (Elf_Addr)(defobj->relocbase + def->st_value); 330228435Skib reloc_jmpslot(where, target, defobj, obj, rel); 331228435Skib break; 332228435Skib 333228435Skib case R_386_IRELATIVE: 334228435Skib break; 335228435Skib 336228435Skib default: 337228435Skib _rtld_error("Unknown relocation type %x in PLT", 338228435Skib ELF_R_TYPE(rel->r_info)); 339228435Skib return (-1); 340228435Skib } 34148205Sjdp } 342228435Skib 34356780Sjdp obj->jmpslots_done = true; 34438816Sdfr return 0; 34538816Sdfr} 346133063Sdfr 347228435Skibint 348228435Skibreloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate) 349228435Skib{ 350228435Skib const Elf_Rel *rellim; 351228435Skib const Elf_Rel *rel; 352228435Skib Elf_Addr *where, target; 353228435Skib 354228503Skib if (!obj->irelative) 355228503Skib return (0); 356228435Skib rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); 357228435Skib for (rel = obj->pltrel; rel < rellim; rel++) { 358228435Skib switch (ELF_R_TYPE(rel->r_info)) { 359228435Skib case R_386_IRELATIVE: 360228435Skib where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 361228503Skib lock_release(rtld_bind_lock, lockstate); 362309061Skib target = call_ifunc_resolver(obj->relocbase + *where); 363228503Skib wlock_acquire(rtld_bind_lock, lockstate); 364228435Skib *where = target; 365228435Skib break; 366228435Skib } 367228435Skib } 368228503Skib obj->irelative = false; 369228435Skib return (0); 370228435Skib} 371228435Skib 372228435Skibint 373233231Skibreloc_gnu_ifunc(Obj_Entry *obj, int flags, RtldLockState *lockstate) 374228435Skib{ 375228435Skib const Elf_Rel *rellim; 376228435Skib const Elf_Rel *rel; 377228435Skib 378228435Skib if (!obj->gnu_ifunc) 379228435Skib return (0); 380228435Skib rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); 381228435Skib for (rel = obj->pltrel; rel < rellim; rel++) { 382228435Skib Elf_Addr *where, target; 383228435Skib const Elf_Sym *def; 384228435Skib const Obj_Entry *defobj; 385228435Skib 386228435Skib switch (ELF_R_TYPE(rel->r_info)) { 387228435Skib case R_386_JMP_SLOT: 388228435Skib where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 389233231Skib def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, 390233231Skib SYMLOOK_IN_PLT | flags, NULL, lockstate); 391228435Skib if (def == NULL) 392228435Skib return (-1); 393228435Skib if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) 394228435Skib continue; 395228503Skib lock_release(rtld_bind_lock, lockstate); 396228435Skib target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); 397228503Skib wlock_acquire(rtld_bind_lock, lockstate); 398228435Skib reloc_jmpslot(where, target, defobj, obj, rel); 399228435Skib break; 400228435Skib } 401228435Skib } 402228435Skib 403228435Skib obj->gnu_ifunc = false; 404228435Skib return (0); 405228435Skib} 406228435Skib 407309061Skibuint32_t cpu_feature, cpu_feature2, cpu_stdext_feature, cpu_stdext_feature2; 408309061Skib 409309061Skibstatic void 410309061Skibrtld_cpuid_count(int idx, int cnt, u_int *p) 411309061Skib{ 412309061Skib 413309061Skib __asm __volatile( 414309061Skib " pushl %%ebx\n" 415309061Skib " cpuid\n" 416309061Skib " movl %%ebx,%1\n" 417309061Skib " popl %%ebx\n" 418309061Skib : "=a" (p[0]), "=r" (p[1]), "=c" (p[2]), "=d" (p[3]) 419309061Skib : "0" (idx), "2" (cnt)); 420309061Skib} 421309061Skib 422133063Sdfrvoid 423309061Skibifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 424309061Skib{ 425309061Skib u_int p[4], cpu_high; 426309061Skib int cpuid_supported; 427309061Skib 428309061Skib __asm __volatile( 429309061Skib " pushfl\n" 430309061Skib " popl %%eax\n" 431309061Skib " movl %%eax,%%ecx\n" 432309061Skib " xorl $0x200000,%%eax\n" 433309061Skib " pushl %%eax\n" 434309061Skib " popfl\n" 435309061Skib " pushfl\n" 436309061Skib " popl %%eax\n" 437309061Skib " xorl %%eax,%%ecx\n" 438309061Skib " je 1f\n" 439309061Skib " movl $1,%0\n" 440309061Skib " jmp 2f\n" 441309061Skib "1: movl $0,%0\n" 442309061Skib "2:\n" 443309061Skib : "=r" (cpuid_supported) : : "eax", "ecx"); 444309061Skib if (!cpuid_supported) 445309061Skib return; 446309061Skib 447309061Skib rtld_cpuid_count(1, 0, p); 448309061Skib cpu_feature = p[3]; 449309061Skib cpu_feature2 = p[2]; 450309061Skib rtld_cpuid_count(0, 0, p); 451309061Skib cpu_high = p[0]; 452309061Skib if (cpu_high >= 7) { 453309061Skib rtld_cpuid_count(7, 0, p); 454309061Skib cpu_stdext_feature = p[1]; 455309061Skib cpu_stdext_feature2 = p[2]; 456309061Skib } 457309061Skib} 458309061Skib 459309061Skibvoid 460331206Smariuspre_init(void) 461331206Smarius{ 462331206Smarius 463331206Smarius} 464331206Smarius 465331206Smariusvoid 466133063Sdfrallocate_initial_tls(Obj_Entry *objs) 467133063Sdfr{ 468133063Sdfr void* tls; 469133063Sdfr 470133063Sdfr /* 471133063Sdfr * Fix the size of the static TLS block by using the maximum 472133063Sdfr * offset allocated so far and adding a bit for dynamic modules to 473133063Sdfr * use. 474133063Sdfr */ 475133063Sdfr tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; 476157198Sdavidxu tls = allocate_tls(objs, NULL, 3*sizeof(Elf_Addr), sizeof(Elf_Addr)); 477147673Speter i386_set_gsbase(tls); 478133063Sdfr} 479133063Sdfr 480133063Sdfr/* GNU ABI */ 481133063Sdfr__attribute__((__regparm__(1))) 482133063Sdfrvoid *___tls_get_addr(tls_index *ti) 483133063Sdfr{ 484133063Sdfr Elf_Addr** segbase; 485133063Sdfr 486133063Sdfr __asm __volatile("movl %%gs:0, %0" : "=r" (segbase)); 487133063Sdfr 488133063Sdfr return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); 489133063Sdfr} 490133063Sdfr 491133063Sdfr/* Sun ABI */ 492133063Sdfrvoid *__tls_get_addr(tls_index *ti) 493133063Sdfr{ 494133063Sdfr Elf_Addr** segbase; 495133063Sdfr 496133063Sdfr __asm __volatile("movl %%gs:0, %0" : "=r" (segbase)); 497133063Sdfr 498133063Sdfr return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); 499133063Sdfr} 500