From 0fa059a149a9d59b9c7f2dcfec372b91f6aafd69 Mon Sep 17 00:00:00 2001 From: Hongchen Zhang Date: Mon, 28 Jul 2025 11:50:45 +0800 Subject: [PATCH] LoongArch : add loongarch hotpatch support Signed-off-by: Hongchen Zhang --- ...gArch-add-loongarch-hotpatch-support.patch | 612 ++++++++++++++++++ kpatch.spec | 10 +- 2 files changed, 621 insertions(+), 1 deletion(-) create mode 100644 0060-LoongArch-add-loongarch-hotpatch-support.patch diff --git a/0060-LoongArch-add-loongarch-hotpatch-support.patch b/0060-LoongArch-add-loongarch-hotpatch-support.patch new file mode 100644 index 0000000..6696aa0 --- /dev/null +++ b/0060-LoongArch-add-loongarch-hotpatch-support.patch @@ -0,0 +1,612 @@ +From 5aab63fa8a0ea2fbd7d1c2fc12c4744fb54743f6 Mon Sep 17 00:00:00 2001 +From: Hongchen Zhang +Date: Thu, 17 Jun 2021 10:46:21 +0800 +Subject: [PATCH] LoongArch: add loongarch hotpatch support + +Signed-off-by: Hongchen Zhang +--- + kpatch-build/create-diff-object.c | 348 +++++++++++++++++++++++++++++- + kpatch-build/kpatch-build | 3 + + kpatch-build/kpatch-cc | 17 +- + kpatch-build/kpatch-elf.c | 15 +- + kpatch-build/kpatch-elf.h | 1 + + kpatch-build/list.h | 9 + + 6 files changed, 384 insertions(+), 9 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index f65297b8e65c..d1e1d2ba15fc 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -183,6 +183,7 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf, + return false; + case ARM64: + case RISCV64: ++ case LOONGARCH: + return false; + default: + ERROR("unsupported arch"); +@@ -219,6 +220,9 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf, + */ + static struct rela *toc_rela(const struct rela *rela) + { ++#ifdef __loongarch__ ++ return (struct rela *)rela; ++#endif + if (rela->type != R_PPC64_TOC16_HA && + rela->type != R_PPC64_TOC16_LO_DS) + return (struct rela *)rela; +@@ -721,6 +725,21 @@ static bool insn_is_load_immediate(struct kpatch_elf *kelf, void *addr) + + break; + ++ case LOONGARCH: ++ /* arg2: addi.w r5, r5, imm */ ++ if ((*(unsigned int *)insn & 0xffc003ff) == 0x28000a5) ++ return true; ++ /* arg2: ori r5, r5, imm */ ++ if ((*(unsigned int *)insn & 0xffc003ff) == 0x38000a5) ++ return true; ++ /* arg3: addi.w r6, r6, imm */ ++ if ((*(unsigned int *)insn & 0xffc003ff) == 0x28000c6) ++ return true; ++ /* arg3: ori r6, r6, imm */ ++ if ((*(unsigned int *)insn & 0xffc003ff) == 0x38000c6) ++ return true; ++ break; ++ + case S390: + /* arg2: lghi %r3, imm */ + if (insn[0] == 0xa7 && insn[1] == 0x39) +@@ -2562,22 +2581,22 @@ 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 | RISCV64, ++ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64 | LOONGARCH, + .group_size = bug_table_group_size, + }, + { + .name = ".fixup", +- .arch = X86_64 | PPC64 | S390 | ARM64, ++ .arch = X86_64 | PPC64 | S390 | ARM64 | LOONGARCH, + .group_size = fixup_group_size, + }, + { + .name = "__ex_table", /* must come after .fixup */ +- .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64, ++ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64 | LOONGARCH, + .group_size = ex_table_group_size, + }, + { + .name = "__jump_table", +- .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64, ++ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64 | LOONGARCH, + .group_size = jump_table_group_size, + .group_filter = jump_table_group_filter, + }, +@@ -2938,6 +2957,12 @@ static void kpatch_check_relocations(struct kpatch_elf *kelf) + long sec_size; + long sec_off; + ++ /* LoongArch rela's SYM+addend maybe outside of range, but it is ok */ ++ if (kelf->arch == LOONGARCH) { ++ log_debug("do not check relocations for LoongArch\n"); ++ return; ++ } ++ + list_for_each_entry(relasec, &kelf->sections, list) { + if (!is_rela_section(relasec)) + continue; +@@ -3459,11 +3484,23 @@ static int function_ptr_rela(const struct rela *rela) + !rela_toc->sym->parent && + (rela_toc->addend == (int)rela_toc->sym->sym.st_value || + rela_toc->addend == (int)rela_toc->sym->sym.st_value - entry_offset) && ++#ifdef __loongarch__ ++ (rela->type == R_LARCH_MARK_LA || ++ rela->type == R_LARCH_B26 || ++ rela->type == R_LARCH_32_PCREL || ++ rela->type == R_LARCH_64_PCREL || ++ rela->type == R_LARCH_GOT_PC_HI20 || ++ rela->type == R_LARCH_GOT_PC_LO12 || ++ rela->type == R_LARCH_SOP_PUSH_ABSOLUTE || ++ rela->type == R_LARCH_SOP_PUSH_PLT_PCREL) ++#else + (rela->type == R_X86_64_32S || + rela->type == R_PPC64_TOC16_HA || + rela->type == R_PPC64_TOC16_LO_DS || + rela->type == R_AARCH64_ADR_PREL_PG_HI21 || +- rela->type == R_AARCH64_ADD_ABS_LO12_NC)); ++ rela->type == R_AARCH64_ADD_ABS_LO12_NC) ++#endif ++ ); + } + + static bool need_klp_reloc(struct kpatch_elf *kelf, struct lookup_table *table, +@@ -3626,6 +3663,252 @@ static bool need_klp_reloc(struct kpatch_elf *kelf, struct lookup_table *table, + return false; + } + ++static bool is_la_pcrel(void *ptr) ++{ ++ unsigned int *insn = ptr; ++ int rd; ++ ++ /* pcaddu12i rd, si20 */ ++ if ((*insn & 0xfe000000) != 0x1c000000) ++ return false; ++ ++ rd = *insn & 0x1f; ++ ++ /* addi.d rd, rd, si20 */ ++ if ((*(insn + 1) & 0xffc003ff) != (0x02c00000U | rd | (rd << 5))) ++ return false; ++ ++ return true; ++} ++ ++static void la_pcrel_to_la_got(void *ptr) ++{ ++ unsigned int *insn = ptr; ++ int rd; ++ ++ rd = *insn & 0x1f; ++ ++ /* ld.d rd, rd, si20 */ ++ *(insn + 1) = 0x28c00000 | rd | (rd << 5); ++} ++ ++static void kpatch_create_got_sections(struct kpatch_elf *kelf) ++{ ++ struct rela *rela, *rela2, *prev_rela; ++ struct section *sec, *kgot_sec; ++ unsigned int *kgots; ++ int kgot_nr = 0; ++ struct symbol *kgot_sym, *null_sym; ++ unsigned int offset; ++ void *ndata_buf; ++ ++ kgot_sec = create_section_pair(kelf, ".kpatch_got", 8, 0); ++ ++ ALLOC_LINK(kgot_sym, &kelf->symbols); ++ kgot_sym->sec = kgot_sec; ++ kgot_sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); ++ kgot_sym->type = STT_SECTION; ++ kgot_sym->bind = STB_LOCAL; ++ kgot_sym->name = kgot_sec->name; ++ kgot_sec->secsym = kgot_sym; ++ ++ null_sym = find_symbol_by_index(&kelf->symbols, 0); ++ ++ kgot_sec->include = 1; ++ kgot_sec->rela->include = 1; ++ ++ list_for_each_entry(sec, &kelf->sections, list) { ++ if (!is_rela_section(sec) || !(sec->base->sh.sh_flags & SHF_EXECINSTR)) ++ continue; ++ ndata_buf = NULL; ++ list_for_each_entry(rela, &sec->relas, list) { ++ if (rela->sym->sec) ++ continue; ++ if (rela->type != R_LARCH_SOP_PUSH_PCREL) ++ continue; ++ if (!is_la_pcrel(sec->base->data->d_buf + rela->offset)) ++ continue; ++ if (ndata_buf == NULL) { ++ ndata_buf = malloc(sec->base->data->d_size + 4); ++ ndata_buf = ndata_buf + 4 - ((unsigned long)ndata_buf % 4); ++ memcpy(ndata_buf, sec->base->data->d_buf, sec->base->data->d_size); ++ sec->base->data->d_buf = ndata_buf; ++ } ++ la_pcrel_to_la_got(sec->base->data->d_buf + rela->offset); ++ ++ ALLOC_LINK(rela2, &kgot_sec->rela->relas); ++ rela2->sym = rela->sym; ++ rela2->type = R_LARCH_64; ++ rela2->addend = 0; ++ rela2->offset = kgot_nr * 8; ++ ++ /* remove old rela for la.pcrel */ ++ prev_rela = list_entry(rela->list.prev, struct rela, list); ++ offset = rela->offset; ++ while ((rela->offset >= offset) && (rela->offset <= offset + 4)) { ++ list_del(&rela->list); ++ rela = list_next_entry(prev_rela, list); ++ } ++ /* add rela for la.got */ ++ ++#define LA_ADD_GOT_RELA(rsym, rtype, raddend, roffset) \ ++ do { \ ++ ALLOC_LINK(rela2, &rela->list); \ ++ rela2->sym = rsym; \ ++ rela2->type = rtype; \ ++ rela2->addend = raddend; \ ++ rela2->offset = roffset; \ ++ } while (0) ++ ++ LA_ADD_GOT_RELA(kgot_sym, R_LARCH_SOP_PUSH_PCREL, 0x800, offset); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, kgot_nr * 8, offset); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_ADD, 0, offset); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0xc, offset); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_SR, 0, offset); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_POP_32_S_5_20, 0, offset); ++ ++ LA_ADD_GOT_RELA(kgot_sym, R_LARCH_SOP_PUSH_PCREL, 0x4, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, kgot_nr * 8, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_ADD, 0, offset + 4); ++ LA_ADD_GOT_RELA(kgot_sym, R_LARCH_SOP_PUSH_PCREL, 0x804, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, kgot_nr * 8, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_ADD, 0, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0xc, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_SR, 0, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0xc, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_SL, 0, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_SUB, 0, offset + 4); ++ LA_ADD_GOT_RELA(null_sym, R_LARCH_SOP_POP_32_S_10_12, 0, offset + 4); ++ ++ rela = list_entry(rela->list.prev, struct rela, list); ++ ++ log_debug("add kpatch got for [%s + %#lx]: index:%d\n", ++ rela->sym->name, rela->addend, kgot_nr); ++ kgot_nr++; ++ } ++ } ++ ++ kgots = kgot_sec->data->d_buf = malloc(kgot_nr * 8); ++ memset(kgots, 0, kgot_nr * 8); ++ kgot_sec->data->d_size = kgot_nr * 8; ++} ++ ++static bool is_short_call(void *ptr) ++{ ++ unsigned int *insn = (unsigned int *)ptr; ++ ++ /* b symbol */ ++ if ((*insn & 0xfc000000) == 0x50000000) ++ return true; ++ ++ /* bl symbol */ ++ if ((*insn & 0xfc000000) == 0x54000000) ++ return true; ++ ++ return false; ++} ++ ++static void kpatch_create_trampoline_sections(struct kpatch_elf *kelf) ++{ ++ int nr; ++ struct rela *rela, *rela2; ++ struct section *sec, *ktramp_sec; ++ unsigned int ktramp_item[8] = { 0x14000014,/* lu12i.w t8, 0 */ ++ 0x03800294,/* ori t8,t8, 0 */ ++ 0x16000014,/* lu32i.d t8,t8, 0 */ ++ 0x03000294,/* lu52i.d t8,t8, 0 */ ++ 0x4c000280,/* jirl r0,t8, 0 */ ++ 0x002a0000,/* break 0 */ ++ 0x002a0000,/* break 0 */ ++ 0x002a0000,/* break 0 */ ++ }; ++ unsigned int *ktramps; ++ int tramp_nr = 0; ++ struct symbol *tramp_sym, *null_sym; ++ ++ /* create .text.kpatch_trampoline text/rela section pair */ ++ ktramp_sec = create_section_pair(kelf, ".text.kpatch_trampoline", 32, tramp_nr); ++ ktramp_sec->sh.sh_flags |= SHF_EXECINSTR; ++ ++ /* create .text.kpatch_trampoline section symbol */ ++ ALLOC_LINK(tramp_sym, &kelf->symbols); ++ tramp_sym->sec = ktramp_sec; ++ tramp_sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); ++ tramp_sym->type = STT_SECTION; ++ tramp_sym->bind = STB_LOCAL; ++ tramp_sym->name = ktramp_sec->name; ++ ktramp_sec->secsym = tramp_sym; ++ ++ null_sym = find_symbol_by_index(&kelf->symbols, 0); ++ ++ ktramp_sec->include = 1; ++ ktramp_sec->rela->include = 1; ++ ++ list_for_each_entry(sec, &kelf->sections, list) { ++ if (!is_rela_section(sec) || !(sec->base->sh.sh_flags & SHF_EXECINSTR)) ++ continue; ++ if (!strcmp(sec->name, ".rela.text.kpatch_trampoline")) ++ continue; ++ list_for_each_entry(rela, &sec->relas, list) { ++ ++ if (rela->sym->type != STT_FUNC) ++ continue; ++ if (rela->sym->sec) ++ continue; ++ if (!is_short_call(sec->base->data->d_buf + rela->offset)) ++ continue; ++ ++ /* add trampoline rela */ ++#define LA_ADD_RELA(rsym, rtype, raddend, roffset) \ ++ do { \ ++ ALLOC_LINK(rela2, &ktramp_sec->rela->relas); \ ++ rela2->sym = rsym; \ ++ rela2->type = rtype; \ ++ rela2->addend = raddend; \ ++ rela2->offset = roffset; \ ++ } while (0) ++ ++ LA_ADD_RELA(rela->sym, R_LARCH_MARK_LA, 0, tramp_nr * 32); ++ LA_ADD_RELA(rela->sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0, tramp_nr * 32); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0x20, tramp_nr * 32); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_SL, 0, tramp_nr * 32); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0x2c, tramp_nr * 32); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_SR, 0, tramp_nr * 32); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_POP_32_S_5_20, 0, tramp_nr * 32); ++ ++ LA_ADD_RELA(rela->sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0, tramp_nr * 32 + 4); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0xfff, tramp_nr * 32 + 4); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_AND, 0, tramp_nr * 32 + 4); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_POP_32_U_10_12, 0, tramp_nr * 32 + 4); ++ ++ LA_ADD_RELA(rela->sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0, tramp_nr * 32 + 8); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0xc, tramp_nr * 32 + 8); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_SL, 0, tramp_nr * 32 + 8); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0x2c, tramp_nr * 32 + 8); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_SR, 0, tramp_nr * 32 + 8); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_POP_32_S_5_20, 0, tramp_nr * 32 + 8); ++ ++ LA_ADD_RELA(rela->sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0, tramp_nr * 32 + 12); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_PUSH_ABSOLUTE, 0x34, tramp_nr * 32 + 12); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_SR, 0, tramp_nr * 32 + 12); ++ LA_ADD_RELA(null_sym, R_LARCH_SOP_POP_32_S_10_12, 0, tramp_nr * 32 + 12); ++ ++ /* redirect to trampoline */ ++ log_debug("redirect [%s + %#x]:(%s + %#lx) to (%s + %#x)\n", ++ sec->base->name, rela->offset, rela->sym->name, rela->addend, ++ ktramp_sec->name, tramp_nr * 32); ++ rela->sym = tramp_sym; ++ rela->addend = tramp_nr * 32; ++ tramp_nr++; ++ } ++ } ++ ++ ktramps = ktramp_sec->data->d_buf = malloc(tramp_nr * 32); ++ for (nr = 0; nr < tramp_nr; nr++) ++ memcpy((void *)ktramps + nr * 32, ktramp_item, 32); ++ ktramp_sec->data->d_size = tramp_nr * 32; ++} ++ + /* + * kpatch_create_intermediate_sections() + * +@@ -3683,6 +3966,24 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + */ + if (need_klp_reloc(kelf, table, relasec, rela)) + toc_rela(rela)->need_klp_reloc = true; ++ ++ if (kelf->arch == LOONGARCH) { ++ /* ++ * loongarch use stack based rela,mark the following rela ++ * which at the same offset. ++ */ ++ list_for_each_entry_continue(rela, &relasec->relas, list) { ++ if (rela->offset != list_prev_entry(rela, list)->offset) ++ break; ++ if (list_prev_entry(rela, list)->need_klp_reloc) { ++ nr++; ++ rela->need_klp_reloc = 1; ++ } else { ++ rela->need_klp_reloc = 0; ++ } ++ } ++ rela = list_prev_entry(rela, list); ++ } + } + } + +@@ -3749,7 +4050,9 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + ERROR("unsupported klp relocation reference to symbol '%s' in module-specific special section '%s'", + rela->sym->name, relasec->base->name); + +- if (!lookup_symbol(table, rela->sym, &symbol)) ++ if (kelf->arch == LOONGARCH && !strlen(rela->sym->name)) { ++ /* LoongArch rela's symbol may be NULL, don't lookup it */ ++ } else if (!lookup_symbol(table, rela->sym, &symbol)) + ERROR("can't find symbol '%s' in symbol table", + rela->sym->name); + +@@ -4027,6 +4330,19 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) + insn_offset = sym->sym.st_value; + break; + } ++ case LOONGARCH: { ++ bool found = false; ++ unsigned int *insn = sym->sec->data->d_buf + sym->sym.st_value; ++ ++ if (*insn == 0x03400000 && *(insn + 1) == 0x03400000) ++ found = true; ++ ++ if (!found) ++ ERROR("%s: unexpected instruction at the start of the function", sym->name); ++ ++ insn_offset = 0; ++ break; ++ } + default: + ERROR("unsupported arch"); + } +@@ -4199,6 +4515,8 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) + struct symbol *sym; + struct rela *rela; + unsigned char *insn; ++ struct section *patch_sec; ++ + list_for_each_entry(sym, &kelf->symbols, list) { + if (sym->type != STT_FUNC || sym->is_pfx || + !sym->sec || !sym->sec->rela) +@@ -4234,6 +4552,20 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) + insn[4] == 0x00 && insn[5] == 0x00) + sym->has_func_profiling = 1; + break; ++ case LOONGARCH: ++ patch_sec = find_section_by_name(&kelf->sections, ++ "__patchable_function_entries"); ++ if (patch_sec) { ++ list_for_each_entry(rela, &patch_sec->rela->relas, list) { ++ if (rela->sym->sec == sym->sec && ++ (rela->sym->sym.st_value + rela->addend == sym->sym.st_value)) { ++ sym->has_func_profiling = 1; ++ break; ++ } ++ } ++ } ++ break; ++ + default: + ERROR("unsupported arch"); + } +@@ -4400,6 +4732,10 @@ int main(int argc, char *argv[]) + /* create strings, patches, and klp relocation sections */ + kpatch_create_strings_elements(kelf_out); + kpatch_create_patches_sections(kelf_out, lookup, parent_name); ++ if (kelf_out->arch == LOONGARCH) { ++ kpatch_create_got_sections(kelf_out); ++ kpatch_create_trampoline_sections(kelf_out); ++ } + kpatch_create_intermediate_sections(kelf_out, lookup, parent_name, patch_name); + kpatch_create_kpatch_arch_section(kelf_out, parent_name); + kpatch_create_callbacks_objname_rela(kelf_out, parent_name); +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index b92755559db1..f04f28985acf 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -349,6 +349,9 @@ find_special_section_data() { + "s390x") + check[a]=true # alt_instr + ;; ++ "loongarch64") ++ check[a]=true # alt_instr ++ ;; + "aarch64") + check[a]=true # alt_instr + ;; +diff --git a/kpatch-build/kpatch-cc b/kpatch-build/kpatch-cc +index 509d1ca52692..9316d7c66f2b 100755 +--- a/kpatch-build/kpatch-cc ++++ b/kpatch-build/kpatch-cc +@@ -7,11 +7,24 @@ fi + TOOLCHAINCMD="$1" + shift + ++declare -a args=("$@") ++ ++filtered_array=() ++for element in "${args[@]}"; do ++ if [[ "$element" != "-mdirect-extern-access" ]]; then ++ if [[ "$element" != "-fdirect-access-external-data" ]]; then ++ filtered_array+=("$element") ++ fi ++ fi ++done ++ ++args=("${filtered_array[@]}") ++ + if [[ -z "$KPATCH_GCC_TEMPDIR" ]]; then +- exec "$TOOLCHAINCMD" "$@" ++ exec "$TOOLCHAINCMD" "${args[@]}" + fi + +-declare -a args=("$@") ++#declare -a args=("$@") + + if [[ "$TOOLCHAINCMD" =~ ^(.*-)?gcc$ || + "$TOOLCHAINCMD" =~ ^(.*-)?g\+\+$ || +diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c +index d6398b3ce2f8..86bddb66ba19 100644 +--- a/kpatch-build/kpatch-elf.c ++++ b/kpatch-build/kpatch-elf.c +@@ -146,6 +146,8 @@ unsigned int absolute_rela_type(struct kpatch_elf *kelf) + return R_AARCH64_ABS64; + case RISCV64: + return R_RISCV_64; ++ case LOONGARCH: ++ return R_LARCH_64; + default: + ERROR("unsupported arch"); + } +@@ -212,6 +214,7 @@ long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec, + case PPC64: + case ARM64: + case RISCV64: ++ case LOONGARCH: + add_off = 0; + break; + case X86_64: +@@ -268,6 +271,7 @@ unsigned int insn_length(struct kpatch_elf *kelf, void *addr) + + case PPC64: + case ARM64: ++ case LOONGARCH: + return 4; + + case S390: +@@ -334,11 +338,17 @@ static void kpatch_create_rela_list(struct kpatch_elf *kelf, + rela->sym = find_symbol_by_index(&kelf->symbols, symndx); + if (!rela->sym) + ERROR("could not find rela entry symbol\n"); ++ + if (rela->sym->sec && + (rela->sym->sec->sh.sh_flags & SHF_STRINGS)) { +- rela->string = rela->sym->sec->data->d_buf + ++ if (kelf->arch == LOONGARCH) { ++ rela->string = rela->sym->sec->data->d_buf + ++ rela->sym->sym.st_value; ++ } else { ++ rela->string = rela->sym->sec->data->d_buf + + rela->sym->sym.st_value + + rela_target_offset(kelf, relasec, rela); ++ } + if (!rela->string) + ERROR("could not lookup rela string for %s+%ld", + rela->sym->name, rela->addend); +@@ -611,6 +621,9 @@ struct kpatch_elf *kpatch_elf_open(const char *name) + case EM_RISCV: + kelf->arch = RISCV64; + break; ++ case EM_LOONGARCH: ++ kelf->arch = LOONGARCH; ++ break; + default: + ERROR("Unsupported target architecture"); + } +diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h +index f2cf60a0333f..5a7e6ca4c93b 100644 +--- a/kpatch-build/kpatch-elf.h ++++ b/kpatch-build/kpatch-elf.h +@@ -117,6 +117,7 @@ enum architecture { + S390 = 0x1 << 2, + ARM64 = 0x1 << 3, + RISCV64= 0x1 << 4, ++ LOONGARCH = 0x1 << 5, + }; + + struct kpatch_elf { +diff --git a/kpatch-build/list.h b/kpatch-build/list.h +index ad4643c10f94..827642f24743 100644 +--- a/kpatch-build/list.h ++++ b/kpatch-build/list.h +@@ -180,6 +180,15 @@ static inline void list_replace(struct list_head *old, + #define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + ++/** ++ * list_prev_entry - get the prev element in list ++ * @pos: the type * to cursor ++ * @member: the name of the list_head within the struct. ++ */ ++#define list_prev_entry(pos, member) \ ++ list_entry((pos)->member.prev, typeof(*(pos)), member) ++ ++ + /** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. +-- +2.41.0 + diff --git a/kpatch.spec b/kpatch.spec index 072ba8f..4588bf9 100644 --- a/kpatch.spec +++ b/kpatch.spec @@ -1,7 +1,7 @@ Name: kpatch Epoch: 1 Version: 0.9.9 -Release: 15 +Release: 16 Summary: A Linux dynamic kernel patching infrastructure License: GPLv2 @@ -65,6 +65,8 @@ Patch9007:huawei-remove-.export_symbol-section-to-avoid-compile-error.patch Patch9008:huawei-ignore-the-change-of-the-hibifur-module.patch Patch9009:huawei-check-whether-the-directory-is-user-source-directory.patch +Patch9100: 0060-LoongArch-add-loongarch-hotpatch-support.patch + BuildRequires: gcc elfutils-libelf-devel kernel-devel git %ifarch ppc64le BuildRequires: gcc-plugin-devel gcc-c++ @@ -127,6 +129,12 @@ popd %{_mandir}/man1/*.1.gz %changelog +* Mon Jul 28 2025 Hongchen Zhang - 1:0.9.9-16 +- Type:update +- CVE:NA +- SUG:NA +- DESC: add LoongArch hotpatch support + * Thu Jul 10 2025 fuanan - 1:0.9.9-15 - Type:bugfix - CVE:NA -- Gitee