diff --git a/headers/private/system/arch/sparc/arch_elf.h b/headers/private/system/arch/sparc/arch_elf.h index e69de29bb2..166fa6a6f3 100644 --- a/headers/private/system/arch/sparc/arch_elf.h +++ b/headers/private/system/arch/sparc/arch_elf.h @@ -0,0 +1,72 @@ +/* + * Copyright 2020, Haiku, inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_SPARC_ELF_H +#define _KERNEL_ARCH_SPARC_ELF_H + +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_PC_HH22 37 +#define R_SPARC_PC_HM10 38 +#define R_SPARC_PC_LM22 39 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 +#define R_SPARC_DISP64 46 +#define R_SPARC_PLT64 47 +#define R_SPARC_HIX22 48 +#define R_SPARC_LOX10 49 +#define R_SPARC_H44 50 +#define R_SPARC_M44 51 +#define R_SPARC_L44 52 +#define R_SPARC_REGISTER 53 +#define R_SPARC_UA64 54 +#define R_SPARC_UA16 55 +#define R_SPARC_GOTDATA_HIX22 80 +#define R_SPARC_GOTDATA_LOX10 81 +#define R_SPARC_GOTDATA_OP_HIX22 82 +#define R_SPARC_GOTDATA_OP_LOX10 83 +#define R_SPARC_GOTDATA_OP 84 +#define R_SPARC_H34 85 +#define R_SPARC_SIZE32 86 +#define R_SPARC_SIZE64 87 + +#endif /* _KERNEL_ARCH_SPARC_ELF_H */ diff --git a/src/system/kernel/arch/sparc/Jamfile b/src/system/kernel/arch/sparc/Jamfile index e095f8c381..706d016676 100644 --- a/src/system/kernel/arch/sparc/Jamfile +++ b/src/system/kernel/arch/sparc/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src system kernel arch sparc ; +UsePrivateKernelHeaders ; + KernelMergeObject kernel_arch_sparc.o : arch_asm.S arch_commpage.cpp diff --git a/src/system/kernel/arch/sparc/arch_elf.cpp b/src/system/kernel/arch/sparc/arch_elf.cpp index cde850bb4f..1c5ce22369 100644 --- a/src/system/kernel/arch/sparc/arch_elf.cpp +++ b/src/system/kernel/arch/sparc/arch_elf.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019, Adrien Destugues + * Copyright 2019-2020, Adrien Destugues * Copyright 2010, Ithamar R. Adema * Copyright 2009, Johannes Wischert, johanneswi@gmail.com. * Copyright 2005, Ingo Weinhold . @@ -11,6 +11,7 @@ #include #include +#include #include @@ -52,48 +53,37 @@ arch_elf_relocate_rel(struct elf_image_info *image, static inline void -write_32(addr_t P, Elf32_Word value) +write_word32(addr_t P, Elf64_Word value) { - *(Elf32_Word*)P = value; + *(Elf64_Word*)P = value; } static inline void -write_16(addr_t P, Elf32_Word value) +write_word64(addr_t P, Elf64_Xword value) { - // bits 16:29 - *(Elf32_Half*)P = (Elf32_Half)value; + *(Elf64_Xword*)P = value; } -static inline bool -write_16_check(addr_t P, Elf32_Word value) +static inline void +write_hi30(addr_t P, Elf64_Word value) { - // bits 15:0 - if ((value & 0xffff0000) && (~value & 0xffff8000)) - return false; - *(Elf32_Half*)P = (Elf32_Half)value; - return true; + *(Elf64_Word*)P |= value >> 2; } -static inline bool -write_8(addr_t P, Elf32_Word value) +static inline void +write_hi22(addr_t P, Elf64_Word value) { - // bits 7:0 - *(uint8 *)P = (uint8)value; - return true; + *(Elf64_Word*)P |= value >> 10; } -static inline bool -write_8_check(addr_t P, Elf32_Word value) +static inline void +write_lo10(addr_t P, Elf64_Word value) { - // bits 7:0 - if ((value & 0xffffff00) && (~value & 0xffffff80)) - return false; - *(uint8 *)P = (uint8)value; - return true; + *(Elf64_Word*)P |= value & 0x3ff; } @@ -107,5 +97,140 @@ arch_elf_relocate_rela(struct elf_image_info *image, struct elf_image_info *resolve_image, Elf64_Rela *rel, int rel_len) #endif { + int i; + Elf64_Sym *sym; + int vlErr; + + Elf64_Addr S = 0; // symbol address + //addr_t R = 0; // section relative symbol address + + //addr_t G = 0; // GOT address + //addr_t L = 0; // PLT address + + #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) + + // TODO: Get the GOT address! + #define REQUIRE_GOT \ + if (G == 0) { \ + dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \ + return B_ERROR; \ + } + + // TODO: Get the PLT address! + #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(Elf64_Rela) < rel_len; i++) { +#if CHATTY + dprintf("looking at rel type %" PRIu64 ", offset 0x%lx, sym 0x%lx, " + "addend 0x%lx\n", ELF64_R_TYPE(rel[i].r_info), rel[i].r_offset, + ELF64_R_SYM(rel[i].r_info), rel[i].r_addend); +#endif + // Relocation types and what to do with them are defined in Oracle docs + // Documentation Home > Linker and Libraries Guide + // > ChapterĀ 7 Object File Format > File Format > Relocation Sections + // > Relocation Types (Processor-Specific) > SPARC: Relocation Types + // https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-24/index.html + // https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-24-1/index.html + switch (ELF64_R_TYPE(rel[i].r_info)) { + case R_SPARC_WDISP30: + case R_SPARC_HI22: + case R_SPARC_LO10: + case R_SPARC_GLOB_DAT: + case R_SPARC_JMP_SLOT: + case R_SPARC_64: + sym = SYMBOL(image, ELF64_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 %" PRIu64 ", offset 0x%lx, " + "sym 0x%lx, addend 0x%lx\n", __FUNCTION__, i, + ELF64_R_TYPE(rel[i].r_info), + rel[i].r_offset, ELF64_R_SYM(rel[i].r_info), + rel[i].r_addend); + return vlErr; + } + break; + } + + switch (ELF64_R_TYPE(rel[i].r_info)) { + case R_SPARC_WDISP30: + { + write_hi30(P, S + A - P); + } + case R_SPARC_HI22: + { + write_hi22(P, S + A); + break; + } + case R_SPARC_LO10: + { + write_lo10(P, S + A); + break; + } + case R_SPARC_GLOB_DAT: + { + write_word64(P, S + A); + break; + } + case R_SPARC_JMP_SLOT: + { + // Created by the link-editor for dynamic objects to provide + // lazy binding. The relocation offset member gives the + // location of a procedure linkage table entry. The runtime + // linker modifies the procedure linkage table entry to + // transfer control to the designated symbol address. + addr_t jumpOffset = S - (P + 8); + if ((jumpOffset & 0xc0000000) != 0 + && (~jumpOffset & 0xc0000000) != 0) { + // Offset > 30 bit. + // TODO: Implement! + // See https://docs.oracle.com/cd/E26502_01/html/E26507/chapter6-1235.html + // examples .PLT102 and .PLT103 + dprintf("arch_elf_relocate_rela(): R_SPARC_JMP_SLOT: " + "Offsets > 30 bit currently not supported!\n"); + dprintf("jumpOffset: %p\n", (void*)jumpOffset); + return B_ERROR; + } else { + uint32* instructions = (uint32*)P; + // We need to use a call instruction because it has a lot + // of space for the destination (30 bits). However, it + // erases o7, which we don't want. + // We could avoid this with a JMPL if the displacement was + // small enough, but it probably isn't. + // So, we store o7 in g1 before the call, and restore it + // in the branch delay slot. Crazy, but it works! + instructions[0] = 0x01000000; // NOP to preserve the alignment? + instructions[1] = 0x8210000f; // MOV %o7, %g1 + instructions[2] = 0x40000000 | ((jumpOffset >> 2) & 0x3fffffff); + instructions[3] = 0x9e100001; // MOV %g1, %o7 + } + break; + } + case R_SPARC_RELATIVE: + { + write_word32(P, B + A); + break; + } + case R_SPARC_64: + { + write_word64(P, S + A); + break; + } + default: + dprintf("arch_elf_relocate_rela: unhandled relocation type %" + PRIu64 "\n", ELF64_R_TYPE(rel[i].r_info)); + return B_ERROR; + } + } return B_OK; }