summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-elf/i386/reloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/rtld-elf/i386/reloc.c')
-rw-r--r--libexec/rtld-elf/i386/reloc.c264
1 files changed, 120 insertions, 144 deletions
diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c
index 58073db..c1e0a39 100644
--- a/libexec/rtld-elf/i386/reloc.c
+++ b/libexec/rtld-elf/i386/reloc.c
@@ -126,168 +126,144 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
const Elf_Rel *rellim;
const Elf_Rel *rel;
SymCache *cache;
- int r = -1;
+ const Elf_Sym *def;
+ const Obj_Entry *defobj;
+ Elf_Addr *where, symval, add;
+ int r;
+ r = -1;
/*
* The dynamic loader may be called from a thread, we have
* limited amounts of stack available so we cannot use alloca().
*/
if (obj != obj_rtld) {
- cache = calloc(obj->dynsymcount, sizeof(SymCache));
- /* No need to check for NULL here */
+ cache = calloc(obj->dynsymcount, sizeof(SymCache));
+ /* No need to check for NULL here */
} else
- cache = NULL;
+ cache = NULL;
- rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
+ rellim = (const Elf_Rel *)((caddr_t) obj->rel + obj->relsize);
for (rel = obj->rel; rel < rellim; rel++) {
- Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
-
- switch (ELF_R_TYPE(rel->r_info)) {
-
- case R_386_NONE:
- break;
-
- case R_386_32:
- {
- const Elf_Sym *def;
- const Obj_Entry *defobj;
-
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
- flags, cache, lockstate);
- if (def == NULL)
- goto done;
-
- *where += (Elf_Addr) (defobj->relocbase + def->st_value);
- }
- break;
-
- case R_386_PC32:
- /*
- * I don't think the dynamic linker should ever see this
- * type of relocation. But the binutils-2.6 tools sometimes
- * generate it.
- */
- {
- const Elf_Sym *def;
- const Obj_Entry *defobj;
-
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
- flags, cache, lockstate);
- if (def == NULL)
- goto done;
-
- *where +=
- (Elf_Addr) (defobj->relocbase + def->st_value) -
- (Elf_Addr) where;
- }
- break;
-
- case R_386_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->mainprog) {
- _rtld_error("%s: Unexpected R_386_COPY relocation"
- " in shared library", obj->path);
- goto done;
- }
- break;
-
- case R_386_GLOB_DAT:
- {
- const Elf_Sym *def;
- const Obj_Entry *defobj;
-
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
- flags, cache, lockstate);
- if (def == NULL)
- goto done;
-
- *where = (Elf_Addr) (defobj->relocbase + def->st_value);
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_386_32:
+ case R_386_PC32:
+ case R_386_GLOB_DAT:
+ case R_386_TLS_TPOFF:
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_DTPOFF32:
+ def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
+ flags, cache, lockstate);
+ if (def == NULL)
+ goto done;
+ if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_386_32:
+ case R_386_PC32:
+ case R_386_GLOB_DAT:
+ if ((flags & SYMLOOK_IFUNC) == 0) {
+ obj->non_plt_gnu_ifunc = true;
+ continue;
+ }
+ symval = (Elf_Addr)rtld_resolve_ifunc(
+ defobj, def);
+ break;
+ case R_386_TLS_TPOFF:
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_DTPOFF32:
+ _rtld_error("%s: IFUNC for TLS reloc",
+ obj->path);
+ goto done;
+ }
+ } else {
+ if ((flags & SYMLOOK_IFUNC) != 0)
+ continue;
+ symval = (Elf_Addr)defobj->relocbase +
+ def->st_value;
+ }
+ break;
+ default:
+ if ((flags & SYMLOOK_IFUNC) != 0)
+ continue;
+ break;
}
- break;
-
- case R_386_RELATIVE:
- *where += (Elf_Addr) obj->relocbase;
- break;
-
- case R_386_TLS_TPOFF:
- case R_386_TLS_TPOFF32:
- {
- const Elf_Sym *def;
- const Obj_Entry *defobj;
- Elf_Addr add;
-
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
- flags, cache, lockstate);
- if (def == NULL)
- goto done;
-
+ where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_386_NONE:
+ break;
+ case R_386_32:
+ *where += symval;
+ break;
+ case R_386_PC32:
/*
- * We lazily allocate offsets for static TLS as we
- * see the first relocation that references the
- * TLS block. This allows us to support (small
- * amounts of) static TLS in dynamically loaded
- * modules. If we run out of space, we generate an
- * error.
+ * I don't think the dynamic linker should ever
+ * see this type of relocation. But the
+ * binutils-2.6 tools sometimes generate it.
*/
- if (!defobj->tls_done) {
- if (!allocate_tls_offset((Obj_Entry*) defobj)) {
- _rtld_error("%s: No space available for static "
- "Thread Local Storage", obj->path);
- goto done;
+ *where += symval - (Elf_Addr)where;
+ break;
+ case R_386_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->mainprog) {
+ _rtld_error("%s: Unexpected R_386_COPY "
+ "relocation in shared library", obj->path);
+ goto done;
}
- }
- add = (Elf_Addr) (def->st_value - defobj->tlsoffset);
- if (ELF_R_TYPE(rel->r_info) == R_386_TLS_TPOFF)
- *where += add;
- else
- *where -= add;
- }
- break;
-
- case R_386_TLS_DTPMOD32:
- {
- const Elf_Sym *def;
- const Obj_Entry *defobj;
-
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
- flags, cache, lockstate);
- if (def == NULL)
- goto done;
-
- *where += (Elf_Addr) defobj->tlsindex;
- }
- break;
-
- case R_386_TLS_DTPOFF32:
- {
- const Elf_Sym *def;
- const Obj_Entry *defobj;
-
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
- flags, cache, lockstate);
- if (def == NULL)
+ break;
+ case R_386_GLOB_DAT:
+ *where = symval;
+ break;
+ case R_386_RELATIVE:
+ *where += (Elf_Addr)obj->relocbase;
+ break;
+ case R_386_TLS_TPOFF:
+ case R_386_TLS_TPOFF32:
+ /*
+ * We lazily allocate offsets for static TLS
+ * as we see the first relocation that
+ * references the TLS block. This allows us to
+ * support (small amounts of) static TLS in
+ * dynamically loaded modules. If we run out
+ * of space, we generate an error.
+ */
+ if (!defobj->tls_done) {
+ if (!allocate_tls_offset((Obj_Entry*) defobj)) {
+ _rtld_error("%s: No space available "
+ "for static Thread Local Storage",
+ obj->path);
+ goto done;
+ }
+ }
+ add = (Elf_Addr)(def->st_value - defobj->tlsoffset);
+ if (ELF_R_TYPE(rel->r_info) == R_386_TLS_TPOFF)
+ *where += add;
+ else
+ *where -= add;
+ break;
+ case R_386_TLS_DTPMOD32:
+ *where += (Elf_Addr)defobj->tlsindex;
+ break;
+ case R_386_TLS_DTPOFF32:
+ *where += (Elf_Addr) def->st_value;
+ break;
+ default:
+ _rtld_error("%s: Unsupported relocation type %d"
+ " in non-PLT relocations\n", obj->path,
+ ELF_R_TYPE(rel->r_info));
goto done;
-
- *where += (Elf_Addr) def->st_value;
}
- break;
-
- default:
- _rtld_error("%s: Unsupported relocation type %d"
- " in non-PLT relocations\n", obj->path,
- ELF_R_TYPE(rel->r_info));
- goto done;
- }
}
r = 0;
done:
- if (cache != NULL)
- free(cache);
+ free(cache);
return (r);
}
OpenPOWER on IntegriCloud