diff options
Diffstat (limited to 'libexec/ld.so/arm')
-rw-r--r-- | libexec/ld.so/arm/rtld_machine.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/libexec/ld.so/arm/rtld_machine.c b/libexec/ld.so/arm/rtld_machine.c index 6385a2f7911..258845d6b9a 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.16 2011/04/06 11:36:25 miod Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.17 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 2004 Dale Rahn @@ -161,18 +161,27 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz) { long i; long numrel; + long relrel; int fails = 0; Elf_Addr loff; + Elf_Addr prev_value = 0; + const Elf_Sym *prev_sym = NULL; Elf_Rel *rels; struct load_list *llist; loff = object->obj_base; numrel = object->Dyn.info[relsz] / sizeof(Elf_Rel); + relrel = rel == DT_REL ? object->relcount : 0; rels = (Elf_Rel *)(object->Dyn.info[rel]); if (rels == NULL) return(0); + if (relrel > numrel) { + _dl_printf("relcount > numrel: %ld > %ld\n", relrel, numrel); + _dl_exit(20); + } + /* * unprotect some segments if we need it. */ @@ -186,7 +195,20 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz) } } - for (i = 0; i < numrel; i++, rels++) { + /* tight loop for leading RELATIVE relocs */ + for (i = 0; i < relrel; i++, rels++) { + Elf_Addr *where; + +#ifdef DEBUG + if (ELF_R_TYPE(rels->r_info) != R_TYPE(RELATIVE)) { + _dl_printf("RELCOUNT wrong\n"); + _dl_exit(20); + } +#endif + where = (Elf_Addr *)(rels->r_offset + loff); + *where += loff; + } + for (; i < numrel; i++, rels++) { Elf_Addr *where, value, ooff, mask; Elf_Word type; const Elf_Sym *sym, *this; @@ -225,6 +247,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz) if (sym->st_shndx != SHN_UNDEF && ELF_ST_BIND(sym->st_info) == STB_LOCAL) { value += loff; + } else if (sym == prev_sym) { + value += prev_value; } else { this = NULL; ooff = _dl_find_symbol_bysym(object, @@ -240,7 +264,9 @@ resolve_failed: fails++; continue; } - value += (Elf_Addr)(ooff + this->st_value); + prev_sym = sym; + prev_value = (Elf_Addr)(ooff + this->st_value); + value += prev_value; } } |