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