* Copyright 2007, François Revol, revol@free.fr.
* Distributed under the terms of the MIT License.
*
* Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*
*
* Copyright 2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#ifdef _BOOT_MODE
#include <boot/arch.h>
#endif
#include <KernelExport.h>
#include <elf_priv.h>
#include <arch/elf.h>
#ifdef TRACE_ARCH_ELF
# define TRACE(x) dprintf x
# define CHATTY 1
#else
# define TRACE(x) ;
# define CHATTY 0
#endif
#ifdef TRACE_ARCH_ELF
static const char *kRelocations[] = {
"R_68K_NONE",
"R_68K_32",
"R_68K_16",
"R_68K_8",
"R_68K_PC32",
"R_68K_PC16",
"R_68K_PC8",
"R_68K_GOT32",
"R_68K_GOT16",
"R_68K_GOT8",
"R_68K_GOT32O",
"R_68K_GOT16O",
"R_68K_GOT8O",
"R_68K_PLT32",
"R_68K_PLT16",
"R_68K_PLT8",
"R_68K_PLT32O",
"R_68K_PLT16O",
"R_68K_PLT8O",
"R_68K_COPY",
"R_68K_GLOB_DAT",
"R_68K_JMP_SLOT",
"R_68K_RELATIVE",
"R_68K_GNU_VTINHERIT",
"R_68K_GNU_VTENTRY",
#if 0
"R_386_NONE",
"R_386_32",
"R_386_PC32",
"R_386_GOT32",
"R_386_PLT32",
"R_386_COPY",
"R_386_GLOB_DAT",
"R_386_JMP_SLOT",
"R_386_RELATIVE",
"R_386_GOTOFF",
"R_386_GOTPC",
#endif
};
#endif
#ifdef _BOOT_MODE
status_t
boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel,
int rel_len)
#else
int
arch_elf_relocate_rel(struct elf_image_info *image,
struct elf_image_info *resolve_image, Elf32_Rel *rel, int rel_len)
#endif
{
return B_NO_ERROR;
}
static inline void
write_32(addr_t P, Elf32_Word value)
{
*(Elf32_Word*)P = value;
}
static inline void
write_16(addr_t P, Elf32_Word value)
{
*(Elf32_Half*)P = (Elf32_Half)value;
}
static inline bool
write_16_check(addr_t P, Elf32_Word value)
{
if ((value & 0xffff0000) && (~value & 0xffff8000))
return false;
*(Elf32_Half*)P = (Elf32_Half)value;
return true;
}
static inline bool
write_8(addr_t P, Elf32_Word value)
{
*(uint8 *)P = (uint8)value;
return true;
}
static inline bool
write_8_check(addr_t P, Elf32_Word value)
{
if ((value & 0xffffff00) && (~value & 0xffffff80))
return false;
*(uint8 *)P = (uint8)value;
return true;
}
#ifdef _BOOT_MODE
status_t
boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
Elf32_Rela *rel, int rel_len)
#else
int
arch_elf_relocate_rela(struct elf_image_info *image,
struct elf_image_info *resolve_image, Elf32_Rela *rel, int rel_len)
#endif
{
int i;
Elf32_Sym *sym;
int vlErr;
elf_addr S = 0;
addr_t R = 0;
addr_t G = 0;
addr_t L = 0;
#define P ((addr_t)(image->text_region.delta + rel[i].r_offset))
#define A ((addr_t)rel[i].r_addend)
#define B (image->text_region.delta)
#define REQUIRE_GOT \
if (G == 0) { \
dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \
return B_ERROR; \
}
#define REQUIRE_PLT \
if (L == 0) { \
dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \
return B_ERROR; \
}
for (i = 0; i * (int)sizeof(Elf32_Rela) < rel_len; i++) {
#if CHATTY
dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n",
ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
#endif
switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_68K_32:
case R_68K_16:
case R_68K_8:
case R_68K_PC32:
case R_68K_PC16:
case R_68K_PC8:
case R_68K_GLOB_DAT:
case R_68K_JMP_SLOT:
sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
#ifdef _BOOT_MODE
vlErr = boot_elf_resolve_symbol(image, sym, &S);
#else
vlErr = elf_resolve_symbol(image, sym, resolve_image, &S);
#endif
if (vlErr < 0) {
dprintf("%s(): Failed to relocate "
"entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, "
"addend 0x%lx\n", __FUNCTION__, i, ELF32_R_TYPE(rel[i].r_info),
rel[i].r_offset, ELF32_R_SYM(rel[i].r_info),
rel[i].r_addend);
return vlErr;
}
break;
}
switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_68K_NONE:
break;
case R_68K_COPY:
dprintf("arch_elf_relocate_rela(): R_68K_COPY not yet "
"supported!\n");
return B_ERROR;
case R_68K_32:
case R_68K_GLOB_DAT:
write_32(P, S + A);
break;
case R_68K_16:
if (write_16_check(P, S + A))
break;
dprintf("R_68K_16 overflow\n");
return B_BAD_DATA;
case R_68K_8:
if (write_8_check(P, S + A))
break;
dprintf("R_68K_8 overflow\n");
return B_BAD_DATA;
case R_68K_PC32:
write_32(P, (S + A - P));
break;
case R_68K_PC16:
if (write_16_check(P, (S + A - P)))
break;
dprintf("R_68K_PC16 overflow\n");
return B_BAD_DATA;
case R_68K_PC8:
if (write_8(P, (S + A - P)))
break;
dprintf("R_68K_PC8 overflow\n");
return B_BAD_DATA;
case R_68K_GOT32:
REQUIRE_GOT;
write_32(P, (G + A - P));
break;
case R_68K_GOT16:
REQUIRE_GOT;
if (write_16_check(P, (G + A - P)))
break;
dprintf("R_68K_GOT16 overflow\n");
return B_BAD_DATA;
case R_68K_GOT8:
REQUIRE_GOT;
if (write_8_check(P, (G + A - P)))
break;
dprintf("R_68K_GOT8 overflow\n");
return B_BAD_DATA;
case R_68K_GOT32O:
REQUIRE_GOT;
write_32(P, (G + A));
break;
case R_68K_GOT16O:
REQUIRE_GOT;
if (write_16_check(P, (G + A)))
break;
dprintf("R_68K_GOT16 overflow\n");
return B_BAD_DATA;
case R_68K_GOT8O:
REQUIRE_GOT;
if (write_8_check(P, (G + A)))
break;
dprintf("R_68K_GOT8 overflow\n");
return B_BAD_DATA;
case R_68K_JMP_SLOT:
write_32(P, S + A);
break;
case R_68K_RELATIVE:
write_32(P, B + A);
break;
case R_68K_PLT32:
REQUIRE_PLT;
write_32(P, (L + A - P));
break;
case R_68K_PLT16:
REQUIRE_PLT;
if (write_16_check(P, (L + A - P)))
break;
dprintf("R_68K_PLT16 overflow\n");
return B_BAD_DATA;
case R_68K_PLT8:
REQUIRE_PLT;
if (write_8_check(P, (L + A - P)))
break;
dprintf("R_68K_PLT8 overflow\n");
return B_BAD_DATA;
case R_68K_PLT32O:
REQUIRE_PLT;
write_32(P, (L + A));
break;
case R_68K_PLT16O:
REQUIRE_PLT;
if (write_16_check(P, (L + A)))
break;
dprintf("R_68K_PLT16O overflow\n");
return B_BAD_DATA;
case R_68K_PLT8O:
REQUIRE_PLT;
if (write_8_check(P, (L + A)))
break;
dprintf("R_68K_PLT8O overflow\n");
return B_BAD_DATA;
default:
dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
return B_ERROR;
}
}
return B_NO_ERROR;
}