diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 2001-09-25 14:12:24 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 2001-09-25 14:12:24 +0000 |
commit | ed31172b7bf14e86dc017f027f4a41780acba725 (patch) | |
tree | 6192d161600ae866c5c55059018294c38f416c5a | |
parent | 359c63ae6edcfabc5599be1c838d6ccd62d6c013 (diff) |
Borrow a big chunk of code from the NetBSD ld.elf_so to do all the
basic relocations with a table.
-rw-r--r-- | libexec/ld.so/sparc64/rtld_machine.c | 294 |
1 files changed, 223 insertions, 71 deletions
diff --git a/libexec/ld.so/sparc64/rtld_machine.c b/libexec/ld.so/sparc64/rtld_machine.c index 2296ffd2ea9..01576a4fe93 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.1 2001/09/23 00:14:56 drahn Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.2 2001/09/25 14:12:23 art Exp $ */ /* * Copyright (c) 1999 Dale Rahn @@ -31,7 +31,42 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + */ +/*- + * Copyright (c) 2000 Eduardo Horvath. + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Paul Kranenburg. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ #define _DYN_LOADER @@ -47,17 +82,125 @@ #include "archdep.h" #include "resolve.h" -void -_dl_bcopy(void *src, void *dest, int size) -{ - unsigned char *psrc, *pdest; - int i; - psrc = src; - pdest = dest; - for (i = 0; i < size; i++) { - pdest[i] = psrc[i]; - } -} +/* + * 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_U 0x04000000 /* Unaligned */ +#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ +#define _RF_RS(s) ( (s) & 0xff) /* right shift */ +static int reloc_target_flags[] = { + 0, /* NONE */ + _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */ + _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELOC_32 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* DISP_8 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* DISP_16 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HI22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 13 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LO10 */ + _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */ + _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */ + _RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */ + _RF_SZ(32) | _RF_RS(0), /* COPY */ + _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */ + _RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */ + _RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0), /* RELATIVE */ + _RF_S|_RF_A| _RF_U| _RF_SZ(32) | _RF_RS(0), /* UA_32 */ + + _RF_A| _RF_SZ(32) | _RF_RS(0), /* PLT32 */ + _RF_A| _RF_SZ(32) | _RF_RS(10), /* HIPLT22 */ + _RF_A| _RF_SZ(32) | _RF_RS(0), /* LOPLT10 */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT32 */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PCPLT22 */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT10 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 10 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 11 */ + _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* 64 */ + _RF_S|_RF_A|/*extra*/ _RF_SZ(32) | _RF_RS(0), /* OLO10 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(42), /* HH22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(32), /* HM10 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LM22 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(42), /* PC_HH22 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(32), /* PC_HM10 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC_LM22 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP16 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP19 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_JMP */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 7 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 5 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 6 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(64) | _RF_RS(0), /* DISP64 */ + _RF_A| _RF_SZ(64) | _RF_RS(0), /* PLT64 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HIX22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LOX10 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(22), /* H44 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(12), /* M44 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* L44 */ + _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REGISTER */ + _RF_S|_RF_A| _RF_U| _RF_SZ(64) | _RF_RS(0), /* UA64 */ + _RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0), /* UA16 */ +}; + +#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_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 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 long reloc_target_bitmask[] = { +#define _BM(x) (~(-(1ULL << (x)))) + 0, /* NONE */ + _BM(8), _BM(16), _BM(32), /* RELOC_8, _16, _32 */ + _BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */ + _BM(30), _BM(22), /* WDISP30, WDISP22 */ + _BM(22), _BM(22), /* HI22, _22 */ + _BM(13), _BM(10), /* RELOC_13, _LO10 */ + _BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */ + _BM(10), _BM(22), /* _PC10, _PC22 */ + _BM(30), 0, /* _WPLT30, _COPY */ + _BM(32), _BM(32), _BM(32), /* _GLOB_DAT, JMP_SLOT, _RELATIVE */ + _BM(32), _BM(32), /* _UA32, PLT32 */ + _BM(22), _BM(10), /* _HIPLT22, LOPLT10 */ + _BM(32), _BM(22), _BM(10), /* _PCPLT32, _PCPLT22, _PCPLT10 */ + _BM(10), _BM(11), -1, /* _10, _11, _64 */ + _BM(10), _BM(22), /* _OLO10, _HH22 */ + _BM(10), _BM(22), /* _HM10, _LM22 */ + _BM(22), _BM(10), _BM(22), /* _PC_HH22, _PC_HM10, _PC_LM22 */ + _BM(16), _BM(19), /* _WDISP16, _WDISP19 */ + -1, /* GLOB_JMP */ + _BM(7), _BM(5), _BM(6) /* _7, _5, _6 */ + -1, -1, /* DISP64, PLT64 */ + _BM(22), _BM(13), /* HIX22, LOX10 */ + _BM(22), _BM(10), _BM(13), /* H44, M44, L44 */ + -1, -1, _BM(16), /* REGISTER, UA64, UA16 */ +#undef _BM +}; +#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) int _dl_md_reloc(elf_object_t *object, int rel, int relasz) @@ -65,8 +208,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) long i; long numrela; long fails = 0; - Elf64_Addr loff; - Elf64_Rela *relas; + Elf_Addr loff, mask; + Elf_RelA *relas; load_list_t *llist; loff = object->load_offs; @@ -92,73 +235,82 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) } for (i = 0; i < numrela; i++, relas++) { - Elf64_Addr *r_addr; - Elf64_Addr ooff; - const Elf64_Sym *sym, *this; + Elf_Addr *where, value, ooff; + Elf_Word type; + const Elf_Sym *sym, *this; const char *symn; - r_addr = (Elf64_Addr *)(relas->r_offset + loff); + where = (Elf64_Addr *)(relas->r_offset + loff); + + type = ELF_R_TYPE(relas->r_info); + value = relas->r_addend; + + if (type == R_TYPE(NONE)) + continue; - if (ELF64_R_SYM(relas->r_info) == 0xffffffff) { + if (type == R_TYPE(JMP_SLOT)) { +_dl_printf("JMP_SLOT relocation\n"); continue; } - sym = object->dyn.symtab; - sym += ELF64_R_SYM(relas->r_info); - symn = object->dyn.strtab + sym->st_name; + if (type == R_TYPE(COPY)) { +_dl_printf("COPY relocation\n"); + continue; + } - this = NULL; - switch (ELF64_R_TYPE(relas->r_info)) { - case R_TYPE(64): + if (type == R_TYPE(RELATIVE)) { + *where = (Elf_Addr)(loff + value); + continue; + } + + if (RELOC_RESOLVE_SYMBOL(type)) { + sym = object->dyn.symtab; + sym += ELF_R_SYM(relas->r_info); + symn = object->dyn.strtab + sym->st_name; + + this = NULL; ooff = _dl_find_symbol(symn, _dl_objects, &this, 0, 1); - if (this == NULL) - goto resolve_failed; - *r_addr += ooff + this->st_value + relas->r_addend; - break; - case R_TYPE(RELATIVE): - /* - * There is a lot of unaligned RELATIVE - * relocs generated by gcc in the exception handlers. - */ - if ((((Elf_Addr) r_addr) & 0x7) != 0) { - Elf_Addr tmp; -#if 0 -_dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr, -ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff); -#endif - _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr)); - tmp += loff; - _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr)); - } else { - *r_addr += loff; + if (this == NULL) { + _dl_printf("%s: %s :can't resolve reference '%s'\n", + _dl_progname, object->load_name, symn); + fails++; + continue; } - break; - case R_TYPE(JMP_SLOT): - ooff = _dl_find_symbol(symn, _dl_objects, &this, 0, 1); - if (this == NULL) - goto resolve_failed; - *r_addr = ooff + this->st_value + relas->r_addend; - break; - case R_TYPE(GLOB_DAT): - ooff = _dl_find_symbol(symn, _dl_objects, &this, 0, 1); - if (this == NULL) - goto resolve_failed; - *r_addr = ooff + this->st_value + relas->r_addend; - break; - case R_TYPE(NONE): - break; - default: - _dl_printf("%s:" - " %s: unsupported relocation '%s' %d at %lx\n", - _dl_progname, object->load_name, symn, - ELF64_R_TYPE(relas->r_info), r_addr ); - _dl_exit(1); } - continue; -resolve_failed: - _dl_printf("%s: %s :can't resolve reference '%s'\n", - _dl_progname, object->load_name, symn); - fails++; + + if (RELOC_PC_RELATIVE(type)) { + value -= (Elf_Addr)where; + } + + if (RELOC_BASE_RELATIVE(type)) { + value += loff; + } + + if (RELOC_UNALIGNED(type)) { + /* Handle unaligned relocations. */ + Elf_Addr tmp = 0; + char *ptr = (char *)where; + int i, size = RELOC_TARGET_SIZE(type)/8; + + /* Read it in one byte at a time. */ + for (i=0; i<size; i++) + tmp = (tmp << 8) | ptr[i]; + + tmp &= ~mask; + tmp |= value; + + /* Write it back out. */ + for (i=0; i<size; i++) + ptr[i] = ((tmp >> (8*i)) & 0xff); + } else if (RELOC_TARGET_SIZE(type) > 32) { + *where &= ~mask; + *where |= value; + } else { + Elf32_Addr *where32 = (Elf32_Addr *)where; + + *where32 &= ~mask; + *where32 |= value; + } } /* * flush ?? - XXX |