From 2e5b3a405f3e712eedd7886ed4cf91d71e615b7b Mon Sep 17 00:00:00 2001 From: Philip Guenther Date: Thu, 28 Nov 2019 16:54:31 +0000 Subject: Revert yesterday's _dl_md_reloc() and _dl_md_reloc_got() changes: something's broken on at least i386. --- libexec/ld.so/aarch64/rtld_machine.c | 238 ++++++++++++++++----------- libexec/ld.so/amd64/rtld_machine.c | 285 +++++++++++++++++++++----------- libexec/ld.so/arm/rtld_machine.c | 304 ++++++++++++++++++++++++----------- libexec/ld.so/hppa/boot_md.c | 17 +- libexec/ld.so/i386/rtld_machine.c | 273 ++++++++++++++++++++----------- 5 files changed, 731 insertions(+), 386 deletions(-) (limited to 'libexec') 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; } -- cgit v1.2.3