* Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de
* Distributed under the terms of the MIT License.
*
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
* Copyright 2002, Manuel J. Petit. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#include "runtime_loader_private.h"
#include <runtime_loader.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef TRACE_RLD
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
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;
}
static int
relocate_rela(image_t *rootImage, image_t *image, Elf32_Rela *rel, int rel_len,
SymbolLookupCache* cache)
{
int i;
addr_t S;
addr_t final_val;
# define P ((addr_t *)(image->regions[0].delta + rel[i].r_offset))
#define A ((addr_t)rel[i].r_addend)
# define B (image->regions[0].delta)
for (i = 0; i * (int)sizeof(Elf32_Rel) < rel_len; i++) {
unsigned type = ELF32_R_TYPE(rel[i].r_info);
switch (type) {
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:
{
Elf32_Sym *sym;
status_t status;
sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
status = resolve_symbol(rootImage, image, sym, cache, &S);
if (status < B_OK) {
TRACE(("resolve symbol \"%s\" returned: %ld\n",
SYMNAME(image, sym), status));
printf("resolve symbol \"%s\" returned: %ld\n",
SYMNAME(image, sym), status);
return status;
}
}
}
switch (type) {
case R_68K_NONE:
continue;
case R_68K_32:
write_32(P, S + A);
break;
case R_68K_16:
if (write_16_check(P, S + A))
break;
TRACE(("R_68K_16 overflow\n"));
return B_BAD_DATA;
case R_68K_8:
if (write_8_check(P, S + A))
break;
TRACE(("R_68K_8 overflow\n"));
return B_BAD_DATA;
case R_68K_PC32:
write_32(P, (S + A - (addr_t)P));
break;
#if 0
case R_68K_PC16:
if (write_16_check(P, (S + A - P)))
break;
TRACE(("R_68K_PC16 overflow\n"));
return B_BAD_DATA;
case R_68K_PC8:
if (write_8(P, (S + A - P)))
break;
TRACE(("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;
TRACE(("R_68K_GOT16 overflow\n"));
return B_BAD_DATA;
case R_68K_GOT8:
REQUIRE_GOT;
if (write_8_check(P, (G + A - P)))
break;
TRACE(("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;
TRACE(("R_68K_GOT16 overflow\n"));
return B_BAD_DATA;
case R_68K_GOT8O:
REQUIRE_GOT;
if (write_8_check(P, (G + A)))
break;
TRACE(("R_68K_GOT8 overflow\n"));
return B_BAD_DATA;
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;
TRACE(("R_68K_PLT16 overflow\n"));
return B_BAD_DATA;
case R_68K_PLT8:
REQUIRE_PLT;
if (write_8_check(P, (L + A - P)))
break;
TRACE(("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;
TRACE(("R_68K_PLT16O overflow\n"));
return B_BAD_DATA;
case R_68K_PLT8O:
REQUIRE_PLT;
if (write_8_check(P, (L + A)))
break;
TRACE(("R_68K_PLT8O overflow\n"));
return B_BAD_DATA;
case R_386_GOT32:
final_val = G + A;
break;
case R_386_PLT32:
final_val = L + A - (addr_t)P;
break;
#endif
case R_68K_COPY:
continue;
case R_68K_GLOB_DAT:
write_32(P, S);
break;
case R_68K_JMP_SLOT:
write_32(P, S);
break;
#if 0
case R_386_JMP_SLOT:
write_32(P, S);
break;
#endif
case R_68K_RELATIVE:
write_32(P, B + A);
break;
#if 0
case R_386_GOTOFF:
final_val = S + A - GOT;
break;
case R_386_GOTPC:
final_val = GOT + A - P;
break;
#endif
default:
TRACE(("unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info)));
return B_NOT_ALLOWED;
}
*P = final_val;
}
# undef P
# undef A
# undef B
return B_NO_ERROR;
}
status_t
arch_relocate_image(image_t *rootImage, image_t *image,
SymbolLookupCache* cache)
{
status_t status;
if (image->rel) {
TRACE(("RELA relocations not supported\n"));
return EOPNOTSUPP;
}
if (image->pltrel) {
TRACE(("RELA relocations not supported\n"));
return EOPNOTSUPP;
#if 0
status = relocate_rel(rootImage, image, image->pltrel,
image->pltrel_len);
if (status < B_OK)
return status;
#endif
}
if (image->rela) {
status = relocate_rela(rootImage, image, image->rela, image->rela_len,
cache);
if (status < B_OK)
return status;
}
#if 0
if (image->pltrela) {
status = relocate_rela(rootImage, image, image->pltrela,
image->pltrela_len);
if (status < B_OK)
return status;
}
#endif
return B_OK;
}