uboot/tools/prelink-riscv.inc
<<
>>
Prefs
   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