/* * Copyright 2019-2020, Adrien Destugues * Copyright 2010, Ithamar R. Adema * Copyright 2009, Johannes Wischert, johanneswi@gmail.com. * Copyright 2005, Ingo Weinhold . * Copyright 2002, Travis Geiselbrecht. All rights reserved. * Distributed under the terms of the MIT License. */ #include #include #include #include //#define TRACE_ARCH_ELF #ifdef TRACE_ARCH_ELF # define TRACE(x) dprintf x # define CHATTY 1 #else # define TRACE(x) ; # define CHATTY 0 #endif #ifndef _BOOT_MODE static bool is_in_image(struct elf_image_info *image, addr_t address) { return (address >= image->text_region.start && address < image->text_region.start + image->text_region.size) || (address >= image->data_region.start && address < image->data_region.start + image->data_region.size); } #endif // !_BOOT_MODE #ifdef _BOOT_MODE status_t boot_arch_elf_relocate_rel(struct preloaded_elf64_image *image, Elf64_Rel *rel, int rel_len) #else int arch_elf_relocate_rel(struct elf_image_info *image, struct elf_image_info *resolve_image, Elf64_Rel *rel, int rel_len) #endif { // there are no rel entries in M68K elf return B_NO_ERROR; } static inline void write_word32(addr_t P, Elf64_Word value) { *(Elf64_Word*)P = value; } static inline void write_word64(addr_t P, Elf64_Xword value) { *(Elf64_Xword*)P = value; } static inline void write_hi30(addr_t P, Elf64_Word value) { *(Elf64_Word*)P |= value >> 2; } static inline void write_hi22(addr_t P, Elf64_Word value) { *(Elf64_Word*)P |= value >> 10; } static inline void write_lo10(addr_t P, Elf64_Word value) { *(Elf64_Word*)P |= value & 0x3ff; } static inline void write_hh22(addr_t P, Elf64_Xword value) { *(Elf64_Word*)P |= value >> 42; } static inline void write_hm10(addr_t P, Elf64_Xword value) { *(Elf64_Word*)P |= (value >> 32) & 0x3ff; } #ifdef _BOOT_MODE status_t boot_arch_elf_relocate_rela(struct preloaded_elf64_image *image, Elf64_Rela *rel, int rel_len) #else int 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_HH22: case R_SPARC_LM22: case R_SPARC_HM10: 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: case R_SPARC_LM22: { write_hi22(P, S + A); break; } case R_SPARC_LO10: { write_lo10(P, S + A); break; } case R_SPARC_HH22: { write_hh22(P, S + A); break; } case R_SPARC_HM10: { write_hm10(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; }