linux/arch/riscv/include/asm/module.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/* Copyright (C) 2017 Andes Technology Corporation */
   3
   4#ifndef _ASM_RISCV_MODULE_H
   5#define _ASM_RISCV_MODULE_H
   6
   7#include <asm-generic/module.h>
   8
   9#define MODULE_ARCH_VERMAGIC    "riscv"
  10
  11struct module;
  12unsigned long module_emit_got_entry(struct module *mod, unsigned long val);
  13unsigned long module_emit_plt_entry(struct module *mod, unsigned long val);
  14
  15#ifdef CONFIG_MODULE_SECTIONS
  16struct mod_section {
  17        Elf_Shdr *shdr;
  18        int num_entries;
  19        int max_entries;
  20};
  21
  22struct mod_arch_specific {
  23        struct mod_section got;
  24        struct mod_section plt;
  25        struct mod_section got_plt;
  26};
  27
  28struct got_entry {
  29        unsigned long symbol_addr;      /* the real variable address */
  30};
  31
  32static inline struct got_entry emit_got_entry(unsigned long val)
  33{
  34        return (struct got_entry) {val};
  35}
  36
  37static inline struct got_entry *get_got_entry(unsigned long val,
  38                                              const struct mod_section *sec)
  39{
  40        struct got_entry *got = (struct got_entry *)(sec->shdr->sh_addr);
  41        int i;
  42        for (i = 0; i < sec->num_entries; i++) {
  43                if (got[i].symbol_addr == val)
  44                        return &got[i];
  45        }
  46        return NULL;
  47}
  48
  49struct plt_entry {
  50        /*
  51         * Trampoline code to real target address. The return address
  52         * should be the original (pc+4) before entring plt entry.
  53         */
  54        u32 insn_auipc;         /* auipc t0, 0x0                       */
  55        u32 insn_ld;            /* ld    t1, 0x10(t0)                  */
  56        u32 insn_jr;            /* jr    t1                            */
  57};
  58
  59#define OPC_AUIPC  0x0017
  60#define OPC_LD     0x3003
  61#define OPC_JALR   0x0067
  62#define REG_T0     0x5
  63#define REG_T1     0x6
  64
  65static inline struct plt_entry emit_plt_entry(unsigned long val,
  66                                              unsigned long plt,
  67                                              unsigned long got_plt)
  68{
  69        /*
  70         * U-Type encoding:
  71         * +------------+----------+----------+
  72         * | imm[31:12] | rd[11:7] | opc[6:0] |
  73         * +------------+----------+----------+
  74         *
  75         * I-Type encoding:
  76         * +------------+------------+--------+----------+----------+
  77         * | imm[31:20] | rs1[19:15] | funct3 | rd[11:7] | opc[6:0] |
  78         * +------------+------------+--------+----------+----------+
  79         *
  80         */
  81        unsigned long offset = got_plt - plt;
  82        u32 hi20 = (offset + 0x800) & 0xfffff000;
  83        u32 lo12 = (offset - hi20);
  84        return (struct plt_entry) {
  85                OPC_AUIPC | (REG_T0 << 7) | hi20,
  86                OPC_LD | (lo12 << 20) | (REG_T0 << 15) | (REG_T1 << 7),
  87                OPC_JALR | (REG_T1 << 15)
  88        };
  89}
  90
  91static inline int get_got_plt_idx(unsigned long val, const struct mod_section *sec)
  92{
  93        struct got_entry *got_plt = (struct got_entry *)sec->shdr->sh_addr;
  94        int i;
  95        for (i = 0; i < sec->num_entries; i++) {
  96                if (got_plt[i].symbol_addr == val)
  97                        return i;
  98        }
  99        return -1;
 100}
 101
 102static inline struct plt_entry *get_plt_entry(unsigned long val,
 103                                              const struct mod_section *sec_plt,
 104                                              const struct mod_section *sec_got_plt)
 105{
 106        struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr;
 107        int got_plt_idx = get_got_plt_idx(val, sec_got_plt);
 108        if (got_plt_idx >= 0)
 109                return plt + got_plt_idx;
 110        else
 111                return NULL;
 112}
 113
 114#endif /* CONFIG_MODULE_SECTIONS */
 115
 116#endif /* _ASM_RISCV_MODULE_H */
 117