On Tue, Jul 07, 2026 at 03:20:21PM +0800, George Guo wrote:
> From: George Guo <[email protected]>
>
> objtool needs to split the kernel's special sections into per-entry
> symbols when generating livepatch modules. Mark them so it can:
>
> - .altinstructions and __ex_table are read-only, so set an explicit
> entry size via SHF_MERGE (ALT_INSTR_SIZE / EXTABLE_SIZE).
>
> - __bug_table and __jump_table are writable. SHF_MERGE cannot be
> combined with SHF_WRITE (Clang rejects it), so annotate each entry
> with ANNOTATE_DATA_SPECIAL instead, mirroring x86/arm64.
>
> Co-developed-by: Kexin Liu <[email protected]>
> Signed-off-by: Kexin Liu <[email protected]>
> Signed-off-by: George Guo <[email protected]>
> ---
> arch/loongarch/include/asm/alternative-asm.h | 5 +++--
> arch/loongarch/include/asm/alternative.h | 6 ++++--
> arch/loongarch/include/asm/asm-extable.h | 10 ++++++++--
> arch/loongarch/include/asm/bug.h | 1 +
> arch/loongarch/include/asm/jump_label.h | 2 ++
> arch/loongarch/kernel/asm-offsets.c | 20 ++++++++++++++++++++
> 6 files changed, 38 insertions(+), 6 deletions(-)
>
> diff --git a/arch/loongarch/include/asm/alternative-asm.h
> b/arch/loongarch/include/asm/alternative-asm.h
> index 7dc29bd9b2f0..d940d9d2c0e1 100644
> --- a/arch/loongarch/include/asm/alternative-asm.h
> +++ b/arch/loongarch/include/asm/alternative-asm.h
> @@ -5,6 +5,7 @@
> #ifdef __ASSEMBLER__
>
> #include <asm/asm.h>
> +#include <generated/asm-offsets.h>
>
> /*
> * Issue one struct alt_instr descriptor entry (need to put it into
> @@ -33,7 +34,7 @@
> .fill - (((144f-143f)-(141b-140b)) > 0) * ((144f-143f)-(141b-140b)) /
> 4, 4, 0x03400000
> 142 :
>
> - .pushsection .altinstructions, "a"
> + .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE
> altinstruction_entry 140b, 143f, \feature, 142b-140b, 144f-143f
> .popsection
>
> @@ -63,7 +64,7 @@
> (alt_max_short(new_len1, new_len2) - (old_len)) / 4, 4,
> 0x03400000
> 142 :
>
> - .pushsection .altinstructions, "a"
> + .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE
> altinstruction_entry 140b, 143f, \feature1, 142b-140b, 144f-143f,
> 142b-141b
> altinstruction_entry 140b, 144f, \feature2, 142b-140b, 145f-144f,
> 142b-141b
> .popsection
> diff --git a/arch/loongarch/include/asm/alternative.h
> b/arch/loongarch/include/asm/alternative.h
> index b5bae21fb3c8..8f7712ed2f4e 100644
> --- a/arch/loongarch/include/asm/alternative.h
> +++ b/arch/loongarch/include/asm/alternative.h
> @@ -70,7 +70,8 @@ extern void apply_alternatives(struct alt_instr *start,
> struct alt_instr *end);
> /* alternative assembly primitive: */
> #define ALTERNATIVE(oldinstr, newinstr, feature) \
> OLDINSTR(oldinstr, 1) \
> - ".pushsection .altinstructions,\"a\"\n" \
> + ".pushsection .altinstructions, \"aM\", @progbits, " \
> + __stringify(ALT_INSTR_SIZE) "\n" \
> ALTINSTR_ENTRY(feature, 1) \
> ".popsection\n" \
> ".subsection 1\n" \
> @@ -79,7 +80,8 @@ extern void apply_alternatives(struct alt_instr *start,
> struct alt_instr *end);
>
> #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
> OLDINSTR_2(oldinstr, 1, 2) \
> - ".pushsection .altinstructions,\"a\"\n" \
> + ".pushsection .altinstructions, \"aM\", @progbits, " \
> + __stringify(ALT_INSTR_SIZE) "\n" \
> ALTINSTR_ENTRY(feature1, 1) \
> ALTINSTR_ENTRY(feature2, 2) \
> ".popsection\n" \
> diff --git a/arch/loongarch/include/asm/asm-extable.h
> b/arch/loongarch/include/asm/asm-extable.h
> index d60bdf2e6377..2d7eef7c0b39 100644
> --- a/arch/loongarch/include/asm/asm-extable.h
> +++ b/arch/loongarch/include/asm/asm-extable.h
> @@ -7,10 +7,15 @@
> #define EX_TYPE_UACCESS_ERR_ZERO 2
> #define EX_TYPE_BPF 3
>
> +#ifndef COMPILE_OFFSETS
> +#include <asm/asm-offsets.h>
> +#endif
> +
> #ifdef __ASSEMBLER__
>
> #define __ASM_EXTABLE_RAW(insn, fixup, type, data) \
> - .pushsection __ex_table, "a"; \
> + .pushsection __ex_table, "aM", @progbits, \
> + EXTABLE_SIZE; \
> .balign 4; \
> .long ((insn) - .); \
> .long ((fixup) - .); \
> @@ -29,7 +34,8 @@
> #include <asm/gpr-num.h>
>
> #define __ASM_EXTABLE_RAW(insn, fixup, type, data) \
> - ".pushsection __ex_table, \"a\"\n" \
> + ".pushsection __ex_table, \"aM\", @progbits, "\
> + __stringify(EXTABLE_SIZE) "\n" \
> ".balign 4\n" \
> ".long ((" insn ") - .)\n" \
> ".long ((" fixup ") - .)\n" \
> diff --git a/arch/loongarch/include/asm/bug.h
> b/arch/loongarch/include/asm/bug.h
> index d090a5bec5eb..14e3acbaad8d 100644
> --- a/arch/loongarch/include/asm/bug.h
> +++ b/arch/loongarch/include/asm/bug.h
> @@ -25,6 +25,7 @@
> #define __BUG_ENTRY(cond_str, flags) \
> .pushsection __bug_table, "aw"; \
> .align 2; \
> + __ANNOTATE_DATA_SPECIAL; \
> 10000: .long 10001f - .; \
> _BUGVERBOSE_LOCATION(WARN_CONDITION_STR(cond_str) __FILE__,
> __LINE__) \
> .short flags; \
> diff --git a/arch/loongarch/include/asm/jump_label.h
> b/arch/loongarch/include/asm/jump_label.h
> index 7ef4ae3abf08..d20f0fa24b6b 100644
> --- a/arch/loongarch/include/asm/jump_label.h
> +++ b/arch/loongarch/include/asm/jump_label.h
> @@ -12,6 +12,7 @@
> #include <linux/types.h>
> #include <linux/stringify.h>
> #include <asm/asm.h>
> +#include <linux/objtool.h>
>
> #define HAVE_JUMP_LABEL_BATCH
>
> @@ -27,6 +28,7 @@
> #define JUMP_TABLE_ENTRY(key, label) \
> ".pushsection __jump_table, \"aw\" \n\t" \
> ".align " __stringify(PTRLOG) " \n\t" \
> + ANNOTATE_DATA_SPECIAL "\n\t" \
> ".long 1b - ., " label " - . \n\t" \
> JUMP_LABEL_TYPE key " - . \n\t" \
> ".popsection \n\t"
> diff --git a/arch/loongarch/kernel/asm-offsets.c
> b/arch/loongarch/kernel/asm-offsets.c
> index 2cc953f113ac..470323aa022c 100644
> --- a/arch/loongarch/kernel/asm-offsets.c
> +++ b/arch/loongarch/kernel/asm-offsets.c
> @@ -18,6 +18,8 @@
> #include <asm/ftrace.h>
> #include <asm/sigframe.h>
> #include <vdso/datapage.h>
> +#include <asm/alternative.h>
> +#include <asm/extable.h>
>
> static void __used output_ptreg_defines(void)
> {
> @@ -323,3 +325,21 @@ static void __used output_vdso_defines(void)
> DEFINE(__VDSO_PAGES, VDSO_NR_PAGES);
> BLANK();
> }
> +
> +static void __used output_extable_defines(void)
> +{
> + COMMENT("LoongArch exception table entry offsets.");
> +
> + DEFINE(EXTABLE_SIZE, sizeof(struct exception_table_entry));
> + BLANK();
> +}
> +
> +static void __used output_alt_instr_defines(void)
> +{
> + COMMENT("LoongArch alternative instructions offsets.");
> +
> + DEFINE(ALT_INSTR_SIZE, sizeof(struct alt_instr));
> + BLANK();
> +}
> +
> +
> --
> 2.25.1
>
Hello George,
I've run into another test case while exercising v3 on LoongArch (Clang
build).I
a
Setup
=====
Maybe my config was too small, but I couldn't find any existing vmlinux
.c file that emits .altinstructions on LoongArch, all in-tree
ALTERNATIVE() sites are in arch/loongarch/lib/*.S, which we can't modify
with klp-build.
I added a minimal dummy function to arch/loongarch/kernel/alternative.c
so I could test:
$ cat base-vmlinux.patch
diff --git a/arch/loongarch/kernel/alternative.c
b/arch/loongarch/kernel/alternative.c
index 0e0c766df1e3..01d81db79b3f 100644
--- a/arch/loongarch/kernel/alternative.c
+++ b/arch/loongarch/kernel/alternative.c
@@ -3,6 +3,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <asm/alternative.h>
+#include <asm/cpu.h>
#include <asm/cacheflush.h>
#include <asm/inst.h>
#include <asm/sections.h>
@@ -245,3 +246,15 @@ void __init alternative_instructions(void)
alternatives_patched = 1;
}
+
+/*
+ * klp-build repro hook: vmlinux .c function with ALTERNATIVE().
+ */I
+staatic int klp_build_alt_test_base = 10;
+
+static noinline int __used klp_build_alt_test_compute(int input)
+{
+ asm volatile(ALTERNATIVE("nop", "nop", CPU_FEATURE_FPU) : : :
"memory");
+
+ return input + klp_build_alt_test_base;
+}
Then a one-line klp-build patch to modify the function:
$ cat test-alternatives.patch
diff --git a/arch/loongarch/kernel/alternative.c
b/arch/loongarch/kernel/alternative.c
index 01d81db79b3f..f5d5c4f0d8ef 100644
--- a/arch/loongarch/kernel/alternative.c
+++ b/arch/loongarch/kernel/alternative.c
@@ -256,5 +256,5 @@ static noinline int __used klp_build_alt_test_compute(int
input)
{
asm volatile(ALTERNATIVE("nop", "nop", CPU_FEATURE_FPU) : : :
"memory");
- return input + klp_build_alt_test_base;
+ return input + klp_build_alt_test_base + 1;
Repro
=====
Build the kernel as usual, then klp-build the test-alternatives.patch:
$ patch -p1 < base-vmlinux.patch
patching file arch/loongarch/kernel/alternative.c
$ ARCH=loongarch LLVM=1 make -j$(nproc)
...
$ ARCH=loongarch LLVM=1 ./sIcripts/livepatch/klp-build -T
test-alternatives.patch
a
Result
======
klp-build gets through the diff step, then fails linking the livepatch
module:
...
Diffing objects
vmlinux.o: changed function: klp_build_alt_test_compute
Building patch module: livepatch-test-alternatives.ko
livepatch-test-alternatives.o: error: objtool:
.text.klp_build_alt_test_compute+0x14: special: can't find new instruction
make[3]: *** [/home/jolawren/src/linux/scripts/Makefile.build:507:
livepatch-test-alternatives.o] Error 255
make[3]: *** Deleting file 'livepatch-test-alternatives.o'
make[2]: *** [/home/jolawren/src/linux/Makefile:2141: .] Error 2
make[1]: *** [/home/jolawren/src/linux/Makefile:248: __sub-make] Error 2
make: *** [Makefile:248: __sub-make] Error 2
error: klp-build: line 964: '"${cmd[@]}" > >(tee -a "$log") 2> >(tee -a
"$log" 1>&2)'
Should v3 (or a follow-up patch) include the inline alternative
cloning support? Or is patching functions that contain ALTERNATIVE()
intentionally out of scope for LoongArch KLP for now?
If the latter, it would be worth calling out explicitly as this patch
reads as though .altinstructions is supported end-to-end.
Regards,
--
Joe