1/* 2 * Copyright (C) 2017 Andes Technology 3 * Chih-Mao Chen <cmchen@andestech.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 * 7 * Statically process runtime relocations on RISC-V ELF images 8 * so that it can be directly executed when loaded at LMA 9 * without fixup. Both RV32 and RV64 are supported. 10 */ 11 12#define CONCAT_IMPL(x, y) x##y 13#define CONCAT(x, y) CONCAT_IMPL(x, y) 14#define CONCAT3(x, y, z) CONCAT(CONCAT(x, y), z) 15 16#define prelink_nn CONCAT(prelink, PRELINK_INC_BITS) 17#define uintnn_t CONCAT3(uint, PRELINK_INC_BITS, _t) 18#define get_offset_nn CONCAT(get_offset_, PRELINK_INC_BITS) 19#define Elf_Ehdr CONCAT3(Elf, PRELINK_INC_BITS, _Ehdr) 20#define Elf_Phdr CONCAT3(Elf, PRELINK_INC_BITS, _Phdr) 21#define Elf_Rela CONCAT3(Elf, PRELINK_INC_BITS, _Rela) 22#define Elf_Sym CONCAT3(Elf, PRELINK_INC_BITS, _Sym) 23#define Elf_Dyn CONCAT3(Elf, PRELINK_INC_BITS, _Dyn) 24#define Elf_Addr CONCAT3(Elf, PRELINK_INC_BITS, _Addr) 25#define ELF_R_TYPE CONCAT3(ELF, PRELINK_INC_BITS, _R_TYPE) 26#define ELF_R_SYM CONCAT3(ELF, PRELINK_INC_BITS, _R_SYM) 27 28static void* get_offset_nn (void* data, Elf_Phdr* phdrs, size_t phnum, Elf_Addr addr) 29{ 30 Elf_Phdr *p; 31 32 for (p = phdrs; p < phdrs + phnum; ++p) 33 if (p->p_vaddr <= addr && p->p_vaddr + p->p_memsz > addr) 34 return data + p->p_offset + (addr - p->p_vaddr); 35 36 return NULL; 37} 38 39static void prelink_nn(void *data) 40{ 41 Elf_Ehdr *ehdr = data; 42 Elf_Phdr *p; 43 Elf_Dyn *dyn; 44 Elf_Rela *r; 45 46 if (ehdr->e_machine != EM_RISCV) 47 die("Machine type is not RISC-V"); 48 49 Elf_Phdr *phdrs = data + ehdr->e_phoff; 50 51 Elf_Dyn *dyns = NULL; 52 for (p = phdrs; p < phdrs + ehdr->e_phnum; ++p) { 53 if (p->p_type == PT_DYNAMIC) { 54 dyns = data + p->p_offset; 55 break; 56 } 57 } 58 59 if (dyns == NULL) 60 die("No dynamic section found"); 61 62 Elf_Rela *rela_dyn = NULL; 63 size_t rela_count = 0; 64 Elf_Sym *dynsym = NULL; 65 for (dyn = dyns;; ++dyn) { 66 if (dyn->d_tag == DT_NULL) 67 break; 68 else if (dyn->d_tag == DT_RELA) 69 rela_dyn = get_offset_nn(data, phdrs, ehdr->e_phnum, + dyn->d_un.d_ptr); 70 else if (dyn->d_tag == DT_RELASZ) 71 rela_count = dyn->d_un.d_val / sizeof(Elf_Rela); 72 else if (dyn->d_tag == DT_SYMTAB) 73 dynsym = get_offset_nn(data, phdrs, ehdr->e_phnum, + dyn->d_un.d_ptr); 74 75 } 76 77 if (rela_dyn == NULL) 78 die("No .rela.dyn found"); 79 80 if (dynsym == NULL) 81 die("No .dynsym found"); 82 83 for (r = rela_dyn; r < rela_dyn + rela_count; ++r) { 84 void* buf = get_offset_nn(data, phdrs, ehdr->e_phnum, r->r_offset); 85 86 if (buf == NULL) 87 continue; 88 89 if (ELF_R_TYPE(r->r_info) == R_RISCV_RELATIVE) 90 *((uintnn_t*) buf) = r->r_addend; 91 else if (ELF_R_TYPE(r->r_info) == R_RISCV_32) 92 *((uint32_t*) buf) = dynsym[ELF_R_SYM(r->r_info)].st_value; 93 else if (ELF_R_TYPE(r->r_info) == R_RISCV_64) 94 *((uint64_t*) buf) = dynsym[ELF_R_SYM(r->r_info)].st_value; 95 } 96} 97 98#undef prelink_nn 99#undef uintnn_t 100#undef get_offset_nn 101#undef Elf_Ehdr 102#undef Elf_Phdr 103#undef Elf_Rela 104#undef Elf_Sym 105#undef Elf_Dyn 106#undef Elf_Addr 107#undef ELF_R_TYPE 108#undef ELF_R_SYM 109 110#undef CONCAT_IMPL 111#undef CONCAT 112#undef CONCAT3 113