/* * Process the special R_xxx_COPY relocations in the main program. These * copy data from a shared object into a region in the main program's BSS * segment. * * Returns 0 on success, -1 on failure. */ int _rtld_do_copy_relocations(const Obj_Entry *dstobj) { #ifndef RTLD_INHIBIT_COPY_RELOCS /* COPY relocations are invalid elsewhere */ assert(!dstobj->isdynamic); if (dstobj->rel != NULL) { const Elf_Rel *rel; for (rel = dstobj->rel; rel < dstobj->rellim; ++rel) { if (ELF_R_TYPE(rel->r_info) == R_TYPE(COPY)) { Elf_Rela ourrela; ourrela.r_info = rel->r_info; ourrela.r_offset = rel->r_offset; ourrela.r_addend = 0; if (_rtld_do_copy_relocation(dstobj, &ourrela) < 0) return (-1); } } } if (dstobj->rela != NULL) { const Elf_Rela *rela; for (rela = dstobj->rela; rela < dstobj->relalim; ++rela) { if (ELF_R_TYPE(rela->r_info) == R_TYPE(COPY)) { if (_rtld_do_copy_relocation(dstobj, rela) < 0) return (-1); } } } #endif /* RTLD_INHIBIT_COPY_RELOCS */ return (0); }
int kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data, bool isrela, bool local) { Elf_Addr *where; uintptr_t addr, tmp; int rtype, symnum; const Elf_Rela *rela; if (!isrela) { printf("kobj_reloc: support only RELA relocations\n"); return -1; } rela = data; where = (Elf_Addr *)(relocbase + rela->r_offset); symnum = ELF_R_SYM(rela->r_info); rtype = ELF_R_TYPE(rela->r_info); switch (rtype) { case R_TYPE(NONE): break; case R_TYPE(PC32): addr = kobj_sym_lookup(ko, symnum); if (addr == 0) return -1; tmp = (Elf_Addr)(addr + rela->r_addend) - (Elf_Addr)where; if (*where != tmp) *where = tmp; break; case R_TYPE(32): case R_TYPE(GLOB_DAT): addr = kobj_sym_lookup(ko, symnum); if (addr == 0) return -1; tmp = (Elf_Addr)(addr + *where + rela->r_addend); *where = tmp; break; case R_TYPE(RELATIVE): *where += (Elf_Addr)(relocbase + rela->r_addend); break; default: printf("kobj_reloc: unexpected relocation type %d\n", (int)rtype); return -1; } return 0; }
static int _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel, Elf_Addr *tp) { Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset); Elf_Addr new_value; const Elf_Sym *def; const Obj_Entry *defobj; unsigned long info = rel->r_info; assert(ELF_R_TYPE(info) == R_TYPE(JUMP_SLOT)); def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); if (__predict_false(def == NULL)) return -1; if (__predict_false(def == &_rtld_sym_zero)) return 0; if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { if (tp == NULL) return 0; new_value = _rtld_resolve_ifunc(defobj, def); } else { new_value = (Elf_Addr)(defobj->relocbase + def->st_value); } rdbg(("bind now/fixup in %s --> old=%p new=%p", defobj->strtab + def->st_name, (void *)*where, (void *)new_value)); if (*where != new_value) *where = new_value; if (tp) *tp = new_value; return 0; }
static inline int _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp) { Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); Elf_Addr new_value; const Elf_Sym *def; const Obj_Entry *defobj; unsigned long info = rela->r_info; assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); if (__predict_false(def == NULL)) return -1; if (__predict_false(def == &_rtld_sym_zero)) return 0; new_value = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend); rdbg(("bind now/fixup in %s --> old=%p new=%p", defobj->strtab + def->st_name, (void *)*where, (void *)new_value)); if (*where != new_value) *where = new_value; if (tp) *tp = new_value - rela->r_addend; return 0; }
int _rtld_relocate_plt_lazy(const Obj_Entry *obj) { if (!obj->relocbase) return 0; for (const Elf_Rel *rel = obj->pltrel; rel < obj->pltrellim; rel++) { Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset); assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JUMP_SLOT)); /* Just relocate the GOT slots pointing into the PLT */ *where += (Elf_Addr)obj->relocbase; rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); } return 0; }
int _rtld_relocate_plt_lazy(const Obj_Entry *obj) { const Elf_Rela *rela; if (!obj->relocbase) return 0; for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); /* Just relocate the GOT slots pointing into the PLT */ *where += (Elf_Addr)obj->relocbase; rdbg(("lazy fixup pltgot %p in %s --> %p", where, obj->path, (void *)*where)); } return 0; }
void _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) { const Elf_Rel *rel = 0, *rellim; Elf_Addr relsz = 0; const Elf_Sym *symtab = NULL, *sym; Elf_Addr *where; Elf_Addr *got = NULL; Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0; size_t i; for (; dynp->d_tag != DT_NULL; dynp++) { switch (dynp->d_tag) { case DT_REL: rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); break; case DT_RELSZ: relsz = dynp->d_un.d_val; break; case DT_SYMTAB: symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr); break; case DT_PLTGOT: got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr); break; case DT_MIPS_LOCAL_GOTNO: local_gotno = dynp->d_un.d_val; break; case DT_MIPS_SYMTABNO: symtabno = dynp->d_un.d_val; break; case DT_MIPS_GOTSYM: gotsym = dynp->d_un.d_val; break; } } i = (got[1] & GOT1_MASK) ? 2 : 1; /* Relocate the local GOT entries */ got += i; for (; i < local_gotno; i++) { *got++ += relocbase; } sym = symtab + gotsym; /* Now do the global GOT entries */ for (i = gotsym; i < symtabno; i++) { *got = sym->st_value + relocbase; ++sym; ++got; } rellim = (const Elf_Rel *)((caddr_t)rel + relsz); for (; rel < rellim; rel++) { Elf_Word r_symndx, r_type; where = (void *)(relocbase + rel->r_offset); r_symndx = ELF_R_SYM(rel->r_info); r_type = ELF_R_TYPE(rel->r_info); switch (r_type & 0xff) { case R_TYPE(REL32): { const size_t rlen = ELF_R_NXTTYPE_64_P(r_type) ? sizeof(Elf_Sxword) : sizeof(Elf_Sword); Elf_Sxword old = load_ptr(where, rlen); Elf_Sxword val = old; #ifdef __mips_n64 assert(r_type == R_TYPE(REL32) || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8))); #endif assert(r_symndx < gotsym); sym = symtab + r_symndx; assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL); val += relocbase; store_ptr(where, val, sizeof(Elf_Sword)); dbg("REL32/L(%p) %p -> %p in <self>", where, (void *)old, (void *)val); store_ptr(where, val, rlen); break; } case R_TYPE(GPREL32): case R_TYPE(NONE): break; default: abort(); break; } } }
/* * 1. _gp_disp symbol are not considered in this file. * 2. There is a local/external column; * local corresponds to (STB_LOCAL & STT_SECTION) and * all others are external. Because if the type of a * symbol is STT_SECTION, it must be STB_LOCAL. Thus * just consider symtype here. */ bool rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, const Elf_Rel* rel, const rtems_rtl_obj_sect_t* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { Elf_Addr *where; Elf_Word tmp; Elf_Word addend = (Elf_Word)0; Elf_Word local = 0; uint32_t t; static Elf_Addr *where_hi16; static Elf_Addr ahl; where = (Elf_Addr *)(sect->base + rel->r_offset); addend = *where; if (syminfo == STT_SECTION) local = 1; switch (ELF_R_TYPE(rel->r_info)) { case R_TYPE(NONE): break; case R_TYPE(16): tmp = addend & 0xffff; if ((tmp & 0x8000) == 0x8000) tmp |= 0xffff0000; /* Sign extend */ tmp = symvalue + (int)tmp; if ((tmp & 0xffff0000) != 0) { printf("R_MIPS_16 Overflow\n"); return false; } *where = (tmp & 0xffff) | (*where & 0xffff0000); if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: R_MIPS_16 %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(32): tmp = symvalue + addend; if (addend != tmp) *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: R_MIPS_32 %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(26): addend &= 0x03ffffff; addend <<= 2; if (local == 1) { /* STB_LOCAL and STT_SECTION */ tmp = symvalue + (((Elf_Addr)where & 0xf0000000) | addend); tmp >>= 2; } else { /* external */
int _rtld_relocate_nonplt_objects(Obj_Entry *obj) { for (const Elf_Rela *rela = obj->rela; rela < obj->relalim; rela++) { Elf_Addr *where; const Elf_Sym *def; const Obj_Entry *defobj; unsigned long symnum; Elf_Addr addend; where = (Elf_Addr *)(obj->relocbase + rela->r_offset); symnum = ELF_R_SYM(rela->r_info); addend = rela->r_addend; switch (ELF_R_TYPE(rela->r_info)) { case R_TYPE(NONE): break; case R_TYPE(ABS64): /* word B + S + A */ case R_TYPE(GLOB_DAT): /* word B + S */ def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; *where = addend + (Elf_Addr)defobj->relocbase + def->st_value; rdbg(("ABS64/GLOB_DAT %s in %s --> %p @ %p in %s", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)tmp, where, defobj->path)); break; case R_TYPE(RELATIVE): /* word B + A */ *where = addend + (Elf_Addr)obj->relocbase; rdbg(("RELATIVE in %s --> %p", obj->path, (void *)tmp)); break; case R_TYPE(COPY): /* * These are deferred until all other relocations have * been done. All we do here is make sure that the * COPY relocation is not in a shared library. They * are allowed only in executable files. */ if (obj->isdynamic) { _rtld_error( "%s: Unexpected R_COPY relocation in shared library", obj->path); return -1; } rdbg(("COPY (avoid in main)")); break; case R_TLS_TYPE(TLS_DTPREL): def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; *where = addend + (Elf_Addr)(def->st_value); rdbg(("TLS_DTPOFF32 %s in %s --> %p", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)tmp)); break; case R_TLS_TYPE(TLS_DTPMOD): def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; *where = (Elf_Addr)(defobj->tlsindex); rdbg(("TLS_DTPMOD %s in %s --> %p", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)tmp)); break; case R_TLS_TYPE(TLS_TPREL): def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; if (!defobj->tls_done && _rtld_tls_offset_allocate(obj)) return -1; *where = (Elf_Addr)def->st_value + defobj->tlsoffset + sizeof(struct tls_tcb); rdbg(("TLS_TPOFF32 %s in %s --> %p", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)tmp)); break; default: rdbg(("sym = %lu, type = %lu, offset = %p, " "contents = %p, symbol = %s", symnum, (u_long)ELF_R_TYPE(rela->r_info), (void *)rela->r_offset, *where, obj->strtab + obj->symtab[symnum].st_name)); _rtld_error("%s: Unsupported relocation type %ld " "in non-PLT relocations", obj->path, (u_long) ELF_R_TYPE(rela->r_info)); return -1; } } return 0; }
int _rtld_relocate_nonplt_objects(Obj_Entry *obj) { const Elf_Rel *rel; for (rel = obj->rel; rel < obj->rellim; rel++) { Elf_Addr *where; const Elf_Sym *def; const Obj_Entry *defobj; Elf_Addr tmp; unsigned long symnum; where = (Elf_Addr *)(obj->relocbase + rel->r_offset); symnum = ELF_R_SYM(rel->r_info); switch (ELF_R_TYPE(rel->r_info)) { case R_TYPE(NONE): break; #if 1 /* XXX should not occur */ case R_TYPE(PC24): { /* word32 S - P + A */ Elf32_Sword addend; /* * Extract addend and sign-extend if needed. */ addend = *where; if (addend & 0x00800000) addend |= 0xff000000; def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; tmp = (Elf_Addr)obj->relocbase + def->st_value - (Elf_Addr)where + (addend << 2); if ((tmp & 0xfe000000) != 0xfe000000 && (tmp & 0xfe000000) != 0) { _rtld_error( "%s: R_ARM_PC24 relocation @ %p to %s failed " "(displacement %ld (%#lx) out of range)", obj->path, where, obj->strtab + obj->symtab[symnum].st_name, (long) tmp, (long) tmp); return -1; } tmp >>= 2; *where = (*where & 0xff000000) | (tmp & 0x00ffffff); rdbg(("PC24 %s in %s --> %p @ %p in %s", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)*where, where, defobj->path)); break; } #endif case R_TYPE(ABS32): /* word32 B + S + A */ case R_TYPE(GLOB_DAT): /* word32 B + S */ def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; if (__predict_true(RELOC_ALIGNED_P(where))) { tmp = *where + (Elf_Addr)defobj->relocbase + def->st_value; /* Set the Thumb bit, if needed. */ if (ELF_ST_TYPE(def->st_info) == STT_ARM_TFUNC) tmp |= 1; *where = tmp; } else { tmp = load_ptr(where) + (Elf_Addr)defobj->relocbase + def->st_value; /* Set the Thumb bit, if needed. */ if (ELF_ST_TYPE(def->st_info) == STT_ARM_TFUNC) tmp |= 1; store_ptr(where, tmp); } rdbg(("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)tmp, where, defobj->path)); break; case R_TYPE(RELATIVE): /* word32 B + A */ if (__predict_true(RELOC_ALIGNED_P(where))) { tmp = *where + (Elf_Addr)obj->relocbase; *where = tmp; } else { tmp = load_ptr(where) + (Elf_Addr)obj->relocbase; store_ptr(where, tmp); } rdbg(("RELATIVE in %s --> %p", obj->path, (void *)tmp)); break; case R_TYPE(COPY): /* * These are deferred until all other relocations have * been done. All we do here is make sure that the * COPY relocation is not in a shared library. They * are allowed only in executable files. */ if (obj->isdynamic) { _rtld_error( "%s: Unexpected R_COPY relocation in shared library", obj->path); return -1; } rdbg(("COPY (avoid in main)")); break; #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) case R_TYPE(TLS_DTPOFF32): def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; tmp = (Elf_Addr)(def->st_value); if (__predict_true(RELOC_ALIGNED_P(where))) *where = tmp; else store_ptr(where, tmp); rdbg(("TLS_DTPOFF32 %s in %s --> %p", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)tmp)); break; case R_TYPE(TLS_DTPMOD32): def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; tmp = (Elf_Addr)(defobj->tlsindex); if (__predict_true(RELOC_ALIGNED_P(where))) *where = tmp; else store_ptr(where, tmp); rdbg(("TLS_DTPMOD32 %s in %s --> %p", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)tmp)); break; case R_TYPE(TLS_TPOFF32): def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; if (!defobj->tls_done && _rtld_tls_offset_allocate(obj)) return -1; tmp = (Elf_Addr)def->st_value + defobj->tlsoffset + sizeof(struct tls_tcb); if (__predict_true(RELOC_ALIGNED_P(where))) *where = tmp; else store_ptr(where, tmp); rdbg(("TLS_TPOFF32 %s in %s --> %p", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)tmp)); break; #endif default: rdbg(("sym = %lu, type = %lu, offset = %p, " "contents = %p, symbol = %s", symnum, (u_long)ELF_R_TYPE(rel->r_info), (void *)rel->r_offset, (void *)load_ptr(where), obj->strtab + obj->symtab[symnum].st_name)); _rtld_error("%s: Unsupported relocation type %ld " "in non-PLT relocations", obj->path, (u_long) ELF_R_TYPE(rel->r_info)); return -1; } } return 0; }
int _rtld_relocate_nonplt_objects(Obj_Entry *obj) { const Elf_Rela *rela; for (rela = obj->rela; rela < obj->relalim; rela++) { Elf_Addr *where; const Elf_Sym *def; const Obj_Entry *defobj; Elf_Addr tmp; unsigned long symnum; where = (Elf_Addr *)(obj->relocbase + rela->r_offset); symnum = ELF_R_SYM(rela->r_info); switch (ELF_R_TYPE(rela->r_info)) { case R_TYPE(NONE): break; case R_TYPE(32): /* word32 S + A */ case R_TYPE(GLOB_DAT): /* word32 S + A */ def = _rtld_find_symdef(symnum, obj, &defobj, false); if (def == NULL) return -1; tmp = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend); if (*where != tmp) *where = tmp; rdbg(("32/GLOB_DAT %s in %s --> %p in %s", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)*where, defobj->path)); break; case R_TYPE(RELATIVE): /* word32 B + A */ tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); if (*where != tmp) *where = tmp; rdbg(("RELATIVE in %s --> %p", obj->path, (void *)*where)); break; case R_TYPE(COPY): /* * These are deferred until all other relocations have * been done. All we do here is make sure that the * COPY relocation is not in a shared library. They * are allowed only in executable files. */ if (obj->isdynamic) { _rtld_error( "%s: Unexpected R_COPY relocation in shared library", obj->path); return -1; } rdbg(("COPY (avoid in main)")); break; default: rdbg(("sym = %lu, type = %lu, offset = %p, " "addend = %p, contents = %p, symbol = %s", symnum, (u_long)ELF_R_TYPE(rela->r_info), (void *)rela->r_offset, (void *)rela->r_addend, (void *)*where, obj->strtab + obj->symtab[symnum].st_name)); _rtld_error("%s: Unsupported relocation type %ld " "in non-PLT relocations", obj->path, (u_long) ELF_R_TYPE(rela->r_info)); return -1; } } return 0; }
bool rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, const Elf_Rel* rel, const rtems_rtl_obj_sect_t* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { Elf_Addr target = 0; Elf_Addr* where; Elf_Addr tmp; where = (Elf_Addr *)(sect->base + rel->r_offset); switch (ELF_R_TYPE(rel->r_info)) { case R_TYPE(NONE): break; case R_TYPE(PC32): target = (Elf_Addr) symvalue; *where += target - (Elf_Addr)where; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: reloc PC32 in %s --> %p (%p @ %p) in %s\n", sect->name, (void*) symvalue, (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(GOT32): case R_TYPE(32): case R_TYPE(GLOB_DAT): target = (Elf_Addr) symvalue; tmp = target + *where; if (*where != tmp) *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: reloc 32/GLOB_DAT in %s --> %p @ %p in %s\n", sect->name, (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(RELATIVE): *where += (Elf_Addr)sect->base; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: reloc RELATIVE in %s --> %p @ %p\n", rtems_rtl_obj_oname (obj), (void *)*where, where); break; case R_TYPE(COPY): printf ("rtl: reloc COPY (please report)\n"); break; default: printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " "contents = %p\n", ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), (void *)rel->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, "%s: Unsupported relocation type %ld " "in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); return false; } return true; }
void _dlstart_c(size_t *sp, size_t *dynv) { size_t i, aux[AUX_CNT], dyn[DYN_CNT]; size_t *rel, rel_size, base; int argc = *sp; char **argv = (void *)(sp+1); for (i=argc+1; argv[i]; i++); size_t *auxv = (void *)(argv+i+1); for (i=0; i<AUX_CNT; i++) aux[i] = 0; for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT) aux[auxv[i]] = auxv[i+1]; #if DL_FDPIC struct fdpic_loadseg *segs, fakeseg; size_t j; if (dynv) { /* crt_arch.h entry point asm is responsible for reserving * space and moving the extra fdpic arguments to the stack * vector where they are easily accessible from C. */ segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->segs; } else { /* If dynv is null, the entry point was started from loader * that is not fdpic-aware. We can assume normal fixed- * displacement ELF loading was performed, but when ldso was * run as a command, finding the Ehdr is a heursitic: we * have to assume Phdrs start in the first 4k of the file. */ base = aux[AT_BASE]; if (!base) base = aux[AT_PHDR] & -4096; segs = &fakeseg; segs[0].addr = base; segs[0].p_vaddr = 0; segs[0].p_memsz = -1; Ehdr *eh = (void *)base; Phdr *ph = (void *)(base + eh->e_phoff); size_t phnum = eh->e_phnum; size_t phent = eh->e_phentsize; while (phnum-- && ph->p_type != PT_DYNAMIC) ph = (void *)((size_t)ph + phent); dynv = (void *)(base + ph->p_vaddr); } #endif for (i=0; i<DYN_CNT; i++) dyn[i] = 0; for (i=0; dynv[i]; i+=2) if (dynv[i]<DYN_CNT) dyn[dynv[i]] = dynv[i+1]; #if DL_FDPIC for (i=0; i<DYN_CNT; i++) { if (i==DT_RELASZ || i==DT_RELSZ) continue; if (!dyn[i]) continue; for (j=0; dyn[i]-segs[j].p_vaddr >= segs[j].p_memsz; j++); dyn[i] += segs[j].addr - segs[j].p_vaddr; } base = 0; const Sym *syms = (void *)dyn[DT_SYMTAB]; rel = (void *)dyn[DT_RELA]; rel_size = dyn[DT_RELASZ]; for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) { if (!IS_RELATIVE(rel[1], syms)) continue; for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++); size_t *rel_addr = (void *) (rel[0] + segs[j].addr - segs[j].p_vaddr); if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) { *rel_addr += segs[rel_addr[1]].addr - segs[rel_addr[1]].p_vaddr + syms[R_SYM(rel[1])].st_value; rel_addr[1] = dyn[DT_PLTGOT]; } else { size_t val = syms[R_SYM(rel[1])].st_value; for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++); *rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val; } } #else /* If the dynamic linker is invoked as a command, its load * address is not available in the aux vector. Instead, compute * the load address as the difference between &_DYNAMIC and the * virtual address in the PT_DYNAMIC program header. */ base = aux[AT_BASE]; if (!base) { size_t phnum = aux[AT_PHNUM]; size_t phentsize = aux[AT_PHENT]; Phdr *ph = (void *)aux[AT_PHDR]; for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) { if (ph->p_type == PT_DYNAMIC) { base = (size_t)dynv - ph->p_vaddr; break; } } } /* MIPS uses an ugly packed form for GOT relocations. Since we * can't make function calls yet and the code is tiny anyway, * it's simply inlined here. */ if (NEED_MIPS_GOT_RELOCS) { size_t local_cnt = 0; size_t *got = (void *)(base + dyn[DT_PLTGOT]); for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO) local_cnt = dynv[i+1]; for (i=0; i<local_cnt; i++) got[i] += base; } rel = (void *)(base+dyn[DT_REL]); rel_size = dyn[DT_RELSZ]; for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) { if (!IS_RELATIVE(rel[1], 0)) continue; size_t *rel_addr = (void *)(base + rel[0]); *rel_addr += base; } rel = (void *)(base+dyn[DT_RELA]); rel_size = dyn[DT_RELASZ]; for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) { if (!IS_RELATIVE(rel[1], 0)) continue; size_t *rel_addr = (void *)(base + rel[0]); *rel_addr = base + rel[2]; } #endif stage2_func dls2; GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]); dls2((void *)base, sp); }
int reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, RtldLockState *lockstate) { const Elf_Rel *rel; const Elf_Rel *rellim; Elf_Addr *got = obj->pltgot; const Elf_Sym *sym, *def; const Obj_Entry *defobj; Elf_Word i; #ifdef SUPPORT_OLD_BROKEN_LD int broken; #endif /* The relocation for the dynamic loader has already been done. */ if (obj == obj_rtld) return (0); if ((flags & SYMLOOK_IFUNC) != 0) /* XXX not implemented */ return (0); #ifdef SUPPORT_OLD_BROKEN_LD broken = 0; sym = obj->symtab; for (i = 1; i < 12; i++) if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE)) broken = 1; dbg("%s: broken=%d", obj->path, broken); #endif i = (got[1] & GOT1_MASK) ? 2 : 1; /* Relocate the local GOT entries */ got += i; dbg("got:%p for %d entries adding %p", got, obj->local_gotno, obj->relocbase); for (; i < obj->local_gotno; i++) { *got += (Elf_Addr)obj->relocbase; got++; } sym = obj->symtab + obj->gotsym; dbg("got:%p for %d entries", got, obj->symtabno); /* Now do the global GOT entries */ for (i = obj->gotsym; i < obj->symtabno; i++) { dbg(" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym, sym->st_name + obj->strtab, (u_long) *got); #ifdef SUPPORT_OLD_BROKEN_LD if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && broken && sym->st_shndx == SHN_UNDEF) { /* * XXX DANGER WILL ROBINSON! * You might think this is stupid, as it intentionally * defeats lazy binding -- and you'd be right. * Unfortunately, for lazy binding to work right, we * need to a way to force the GOT slots used for * function pointers to be resolved immediately. This * is supposed to be done automatically by the linker, * by not outputting a PLT slot and setting st_value * to 0 if there are non-PLT references, but older * versions of GNU ld do not do this. */ def = find_symdef(i, obj, &defobj, flags, NULL, lockstate); if (def == NULL) return -1; *got = def->st_value + (Elf_Addr)defobj->relocbase; } else #endif if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) { /* * If there are non-PLT references to the function, * st_value should be 0, forcing us to resolve the * address immediately. * * XXX DANGER WILL ROBINSON! * The linker is not outputting PLT slots for calls to * functions that are defined in the same shared * library. This is a bug, because it can screw up * link ordering rules if the symbol is defined in * more than one module. For now, if there is a * definition, we fail the test above and force a full * symbol lookup. This means that all intra-module * calls are bound immediately. - mycroft, 2003/09/24 */ *got = sym->st_value + (Elf_Addr)obj->relocbase; if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) { dbg("Warning2, i:%d maps to relocbase address:%p", i, obj->relocbase); } } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) { /* Symbols with index SHN_ABS are not relocated. */ if (sym->st_shndx != SHN_ABS) { *got = sym->st_value + (Elf_Addr)obj->relocbase; if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) { dbg("Warning3, i:%d maps to relocbase address:%p", i, obj->relocbase); } } } else { /* TODO: add cache here */ def = find_symdef(i, obj, &defobj, flags, NULL, lockstate); if (def == NULL) { dbg("Warning4, can't find symbole %d", i); return -1; } *got = def->st_value + (Elf_Addr)defobj->relocbase; if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) { dbg("Warning4, i:%d maps to relocbase address:%p", i, obj->relocbase); dbg("via first obj symbol %s", obj->strtab + obj->symtab[i].st_name); dbg("found in obj %p:%s", defobj, defobj->path); } } dbg(" --> now %lx", (u_long) *got); ++sym; ++got; } got = obj->pltgot; rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize); for (rel = obj->rel; rel < rellim; rel++) { Elf_Word r_symndx, r_type; void *where; where = obj->relocbase + rel->r_offset; r_symndx = ELF_R_SYM(rel->r_info); r_type = ELF_R_TYPE(rel->r_info); switch (r_type & 0xff) { case R_TYPE(NONE): break; case R_TYPE(REL32): { /* 32-bit PC-relative reference */ const size_t rlen = ELF_R_NXTTYPE_64_P(r_type) ? sizeof(Elf_Sxword) : sizeof(Elf_Sword); Elf_Sxword old = load_ptr(where, rlen); Elf_Sxword val = old; def = obj->symtab + r_symndx; if (r_symndx >= obj->gotsym) { val += got[obj->local_gotno + r_symndx - obj->gotsym]; dbg("REL32/G(%p) %p --> %p (%s) in %s", where, (void *)old, (void *)val, obj->strtab + def->st_name, obj->path); } else { /* * XXX: ABI DIFFERENCE! * * Old NetBSD binutils would generate shared * libs with section-relative relocations being * already adjusted for the start address of * the section. * * New binutils, OTOH, generate shared libs * with the same relocations being based at * zero, so we need to add in the start address * of the section. * * --rkb, Oct 6, 2001 */ if (def->st_info == ELF_ST_INFO(STB_LOCAL, STT_SECTION) #ifdef SUPPORT_OLD_BROKEN_LD && !broken #endif ) val += (Elf_Addr)def->st_value; val += (Elf_Addr)obj->relocbase; dbg("REL32/L(%p) %p -> %p (%s) in %s", where, (void *)old, (void *)val, obj->strtab + def->st_name, obj->path); } store_ptr(where, val, rlen); break; } #ifdef __mips_n64 case R_TYPE(TLS_DTPMOD64): #else case R_TYPE(TLS_DTPMOD32): #endif { const size_t rlen = sizeof(Elf_Addr); Elf_Addr old = load_ptr(where, rlen); Elf_Addr val = old; def = find_symdef(r_symndx, obj, &defobj, flags, NULL, lockstate); if (def == NULL) return -1; val += (Elf_Addr)defobj->tlsindex; store_ptr(where, val, rlen); dbg("DTPMOD %s in %s %p --> %p in %s", obj->strtab + obj->symtab[r_symndx].st_name, obj->path, (void *)old, (void*)val, defobj->path); break; } #ifdef __mips_n64 case R_TYPE(TLS_DTPREL64): #else case R_TYPE(TLS_DTPREL32): #endif { const size_t rlen = sizeof(Elf_Addr); Elf_Addr old = load_ptr(where, rlen); Elf_Addr val = old; def = find_symdef(r_symndx, obj, &defobj, flags, NULL, lockstate); if (def == NULL) return -1; if (!defobj->tls_done && allocate_tls_offset(obj)) return -1; val += (Elf_Addr)def->st_value - TLS_DTP_OFFSET; store_ptr(where, val, rlen); dbg("DTPREL %s in %s %p --> %p in %s", obj->strtab + obj->symtab[r_symndx].st_name, obj->path, (void*)old, (void *)val, defobj->path); break; } #ifdef __mips_n64 case R_TYPE(TLS_TPREL64): #else case R_TYPE(TLS_TPREL32): #endif { const size_t rlen = sizeof(Elf_Addr); Elf_Addr old = load_ptr(where, rlen); Elf_Addr val = old; def = find_symdef(r_symndx, obj, &defobj, flags, NULL, lockstate); if (def == NULL) return -1; if (!defobj->tls_done && allocate_tls_offset(obj)) return -1; val += (Elf_Addr)(def->st_value + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE); store_ptr(where, val, rlen); dbg("TPREL %s in %s %p --> %p in %s", obj->strtab + obj->symtab[r_symndx].st_name, obj->path, (void*)old, (void *)val, defobj->path); break; } default: dbg("sym = %lu, type = %lu, offset = %p, " "contents = %p, symbol = %s", (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info), (void *)rel->r_offset, (void *)load_ptr(where, sizeof(Elf_Sword)), obj->strtab + obj->symtab[r_symndx].st_name); _rtld_error("%s: Unsupported relocation type %ld " "in non-PLT relocations", obj->path, (u_long) ELF_R_TYPE(rel->r_info)); return -1; } } return 0; }
bool rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, const Elf_Rela* rela, const rtems_rtl_obj_sect_t* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { Elf_Addr* where; Elf_Word tmp; uint32_t mask = 0; uint32_t bits = 0; where = (Elf_Addr *)(sect->base + rela->r_offset); switch (ELF_R_TYPE(rela->r_info)) { case R_TYPE(NONE): break; case R_TYPE(32): /* * value:1; Field: word32; Expression: S + A */ *where = symvalue + rela->r_addend; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: ADDR32 %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(14): /* * value:7; Field: low14*; Expression: (S + A) >> 2 */ case R_TYPE(24): /* * value:2; Field: low24*; Expression: (S + A) >> 2 */ if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) { bits = 14; mask = 0xfffc; } else { bits = 24; mask = 0x3fffffc; } tmp = (symvalue + rela->r_addend) >> 2; if (tmp > ((1<<bits) - 1 )) { printf("Overflow ADDR14/ADDR24\n"); return false; } tmp = *where; tmp &= ~mask; tmp |= (symvalue + rela->r_addend) & mask; *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: ADDR14/ADDR24 %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(16_HA): /* * value:6; Field:half16; Expression: #ha(S+A) */ tmp = symvalue + rela->r_addend; *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff); if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: 16_HA %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(16_HI): /* * value:5; Field:half16; Expression: #hi(S+A) */ *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: 16_HI %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(16_LO): /* * value:4; Field:half16; Expression: #lo(S+A) */ *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: 16_LO %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(REL14): /* * value:11; Field:low14*; Expression:(S+A-P)>>2 */ case R_TYPE(REL24): /* * value:10; Field:low24*; Expression:(S+A-P)>>2 */ if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) { mask = 0x3fffffc; bits = 24; } else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) { mask = 0xfffc; bits = 14; } tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2; if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) || ((Elf_Sword)tmp < -(1<<(bits-1)))) { printf("Overflow REL14/REL24\n"); return false; } tmp = *where; tmp &= ~mask; tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask; *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: REL24/REL14 %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(REL32): /* * value:26; Field:word32*; Expression:S+A-P */ *where = symvalue + rela->r_addend - (Elf_Addr)where; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: REL32 %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; default: printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " "contents = %p\n", ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info), (void *)rela->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, "%s: Unsupported relocation type %ld " "in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rela->r_info)); return false; } return true; }
int _dl_md_reloc(elf_object_t *object, int rel, int relasz) { long i; long numrela; int fails = 0; Elf64_Addr loff; Elf64_Rela *relas; struct load_list *llist; loff = object->obj_base; numrela = object->Dyn.info[relasz] / sizeof(Elf64_Rela); relas = (Elf64_Rela *)(object->Dyn.info[rel]); if (relas == NULL) return(0); /* * unprotect some segments if we need it. * XXX - we unprotect way to much. only the text can have cow * relocations. */ if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) { _dl_mprotect(llist->start, llist->size, llist->prot|PROT_WRITE); } } } for (i = 0; i < numrela; i++, relas++) { Elf64_Addr *r_addr; Elf64_Addr ooff; const Elf64_Sym *sym, *this; const char *symn; r_addr = (Elf64_Addr *)(relas->r_offset + loff); if (ELF64_R_SYM(relas->r_info) == 0xffffffff) continue; sym = object->dyn.symtab; sym += ELF64_R_SYM(relas->r_info); symn = object->dyn.strtab + sym->st_name; this = NULL; switch (ELF64_R_TYPE(relas->r_info)) { case R_TYPE(REFQUAD): ooff = _dl_find_symbol_bysym(object, ELF64_R_SYM(relas->r_info), &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, sym, NULL); if (this == NULL) goto resolve_failed; *r_addr += ooff + this->st_value + relas->r_addend; break; case R_TYPE(RELATIVE): /* * There is a lot of unaligned RELATIVE * relocs generated by gcc in the exception handlers. */ if ((((Elf_Addr) r_addr) & 0x7) != 0) { Elf_Addr tmp; #if 0 _dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr, ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff); #endif _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr)); tmp += loff; _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr)); } else *r_addr += loff; break; case R_TYPE(JMP_SLOT): ooff = _dl_find_symbol(symn, &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object, NULL); if (this == NULL) goto resolve_failed; *r_addr = ooff + this->st_value + relas->r_addend; break; case R_TYPE(GLOB_DAT): ooff = _dl_find_symbol_bysym(object, ELF64_R_SYM(relas->r_info), &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, sym, NULL); if (this == NULL) goto resolve_failed; *r_addr = ooff + this->st_value + relas->r_addend; break; case R_TYPE(NONE): break; default: _dl_printf("%s:" " %s: unsupported relocation '%s' %d at %lx\n", _dl_progname, object->load_name, symn, ELF64_R_TYPE(relas->r_info), r_addr ); _dl_exit(1); } continue; resolve_failed: if (ELF_ST_BIND(sym->st_info) != STB_WEAK) fails++; } __asm __volatile("imb" : : : "memory"); /* reprotect the unprotected segments */ if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) _dl_mprotect(llist->start, llist->size, llist->prot); } } return (fails); }
int _dl_md_reloc(elf_object_t *object, int rel, int relsz) { long i; long numrel; long relrel; int fails = 0; Elf_Addr loff; Elf_Addr prev_value = 0; const Elf_Sym *prev_sym = NULL; Elf_RelA *rels; struct load_list *llist; loff = object->obj_base; numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); relrel = rel == DT_RELA ? object->relacount : 0; rels = (Elf_RelA *)(object->Dyn.info[rel]); if (rels == NULL) return(0); if (relrel > numrel) { _dl_printf("relacount > numrel: %ld > %ld\n", relrel, numrel); _dl_exit(20); } /* * unprotect some segments if we need it. */ if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) _dl_mprotect(llist->start, llist->size, PROT_READ | PROT_WRITE); } } /* tight loop for leading RELATIVE relocs */ for (i = 0; i < relrel; i++, rels++) { Elf_Addr *where; #ifdef DEBUG if (ELF_R_TYPE(rels->r_info) != R_TYPE(RELATIVE)) { _dl_printf("RELACOUNT wrong\n"); _dl_exit(20); } #endif where = (Elf_Addr *)(rels->r_offset + loff); *where = rels->r_addend + loff; } for (; i < numrel; i++, rels++) { Elf_Addr *where, value, ooff, mask; Elf_Word type; const Elf_Sym *sym, *this; const char *symn; type = ELF_R_TYPE(rels->r_info); if (RELOC_ERROR(type)) { _dl_printf("relocation error %d idx %d\n", type, i); _dl_exit(20); } if (type == R_TYPE(NONE)) continue; if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) continue; where = (Elf_Addr *)(rels->r_offset + loff); if (RELOC_USE_ADDEND(type)) value = rels->r_addend; else value = 0; sym = NULL; symn = NULL; if (RELOC_RESOLVE_SYMBOL(type)) { sym = object->dyn.symtab; sym += ELF_R_SYM(rels->r_info); symn = object->dyn.strtab + sym->st_name; if (sym->st_shndx != SHN_UNDEF && ELF_ST_BIND(sym->st_info) == STB_LOCAL) { value += loff; } else if (sym == prev_sym) { value += prev_value; } else { this = NULL; ooff = _dl_find_symbol_bysym(object, ELF_R_SYM(rels->r_info), &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND| ((type == R_TYPE(JUMP_SLOT))? SYM_PLT:SYM_NOTPLT), sym, NULL); if (this == NULL) { resolve_failed: if (ELF_ST_BIND(sym->st_info) != STB_WEAK) fails++; continue; } prev_sym = sym; prev_value = (Elf_Addr)(ooff + this->st_value); value += prev_value; } } if (type == R_TYPE(JUMP_SLOT)) { _dl_reloc_plt(where, value); continue; } if (type == R_TYPE(COPY)) { void *dstaddr = where; const void *srcaddr; const Elf_Sym *dstsym = sym, *srcsym = NULL; Elf_Addr soff; soff = _dl_find_symbol(symn, &srcsym, SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, dstsym, object, NULL); if (srcsym == NULL) goto resolve_failed; srcaddr = (void *)(soff + srcsym->st_value); _dl_bcopy(srcaddr, dstaddr, dstsym->st_size); continue; } if (RELOC_PC_RELATIVE(type)) value -= (Elf_Addr)where; if (RELOC_BASE_RELATIVE(type)) value += loff; mask = RELOC_VALUE_BITMASK(type); value >>= RELOC_VALUE_RIGHTSHIFT(type); value &= mask; if (RELOC_TARGET_SIZE(type) > 32) { *where &= ~mask; *where |= value; } else { Elf32_Addr *where32 = (Elf32_Addr *)where; *where32 &= ~mask; *where32 |= value; } } /* reprotect the unprotected segments */ if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) _dl_mprotect(llist->start, llist->size, llist->prot); } } return (fails); }