diff --git a/src/system/runtime_loader/arch/m68k/arch_relocate.c b/src/system/runtime_loader/arch/m68k/arch_relocate.c new file mode 100644 index 0000000000..d33fe9cc6d --- /dev/null +++ b/src/system/runtime_loader/arch/m68k/arch_relocate.c @@ -0,0 +1,319 @@ +/* + * 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 + +#include +#include +#include + + +//#define TRACE_RLD +#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) +{ + // bits 16:29 + *(Elf32_Half*)P = (Elf32_Half)value; +} + + +static inline bool +write_16_check(addr_t P, Elf32_Word value) +{ + // bits 15:0 + 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) +{ + // bits 7:0 + *(uint8 *)P = (uint8)value; + return true; +} + + +static inline bool +write_8_check(addr_t P, Elf32_Word value) +{ + // bits 7:0 + if ((value & 0xffffff00) && (~value & 0xffffff80)) + return false; + *(uint8 *)P = (uint8)value; + return true; +} + + +static int +relocate_rela(image_t *rootImage, image_t *image, struct Elf32_Rela *rel, + int rel_len) +{ + int i; + addr_t S; + addr_t final_val; + +# define P ((addr_t *)(image->regions[0].delta + rel[i].r_offset)) +//# define A (*(P)) +#define A ((addr_t)rel[i].r_addend) +# define B (image->regions[0].delta) + + for (i = 0; i * (int)sizeof(struct 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: + { + struct Elf32_Sym *sym; + status_t status; + sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); + + status = resolve_symbol(rootImage, image, sym, &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: + /* what ? */ + continue; + case R_68K_GLOB_DAT: + write_32(P, S/* + A*/); + break; + case R_68K_JMP_SLOT: + //XXX ? write_32(P, (G + A)); + 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) +{ + status_t status; + + // deal with the rels first + 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); + //int i; + if (status < B_OK) + return status; + //TRACE(("RELA relocations not supported\n")); + //return EOPNOTSUPP; + + //for (i = 1; i * (int)sizeof(struct Elf32_Rela) < image->rela_len; i++) { + // printf("rela: type %d\n", ELF32_R_TYPE(image->rela[i].r_info)); + //} + } + +#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; +}