summaryrefslogtreecommitdiff
path: root/libexec/ld.so/alpha
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/ld.so/alpha')
-rw-r--r--libexec/ld.so/alpha/rtld_machine.c43
1 files changed, 40 insertions, 3 deletions
diff --git a/libexec/ld.so/alpha/rtld_machine.c b/libexec/ld.so/alpha/rtld_machine.c
index 394bf99507a..37480b01f54 100644
--- a/libexec/ld.so/alpha/rtld_machine.c
+++ b/libexec/ld.so/alpha/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.47 2012/12/05 23:20:06 deraadt Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.48 2013/05/08 20:55:14 guenther Exp $ */
/*
* Copyright (c) 1999 Dale Rahn
@@ -47,18 +47,27 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
{
long i;
long numrela;
+ long relrel;
int fails = 0;
Elf64_Addr loff;
+ Elf64_Addr prev_value = 0;
+ const Elf_Sym *prev_sym = NULL;
Elf64_Rela *relas;
struct load_list *llist;
loff = object->obj_base;
numrela = object->Dyn.info[relasz] / sizeof(Elf64_Rela);
+ relrel = rel == DT_RELA ? object->relacount : 0;
relas = (Elf64_Rela *)(object->Dyn.info[rel]);
if (relas == NULL)
return(0);
+ if (relrel > numrela) {
+ _dl_printf("relacount > numrel: %ld > %ld\n", relrel, numrela);
+ _dl_exit(20);
+ }
+
/*
* unprotect some segments if we need it.
* XXX - we unprotect way to much. only the text can have cow
@@ -73,7 +82,29 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
}
}
- for (i = 0; i < numrela; i++, relas++) {
+ /* tight loop for leading RELATIVE relocs */
+ for (i = 0; i < relrel; i++, relas++) {
+ Elf_Addr *r_addr;
+
+#ifdef DEBUG
+ if (ELF64_R_TYPE(relas->r_info) != R_TYPE(RELATIVE)) {
+ _dl_printf("RELACOUNT wrong\n");
+ _dl_exit(20);
+ }
+#endif
+
+ r_addr = (Elf64_Addr *)(relas->r_offset + loff);
+
+ /* Handle unaligned RELATIVE relocs */
+ if ((((Elf_Addr)r_addr) & 0x7) != 0) {
+ Elf_Addr tmp;
+ _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
+ tmp += loff;
+ _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
+ } else
+ *r_addr += loff;
+ }
+ for (; i < numrela; i++, relas++) {
Elf64_Addr *r_addr;
Elf64_Addr ooff;
const Elf64_Sym *sym, *this;
@@ -126,13 +157,19 @@ _dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr,
*r_addr = ooff + this->st_value + relas->r_addend;
break;
case R_TYPE(GLOB_DAT):
+ if (sym == prev_sym) {
+ *r_addr = prev_value + relas->r_addend;
+ break;
+ }
ooff = _dl_find_symbol_bysym(object,
ELF64_R_SYM(relas->r_info), &this,
SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
sym, NULL);
if (this == NULL)
goto resolve_failed;
- *r_addr = ooff + this->st_value + relas->r_addend;
+ prev_sym = sym;
+ prev_value = ooff + this->st_value;
+ *r_addr = prev_value + relas->r_addend;
break;
case R_TYPE(NONE):
break;