From 42ac26f2b0c94f27170fdca2d7d05dbfb9a1d3fd Mon Sep 17 00:00:00 2001 From: Rick Chen Date: Tue, 26 Dec 2017 13:55:56 +0800 Subject: [PATCH] riscv: tools: Prelink u-boot Add prelink-riscv to arrange .rela.dyn and .rela.got in compile time. So that u-boot can be directly executed without fixup. Signed-off-by: Chih-Mao Chen Signed-off-by: Rick Chen Signed-off-by: Rick Chen Signed-off-by: Greentime Hu --- Makefile | 4 ++ tools/Makefile | 1 + tools/prelink-riscv.c | 102 +++++++++++++++++++++++++++++++++++++++++++ tools/prelink-riscv.inc | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 tools/prelink-riscv.c create mode 100644 tools/prelink-riscv.inc diff --git a/Makefile b/Makefile index d8f419b..23cd340 100644 --- a/Makefile +++ b/Makefile @@ -1264,6 +1264,10 @@ ifeq ($(CONFIG_KALLSYMS),y) $(call cmd,u-boot__) common/system_map.o endif +ifeq ($(CONFIG_RISCV),y) + @tools/prelink-riscv $@ 0 +endif + quiet_cmd_sym ?= SYM $@ cmd_sym ?= $(OBJDUMP) -t $< > $@ u-boot.sym: u-boot FORCE diff --git a/tools/Makefile b/tools/Makefile index 4d32fe5..571f571 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -185,6 +185,7 @@ hostprogs-$(CONFIG_KIRKWOOD) += kwboot hostprogs-$(CONFIG_ARCH_MVEBU) += kwboot hostprogs-y += proftool hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela +hostprogs-$(CONFIG_RISCV) += prelink-riscv hostprogs-y += fdtgrep fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o diff --git a/tools/prelink-riscv.c b/tools/prelink-riscv.c new file mode 100644 index 0000000..632d2da --- /dev/null +++ b/tools/prelink-riscv.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2017 Andes Technology + * Chih-Mao Chen + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Statically process runtime relocations on RISC-V ELF images + * so that it can be directly executed when loaded at LMA + * without fixup. Both RV32 and RV64 are supported. + */ + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ +#error "Only little-endian host is supported" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef EM_RISCV +#define EM_RISCV 243 +#endif + +#ifndef R_RISCV_32 +#define R_RISCV_32 1 +#endif + +#ifndef R_RISCV_64 +#define R_RISCV_64 2 +#endif + +#ifndef R_RISCV_RELATIVE +#define R_RISCV_RELATIVE 3 +#endif + +const char *argv0; + +#define die(fmt, ...) \ + do { \ + fprintf(stderr, "%s: " fmt "\n", argv0, ## __VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define PRELINK_INC_BITS 32 +#include "prelink-riscv.inc" +#undef PRELINK_INC_BITS + +#define PRELINK_INC_BITS 64 +#include "prelink-riscv.inc" +#undef PRELINK_INC_BITS + +int main(int argc, const char *const *argv) +{ + argv0 = argv[0]; + + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv0); + exit(EXIT_FAILURE); + } + + int fd = open(argv[1], O_RDWR, 0); + + if (fd < 0) + die("Cannot open %s: %s", argv[1], strerror(errno)); + + struct stat st; + + if (fstat(fd, &st) < 0) + die("Cannot stat %s: %s", argv[1], strerror(errno)); + + void *data = + mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + if (data == MAP_FAILED) + die("Cannot mmap %s: %s", argv[1], strerror(errno)); + + close(fd); + + unsigned char *e_ident = (unsigned char *)data; + + if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) + die("Invalid ELF file %s", argv[1]); + + bool is64 = e_ident[EI_CLASS] == ELFCLASS64; + + if (is64) + prelink64(data); + else + prelink32(data); + + return 0; +} diff --git a/tools/prelink-riscv.inc b/tools/prelink-riscv.inc new file mode 100644 index 0000000..c07d930 --- /dev/null +++ b/tools/prelink-riscv.inc @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2017 Andes Technology + * Chih-Mao Chen + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Statically process runtime relocations on RISC-V ELF images + * so that it can be directly executed when loaded at LMA + * without fixup. Both RV32 and RV64 are supported. + */ + +#define CONCAT_IMPL(x, y) x##y +#define CONCAT(x, y) CONCAT_IMPL(x, y) +#define CONCAT3(x, y, z) CONCAT(CONCAT(x, y), z) + +#define prelink_nn CONCAT(prelink, PRELINK_INC_BITS) +#define uintnn_t CONCAT3(uint, PRELINK_INC_BITS, _t) +#define get_offset_nn CONCAT(get_offset_, PRELINK_INC_BITS) +#define Elf_Ehdr CONCAT3(Elf, PRELINK_INC_BITS, _Ehdr) +#define Elf_Phdr CONCAT3(Elf, PRELINK_INC_BITS, _Phdr) +#define Elf_Rela CONCAT3(Elf, PRELINK_INC_BITS, _Rela) +#define Elf_Sym CONCAT3(Elf, PRELINK_INC_BITS, _Sym) +#define Elf_Dyn CONCAT3(Elf, PRELINK_INC_BITS, _Dyn) +#define Elf_Addr CONCAT3(Elf, PRELINK_INC_BITS, _Addr) +#define ELF_R_TYPE CONCAT3(ELF, PRELINK_INC_BITS, _R_TYPE) +#define ELF_R_SYM CONCAT3(ELF, PRELINK_INC_BITS, _R_SYM) + +static void* get_offset_nn (void* data, Elf_Phdr* phdrs, size_t phnum, Elf_Addr addr) +{ + Elf_Phdr *p; + + for (p = phdrs; p < phdrs + phnum; ++p) + if (p->p_vaddr <= addr && p->p_vaddr + p->p_memsz > addr) + return data + p->p_offset + (addr - p->p_vaddr); + + return NULL; +} + +static void prelink_nn(void *data) +{ + Elf_Ehdr *ehdr = data; + Elf_Phdr *p; + Elf_Dyn *dyn; + Elf_Rela *r; + + if (ehdr->e_machine != EM_RISCV) + die("Machine type is not RISC-V"); + + Elf_Phdr *phdrs = data + ehdr->e_phoff; + + Elf_Dyn *dyns = NULL; + for (p = phdrs; p < phdrs + ehdr->e_phnum; ++p) { + if (p->p_type == PT_DYNAMIC) { + dyns = data + p->p_offset; + break; + } + } + + if (dyns == NULL) + die("No dynamic section found"); + + Elf_Rela *rela_dyn = NULL; + size_t rela_count = 0; + Elf_Sym *dynsym = NULL; + for (dyn = dyns;; ++dyn) { + if (dyn->d_tag == DT_NULL) + break; + else if (dyn->d_tag == DT_RELA) + rela_dyn = get_offset_nn(data, phdrs, ehdr->e_phnum, + dyn->d_un.d_ptr); + else if (dyn->d_tag == DT_RELASZ) + rela_count = dyn->d_un.d_val / sizeof(Elf_Rela); + else if (dyn->d_tag == DT_SYMTAB) + dynsym = get_offset_nn(data, phdrs, ehdr->e_phnum, + dyn->d_un.d_ptr); + + } + + if (rela_dyn == NULL) + die("No .rela.dyn found"); + + if (dynsym == NULL) + die("No .dynsym found"); + + for (r = rela_dyn; r < rela_dyn + rela_count; ++r) { + void* buf = get_offset_nn(data, phdrs, ehdr->e_phnum, r->r_offset); + + if (buf == NULL) + continue; + + if (ELF_R_TYPE(r->r_info) == R_RISCV_RELATIVE) + *((uintnn_t*) buf) = r->r_addend; + else if (ELF_R_TYPE(r->r_info) == R_RISCV_32) + *((uint32_t*) buf) = dynsym[ELF_R_SYM(r->r_info)].st_value; + else if (ELF_R_TYPE(r->r_info) == R_RISCV_64) + *((uint64_t*) buf) = dynsym[ELF_R_SYM(r->r_info)].st_value; + } +} + +#undef prelink_nn +#undef uintnn_t +#undef get_offset_nn +#undef Elf_Ehdr +#undef Elf_Phdr +#undef Elf_Rela +#undef Elf_Sym +#undef Elf_Dyn +#undef Elf_Addr +#undef ELF_R_TYPE +#undef ELF_R_SYM + +#undef CONCAT_IMPL +#undef CONCAT +#undef CONCAT3