summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authorPhilip Guenther <guenther@cvs.openbsd.org>2019-11-28 16:54:31 +0000
committerPhilip Guenther <guenther@cvs.openbsd.org>2019-11-28 16:54:31 +0000
commit2e5b3a405f3e712eedd7886ed4cf91d71e615b7b (patch)
tree6f64bb8392db00787cc5198b1cd63caca560e2a9 /libexec
parent6bb224be7f4e14cd1dd2f34ec147e40837a46d5d (diff)
Revert yesterday's _dl_md_reloc() and _dl_md_reloc_got() changes:
something's broken on at least i386.
Diffstat (limited to 'libexec')
-rw-r--r--libexec/ld.so/aarch64/rtld_machine.c238
-rw-r--r--libexec/ld.so/amd64/rtld_machine.c285
-rw-r--r--libexec/ld.so/arm/rtld_machine.c304
-rw-r--r--libexec/ld.so/hppa/boot_md.c17
-rw-r--r--libexec/ld.so/i386/rtld_machine.c273
5 files changed, 731 insertions, 386 deletions
diff --git a/libexec/ld.so/aarch64/rtld_machine.c b/libexec/ld.so/aarch64/rtld_machine.c
index 2e4b7efc133..5516364570a 100644
--- a/libexec/ld.so/aarch64/rtld_machine.c
+++ b/libexec/ld.so/aarch64/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.16 2019/11/27 01:24:35 guenther Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.17 2019/11/28 16:54:29 guenther Exp $ */
/*
* Copyright (c) 2004 Dale Rahn
@@ -42,16 +42,68 @@
int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
-void _dl_bind_start(void) __dso_hidden;
+void _dl_bind_start(void); /* XXX */
+Elf_Addr _dl_bind(elf_object_t *object, int index);
+#define _RF_S 0x80000000 /* Resolve symbol */
+#define _RF_A 0x40000000 /* Use addend */
+#define _RF_P 0x20000000 /* Location relative */
+#define _RF_G 0x10000000 /* GOT offset */
+#define _RF_B 0x08000000 /* Load address relative */
+#define _RF_V 0x02000000 /* ERROR */
+#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
+#define _RF_RS(s) ((s) & 0xff) /* right shift */
+static const int reloc_target_flags[] = {
+ [ R_AARCH64_NONE ] = 0,
+ [ R_AARCH64_ABS64 ] =
+ _RF_V|_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* ABS64 */
+ [ R_AARCH64_GLOB_DAT ] =
+ _RF_V|_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */
+ [ R_AARCH64_JUMP_SLOT ] =
+ _RF_V|_RF_S| _RF_SZ(64) | _RF_RS(0), /* JUMP_SLOT */
+ [ R_AARCH64_RELATIVE ] =
+ _RF_V|_RF_B|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REL64 */
+ [ R_AARCH64_TLSDESC ] =
+ _RF_V|_RF_S,
+ [ R_AARCH64_TLS_TPREL64 ] =
+ _RF_V|_RF_S,
+ [ R_AARCH64_COPY ] =
+ _RF_V|_RF_S| _RF_SZ(32) | _RF_RS(0), /* 20 COPY */
+
+};
+
+#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0)
+#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0)
+#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0)
+#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
+#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
+#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
+static const Elf_Addr reloc_target_bitmask[] = {
+#define _BM(x) (~(Elf_Addr)0 >> ((8*sizeof(reloc_target_bitmask[0])) - (x)))
+ [ R_AARCH64_NONE ] = 0,
+ [ R_AARCH64_ABS64 ] = _BM(64),
+ [ R_AARCH64_GLOB_DAT ] = _BM(64),
+ [ R_AARCH64_JUMP_SLOT ] = _BM(64),
+ [ R_AARCH64_RELATIVE ] = _BM(64),
+ [ R_AARCH64_TLSDESC ] = _BM(64),
+ [ R_AARCH64_TLS_TPREL64 ] = _BM(64),
+ [ R_AARCH64_COPY ] = _BM(64),
+#undef _BM
+};
+#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
#define R_TYPE(x) R_AARCH64_ ## x
+void _dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_RelA *rel);
+
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+
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;
@@ -59,7 +111,7 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz)
loff = object->obj_base;
numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA);
- relrel = object->relcount;
+ relrel = rel == DT_RELA ? object->relcount : 0;
rels = (Elf_RelA *)(object->Dyn.info[rel]);
if (rels == NULL)
@@ -76,118 +128,116 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz)
*where += loff;
}
for (; i < numrel; i++, rels++) {
- Elf_Addr *where, value;
+ Elf_Addr *where, value, mask;
Elf_Word type;
const Elf_Sym *sym;
const char *symn;
- where = (Elf_Addr *)(rels->r_offset + loff);
+ type = ELF_R_TYPE(rels->r_info);
- sym = object->dyn.symtab;
- sym += ELF_R_SYM(rels->r_info);
- symn = object->dyn.strtab + sym->st_name;
+ if (type >= nitems(reloc_target_flags) ||
+ (reloc_target_flags[type] & _RF_V) == 0)
+ _dl_die("bad relocation %ld %d", i, type);
- type = ELF_R_TYPE(rels->r_info);
- switch (type) {
- case R_TYPE(NONE):
- case R_TYPE(JUMP_SLOT): /* shouldn't happen */
+ if (type == R_TYPE(NONE))
continue;
- case R_TYPE(RELATIVE):
- *where = loff + rels->r_addend;
+ if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL)
continue;
- case R_TYPE(ABS64):
- case R_TYPE(GLOB_DAT):
+ where = (Elf_Addr *)(rels->r_offset + loff);
+
+ if (RELOC_USE_ADDEND(type))
value = rels->r_addend;
- break;
+ 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 {
+ struct sym_res sr;
+
+ sr = _dl_find_symbol(symn,
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|
+ ((type == R_TYPE(JUMP_SLOT)) ?
+ SYM_PLT : SYM_NOTPLT), sym, object);
+ if (sr.sym == NULL) {
+resolve_failed:
+ if (ELF_ST_BIND(sym->st_info) !=
+ STB_WEAK)
+ fails++;
+ continue;
+ }
+ prev_sym = sym;
+ prev_value = (Elf_Addr)(sr.obj->obj_base +
+ sr.sym->st_value);
+ value += prev_value;
+ }
+ }
- case R_TYPE(COPY):
- {
+ if (type == R_TYPE(JUMP_SLOT)) {
+ /*
+ _dl_reloc_plt((Elf_Word *)where, value, rels);
+ */
+ *where = value;
+ continue;
+ }
+
+ if (type == R_TYPE(COPY)) {
+ void *dstaddr = where;
+ const void *srcaddr;
+ const Elf_Sym *dstsym = sym;
struct sym_res sr;
sr = _dl_find_symbol(symn,
SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT,
- sym, object);
+ dstsym, object);
if (sr.sym == NULL)
- return 1;
+ goto resolve_failed;
- value = sr.obj->obj_base + sr.sym->st_value;
- _dl_bcopy((void *)value, where, sym->st_size);
+ srcaddr = (void *)(sr.obj->obj_base + sr.sym->st_value);
+ _dl_bcopy(srcaddr, dstaddr, dstsym->st_size);
continue;
}
- default:
- _dl_die("bad relocation %d", type);
- }
-
- if (sym->st_shndx != SHN_UNDEF &&
- ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
+ if (RELOC_PC_RELATIVE(type))
+ value -= (Elf_Addr)where;
+ if (RELOC_BASE_RELATIVE(type))
value += loff;
- } else if (sym == prev_sym) {
- value += prev_value;
- } else {
- struct sym_res sr;
-
- sr = _dl_find_symbol(symn,
- SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
- sym, object);
- if (sr.sym == NULL) {
- if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
- return 1;
- continue;
- }
- prev_sym = sym;
- prev_value = sr.obj->obj_base + sr.sym->st_value;
- value += prev_value;
- }
-
- *where = value;
- }
-
- return 0;
-}
-
-static int
-_dl_md_reloc_all_plt(elf_object_t *object, const Elf_RelA *reloc,
- const Elf_RelA *rend)
-{
- for (; reloc < rend; reloc++) {
- const Elf_Sym *sym;
- const char *symn;
- Elf_Addr *where;
- struct sym_res sr;
- sym = object->dyn.symtab;
- sym += ELF_R_SYM(reloc->r_info);
- symn = object->dyn.strtab + sym->st_name;
+ mask = RELOC_VALUE_BITMASK(type);
+ value >>= RELOC_VALUE_RIGHTSHIFT(type);
+ value &= mask;
- sr = _dl_find_symbol(symn,
- SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object);
- if (sr.sym == NULL) {
- if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
- return 1;
- continue;
- }
-
- where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
- *where = sr.obj->obj_base + sr.sym->st_value;
+ *where &= ~mask;
+ *where |= value;
}
- return 0;
+ return fails;
}
/*
* Relocate the Global Offset Table (GOT).
+ * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW,
+ * otherwise the lazy binding plt initialization is performed.
*/
int
_dl_md_reloc_got(elf_object_t *object, int lazy)
{
- Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
- const Elf_RelA *reloc, *rend;
-
- if (pltgot == NULL)
- return 0; /* it is possible to have no PLT/GOT relocations */
+ int fails = 0;
+ Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
+ int i, num;
+ Elf_RelA *rel;
if (object->Dyn.info[DT_PLTREL] != DT_RELA)
return 0;
@@ -195,23 +245,23 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
if (object->traced)
lazy = 1;
- reloc = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
- rend = (Elf_RelA *)((char *)reloc + object->Dyn.info[DT_PLTRELSZ]);
-
- if (!lazy)
- return _dl_md_reloc_all_plt(object, reloc, rend);
+ if (!lazy) {
+ fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
+ } else {
+ rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
+ num = (object->Dyn.info[DT_PLTRELSZ]);
- /* Lazy */
- pltgot[1] = (Elf_Addr)object;
- pltgot[2] = (Elf_Addr)_dl_bind_start;
+ for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) {
+ Elf_Addr *where;
+ where = (Elf_Addr *)(rel->r_offset + object->obj_base);
+ *where += object->obj_base;
+ }
- for (; reloc < rend; reloc++) {
- Elf_Addr *where;
- where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
- *where += object->obj_base;
+ pltgot[1] = (Elf_Addr)object;
+ pltgot[2] = (Elf_Addr)_dl_bind_start;
}
- return 0;
+ return fails;
}
Elf_Addr
diff --git a/libexec/ld.so/amd64/rtld_machine.c b/libexec/ld.so/amd64/rtld_machine.c
index bf8e2401743..16d13e349f1 100644
--- a/libexec/ld.so/amd64/rtld_machine.c
+++ b/libexec/ld.so/amd64/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.37 2019/11/26 23:38:52 guenther Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.38 2019/11/28 16:54:29 guenther Exp $ */
/*
* Copyright (c) 2002,2004 Dale Rahn
@@ -79,12 +79,102 @@
int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
+/*
+ * The following table holds for each relocation type:
+ * - the width in bits of the memory location the relocation
+ * applies to
+ * - the number of bits the relocation value must be shifted to the
+ * right (i.e. discard least significant bits) to fit into
+ * the appropriate field in the instruction word.
+ * - flags indicating whether
+ * * the relocation involves a symbol
+ * * the relocation is relative to the current position
+ * * the relocation is for a GOT entry
+ * * the relocation is relative to the load address
+ *
+ */
+#define _RF_S 0x80000000 /* Resolve symbol */
+#define _RF_A 0x40000000 /* Use addend */
+#define _RF_P 0x20000000 /* Location relative */
+#define _RF_G 0x10000000 /* GOT offset */
+#define _RF_B 0x08000000 /* Load address relative */
+#define _RF_E 0x02000000 /* ERROR */
+#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
+#define _RF_RS(s) ((s) & 0xff) /* right shift */
+static const int reloc_target_flags[] = {
+ 0, /* 0 NONE */
+ _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* 1 _64*/
+ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* 2 PC32 */
+ _RF_G|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 3 GOT32 */
+ _RF_E|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 4 PLT32 */
+ _RF_S| _RF_SZ(32) | _RF_RS(0), /* 5 COPY */
+ _RF_S| _RF_SZ(64) | _RF_RS(0), /* 6 GLOB_DAT*/
+ _RF_S| _RF_SZ(64) | _RF_RS(0), /* 7 JUMP_SLOT*/
+ _RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0), /* 8 RELATIVE*/
+ _RF_E, /* 9 GOTPCREL*/
+ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 10 32 */
+ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 11 32S */
+ _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* 12 16 */
+ _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* 13 PC16 */
+ _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* 14 8 */
+ _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* 15 PC8 */
+ _RF_E, /* 16 DTPMOD64*/
+ _RF_E, /* 17 DTPOFF64*/
+ _RF_E, /* 18 TPOFF64 */
+ _RF_E, /* 19 TLSGD */
+ _RF_E, /* 20 TLSLD */
+ _RF_E, /* 21 DTPOFF32*/
+ _RF_E, /* 22 GOTTPOFF*/
+ _RF_E /* 23 TPOFF32*/
+};
+
+#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0)
+#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0)
+#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0)
+#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
+#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
+#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
+#define RELOC_ERROR(t) (reloc_target_flags[t] & _RF_E)
+
+static const Elf_Addr reloc_target_bitmask[] = {
+#define _BM(x) (~(Elf_Addr)0 >> ((8*sizeof(reloc_target_bitmask[0])) - (x)))
+ 0, /* 0 NONE */
+ _BM(64), /* 1 _64*/
+ _BM(32), /* 2 PC32 */
+ _BM(32), /* 3 GOT32 */
+ _BM(32), /* 4 PLT32 */
+ 0, /* 5 COPY */
+ _BM(64), /* 6 GLOB_DAT*/
+ _BM(64), /* 7 JUMP_SLOT*/
+ _BM(64), /* 8 RELATIVE*/
+ _BM(32), /* 9 GOTPCREL*/
+ _BM(32), /* 10 32 */
+ _BM(32), /* 11 32S */
+ _BM(16), /* 12 16 */
+ _BM(16), /* 13 PC16 */
+ _BM(8), /* 14 8 */
+ _BM(8), /* 15 PC8 */
+ 0, /* 16 DTPMOD64*/
+ 0, /* 17 DTPOFF64*/
+ 0, /* 18 TPOFF64 */
+ 0, /* 19 TLSGD */
+ 0, /* 20 TLSLD */
+ 0, /* 21 DTPOFF32*/
+ 0, /* 22 GOTTPOFF*/
+ 0 /* 23 TPOFF32*/
+#undef _BM
+};
+#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
+
+void _dl_reloc_plt(Elf_Addr *where, Elf_Addr value);
+
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;
@@ -92,9 +182,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz)
loff = object->obj_base;
numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA);
- relrel = object->relacount;
+ relrel = rel == DT_RELA ? object->relacount : 0;
rels = (Elf_RelA *)(object->Dyn.info[rel]);
-
if (rels == NULL)
return 0;
@@ -109,83 +198,111 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz)
*where = rels->r_addend + loff;
}
for (; i < numrel; i++, rels++) {
- Elf_Addr *where, value;
+ Elf_Addr *where, value, mask;
Elf_Word type;
const Elf_Sym *sym;
const char *symn;
- where = (Elf_Addr *)(rels->r_offset + loff);
+ type = ELF_R_TYPE(rels->r_info);
- sym = object->dyn.symtab;
- sym += ELF_R_SYM(rels->r_info);
- symn = object->dyn.strtab + sym->st_name;
+ if (RELOC_ERROR(type))
+ _dl_die("relocation error %d idx %ld", type, i);
- type = ELF_R_TYPE(rels->r_info);
- switch (type) {
- case R_TYPE(NONE):
- case R_TYPE(JUMP_SLOT): /* shouldn't happen */
+ if (type == R_TYPE(NONE))
continue;
- case R_TYPE(RELATIVE):
- *where = rels->r_addend + loff;
+ if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL)
continue;
- case R_TYPE(64):
- value = rels->r_addend;
- break;
+ where = (Elf_Addr *)(rels->r_offset + loff);
- case R_TYPE(GLOB_DAT):
+ if (RELOC_USE_ADDEND(type))
+ value = rels->r_addend;
+ else
value = 0;
- break;
- case R_TYPE(COPY):
- {
+ 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 {
+ struct sym_res sr;
+
+ sr = _dl_find_symbol(symn,
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|
+ ((type == R_TYPE(JUMP_SLOT))?
+ SYM_PLT:SYM_NOTPLT), sym, object);
+ if (sr.sym == NULL) {
+resolve_failed:
+ if (ELF_ST_BIND(sym->st_info) !=
+ STB_WEAK)
+ fails++;
+ continue;
+ }
+ prev_sym = sym;
+ prev_value = (Elf_Addr)(sr.obj->obj_base +
+ sr.sym->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;
struct sym_res sr;
sr = _dl_find_symbol(symn,
SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT,
- sym, object);
+ dstsym, object);
if (sr.sym == NULL)
- return 1;
- value = sr.obj->obj_base + sr.sym->st_value;
- _dl_bcopy((void *)value, where, sym->st_size);
+ goto resolve_failed;
+
+ srcaddr = (void *)(sr.obj->obj_base + sr.sym->st_value);
+ _dl_bcopy(srcaddr, dstaddr, dstsym->st_size);
continue;
}
- default:
- _dl_die("relocation error %d idx %ld", type, i);
- }
+ 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;
- /*
- * Finish the R_X86_64_64 and R_X86_64_GLOB_DAT cases,
- * with caching of the last symbol looked up.
- */
- if (sym->st_shndx != SHN_UNDEF &&
- ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
- value += loff;
- } else if (sym == prev_sym) {
- value += prev_value;
+ if (RELOC_TARGET_SIZE(type) > 32) {
+ *where &= ~mask;
+ *where |= value;
} else {
- struct sym_res sr;
+ Elf32_Addr *where32 = (Elf32_Addr *)where;
- sr = _dl_find_symbol(symn,
- SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
- sym, object);
- if (sr.sym == NULL) {
- if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
- return 1;
- continue;
- }
- prev_sym = sym;
- prev_value = sr.obj->obj_base + sr.sym->st_value;
- value += prev_value;
+ *where32 &= ~mask;
+ *where32 |= value;
}
-
- *where = value;
}
- return 0;
+ return fails;
+}
+
+void
+_dl_reloc_plt(Elf_Addr *where, Elf_Addr value)
+{
+ *where = value;
}
/*
@@ -236,41 +353,14 @@ _dl_bind(elf_object_t *object, int index)
return buf.newval;
}
-static int
-_dl_md_reloc_all_plt(elf_object_t *object, const Elf_RelA *reloc,
- const Elf_RelA *rend)
-{
- for (; reloc < rend; reloc++) {
- const Elf_Sym *sym;
- const char *symn;
- Elf_Addr *where;
- struct sym_res sr;
-
- sym = object->dyn.symtab;
- sym += ELF_R_SYM(reloc->r_info);
- symn = object->dyn.strtab + sym->st_name;
-
- sr = _dl_find_symbol(symn,
- SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object);
- if (sr.sym == NULL) {
- if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
- return 1;
- continue;
- }
-
- where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
- *where = sr.obj->obj_base + sr.sym->st_value;
- }
-
- return 0;
-}
-
int
_dl_md_reloc_got(elf_object_t *object, int lazy)
{
extern void _dl_bind_start(void); /* XXX */
- Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
- const Elf_RelA *reloc, *rend;
+ int fails = 0;
+ Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
+ int i, num;
+ Elf_RelA *rel;
if (pltgot == NULL)
return 0; /* it is possible to have no PLT/GOT relocations */
@@ -281,21 +371,20 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
if (object->traced)
lazy = 1;
- reloc = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
- rend = (Elf_RelA *)((char *)reloc + object->Dyn.info[DT_PLTRELSZ]);
-
- if (!lazy)
- return _dl_md_reloc_all_plt(object, reloc, rend);
-
- /* Lazy */
- pltgot[1] = (Elf_Addr)object;
- pltgot[2] = (Elf_Addr)&_dl_bind_start;
-
- for (; reloc < rend; reloc++) {
- Elf_Addr *where;
- where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
- *where += object->obj_base;
+ if (__predict_false(!lazy)) {
+ fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
+ } else {
+ pltgot[1] = (Elf_Addr)object;
+ pltgot[2] = (Elf_Addr)&_dl_bind_start;
+
+ rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
+ num = (object->Dyn.info[DT_PLTRELSZ]);
+ for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) {
+ Elf_Addr *where;
+ where = (Elf_Addr *)(rel->r_offset + object->obj_base);
+ *where += object->obj_base;
+ }
}
- return 0;
+ return fails;
}
diff --git a/libexec/ld.so/arm/rtld_machine.c b/libexec/ld.so/arm/rtld_machine.c
index da15d87aaa9..e4933e53065 100644
--- a/libexec/ld.so/arm/rtld_machine.c
+++ b/libexec/ld.so/arm/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.37 2019/11/27 01:24:35 guenther Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.38 2019/11/28 16:54:30 guenther Exp $ */
/*
* Copyright (c) 2004 Dale Rahn
@@ -44,15 +44,127 @@ int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
void _dl_bind_start(void); /* XXX */
Elf_Addr _dl_bind(elf_object_t *object, int reloff);
+#define _RF_S 0x80000000 /* Resolve symbol */
+#define _RF_A 0x40000000 /* Use addend */
+#define _RF_P 0x20000000 /* Location relative */
+#define _RF_G 0x10000000 /* GOT offset */
+#define _RF_B 0x08000000 /* Load address relative */
+#define _RF_E 0x02000000 /* ERROR */
+#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
+#define _RF_RS(s) ((s) & 0xff) /* right shift */
+static const int reloc_target_flags[] = {
+ 0, /* 0 NONE */
+ _RF_S|_RF_P|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 1 PC24 */
+ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 2 ABS32 */
+ _RF_S|_RF_P|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 3 REL32 */
+ _RF_S|_RF_P|_RF_A| _RF_E, /* 4 REL13 */
+ _RF_S|_RF_A| _RF_E, /* 5 ABS16 */
+ _RF_S|_RF_A| _RF_E, /* 6 ABS12 */
+ _RF_S|_RF_A| _RF_E, /* 7 T_ABS5 */
+ _RF_S|_RF_A| _RF_E, /* 8 ABS8 */
+ _RF_S|_RF_B|_RF_A| _RF_E, /* 9 SBREL32 */
+ _RF_S|_RF_P|_RF_A| _RF_E, /* 10 T_PC22 */
+ _RF_S|_RF_P|_RF_A| _RF_E, /* 11 T_PC8 */
+ _RF_E, /* 12 Reserved */
+ _RF_S|_RF_A| _RF_E, /* 13 SWI24 */
+ _RF_S|_RF_A| _RF_E, /* 14 T_SWI8 */
+ _RF_E, /* 15 OBSL */
+ _RF_E, /* 16 OBSL */
+ _RF_E, /* 17 UNUSED */
+ _RF_E, /* 18 UNUSED */
+ _RF_E, /* 19 UNUSED */
+ _RF_S| _RF_SZ(32) | _RF_RS(0), /* 20 COPY */
+ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 21 GLOB_DAT */
+ _RF_S| _RF_SZ(32) | _RF_RS(0), /* 22 JUMP_SLOT */
+ _RF_A| _RF_B| _RF_SZ(32) | _RF_RS(0), /* 23 RELATIVE */
+ _RF_E, /* 24 GOTOFF */
+ _RF_E, /* 25 GOTPC */
+ _RF_E, /* 26 GOT32 */
+ _RF_E, /* 27 PLT32 */
+ _RF_E, /* 28 UNUSED */
+ _RF_E, /* 29 UNUSED */
+ _RF_E, /* 30 UNUSED */
+ _RF_E, /* 31 UNUSED */
+ _RF_E, /* 32 A_PCR 0 */
+ _RF_E, /* 33 A_PCR 8 */
+ _RF_E, /* 34 A_PCR 16 */
+ _RF_E, /* 35 B_PCR 0 */
+ _RF_E, /* 36 B_PCR 12 */
+ _RF_E, /* 37 B_PCR 20 */
+ _RF_E, /* 38 RELAB32 */
+ _RF_E, /* 39 ROSGREL32 */
+ _RF_E, /* 40 V4BX */
+ _RF_E, /* 41 STKCHK */
+ _RF_E /* 42 TSTKCHK */
+};
+
+#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0)
+#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0)
+#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0)
+#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
+#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
+#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
+
+static const long reloc_target_bitmask[] = {
+#define _BM(x) (~(-(1ULL << (x))))
+ _BM(0), /* 0 NONE */
+ _BM(24), /* 1 PC24 */
+ _BM(32), /* 2 ABS32 */
+ _BM(32), /* 3 REL32 */
+ _BM(0), /* 4 REL13 */
+ _BM(0), /* 5 ABS16 */
+ _BM(0), /* 6 ABS12 */
+ _BM(0), /* 7 T_ABS5 */
+ _BM(0), /* 8 ABS8 */
+ _BM(32), /* 9 SBREL32 */
+ _BM(0), /* 10 T_PC22 */
+ _BM(0), /* 11 T_PC8 */
+ _BM(0), /* 12 Reserved */
+ _BM(0), /* 13 SWI24 */
+ _BM(0), /* 14 T_SWI8 */
+ _BM(0), /* 15 OBSL */
+ _BM(0), /* 16 OBSL */
+ _BM(0), /* 17 UNUSED */
+ _BM(0), /* 18 UNUSED */
+ _BM(0), /* 19 UNUSED */
+ _BM(32), /* 20 COPY */
+ _BM(32), /* 21 GLOB_DAT */
+ _BM(32), /* 22 JUMP_SLOT */
+ _BM(32), /* 23 RELATIVE */
+ _BM(0), /* 24 GOTOFF */
+ _BM(0), /* 25 GOTPC */
+ _BM(0), /* 26 GOT32 */
+ _BM(0), /* 27 PLT32 */
+ _BM(0), /* 28 UNUSED */
+ _BM(0), /* 29 UNUSED */
+ _BM(0), /* 30 UNUSED */
+ _BM(0), /* 31 UNUSED */
+ _BM(0), /* 32 A_PCR 0 */
+ _BM(0), /* 33 A_PCR 8 */
+ _BM(0), /* 34 A_PCR 16 */
+ _BM(0), /* 35 B_PCR 0 */
+ _BM(0), /* 36 B_PCR 12 */
+ _BM(0), /* 37 B_PCR 20 */
+ _BM(0), /* 38 RELAB32 */
+ _BM(0), /* 39 ROSGREL32 */
+ _BM(0), /* 40 V4BX */
+ _BM(0), /* 41 STKCHK */
+ _BM(0) /* 42 TSTKCHK */
+#undef _BM
+};
+#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
#define R_TYPE(x) R_ARM_ ## x
+void _dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_Rel *rel);
+
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;
@@ -60,7 +172,7 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz)
loff = object->obj_base;
numrel = object->Dyn.info[relsz] / sizeof(Elf_Rel);
- relrel = object->relcount;
+ relrel = rel == DT_REL ? object->relcount : 0;
rels = (Elf_Rel *)(object->Dyn.info[rel]);
if (rels == NULL)
@@ -77,120 +189,118 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz)
*where += loff;
}
for (; i < numrel; i++, rels++) {
- Elf_Addr *where, value;
+ Elf_Addr *where, value, mask;
Elf_Word type;
const Elf_Sym *sym;
const char *symn;
- where = (Elf_Addr *)(rels->r_offset + loff);
-
- sym = object->dyn.symtab;
- sym += ELF_R_SYM(rels->r_info);
- symn = object->dyn.strtab + sym->st_name;
-
type = ELF_R_TYPE(rels->r_info);
- switch (type) {
- case R_TYPE(NONE):
- case R_TYPE(JUMP_SLOT): /* shouldn't happen */
+
+ if (reloc_target_flags[type] & _RF_E)
+ _dl_die("bad relocation %ld %d", i, type);
+ if (type == R_TYPE(NONE))
continue;
- case R_TYPE(RELATIVE):
- *where += loff;
+ if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL)
continue;
- case R_TYPE(ABS32):
- case R_TYPE(GLOB_DAT):
- value = *where;
- break;
+ where = (Elf_Addr *)(rels->r_offset + loff);
- case R_TYPE(COPY):
- {
+ if (RELOC_USE_ADDEND(type))
+#ifdef LDSO_ARCH_IS_RELA_
+ value = rels->r_addend;
+#else
+ value = *where & RELOC_VALUE_BITMASK(type);
+#endif
+ 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 {
+ struct sym_res sr;
+
+ sr = _dl_find_symbol(symn,
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|
+ ((type == R_TYPE(JUMP_SLOT)) ?
+ SYM_PLT : SYM_NOTPLT), sym, object);
+ if (sr.sym == NULL) {
+resolve_failed:
+ if (ELF_ST_BIND(sym->st_info) !=
+ STB_WEAK)
+ fails++;
+ continue;
+ }
+ prev_sym = sym;
+ prev_value = (Elf_Addr)(sr.obj->obj_base +
+ sr.sym->st_value);
+ value += prev_value;
+ }
+ }
+
+ if (type == R_TYPE(JUMP_SLOT)) {
+ /*
+ _dl_reloc_plt((Elf_Word *)where, value, rels);
+ */
+ *where = value;
+ continue;
+ }
+
+ if (type == R_TYPE(COPY)) {
+ void *dstaddr = where;
+ const void *srcaddr;
+ const Elf_Sym *dstsym = sym;
struct sym_res sr;
sr = _dl_find_symbol(symn,
SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT,
- sym, object);
+ dstsym, object);
if (sr.sym == NULL)
- return 1;
+ goto resolve_failed;
- value = sr.obj->obj_base + sr.sym->st_value;
- _dl_bcopy((void *)value, where, sym->st_size);
+ srcaddr = (void *)(sr.obj->obj_base + sr.sym->st_value);
+ _dl_bcopy(srcaddr, dstaddr, dstsym->st_size);
continue;
}
- default:
- _dl_die("relocation error %d", type);
- }
-
-
- /* Finish the ABS32 and GLOB_DAT cases */
- if (sym->st_shndx != SHN_UNDEF &&
- ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
+ if (RELOC_PC_RELATIVE(type))
+ value -= (Elf_Addr)where;
+ if (RELOC_BASE_RELATIVE(type))
value += loff;
- } else if (sym == prev_sym) {
- value += prev_value;
- } else {
- struct sym_res sr;
- sr = _dl_find_symbol(symn,
- SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
- sym, object);
- if (sr.sym == NULL) {
- if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
- return 1;
- continue;
- }
- prev_sym = sym;
- prev_value = sr.obj->obj_base + sr.sym->st_value;
- value += prev_value;
- }
+ mask = RELOC_VALUE_BITMASK(type);
+ value >>= RELOC_VALUE_RIGHTSHIFT(type);
+ value &= mask;
- *where = value;
+ *where &= ~mask;
+ *where |= value;
}
- return 0;
-}
-
-static int
-_dl_md_reloc_all_plt(elf_object_t *object, const Elf_Rel *reloc,
- const Elf_Rel *rend)
-{
- for (; reloc < rend; reloc++) {
- const Elf_Sym *sym;
- const char *symn;
- Elf_Addr *where;
- struct sym_res sr;
-
- sym = object->dyn.symtab;
- sym += ELF_R_SYM(reloc->r_info);
- symn = object->dyn.strtab + sym->st_name;
-
- sr = _dl_find_symbol(symn,
- SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object);
- if (sr.sym == NULL) {
- if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
- return 1;
- continue;
- }
-
- where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
- *where = sr.obj->obj_base + sr.sym->st_value;
- }
-
- return 0;
+ return fails;
}
/*
* Relocate the Global Offset Table (GOT).
+ * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW,
+ * otherwise the lazy binding plt initialization is performed.
*/
int
_dl_md_reloc_got(elf_object_t *object, int lazy)
{
- Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
- const Elf_Rel *reloc, *rend;
-
- if (pltgot == NULL)
- return 0; /* it is possible to have no PLT/GOT relocations */
+ int fails = 0;
+ Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
+ int i, num;
+ Elf_Rel *rel;
if (object->Dyn.info[DT_PLTREL] != DT_REL)
return 0;
@@ -198,23 +308,23 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
if (object->traced)
lazy = 1;
- reloc = (const Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
- rend = (const Elf_Rel *)((char *)reloc + object->Dyn.info[DT_PLTRELSZ]);
-
- if (!lazy)
- return _dl_md_reloc_all_plt(object, reloc, rend);
+ if (!lazy) {
+ fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
+ } else {
+ rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
+ num = (object->Dyn.info[DT_PLTRELSZ]);
- /* Lazy */
- pltgot[1] = (Elf_Addr)object;
- pltgot[2] = (Elf_Addr)_dl_bind_start;
+ for (i = 0; i < num/sizeof(Elf_Rel); i++, rel++) {
+ Elf_Addr *where;
+ where = (Elf_Addr *)(rel->r_offset + object->obj_base);
+ *where += object->obj_base;
+ }
- for (; reloc < rend; reloc++) {
- Elf_Addr *where;
- where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
- *where += object->obj_base;
+ pltgot[1] = (Elf_Addr)object;
+ pltgot[2] = (Elf_Addr)_dl_bind_start;
}
- return 0;
+ return fails;
}
Elf_Addr
diff --git a/libexec/ld.so/hppa/boot_md.c b/libexec/ld.so/hppa/boot_md.c
index bfdba296cbb..465e8a6f593 100644
--- a/libexec/ld.so/hppa/boot_md.c
+++ b/libexec/ld.so/hppa/boot_md.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: boot_md.c,v 1.2 2019/11/27 00:58:59 guenther Exp $ */
+/* $OpenBSD: boot_md.c,v 1.3 2019/11/28 16:54:30 guenther Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -63,7 +63,12 @@ struct boot_dyn {
Elf_Addr *dt_pltgot;
Elf_Addr dt_pltrelsz;
const Elf_Sym *dt_symtab;
+#ifdef HAVE_JMPREL
RELOC_TYPE *dt_jmprel;
+#endif
+#if DT_PROCNUM > 0
+ u_long dt_proc[DT_PROCNUM];
+#endif
};
/*
@@ -129,17 +134,26 @@ _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynp)
dynld.dt_symtab = (void *)(dynp->d_un.d_ptr + loff);
else if (dynp->d_tag == RELOC_TAG) /* DT_{RELA,REL} */
dynld.dt_reloc = (void *)(dynp->d_un.d_ptr + loff);
+#ifdef HAVE_JMPREL
else if (dynp->d_tag == DT_JMPREL)
dynld.dt_jmprel = (void *)(dynp->d_un.d_ptr + loff);
+#endif
/* Now for the tags that are just sizes or counts */
else if (dynp->d_tag == DT_PLTRELSZ)
dynld.dt_pltrelsz = dynp->d_un.d_val;
else if (dynp->d_tag == RELOC_TAG+1) /* DT_{RELA,REL}SZ */
dynld.dt_relocsz = dynp->d_un.d_val;
+#if DT_PROCNUM > 0
+ else if (dynp->d_tag >= DT_LOPROC &&
+ dynp->d_tag < DT_LOPROC + DT_PROCNUM)
+ dynld.dt_proc[dynp->d_tag - DT_LOPROC] =
+ dynp->d_un.d_val;
+#endif /* DT_PROCNUM */
dynp++;
}
+#ifdef HAVE_JMPREL
rp = dynld.dt_jmprel;
for (i = 0; i < dynld.dt_pltrelsz; i += sizeof *rp) {
Elf_Addr *ra;
@@ -153,6 +167,7 @@ _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynp)
RELOC_JMPREL(rp, sp, ra, loff, dynld.dt_pltgot);
rp++;
}
+#endif /* HAVE_JMPREL */
rp = dynld.dt_reloc;
for (i = 0; i < dynld.dt_relocsz; i += sizeof *rp) {
diff --git a/libexec/ld.so/i386/rtld_machine.c b/libexec/ld.so/i386/rtld_machine.c
index e91df002718..6ab0616e112 100644
--- a/libexec/ld.so/i386/rtld_machine.c
+++ b/libexec/ld.so/i386/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.46 2019/11/26 23:38:52 guenther Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.47 2019/11/28 16:54:30 guenther Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -79,12 +79,100 @@
int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
+/*
+ * The following table holds for each relocation type:
+ * - the width in bits of the memory location the relocation
+ * applies to (not currently used)
+ * - the number of bits the relocation value must be shifted to the
+ * right (i.e. discard least significant bits) to fit into
+ * the appropriate field in the instruction word.
+ * - flags indicating whether
+ * * the relocation involves a symbol
+ * * the relocation is relative to the current position
+ * * the relocation is for a GOT entry
+ * * the relocation is relative to the load address
+ *
+ */
+#define _RF_S 0x80000000 /* Resolve symbol */
+#define _RF_A 0x40000000 /* Use addend */
+#define _RF_P 0x20000000 /* Location relative */
+#define _RF_G 0x10000000 /* GOT offset */
+#define _RF_B 0x08000000 /* Load address relative */
+#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
+#define _RF_RS(s) ((s) & 0xff) /* right shift */
+static const int reloc_target_flags[] = {
+ 0, /* NONE */
+ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELOC_32*/
+ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC32 */
+ _RF_G| _RF_SZ(32) | _RF_RS(00), /* GOT32 */
+ _RF_A| _RF_SZ(32) | _RF_RS(0), /* PLT32 */
+ _RF_S| _RF_SZ(32) | _RF_RS(0), /* COPY */
+ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */
+ _RF_S| _RF_SZ(32) | _RF_RS(0), /* JUMP_SLOT */
+ _RF_A| _RF_B| _RF_SZ(32) | _RF_RS(0), /* RELATIVE */
+ 0, /* GOTOFF XXX */
+ 0, /* GOTPC XXX */
+ 0, /* DUMMY 11 */
+ 0, /* DUMMY 12 */
+ 0, /* DUMMY 13 */
+ 0, /* DUMMY 14 */
+ 0, /* DUMMY 15 */
+ 0, /* DUMMY 16 */
+ 0, /* DUMMY 17 */
+ 0, /* DUMMY 18 */
+ 0, /* DUMMY 19 */
+ _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */
+ _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* PC_16 */
+ _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */
+ _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* RELOC_PC8 */
+};
+
+#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0)
+#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0)
+#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0)
+#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
+#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
+#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
+
+static const long reloc_target_bitmask[] = {
+#define _BM(x) (~(-(1ULL << (x))))
+ 0, /* NONE */
+ _BM(32), /* RELOC_32*/
+ _BM(32), /* PC32 */
+ _BM(32), /* GOT32 */
+ _BM(32), /* PLT32 */
+ 0, /* COPY */
+ _BM(32), /* GLOB_DAT */
+ _BM(32), /* JUMP_SLOT */
+ _BM(32), /* RELATIVE */
+ 0, /* GOTOFF XXX */
+ 0, /* GOTPC XXX */
+ 0, /* DUMMY 11 */
+ 0, /* DUMMY 12 */
+ 0, /* DUMMY 13 */
+ 0, /* DUMMY 14 */
+ 0, /* DUMMY 15 */
+ 0, /* DUMMY 16 */
+ 0, /* DUMMY 17 */
+ 0, /* DUMMY 18 */
+ 0, /* DUMMY 19 */
+ _BM(16), /* RELOC_16 */
+ _BM(8), /* PC_16 */
+ _BM(8), /* RELOC_8 */
+ _BM(8), /* RELOC_PC8 */
+#undef _BM
+};
+#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
+
+void _dl_reloc_plt(Elf_Addr *where, Elf_Addr value);
+
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;
@@ -92,9 +180,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz)
loff = object->obj_base;
numrel = object->Dyn.info[relsz] / sizeof(Elf_Rel);
- relrel = object->relcount;
+ relrel = rel == DT_REL ? object->relcount : 0;
rels = (Elf_Rel *)(object->Dyn.info[rel]);
-
if (rels == NULL)
return 0;
@@ -109,79 +196,95 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz)
*where += loff;
}
for (; i < numrel; i++, rels++) {
- Elf_Addr *where, value;
+ Elf_Addr *where, value, mask;
Elf_Word type;
const Elf_Sym *sym;
const char *symn;
- where = (Elf_Addr *)(rels->r_offset + loff);
-
- sym = object->dyn.symtab;
- sym += ELF_R_SYM(rels->r_info);
- symn = object->dyn.strtab + sym->st_name;
-
type = ELF_R_TYPE(rels->r_info);
- switch (type) {
- case R_TYPE(NONE):
- case R_TYPE(JUMP_SLOT): /* shouldn't happen */
+
+ if (type == R_TYPE(NONE))
continue;
- case R_TYPE(RELATIVE):
- *where += loff;
+ if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL)
continue;
- case R_TYPE(32):
- value = *where;
- break;
+ where = (Elf_Addr *)(rels->r_offset + loff);
- case R_TYPE(GLOB_DAT):
+ if (RELOC_USE_ADDEND(type))
+ value = *where & RELOC_VALUE_BITMASK(type);
+ else
value = 0;
- break;
- case R_TYPE(COPY):
- {
+ 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 {
+ struct sym_res sr;
+
+ sr = _dl_find_symbol(symn,
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|
+ ((type == R_TYPE(JUMP_SLOT))?
+ SYM_PLT:SYM_NOTPLT), sym, object);
+ if (sr.sym == NULL) {
+resolve_failed:
+ if (ELF_ST_BIND(sym->st_info) !=
+ STB_WEAK)
+ fails++;
+ continue;
+ }
+ prev_sym = sym;
+ prev_value = (Elf_Addr)(sr.obj->obj_base +
+ sr.sym->st_value);
+ value += prev_value;
+ }
+ }
+
+ if (type == R_TYPE(JUMP_SLOT)) {
+ _dl_reloc_plt((Elf_Word *)where, value);
+ continue;
+ }
+
+ if (type == R_TYPE(COPY)) {
+ void *dstaddr = where;
+ const void *srcaddr;
+ const Elf_Sym *dstsym = sym;
struct sym_res sr;
sr = _dl_find_symbol(symn,
SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT,
- sym, object);
+ dstsym, object);
if (sr.sym == NULL)
- return 1;
+ goto resolve_failed;
- value = sr.obj->obj_base + sr.sym->st_value;
- _dl_bcopy((void *)value, where, sym->st_size);
+ srcaddr = (void *)(sr.obj->obj_base + sr.sym->st_value);
+ _dl_bcopy(srcaddr, dstaddr, dstsym->st_size);
continue;
}
- default:
- _dl_die("unknown relocation %d", type);
- }
-
- if (sym->st_shndx != SHN_UNDEF &&
- ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
+ if (RELOC_PC_RELATIVE(type))
+ value -= (Elf_Addr)where;
+ if (RELOC_BASE_RELATIVE(type))
value += loff;
- } else if (sym == prev_sym) {
- value += prev_value;
- } else {
- struct sym_res sr;
- sr = _dl_find_symbol(symn,
- SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
- sym, object);
- if (sr.sym == NULL) {
- if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
- return 1;
- continue;
- }
- prev_sym = sym;
- prev_value = sr.obj->obj_base + sr.sym->st_value;
- value += prev_value;
- }
+ mask = RELOC_VALUE_BITMASK(type);
+ value >>= RELOC_VALUE_RIGHTSHIFT(type);
+ value &= mask;
- *where = value;
+ *where &= ~mask;
+ *where |= value;
}
- return 0;
+ return fails;
}
#if 0
@@ -194,6 +297,12 @@ struct jmpslot {
#define JUMP 0xe990 /* NOP + JMP opcode */
#endif
+void
+_dl_reloc_plt(Elf_Addr *where, Elf_Addr value)
+{
+ *where = value;
+}
+
/*
* Resolve a symbol at run-time.
*/
@@ -245,41 +354,14 @@ _dl_bind(elf_object_t *object, int index)
return buf.newval;
}
-static int
-_dl_md_reloc_all_plt(elf_object_t *object, const Elf_Rel *reloc,
- const Elf_Rel *rend)
-{
- for (; reloc < rend; reloc++) {
- const Elf_Sym *sym;
- const char *symn;
- Elf_Addr *where;
- struct sym_res sr;
-
- sym = object->dyn.symtab;
- sym += ELF_R_SYM(reloc->r_info);
- symn = object->dyn.strtab + sym->st_name;
-
- sr = _dl_find_symbol(symn,
- SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object);
- if (sr.sym == NULL) {
- if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
- return 1;
- continue;
- }
-
- where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
- *where = sr.obj->obj_base + sr.sym->st_value;
- }
-
- return 0;
-}
-
int
_dl_md_reloc_got(elf_object_t *object, int lazy)
{
extern void _dl_bind_start(void); /* XXX */
- Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
- const Elf_Rel *reloc, *rend;
+ int fails = 0;
+ Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
+ int i, num;
+ Elf_Rel *rel;
if (pltgot == NULL)
return 0; /* it is possible to have no PLT/GOT relocations */
@@ -290,21 +372,20 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
if (object->traced)
lazy = 1;
- reloc = (const Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
- rend = (const Elf_Rel *)((char *)reloc + object->Dyn.info[DT_PLTRELSZ]);
-
- if (!lazy)
- return _dl_md_reloc_all_plt(object, reloc, rend);
-
- /* Lazy */
- pltgot[1] = (Elf_Addr)object;
- pltgot[2] = (Elf_Addr)&_dl_bind_start;
-
- for (; reloc < rend; reloc++) {
- Elf_Addr *where;
- where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
- *where += object->obj_base;
+ if (!lazy) {
+ fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
+ } else {
+ pltgot[1] = (Elf_Addr)object;
+ pltgot[2] = (Elf_Addr)&_dl_bind_start;
+
+ rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
+ num = (object->Dyn.info[DT_PLTRELSZ]);
+ for (i = 0; i < num/sizeof(Elf_Rel); i++, rel++) {
+ Elf_Addr *where;
+ where = (Elf_Addr *)(rel->r_offset + object->obj_base);
+ *where += object->obj_base;
+ }
}
- return 0;
+ return fails;
}