#include <sys/types.h>
#include <machine/elf.h>
#include <errno.h>
#include <stand.h>
#include <link.h>
#include "bootstrap.h"
#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l)
int
__elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata,
int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len)
{
#if (defined(__x86_64__) || defined(__i386__)) && __ELF_WORD_SIZE == 64
Elf64_Addr *where, val;
Elf_Addr addend, addr;
Elf_Size rtype, symidx;
const Elf_Rel *rel;
const Elf_Rela *rela;
switch (reltype) {
case ELF_RELOC_REL:
rel = (const Elf_Rel *)reldata;
where = (Elf64_Addr *)((char *)data + relbase + rel->r_offset -
dataaddr);
addend = 0;
rtype = ELF_R_TYPE(rel->r_info);
symidx = ELF_R_SYM(rel->r_info);
addend = 0;
break;
case ELF_RELOC_RELA:
rela = (const Elf_Rela *)reldata;
where = (Elf64_Addr *)((char *)data + relbase + rela->r_offset -
dataaddr);
addend = rela->r_addend;
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
break;
default:
return (EINVAL);
}
if ((char *)where < (char *)data || (char *)where >= (char *)data + len)
return (0);
if (reltype == ELF_RELOC_REL)
addend = *where;
#define R_X86_64_64 1
#define R_X86_64_RELATIVE 8
switch (rtype) {
case R_X86_64_64:
addr = symaddr(ef, symidx);
if (addr == 0)
return (ESRCH);
val = addr + addend;
*where = val;
break;
case R_X86_64_RELATIVE:
addr = (Elf_Addr)addend + relbase;
val = addr;
*where = val;
break;
default:
printf("\nunhandled relocation type %u\n", (u_int)rtype);
return (EFTYPE);
}
return (0);
#elif defined(__i386__) && __ELF_WORD_SIZE == 32
Elf_Addr addend, addr, *where, val;
Elf_Size rtype, symidx;
const Elf_Rel *rel;
const Elf_Rela *rela;
switch (reltype) {
case ELF_RELOC_REL:
rel = (const Elf_Rel *)reldata;
where = (Elf_Addr *)((char *)data + relbase + rel->r_offset -
dataaddr);
addend = 0;
rtype = ELF_R_TYPE(rel->r_info);
symidx = ELF_R_SYM(rel->r_info);
addend = 0;
break;
case ELF_RELOC_RELA:
rela = (const Elf_Rela *)reldata;
where = (Elf_Addr *)((char *)data + relbase + rela->r_offset -
dataaddr);
addend = rela->r_addend;
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
break;
default:
return (EINVAL);
}
if ((char *)where < (char *)data || (char *)where >= (char *)data + len)
return (0);
if (reltype == ELF_RELOC_REL)
addend = *where;
#define R_386_32 1
#define R_386_GLOB_DAT 6
#define R_386_RELATIVE 8
switch (rtype) {
case R_386_RELATIVE:
addr = addend + relbase;
*where = addr;
break;
case R_386_32:
addr = symaddr(ef, symidx);
if (addr == 0)
return (ESRCH);
val = addr + addend;
*where = val;
break;
default:
printf("\nunhandled relocation type %u\n", (u_int)rtype);
return (EFTYPE);
}
return (0);
#else
return (EOPNOTSUPP);
#endif
}