Index: stand/common/reloc_elf.c =================================================================== --- stand/common/reloc_elf.c +++ stand/common/reloc_elf.c @@ -201,27 +201,81 @@ return (0); #elif defined(__powerpc__) - Elf_Size w; + Elf_Addr *where; + Elf_Half *hwhere; + Elf_Addr addr; + Elf_Addr addend; + Elf_Word rtype, symidx; const Elf_Rela *rela; switch (reltype) { case ELF_RELOC_RELA: rela = reldata; - if (relbase + rela->r_offset >= dataaddr && - relbase + rela->r_offset < dataaddr + len) { - switch (ELF_R_TYPE(rela->r_info)) { - case R_PPC_RELATIVE: - w = relbase + rela->r_addend; - bcopy(&w, (u_char *)data + (relbase + - rela->r_offset - dataaddr), sizeof(w)); - break; - default: - printf("\nunhandled relocation type %u\n", - (u_int)ELF_R_TYPE(rela->r_info)); - return (EFTYPE); - } - } + where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - + dataaddr); + hwhere = (Elf_Half *)where; + addend = rela->r_addend; + rtype = ELF_R_TYPE(rela->r_info); + symidx = ELF_R_SYM(rela->r_info); + break; + default: + printf("\nPPC only supports RELA relocations\n"); + return (EFTYPE); + } + + if ((char *)where < (char *)data || (char *)where >= (char *)data + len) + printf("\nReloc %d outside of data, offset %lu", + rtype, (long)rela->r_offset); + + switch (rtype) { + case R_PPC_NONE: break; + + case R_PPC_ADDR32: /* word32 S + A */ + addr = symaddr(ef, symidx); + if (addr == 0) + return (ESRCH); + *where = addr + addend; + break; + + case R_PPC_ADDR16_LO: /* #lo(S) */ + addr = symaddr(ef, symidx); + if (addr == 0) + return (ESRCH); + /* + * addend values are sometimes relative to sections + * (i.e. .rodata) in rela, where in reality they + * are relative to relbase. Detect this condition. + */ + if (addr > relbase && addr <= (relbase + addend)) + addr = relbase; + addr = addr + addend; + *hwhere = addr & 0xffff; + break; + + case R_PPC_ADDR16_HA: /* #ha(S) */ + addr = symaddr(ef, symidx); + if (addr == 0) + return (ESRCH); + /* + * addend values are sometimes relative to sections + * (i.e. .rodata) in rela, where in reality they + * are relative to relbase. Detect this condition. + */ + if (addr > relbase && addr <= (relbase + addend)) + addr = relbase; + addr = addr + addend; + *hwhere = ((addr >> 16) + ((addr & 0x8000) ? 1 : 0)) + & 0xffff; + break; + + case R_PPC_RELATIVE: /* word32 B + A */ + *where = relbase + addend; + break; + + default: + printf("\nunhandled relocation type %u\n", rtype); + return (EFTYPE); } return (0);