diff options
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/ld.so/alpha/rtld_machine.c | 43 | ||||
-rw-r--r-- | libexec/ld.so/amd64/rtld_machine.c | 32 | ||||
-rw-r--r-- | libexec/ld.so/arm/rtld_machine.c | 32 | ||||
-rw-r--r-- | libexec/ld.so/i386/rtld_machine.c | 32 | ||||
-rw-r--r-- | libexec/ld.so/m68k/rtld_machine.c | 41 | ||||
-rw-r--r-- | libexec/ld.so/m88k/rtld_machine.c | 19 | ||||
-rw-r--r-- | libexec/ld.so/mips64/rtld_machine.c | 36 | ||||
-rw-r--r-- | libexec/ld.so/powerpc/rtld_machine.c | 82 | ||||
-rw-r--r-- | libexec/ld.so/resolve.c | 6 | ||||
-rw-r--r-- | libexec/ld.so/resolve.h | 5 | ||||
-rw-r--r-- | libexec/ld.so/sh/rtld_machine.c | 32 | ||||
-rw-r--r-- | libexec/ld.so/sparc/rtld_machine.c | 32 | ||||
-rw-r--r-- | libexec/ld.so/sparc64/rtld_machine.c | 32 |
13 files changed, 350 insertions, 74 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; diff --git a/libexec/ld.so/amd64/rtld_machine.c b/libexec/ld.so/amd64/rtld_machine.c index c2e25a2ff81..0e717e68106 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.18 2013/03/18 04:22:31 guenther Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.19 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 2002,2004 Dale Rahn @@ -172,17 +172,26 @@ _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_RelA *rels; struct load_list *llist; loff = object->obj_base; numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); + relrel = rel == DT_RELA ? object->relacount : 0; rels = (Elf_RelA *)(object->Dyn.info[rel]); if (rels == NULL) return(0); + if (relrel > numrel) { + _dl_printf("relacount > numrel: %ld > %ld\n", relrel, numrel); + _dl_exit(20); + } + /* * unprotect some segments if we need it. */ @@ -194,7 +203,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("RELACOUNT wrong\n"); + _dl_exit(20); + } +#endif + where = (Elf_Addr *)(rels->r_offset + loff); + *where = rels->r_addend + loff; + } + for (; i < numrel; i++, rels++) { Elf_Addr *where, value, ooff, mask; Elf_Word type; const Elf_Sym *sym, *this; @@ -230,6 +252,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, @@ -245,7 +269,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; } } 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; } } diff --git a/libexec/ld.so/i386/rtld_machine.c b/libexec/ld.so/i386/rtld_machine.c index 06b6002dca0..078553b9223 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.26 2012/12/05 23:20:06 deraadt Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.27 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 2002 Dale Rahn @@ -170,17 +170,26 @@ _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(Elf32_Rel); + relrel = rel == DT_REL ? object->relcount : 0; rels = (Elf32_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. */ @@ -192,7 +201,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; @@ -223,6 +245,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, @@ -238,7 +262,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; } } diff --git a/libexec/ld.so/m68k/rtld_machine.c b/libexec/ld.so/m68k/rtld_machine.c index f8c3abf2594..58b443cb494 100644 --- a/libexec/ld.so/m68k/rtld_machine.c +++ b/libexec/ld.so/m68k/rtld_machine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtld_machine.c,v 1.1 2013/01/23 19:15:58 miod Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.2 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 2013 Miodrag Vallat. @@ -61,6 +61,7 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) { int i; int numrela; + int relrel; int fails = 0; struct load_list *llist; Elf32_Addr loff; @@ -68,6 +69,7 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) loff = object->obj_base; numrela = object->Dyn.info[relasz] / sizeof(Elf32_Rela); + relrel = rel == DT_RELA ? object->relacount : 0; relas = (Elf32_Rela *)(object->Dyn.info[rel]); #ifdef DL_PRINTF_DEBUG @@ -78,6 +80,11 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) if (relas == NULL) return(0); + if (relrel > numrela) { + _dl_printf("relacount > numrela: %ld > %ld\n", relrel, numrela); + _dl_exit(20); + } + /* * Change protection of all write protected segments in the object * so we can do relocations such as PC32. After relocation, @@ -93,12 +100,27 @@ _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++) { + Elf32_Addr *r_addr; + +#ifdef DEBUG + if (ELF_R_TYPE(relas->r_info) != R_68K_RELATIVE) { + _dl_printf("RELACOUNT wrong\n"); + _dl_exit(20); + } +#endif + r_addr = (Elf32_Addr *)(relas->r_offset + loff); + *r_addr = relas->r_addend + loff; + } + for (; i < numrela; i++, relas++) { Elf32_Addr *r_addr = (Elf32_Addr *)(relas->r_offset + loff); Elf32_Addr ooff, addend, newval; const Elf32_Sym *sym, *this; const char *symn; int type; + Elf32_Addr prev_value = 0, prev_ooff = 0; + const Elf32_Sym *prev_sym = NULL; type = ELF32_R_TYPE(relas->r_info); @@ -143,11 +165,11 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) continue; } - ooff = 0; - this = NULL; if (ELF32_R_SYM(relas->r_info) && !(ELF32_ST_BIND(sym->st_info) == STB_LOCAL && - ELF32_ST_TYPE (sym->st_info) == STT_NOTYPE)) { + ELF32_ST_TYPE (sym->st_info) == STT_NOTYPE) && + sym != prev_sym) { + this = NULL; ooff = _dl_find_symbol_bysym(object, ELF32_R_SYM(relas->r_info), &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND| @@ -159,6 +181,9 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) fails++; continue; } + prev_sym = sym; + prev_value = this->st_value; + prev_ooff = ooff; } if (ELF32_ST_BIND(sym->st_info) == STB_LOCAL && @@ -166,18 +191,18 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE)) addend = relas->r_addend; else - addend = this->st_value + relas->r_addend; + addend = prev_value + relas->r_addend; switch (type) { case R_68K_PC32: - newval = ooff + addend; + newval = prev_ooff + addend; newval -= (Elf_Addr)r_addr; *r_addr = newval; break; case R_68K_32: case R_68K_GLOB_DAT: case R_68K_JMP_SLOT: - newval = ooff + addend; + newval = prev_ooff + addend; *r_addr = newval; break; case R_68K_RELATIVE: diff --git a/libexec/ld.so/m88k/rtld_machine.c b/libexec/ld.so/m88k/rtld_machine.c index f8e70e790f8..8ef9d44c31c 100644 --- a/libexec/ld.so/m88k/rtld_machine.c +++ b/libexec/ld.so/m88k/rtld_machine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtld_machine.c,v 1.5 2013/04/20 18:40:42 miod Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.6 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 2013 Miodrag Vallat. @@ -100,6 +100,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) const Elf32_Sym *sym, *this; const char *symn; int type; + Elf32_Addr prev_value = 0, prev_ooff = 0; + const Elf32_Sym *prev_sym = NULL; type = ELF32_R_TYPE(relas->r_info); @@ -144,11 +146,11 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) continue; } - ooff = 0; - this = NULL; if (ELF32_R_SYM(relas->r_info) && !(ELF32_ST_BIND(sym->st_info) == STB_LOCAL && - ELF32_ST_TYPE (sym->st_info) == STT_NOTYPE)) { + ELF32_ST_TYPE (sym->st_info) == STT_NOTYPE) && + sym != prev_sym) { + this = NULL; ooff = _dl_find_symbol_bysym(object, ELF32_R_SYM(relas->r_info), &this, SYM_SEARCH_ALL | SYM_WARNNOTFOUND | @@ -160,12 +162,15 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) fails++; continue; } + prev_sym = sym; + prev_value = this->st_value; + prev_ooff = ooff; } if (type == RELOC_GOTP_ENT) { _dl_md_reloc_gotp_ent((Elf_Addr)r_addr, relas->r_addend + loff, - ooff + this->st_value); + prev_ooff + prev_value); continue; } @@ -174,11 +179,11 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE)) addend = relas->r_addend; else - addend = this->st_value + relas->r_addend; + addend = prev_value + relas->r_addend; switch (type) { case RELOC_32: - newval = ooff + addend; + newval = prev_ooff + addend; *r_addr = newval; break; case RELOC_BBASED_32: diff --git a/libexec/ld.so/mips64/rtld_machine.c b/libexec/ld.so/mips64/rtld_machine.c index 5acd2e8b4cb..905fe5ecf30 100644 --- a/libexec/ld.so/mips64/rtld_machine.c +++ b/libexec/ld.so/mips64/rtld_machine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtld_machine.c,v 1.14 2010/09/11 11:13:20 kettenis Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.15 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 1998-2004 Opsycon AB, Sweden. @@ -50,6 +50,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz) Elf64_Addr got_start, got_end; Elf64_Rel *relocs; const Elf64_Sym *sym, *this; + Elf64_Addr prev_value = 0; + const Elf64_Sym *prev_sym = NULL; loff = object->obj_base; numrel = object->Dyn.info[relsz] / sizeof(Elf64_Rel); @@ -102,17 +104,23 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz) type = ELF64_R_TYPE(relocs->r_info); this = NULL; - if (ELF64_R_SYM(relocs->r_info) && - !(ELF64_ST_BIND(sym->st_info) == STB_LOCAL && - ELF64_ST_TYPE (sym->st_info) == STT_NOTYPE)) { - ooff = _dl_find_symbol(symn, &this, - SYM_SEARCH_ALL | SYM_WARNNOTFOUND | SYM_PLT, - sym, object, NULL); - - if (this == NULL) { - if (ELF_ST_BIND(sym->st_info) != STB_WEAK) - fails++; - continue; + if (ELF64_R_SYM(relocs->r_info)) { + if (sym == prev_sym) + this = sym; /* XXX non-NULL */ + else if (!(ELF64_ST_BIND(sym->st_info) == STB_LOCAL && + ELF64_ST_TYPE (sym->st_info) == STT_NOTYPE)) { + ooff = _dl_find_symbol(symn, &this, + SYM_SEARCH_ALL | SYM_WARNNOTFOUND | SYM_PLT, + sym, object, NULL); + + if (this == NULL) { + if (ELF_ST_BIND(sym->st_info) != + STB_WEAK) + fails++; + continue; + } + prev_sym = sym; + prev_value = this->st_value + ooff; } } @@ -134,10 +142,10 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz) } } else if (this && ((long)r_addr & 7)) { _dl_bcopy((char *)r_addr, &robj, sizeof(robj)); - robj += this->st_value + ooff; + robj += prev_value; _dl_bcopy(&robj, (char *)r_addr, sizeof(robj)); } else if (this) { - *(u_int64_t *)r_addr += this->st_value + ooff; + *(u_int64_t *)r_addr += prev_value; } break; diff --git a/libexec/ld.so/powerpc/rtld_machine.c b/libexec/ld.so/powerpc/rtld_machine.c index 1981f7faedd..28245910a21 100644 --- a/libexec/ld.so/powerpc/rtld_machine.c +++ b/libexec/ld.so/powerpc/rtld_machine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtld_machine.c,v 1.48 2011/04/06 11:36:25 miod Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.49 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 1999 Dale Rahn @@ -77,6 +77,7 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) { int i; int numrela; + long relrel; int fails = 0; struct load_list *llist; Elf32_Addr loff; @@ -86,11 +87,11 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) Elf32_Addr *pltcall; Elf32_Addr *plttable; Elf32_Addr *pltinfo; - Elf32_Addr *first_rela; loff = object->obj_base; numrela = object->Dyn.info[relasz] / sizeof(Elf32_Rela); + relrel = rel == DT_RELA ? object->relacount : 0; relas = (Elf32_Rela *)(object->Dyn.info[rel]); #ifdef DL_PRINTF_DEBUG @@ -101,6 +102,11 @@ _dl_printf("object relocation size %x, numrela %x\n", if (relas == NULL) return(0); + if (relrel > numrela) { + _dl_printf("relcount > numrel: %ld > %ld\n", relrel, numrela); + _dl_exit(20); + } + pltresolve = NULL; pltcall = NULL; plttable = NULL; @@ -168,13 +174,36 @@ _dl_printf("object relocation size %x, numrela %x\n", } } + /* tight loop for leading RELATIVE relocs */ + for (i = 0; i < relrel; i++, relas++) { + Elf_Addr *r_addr; +#ifdef DEBUG + const Elf32_Sym *sym; - for (i = 0; i < numrela; i++, relas++) { + if (ELF32_R_TYPE(relas->r_info) != RELOC_RELATIVE) { + _dl_printf("RELCOUNT wrong\n"); + _dl_exit(20); + } + sym = object->dyn.symtab; + sym += ELF32_R_SYM(relas->r_info); + if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || + (ELF32_ST_TYPE(sym->st_info) != STT_SECTION && + ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE)) { + _dl_printf("RELATIVE relocation against symbol\n"); + _dl_exit(20); + } +#endif + r_addr = (Elf_Addr *)(relas->r_offset + loff); + *r_addr = loff + relas->r_addend; + } + for (; i < numrela; i++, relas++) { Elf32_Addr *r_addr = (Elf32_Addr *)(relas->r_offset + loff); Elf32_Addr ooff; const Elf32_Sym *sym, *this; const char *symn; int type; + Elf32_Addr prev_value = 0, prev_ooff = 0; + const Elf32_Sym *prev_sym = NULL; if (ELF32_R_SYM(relas->r_info) == 0xffffff) continue; @@ -193,16 +222,25 @@ _dl_printf("object relocation size %x, numrela %x\n", if (ELF32_R_SYM(relas->r_info) && !(ELF32_ST_BIND(sym->st_info) == STB_LOCAL && ELF32_ST_TYPE (sym->st_info) == STT_NOTYPE)) { - ooff = _dl_find_symbol_bysym(object, - ELF32_R_SYM(relas->r_info), &this, - SYM_SEARCH_ALL|SYM_WARNNOTFOUND| - ((type == RELOC_JMP_SLOT) ? SYM_PLT:SYM_NOTPLT), - sym, NULL); - - if (this == NULL) { - if (ELF_ST_BIND(sym->st_info) != STB_WEAK) - fails++; - continue; + if (sym == prev_sym) { + this = sym; /* XXX any non-NULL */ + ooff = prev_ooff; + } else { + ooff = _dl_find_symbol_bysym(object, + ELF32_R_SYM(relas->r_info), &this, + SYM_SEARCH_ALL|SYM_WARNNOTFOUND| + ((type == RELOC_JMP_SLOT) ? + SYM_PLT:SYM_NOTPLT), sym, NULL); + + if (this == NULL) { + if (ELF_ST_BIND(sym->st_info) != + STB_WEAK) + fails++; + continue; + } + prev_sym = sym; + prev_value = this->st_value; + prev_ooff = ooff; } } @@ -214,7 +252,7 @@ _dl_printf("object relocation size %x, numrela %x\n", ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { *r_addr = ooff + relas->r_addend; } else { - *r_addr = ooff + this->st_value + + *r_addr = ooff + prev_value + relas->r_addend; } break; @@ -231,13 +269,13 @@ _dl_printf("rel1 r_addr %x val %x loff %x ooff %x addend %x\n", r_addr, #endif } else { - *r_addr = loff + this->st_value + + *r_addr = loff + prev_value + relas->r_addend; } break; case RELOC_JMP_SLOT: { - Elf32_Addr target = ooff + this->st_value + + Elf32_Addr target = ooff + prev_value + relas->r_addend; Elf32_Addr val = target - (Elf32_Addr)r_addr; @@ -246,7 +284,7 @@ _dl_printf("rel1 r_addr %x val %x loff %x ooff %x addend %x\n", r_addr, #ifdef DL_PRINTF_DEBUG _dl_printf(" ooff %x, sym val %x, addend %x" " r_addr %x symn [%s] -> %x\n", - ooff, this->st_value, relas->r_addend, + ooff, prev_value, relas->r_addend, r_addr, symn, val); #endif /* if offset is > RELOC_24 deal with it */ @@ -264,7 +302,7 @@ _dl_printf(" ooff %x, sym val %x, addend %x" } _dl_dcbf(&r_addr[0]); _dl_dcbf(&r_addr[2]); - val= ooff + this->st_value + + val= ooff + prev_value + relas->r_addend; #ifdef DL_PRINTF_DEBUG _dl_printf(" symn [%s] val 0x%x\n", symn, val); @@ -281,13 +319,13 @@ _dl_printf(" symn [%s] val 0x%x\n", symn, val); break; case RELOC_GLOB_DAT: - *r_addr = ooff + this->st_value + relas->r_addend; + *r_addr = ooff + prev_value + relas->r_addend; break; #if 1 /* should not be supported ??? */ case RELOC_REL24: { - Elf32_Addr val = ooff + this->st_value + + Elf32_Addr val = ooff + prev_value + relas->r_addend - (Elf32_Addr)r_addr; if (!B24_VALID_RANGE(val)){ /* invalid offset */ @@ -342,7 +380,7 @@ _dl_printf(" symn [%s] val 0x%x\n", symn, val); case RELOC_REL14: case RELOC_REL14_NTAKEN: { - Elf32_Addr val = ooff + this->st_value + + Elf32_Addr val = ooff + prev_value + relas->r_addend - (Elf32_Addr)r_addr; if (((val & 0xffff8000) != 0) && ((val & 0xffff8000) != 0xffff8000)) { @@ -364,7 +402,7 @@ _dl_printf(" symn [%s] val 0x%x\n", symn, val); #ifdef DL_PRINTF_DEBUG _dl_printf("copy r_addr %x, sym %x [%s] size %d val %x\n", r_addr, sym, symn, sym->st_size, - (ooff + this->st_value+ + (ooff + prev_value+ relas->r_addend)); #endif /* diff --git a/libexec/ld.so/resolve.c b/libexec/ld.so/resolve.c index 8a232c88a32..c6f551f9406 100644 --- a/libexec/ld.so/resolve.c +++ b/libexec/ld.so/resolve.c @@ -1,4 +1,4 @@ -/* $OpenBSD: resolve.c,v 1.61 2013/04/05 12:58:03 kurt Exp $ */ +/* $OpenBSD: resolve.c,v 1.62 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -264,6 +264,10 @@ _dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp, object->obj_flags |= DF_1_NOW; if (dynp->d_tag == DT_FLAGS_1) object->obj_flags |= dynp->d_un.d_val; + if (dynp->d_tag == DT_RELACOUNT) + object->relacount = dynp->d_un.d_val; + if (dynp->d_tag == DT_RELCOUNT) + object->relcount = dynp->d_un.d_val; dynp++; } DL_DEB((" flags %s = 0x%x\n", objname, object->obj_flags )); diff --git a/libexec/ld.so/resolve.h b/libexec/ld.so/resolve.h index 3ebfe7061d5..8a482e53b93 100644 --- a/libexec/ld.so/resolve.h +++ b/libexec/ld.so/resolve.h @@ -1,4 +1,4 @@ -/* $OpenBSD: resolve.h,v 1.67 2013/04/05 12:58:03 kurt Exp $ */ +/* $OpenBSD: resolve.h,v 1.68 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -98,6 +98,9 @@ struct elf_object { } Dyn; #define dyn Dyn.u + Elf_Addr relacount; /* DT_RELACOUNT */ + Elf_Addr relcount; /* DT_RELCOUNT */ + int status; #define STAT_RELOC_DONE 0x01 #define STAT_GOT_DONE 0x02 diff --git a/libexec/ld.so/sh/rtld_machine.c b/libexec/ld.so/sh/rtld_machine.c index d41e4ba3866..77bce195695 100644 --- a/libexec/ld.so/sh/rtld_machine.c +++ b/libexec/ld.so/sh/rtld_machine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtld_machine.c,v 1.17 2013/03/29 22:57:07 miod Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.18 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 2004 Dale Rahn @@ -599,18 +599,27 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) { long i; long numrela; + long relrel; int fails = 0; Elf_Addr loff; + Elf_Addr prev_value = 0; + const Elf_Sym *prev_sym = NULL; Elf_RelA *rels; struct load_list *llist; loff = object->obj_base; numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA); + relrel = rel == DT_RELA ? object->relacount : 0; rels = (Elf_RelA *)(object->Dyn.info[rel]); if (rels == 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. */ @@ -624,7 +633,20 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) } } - for (i = 0; i < numrela; 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("RELACOUNT wrong\n"); + _dl_exit(20); + } +#endif + where = (Elf_Addr *)(rels->r_offset + loff); + *where = rels->r_addend + loff; + } + for (; i < numrela; i++, rels++) { Elf_Addr *where, value, ooff, mask; Elf_Word type; const Elf_Sym *sym, *this; @@ -664,6 +686,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) 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; #if 1 @@ -687,7 +711,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; } } diff --git a/libexec/ld.so/sparc/rtld_machine.c b/libexec/ld.so/sparc/rtld_machine.c index a38e5f34fb4..3bb96859171 100644 --- a/libexec/ld.so/sparc/rtld_machine.c +++ b/libexec/ld.so/sparc/rtld_machine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtld_machine.c,v 1.34 2012/12/05 23:20:07 deraadt Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.35 2013/05/08 20:55:14 guenther Exp $ */ /* * Copyright (c) 1999 Dale Rahn @@ -178,18 +178,27 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) { long i; long numrela; + long relrel; int fails = 0; Elf_Addr loff; + Elf_Addr prev_value = 0; + const Elf_Sym *prev_sym = NULL; Elf_RelA *relas; struct load_list *llist; loff = object->obj_base; numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA); + relrel = rel == DT_RELA ? object->relacount : 0; relas = (Elf_RelA *)(object->Dyn.info[rel]); if (relas == NULL) return(0); + if (relrel > numrela) { + _dl_printf("relacount > numrela: %ld > %ld\n", relrel, numrela); + _dl_exit(20); + } + /* * unprotect some segments if we need it. */ @@ -201,7 +210,20 @@ _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 *where; + +#ifdef DEBUG + if (ELF_R_TYPE(relas->r_info) != R_TYPE(RELATIVE)) { + _dl_printf("RELACOUNT wrong\n"); + _dl_exit(20); + } +#endif + where = (Elf_Addr *)(relas->r_offset + loff); + *where = relas->r_addend + loff; + } + for (; i < numrela; i++, relas++) { Elf_Addr *where, ooff; Elf_Word type, value, mask; const Elf_Sym *sym, *this; @@ -237,6 +259,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) 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, @@ -252,7 +276,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; } } diff --git a/libexec/ld.so/sparc64/rtld_machine.c b/libexec/ld.so/sparc64/rtld_machine.c index 772fbadb15f..d11eacf9a2d 100644 --- a/libexec/ld.so/sparc64/rtld_machine.c +++ b/libexec/ld.so/sparc64/rtld_machine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtld_machine.c,v 1.48 2013/01/31 06:26:27 guenther Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.49 2013/05/08 20:55:15 guenther Exp $ */ /* * Copyright (c) 1999 Dale Rahn @@ -205,18 +205,27 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) { long i; long numrela; + long relrel; int fails = 0; Elf_Addr loff; + Elf_Addr prev_value = 0; + const Elf_Sym *prev_sym = NULL; Elf_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. */ @@ -228,7 +237,20 @@ _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 *where; + +#ifdef DEBUG + if (ELF_R_TYPE(relas->r_info) != R_TYPE(RELATIVE)) { + _dl_printf("RELACOUNT wrong\n"); + _dl_exit(20); + } +#endif + where = (Elf_Addr *)(relas->r_offset + loff); + *where = relas->r_addend + loff; + } + for (; i < numrela; i++, relas++) { Elf_Addr *where, value, ooff, mask; Elf_Word type; const Elf_Sym *sym, *this; @@ -259,6 +281,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) 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, @@ -274,7 +298,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; } } |