sparc: implement elf relocation

Needed to load the kernel properly.

Change-Id: Iab520398271be2ee3a740af4104960367c3b4ea9
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3585
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
PulkoMandy 2021-01-01 00:41:22 +01:00 committed by waddlesplash
parent b992c828cf
commit 76fed28ab1
3 changed files with 224 additions and 25 deletions

View File

@ -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 */

View File

@ -1,5 +1,7 @@
SubDir HAIKU_TOP src system kernel arch sparc ;
UsePrivateKernelHeaders ;
KernelMergeObject kernel_arch_sparc.o :
arch_asm.S
arch_commpage.cpp

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019, Adrien Destugues <pulkomandy@pulkomandy.tk>
* Copyright 2019-2020, Adrien Destugues <pulkomandy@pulkomandy.tk>
* Copyright 2010, Ithamar R. Adema <ithamar.adema@team-embedded.nl>
* Copyright 2009, Johannes Wischert, johanneswi@gmail.com.
* Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
@ -11,6 +11,7 @@
#include <KernelExport.h>
#include <elf_priv.h>
#include <boot/elf.h>
#include <arch/elf.h>
@ -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;
}