2cffc95690
This patch supports dynamic generate got and plt sections mechanism on rv32. It contains the modification as follows: - Always enable MODULE_SECTIONS (both rv64 and rv32) - Change the fixed size type. This patch had been tested by following modules: btrfs 6795991 0 - Live 0xa544b000 test_static_keys 17304 0 - Live 0xa28be000 zstd_compress 1198986 1 btrfs, Live 0xa2a25000 zstd_decompress 608112 1 btrfs, Live 0xa24e7000 lzo 8787 0 - Live 0xa2049000 xor 27461 1 btrfs, Live 0xa2041000 zram 78849 0 - Live 0xa2276000 netdevsim 55909 0 - Live 0xa202d000 tun 211534 0 - Live 0xa21b5000 fuse 566049 0 - Live 0xa25fb000 nfs_layout_flexfiles 192597 0 - Live 0xa229b000 ramoops 74895 0 - Live 0xa2019000 xfs 3973221 0 - Live 0xa507f000 libcrc32c 3053 2 btrfs,xfs, Live 0xa34af000 lzo_compress 17302 2 btrfs,lzo, Live 0xa347d000 lzo_decompress 7178 2 btrfs,lzo, Live 0xa3451000 raid6_pq 142086 1 btrfs, Live 0xa33a4000 reed_solomon 31022 1 ramoops, Live 0xa31eb000 test_bitmap 3734 0 - Live 0xa31af000 test_bpf 1588736 0 - Live 0xa2c11000 test_kmod 41161 0 - Live 0xa29f8000 test_module 1356 0 - Live 0xa299e000 test_printf 6024 0 [permanent], Live 0xa2971000 test_static_key_base 5797 1 test_static_keys, Live 0xa2931000 test_user_copy 4382 0 - Live 0xa28c9000 xxhash 70501 2 zstd_compress,zstd_decompress, Live 0xa2055000 Signed-off-by: Zong Li <zong@andestech.com> Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
117 lines
3.0 KiB
C
117 lines
3.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* Copyright (C) 2017 Andes Technology Corporation */
|
|
|
|
#ifndef _ASM_RISCV_MODULE_H
|
|
#define _ASM_RISCV_MODULE_H
|
|
|
|
#include <asm-generic/module.h>
|
|
|
|
#define MODULE_ARCH_VERMAGIC "riscv"
|
|
|
|
struct module;
|
|
unsigned long module_emit_got_entry(struct module *mod, unsigned long val);
|
|
unsigned long module_emit_plt_entry(struct module *mod, unsigned long val);
|
|
|
|
#ifdef CONFIG_MODULE_SECTIONS
|
|
struct mod_section {
|
|
Elf_Shdr *shdr;
|
|
int num_entries;
|
|
int max_entries;
|
|
};
|
|
|
|
struct mod_arch_specific {
|
|
struct mod_section got;
|
|
struct mod_section plt;
|
|
struct mod_section got_plt;
|
|
};
|
|
|
|
struct got_entry {
|
|
unsigned long symbol_addr; /* the real variable address */
|
|
};
|
|
|
|
static inline struct got_entry emit_got_entry(unsigned long val)
|
|
{
|
|
return (struct got_entry) {val};
|
|
}
|
|
|
|
static inline struct got_entry *get_got_entry(unsigned long val,
|
|
const struct mod_section *sec)
|
|
{
|
|
struct got_entry *got = (struct got_entry *)(sec->shdr->sh_addr);
|
|
int i;
|
|
for (i = 0; i < sec->num_entries; i++) {
|
|
if (got[i].symbol_addr == val)
|
|
return &got[i];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct plt_entry {
|
|
/*
|
|
* Trampoline code to real target address. The return address
|
|
* should be the original (pc+4) before entring plt entry.
|
|
*/
|
|
u32 insn_auipc; /* auipc t0, 0x0 */
|
|
u32 insn_ld; /* ld t1, 0x10(t0) */
|
|
u32 insn_jr; /* jr t1 */
|
|
};
|
|
|
|
#define OPC_AUIPC 0x0017
|
|
#define OPC_LD 0x3003
|
|
#define OPC_JALR 0x0067
|
|
#define REG_T0 0x5
|
|
#define REG_T1 0x6
|
|
|
|
static inline struct plt_entry emit_plt_entry(unsigned long val,
|
|
unsigned long plt,
|
|
unsigned long got_plt)
|
|
{
|
|
/*
|
|
* U-Type encoding:
|
|
* +------------+----------+----------+
|
|
* | imm[31:12] | rd[11:7] | opc[6:0] |
|
|
* +------------+----------+----------+
|
|
*
|
|
* I-Type encoding:
|
|
* +------------+------------+--------+----------+----------+
|
|
* | imm[31:20] | rs1[19:15] | funct3 | rd[11:7] | opc[6:0] |
|
|
* +------------+------------+--------+----------+----------+
|
|
*
|
|
*/
|
|
unsigned long offset = got_plt - plt;
|
|
u32 hi20 = (offset + 0x800) & 0xfffff000;
|
|
u32 lo12 = (offset - hi20);
|
|
return (struct plt_entry) {
|
|
OPC_AUIPC | (REG_T0 << 7) | hi20,
|
|
OPC_LD | (lo12 << 20) | (REG_T0 << 15) | (REG_T1 << 7),
|
|
OPC_JALR | (REG_T1 << 15)
|
|
};
|
|
}
|
|
|
|
static inline int get_got_plt_idx(unsigned long val, const struct mod_section *sec)
|
|
{
|
|
struct got_entry *got_plt = (struct got_entry *)sec->shdr->sh_addr;
|
|
int i;
|
|
for (i = 0; i < sec->num_entries; i++) {
|
|
if (got_plt[i].symbol_addr == val)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static inline struct plt_entry *get_plt_entry(unsigned long val,
|
|
const struct mod_section *sec_plt,
|
|
const struct mod_section *sec_got_plt)
|
|
{
|
|
struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr;
|
|
int got_plt_idx = get_got_plt_idx(val, sec_got_plt);
|
|
if (got_plt_idx >= 0)
|
|
return plt + got_plt_idx;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
#endif /* CONFIG_MODULE_SECTIONS */
|
|
|
|
#endif /* _ASM_RISCV_MODULE_H */
|