Module Name: src Committed By: matt Date: Wed Jun 8 17:19:20 UTC 2011
Modified Files: src/sys/arch/powerpc/powerpc: kobj_machdep.c Log Message: Rework to support more relocations. Reorganize so code doesn't need to be replicated over and over. To generate a diff of this commit: cvs rdiff -u -r1.4 -r1.5 src/sys/arch/powerpc/powerpc/kobj_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/powerpc/powerpc/kobj_machdep.c diff -u src/sys/arch/powerpc/powerpc/kobj_machdep.c:1.4 src/sys/arch/powerpc/powerpc/kobj_machdep.c:1.5 --- src/sys/arch/powerpc/powerpc/kobj_machdep.c:1.4 Fri Mar 25 19:37:51 2011 +++ src/sys/arch/powerpc/powerpc/kobj_machdep.c Wed Jun 8 17:19:20 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: kobj_machdep.c,v 1.4 2011/03/25 19:37:51 riz Exp $ */ +/* $NetBSD: kobj_machdep.c,v 1.5 2011/06/08 17:19:20 matt Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -52,7 +52,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kobj_machdep.c,v 1.4 2011/03/25 19:37:51 riz Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kobj_machdep.c,v 1.5 2011/06/08 17:19:20 matt Exp $"); #define ELFSIZE ARCH_ELFSIZE @@ -69,8 +69,8 @@ Elf_Addr *where; Elf32_Half *hwhere; Elf_Addr addr; - Elf_Addr addend; - Elf_Word rtype, symidx; + Elf_Sword addend; /* needs to be signed */ + u_int rtype, symidx; const Elf_Rela *rela; if (!isrela) { @@ -88,18 +88,28 @@ case R_PPC_NONE: break; - case R_PPC_32: /* word32 S + A */ + case R_PPC_RELATIVE: /* word32 B + A */ + addend += relocbase; /* A += B */ + break; + + case R_PPC_REL32: /* word32 S + A - P */ + case R_PPC_REL16: /* half16* (S + A - P) */ + case R_PPC_REL16_LO: /* half16 #lo(S + A - P) */ + case R_PPC_REL16_HI: /* half16 #hi(S + A - P) */ + case R_PPC_REL16_HA: /* half16 #ha(S + A - P) */ + addend -= relocbase + rela->r_offset; /* A -= P */ + /* FALLTHROUGH */ + + case R_PPC_32: /* word32 S + A */ + case R_PPC_16: /* half16* S + A */ + case R_PPC_16_LO: /* half16 #lo(S + A) */ + case R_PPC_16_HA: /* half16 #ha(S + A) */ + case R_PPC_16_HI: /* half16 #hi(S + A) */ addr = kobj_sym_lookup(ko, symidx); if (addr == 0) return -1; - addr += addend; - *where = addr; - break; - case R_PPC_16_LO: /* #lo(S) */ - addr = kobj_sym_lookup(ko, symidx); - if (addr == 0) - return -1; +#if 0 /* * addend values are sometimes relative to sections * (i.e. .rodata) in rela, where in reality they @@ -108,35 +118,41 @@ if (addr > relocbase && addr <= (relocbase + addend)) addr = relocbase + addend; else - addr += addend; - *hwhere = addr & 0xffff; +#endif + addend += addr; /* A += S */ break; - case R_PPC_16_HA: /* #ha(S) */ - addr = kobj_sym_lookup(ko, symidx); - if (addr == 0) - return -1; - /* - * addend values are sometimes relative to sections - * (i.e. .rodata) in rela, where in reality they - * are relative to relocbase. Detect this condition. - */ - if (addr > relocbase && addr <= (relocbase + addend)) - addr = relocbase + addend; - else - addr += addend; - *hwhere = ((addr >> 16) + ((addr & 0x8000) ? 1 : 0)) - & 0xffff; - break; + default: + printf("kobj_reloc: unexpected relocation type %u\n", rtype); + return -1; + } + - case R_PPC_RELATIVE: /* word32 B + A */ - *where = relocbase + addend; + switch (rtype) { + case R_PPC_RELATIVE: /* word32 B + A */ + case R_PPC_REL32: /* word32 S + A - P */ + case R_PPC_32: /* word32 S + A */ + *where = addend; break; - default: - printf("kobj_reloc: unexpected relocation type %d\n", - (int)rtype); - return -1; + case R_PPC_REL16: /* half16* (S + A - P) */ + case R_PPC_16: /* half16* S + A */ + if ((int16_t) addend != addend) + return -1; + /* FALLTHROUGH */ + case R_PPC_REL16_LO: /* half16 #lo(S + A - P) */ + case R_PPC_16_LO: /* half16 #lo(S + A) */ + *hwhere = addend & 0xffff; + break; + + case R_PPC_REL16_HA: /* half16 #ha(S + A - P) */ + case R_PPC_16_HA: /* half16 #ha(S + A) */ + addend += 0x8000; + /* FALLTHROUGH */ + case R_PPC_REL16_HI: /* half16 #hi(S + A - P) */ + case R_PPC_16_HI: /* half16 #hi(S + A) */ + *hwhere = (addend >> 16) & 0xffff; + break; } return 0;