1 Star 0 Fork 44

PshySimon/kpatch_dev

forked from src-openEuler/kpatch 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
0037-add-initial-riscv64-support.patch 10.07 KB
一键复制 编辑 原始数据 按行查看 历史
HuBin95 提交于 2024-03-02 00:18 . kpatch: upgrade to 0.9.9
From 154b990912bed67bbaeedec1d53fd0881900da85 Mon Sep 17 00:00:00 2001
From: laokz <zhangkai@iscas.ac.cn>
Date: Fri, 20 Oct 2023 20:53:32 +0800
Subject: [PATCH 37/38] add initial riscv64 support
Per the RISC-V psABI, PCREL_HI20 and PCREL_LO12 must
sit in the same section. PCREL_HI20 may be a global
symbol and might be moved to .klp.rela section, so
thouth PCREL_LO12 is a local symbol ".L0 " it must
also be moved to .klp.rela section. This break the
current livepatch specification, but it is inevitable.
Only support openEuler LIVEPATCH_WO_FTRACE mechanism.
Signed-off-by: wangjunqiang <wangjunqiang@iscas.ac.cn>
Signed-off-by: laokz <zhangkai@iscas.ac.cn>
---
kpatch-build/Makefile | 2 +-
kpatch-build/create-diff-object.c | 40 +++++++++++++++++++++++++++---
kpatch-build/create-klp-module.c | 41 +++++++++++++++++++++++++++++++
kpatch-build/kpatch-elf.c | 26 ++++++++++++++++++++
kpatch-build/kpatch-elf.h | 1 +
5 files changed, 105 insertions(+), 5 deletions(-)
diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile
index 5037677..f24165b 100644
--- a/kpatch-build/Makefile
+++ b/kpatch-build/Makefile
@@ -22,7 +22,7 @@ PLUGIN_CFLAGS := $(filter-out -Wconversion, $(CFLAGS))
PLUGIN_CFLAGS += -shared -I$(GCC_PLUGINS_DIR)/include \
-Igcc-plugins -fPIC -fno-rtti -O2 -Wall
endif
-ifeq ($(filter $(ARCH),s390x x86_64 ppc64le aarch64),)
+ifeq ($(filter $(ARCH),s390x x86_64 ppc64le aarch64 riscv64),)
$(error Unsupported architecture ${ARCH}, check https://github.com/dynup/kpatch/#supported-architectures)
endif
diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c
index 0df6cd2..0d1efcf 100644
--- a/kpatch-build/create-diff-object.c
+++ b/kpatch-build/create-diff-object.c
@@ -182,6 +182,7 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf,
case S390:
return false;
case ARM64:
+ case RISCV64:
return false;
default:
ERROR("unsupported arch");
@@ -456,6 +457,18 @@ static int kpatch_mangled_strcmp(char *s1, char *s2)
if (!strncmp(s1, "__UNIQUE_ID_", 12))
return __kpatch_unique_id_strcmp(s1, s2);
+#ifdef __riscv
+ /*
+ * Normally, .L local symbols are not saved in object files. But on RISC-V it IS!
+ * Their names are volatile even with minor changes in other place. So we can
+ * not compare their names reliably. If we must do comparison, just think them
+ * all have the same name.
+ * In fact, we neither correlate them nor give them NEW status.
+ */
+ if (!strncmp(s1, ".L", 2) && !strncmp(s2, ".L", 2))
+ return 0;
+#endif
+
while (*s1 == *s2) {
if (!*s1)
return 0;
@@ -715,6 +728,10 @@ static bool insn_is_load_immediate(struct kpatch_elf *kelf, void *addr)
break;
+ case RISCV64:
+ /* Not implemented and I think it has less meaning. */
+ break;
+
default:
ERROR("unsupported arch");
}
@@ -982,6 +999,10 @@ static void kpatch_compare_symbols(struct list_head *symlist)
if (sym->twin)
kpatch_compare_correlated_symbol(sym);
else
+#ifdef __riscv
+ /* Don't set NEW status for .L local symbols. */
+ if (strncmp(sym->name, ".L", 2))
+#endif
sym->status = NEW;
log_debug("symbol %s is %s\n", sym->name, status_str(sym->status));
@@ -1127,6 +1148,11 @@ static void kpatch_correlate_symbols(struct list_head *symlist_orig,
list_for_each_entry(sym_orig, symlist_orig, list) {
if (sym_orig->twin)
continue;
+#ifdef __riscv
+ /* Don't correlate .L local symbols. */
+ if (!strncmp(sym_orig->name, ".L", 2))
+ continue;
+#endif
list_for_each_entry(sym_patched, symlist_patched, list) {
if (kpatch_mangled_strcmp(sym_orig->name, sym_patched->name) ||
sym_orig->type != sym_patched->type || sym_patched->twin)
@@ -2528,7 +2554,7 @@ static bool static_call_sites_group_filter(struct lookup_table *lookup,
static struct special_section special_sections[] = {
{
.name = "__bug_table",
- .arch = X86_64 | PPC64 | S390 | ARM64,
+ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64,
.group_size = bug_table_group_size,
},
{
@@ -2538,18 +2564,18 @@ static struct special_section special_sections[] = {
},
{
.name = "__ex_table", /* must come after .fixup */
- .arch = X86_64 | PPC64 | S390 | ARM64,
+ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64,
.group_size = ex_table_group_size,
},
{
.name = "__jump_table",
- .arch = X86_64 | PPC64 | S390 | ARM64,
+ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64,
.group_size = jump_table_group_size,
.group_filter = jump_table_group_filter,
},
{
.name = ".printk_index",
- .arch = X86_64 | PPC64 | S390 | ARM64,
+ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64,
.group_size = printk_index_group_size,
},
{
@@ -3020,6 +3046,10 @@ static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf)
strsec->secsym->include = 1;
name = strsec->data->d_buf + rela->addend;
+ /* RISC-V use st_value as offset into string table, addend always 0. */
+ if (kelf->arch == RISCV64)
+ name += rela->sym->sym.st_value;
+
ignoresec = find_section_by_name(&kelf->sections, name);
if (!ignoresec)
ERROR("KPATCH_IGNORE_SECTION: can't find %s", name);
@@ -3916,6 +3946,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
switch(kelf->arch) {
case PPC64:
+ case RISCV64:
case ARM64: {
bool found = false;
@@ -4159,6 +4190,7 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
switch(kelf->arch) {
case PPC64:
+ case RISCV64:
case ARM64:
list_for_each_entry(rela, &sym->sec->rela->relas, list) {
if (!strcmp(rela->sym->name, "_mcount")) {
diff --git a/kpatch-build/create-klp-module.c b/kpatch-build/create-klp-module.c
index 89d37c8..2f41690 100644
--- a/kpatch-build/create-klp-module.c
+++ b/kpatch-build/create-klp-module.c
@@ -162,6 +162,43 @@ static struct section *find_or_add_klp_relasec(struct kpatch_elf *kelf,
return relasec;
}
+/*
+ * Per the RISC-V psABI:
+ *
+ * In the linker relaxation optimization, we introduce a concept called relocation
+ * group; a relocation group consists of 1) relocations associated with the same
+ * target symbol and can be applied with the same relaxation, or 2) relocations
+ * with the linkage relationship (e.g. `R_RISCV_PCREL_LO12_S` linked with
+ * a `R_RISCV_PCREL_HI20`); all relocations in a single group must be present in
+ * the same section, otherwise will split into another relocation group.
+ *
+ * I think that PCREL_L012 must always be in the same section with PCREL_HI20
+ * in any cases, and noticed that linux kernel does the same assumption.
+ *
+ * So here we have to move PCREL_L012 to .klp.rela section along with its PCREL_HI20
+ * part. Note it's still a normal relocation entry, not a klp entry, and the kernel
+ * should recognize it.
+ */
+static void rv64_mv_lo12_to_klp_rela(struct kpatch_elf *kelf, unsigned short shndx,
+ unsigned int hi20offset, struct section *klp_relasec)
+{
+ struct rela *relalo12, *n;
+ struct section *sec = find_section_by_index(&kelf->sections, shndx);
+
+ if (!sec)
+ ERROR("rv64_mv_lo12_to_klp_rela");
+
+ list_for_each_entry_safe(relalo12, n, &sec->rela->relas, list) {
+ if (hi20offset == relalo12->sym->sym.st_value &&
+ (relalo12->type == R_RISCV_PCREL_LO12_I ||
+ relalo12->type == R_RISCV_PCREL_LO12_S)) {
+ list_del(&relalo12->list);
+ list_add_tail(&relalo12->list, &klp_relasec->relas);
+ return;
+ }
+ }
+}
+
/*
* Create klp relocation sections and klp symbols from .kpatch.relocations
* and .kpatch.symbols sections
@@ -240,6 +277,10 @@ static void create_klp_relasecs_and_syms(struct kpatch_elf *kelf, struct section
rela->type = krelas[index].type;
rela->sym = sym;
rela->addend = krelas[index].addend;
+
+ if ((kelf->arch == RISCV64) &&
+ (rela->type == R_RISCV_PCREL_HI20 || rela->type == R_RISCV_GOT_HI20))
+ rv64_mv_lo12_to_klp_rela(kelf, dest->sym.st_shndx, dest_off, klp_relasec);
}
}
diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c
index b639bc2..d6398b3 100644
--- a/kpatch-build/kpatch-elf.c
+++ b/kpatch-build/kpatch-elf.c
@@ -144,6 +144,8 @@ unsigned int absolute_rela_type(struct kpatch_elf *kelf)
return R_390_64;
case ARM64:
return R_AARCH64_ABS64;
+ case RISCV64:
+ return R_RISCV_64;
default:
ERROR("unsupported arch");
}
@@ -209,6 +211,7 @@ long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec,
switch(kelf->arch) {
case PPC64:
case ARM64:
+ case RISCV64:
add_off = 0;
break;
case X86_64:
@@ -278,6 +281,11 @@ unsigned int insn_length(struct kpatch_elf *kelf, void *addr)
return 6;
}
+ case RISCV64:
+ if ((insn[0] & 0x3) == 0x3)
+ return 4;
+ return 2;
+
default:
ERROR("unsupported arch");
}
@@ -600,6 +608,9 @@ struct kpatch_elf *kpatch_elf_open(const char *name)
case EM_AARCH64:
kelf->arch = ARM64;
break;
+ case EM_RISCV:
+ kelf->arch = RISCV64;
+ break;
default:
ERROR("Unsupported target architecture");
}
@@ -1006,6 +1017,17 @@ void kpatch_rebuild_rela_section_data(struct section *sec)
size_t size;
list_for_each_entry(rela, &sec->relas, list)
+#ifdef __riscv
+ /*
+ * R_RISCV_ALIGN is used for LTO and shall be consumed by linker.
+ * Kernel'll see it as an error if encountered.
+ * But kpatch-build only does partial linking($LD -r) and later
+ * strip has no way to remove the relocation entries alone. That
+ * would cause it been left in the .ko falsely.
+ * Here we have to discard it.
+ */
+ if(rela->type != R_RISCV_ALIGN)
+#endif
nr++;
size = nr * sizeof(*relas);
@@ -1020,6 +1042,10 @@ void kpatch_rebuild_rela_section_data(struct section *sec)
sec->sh.sh_size = size;
list_for_each_entry(rela, &sec->relas, list) {
+#ifdef __riscv
+ if(rela->type == R_RISCV_ALIGN)
+ continue;
+#endif
relas[index].r_offset = rela->offset;
relas[index].r_addend = rela->addend;
relas[index].r_info = GELF_R_INFO(rela->sym->index, rela->type);
diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h
index 47e3117..f2cf60a 100644
--- a/kpatch-build/kpatch-elf.h
+++ b/kpatch-build/kpatch-elf.h
@@ -116,6 +116,7 @@ enum architecture {
X86_64 = 0x1 << 1,
S390 = 0x1 << 2,
ARM64 = 0x1 << 3,
+ RISCV64= 0x1 << 4,
};
struct kpatch_elf {
--
2.33.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/pshysimon/kpatch_dev.git
git@gitee.com:pshysimon/kpatch_dev.git
pshysimon
kpatch_dev
kpatch_dev
master

搜索帮助