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; }
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 int _rtld_do_copy_relocation(const Obj_Entry *dstobj, const Elf_Rela *rela) { void *dstaddr = (void *)(dstobj->relocbase + rela->r_offset); const Elf_Sym *dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); const char *name = dstobj->strtab + dstsym->st_name; unsigned long hash = _rtld_elf_hash(name); size_t size = dstsym->st_size; const void *srcaddr; const Elf_Sym *srcsym = NULL; Obj_Entry *srcobj; for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) if ((srcsym = _rtld_symlook_obj(name, hash, srcobj, false)) != NULL) break; if (srcobj == NULL) { _rtld_error("Undefined symbol \"%s\" referenced from COPY" " relocation in %s", name, dstobj->path); return (-1); } srcaddr = (const void *)(srcobj->relocbase + srcsym->st_value); (void)memcpy(dstaddr, srcaddr, size); rdbg(("COPY %s %s %s --> src=%p dst=%p size %ld", dstobj->path, srcobj->path, name, srcaddr, (void *)dstaddr, (long)size)); return (0); }
static inline int _rtld_relocate_plt_object(const Obj_Entry *obj, Elf_Word sym, Elf_Addr *tp) { Elf_Addr *got = obj->pltgot; const Elf_Sym *def; const Obj_Entry *defobj; Elf_Addr new_value; def = _rtld_find_plt_symdef(sym, 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 --> new=%p", defobj->strtab + def->st_name, (void *)new_value)); got[obj->local_gotno + sym - obj->gotsym] = new_value; if (tp) *tp = new_value; return 0; }
static void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { if(EV_ERROR & revents) { rdlog(LOG_ERR,"Read callback error: %s",mystrerror(errno,errbuf, ERROR_BUFFER_SIZE)); } struct connection_private *connection = (struct connection_private *) watcher->data; struct sockaddr_in6 saddr; #ifdef CONNECTION_PRIVATE_MAGIC assert(connection->magic == CONNECTION_PRIVATE_MAGIC); #endif char *buffer = calloc(READ_BUFFER_SIZE,sizeof(char)); const int recv_result = receive_from_socket(watcher->fd,&saddr,buffer,READ_BUFFER_SIZE); if(recv_result > 0){ process_data_received_from_socket(buffer,(size_t)recv_result,connection->client, connection->callback,connection->callback_opaque); }else if(recv_result < 0){ if(errno == EAGAIN){ rdbg("Socket not ready. re-trying"); free(buffer); return; }else{ rdlog(LOG_ERR,"Recv error: %s",mystrerror(errno,errbuf,ERROR_BUFFER_SIZE)); free(buffer); close_socket_and_stop_watcher(loop,watcher); return; } }else{ /* recv_result == 0 */ free(buffer); close_socket_and_stop_watcher(loop,watcher); return; } if(NULL!=global_config.response && !connection->first_response_sent){ int send_ret = 1; rdlog(LOG_DEBUG,"Sending first response..."); if(global_config.response_len == 0){ rdlog(LOG_ERR,"Can't send first response to %s: size of response == 0",connection->client); connection->first_response_sent = 1; } else { send_ret = send_to_socket(watcher->fd,global_config.response,(size_t)global_config.response_len-1); } if(send_ret <= 0){ rdlog(LOG_ERR,"Cannot send first response to %s socket: %s", connection->client, mystrerror(errno,errbuf,ERROR_BUFFER_SIZE)); close_socket_and_stop_watcher(loop,watcher); } rdlog(LOG_DEBUG,"first response ok"); connection->first_response_sent = 1; } }
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; }
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; }
/* * Relocate newly-loaded shared objects. The argument is a pointer to * the Obj_Entry for the first such object. All objects from the first * to the end of the list of objects are relocated. Returns 0 on success, * or -1 on failure. */ int _rtld_relocate_objects(Obj_Entry *first, bool bind_now) { Obj_Entry *obj; int ok = 1; for (obj = first; obj != NULL; obj = obj->next) { if (obj->nbuckets == 0 || obj->nchains == 0 || obj->buckets == NULL || obj->symtab == NULL || obj->strtab == NULL) { _rtld_error("%s: Shared object has no run-time" " symbol table", obj->path); return -1; } if (obj->nbuckets == UINT32_MAX) { _rtld_error("%s: Symbol table too large", obj->path); return -1; } rdbg((" relocating %s (%ld/%ld rel/rela, %ld/%ld plt rel/rela)", obj->path, (long)(obj->rellim - obj->rel), (long)(obj->relalim - obj->rela), (long)(obj->pltrellim - obj->pltrel), (long)(obj->pltrelalim - obj->pltrela))); #ifndef __minix if (obj->textrel) { /* * There are relocations to the write-protected text * segment. */ if (mprotect(obj->mapbase, obj->textsize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) { _rtld_error("%s: Cannot write-enable text " "segment: %s", obj->path, xstrerror(errno)); return -1; } } #endif dbg(("doing non-PLT relocations")); if (_rtld_relocate_nonplt_objects(obj) < 0) ok = 0; #ifndef __minix if (obj->textrel) { /* Re-protected the text segment. */ if (mprotect(obj->mapbase, obj->textsize, PROT_READ | PROT_EXEC) == -1) { _rtld_error("%s: Cannot write-protect text " "segment: %s", obj->path, xstrerror(errno)); return -1; } } #endif dbg(("doing lazy PLT binding")); if (_rtld_relocate_plt_lazy(obj) < 0) ok = 0; #if defined(__hppa__) bind_now = 1; #endif if (obj->z_now || bind_now) { dbg(("doing immediate PLT binding")); if (_rtld_relocate_plt_objects(obj) < 0) ok = 0; } if (!ok) return -1; /* Set some sanity-checking numbers in the Obj_Entry. */ obj->magic = RTLD_MAGIC; obj->version = RTLD_VERSION; /* Fill in the dynamic linker entry points. */ obj->dlopen = dlopen; obj->dlsym = dlsym; obj->dlerror = dlerror; obj->dlclose = dlclose; obj->dladdr = dladdr; dbg(("fixing up PLTGOT")); /* Set the special PLTGOT entries. */ if (obj->pltgot != NULL) _rtld_setup_pltgot(obj); } 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; }
static void set_keepalive_opt(int fd){ int i=1; const int sso_rc = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&i, sizeof(int)); if(sso_rc == -1) rdbg("Can't set SO_KEEPALIVE option"); }
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_Rel *rel; 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 #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] & 0x80000000) ? 2 : 1; /* Relocate the local GOT entries */ got += i; for (; i < obj->local_gotno; i++) *got++ += (Elf_Addr)obj->relocbase; sym = obj->symtab + obj->gotsym; /* Now do the global GOT entries */ for (i = obj->gotsym; i < obj->symtabno; i++) { rdbg((" 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 = _rtld_find_symdef(i, obj, &defobj, false); 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; } 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; } else { def = _rtld_find_symdef(i, obj, &defobj, false); if (def == NULL) return -1; *got = def->st_value + (Elf_Addr)defobj->relocbase; } rdbg((" --> now %lx", (u_long) *got)); ++sym; ++got; } got = obj->pltgot; for (rel = obj->rel; rel < obj->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]; rdbg(("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; rdbg(("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; } #if ELFSIZE == 64 case R_TYPE(TLS_DTPMOD64): #else case R_TYPE(TLS_DTPMOD32): #endif { Elf_Addr old = load_ptr(where, ELFSIZE / 8); Elf_Addr val = old; def = _rtld_find_symdef(r_symndx, obj, &defobj, false); if (def == NULL) return -1; val += (Elf_Addr)defobj->tlsindex; store_ptr(where, val, ELFSIZE / 8); rdbg(("DTPMOD %s in %s --> %p in %s", obj->strtab + obj->symtab[r_symndx].st_name, obj->path, (void *)old, defobj->path)); break; } #if ELFSIZE == 64 case R_TYPE(TLS_DTPREL64): #else case R_TYPE(TLS_DTPREL32): #endif { Elf_Addr old = load_ptr(where, ELFSIZE / 8); Elf_Addr val = old; def = _rtld_find_symdef(r_symndx, obj, &defobj, false); if (def == NULL) return -1; if (!defobj->tls_done && _rtld_tls_offset_allocate(obj)) return -1; val += (Elf_Addr)def->st_value - TLS_DTV_OFFSET; store_ptr(where, val, ELFSIZE / 8); rdbg(("DTPREL %s in %s --> %p in %s", obj->strtab + obj->symtab[r_symndx].st_name, obj->path, (void *)old, defobj->path)); break; } #if ELFSIZE == 64 case R_TYPE(TLS_TPREL64): #else case R_TYPE(TLS_TPREL32): #endif { Elf_Addr old = load_ptr(where, ELFSIZE / 8); Elf_Addr val = old; def = _rtld_find_symdef(r_symndx, obj, &defobj, false); if (def == NULL) return -1; if (!defobj->tls_done && _rtld_tls_offset_allocate(obj)) return -1; val += (Elf_Addr)(def->st_value + defobj->tlsoffset - TLS_TP_OFFSET); store_ptr(where, val, ELFSIZE / 8); rdbg(("TPREL %s in %s --> %p in %s", obj->strtab + obj->symtab[r_symndx].st_name, obj->path, where, defobj->path)); break; } default: rdbg(("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; }
void _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) { const Elf_Rel *rel = 0, *rellim; Elf_Addr relsz = 0; void *where; const Elf_Sym *symtab = NULL, *sym; 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] & 0x80000000) ? 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 *)((uintptr_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; #if ELFSIZE == 64 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)); rdbg(("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(); } } }