Skip to content

[RFC] add riscv64 kpatch-build support - #1529

Draft
qiruibd wants to merge 26 commits into
dynup:masterfrom
qiruibd:riscv_Dev
Draft

qiruibd wants to merge 26 commits into
dynup:masterfrom
qiruibd:riscv_Dev

Conversation

@qiruibd

@qiruibd qiruibd commented Oct 6, 2026

Copy link
Copy Markdown

This is a Draft/RFC PR to start review of riscv64 support for kpatch-build.

It depends on the corresponding unit-test object PR:

The test/unit/objs submodule currently points to the head commit of that PR:

  • a482f758ab231426685ca8cbd1c0d1b557c61d08

Once dynup/kpatch-unit-test-objs#58 is merged, I will refresh this PR so the
submodule points at the final upstream commit.

Summary

This series adds initial riscv64 support to kpatch-build, including:

  • riscv64 architecture detection and build support
  • RISC-V ftrace callsite handling
  • RISC-V mapping symbol and local label handling
  • RISC-V special section handling for .alternative, __jump_table, and related
    relocations
  • RISC-V intermediate relocation metadata
  • RISC-V KLP relocation slots
  • RISC-V PC-relative load handling
  • RISC-V syscall wrapper macro support
  • RISC-V skip-vmlinux-final-link support
  • Linux 6.12.95 integration test coverage
  • riscv64 unit test harness support

The series also includes a few prerequisite fixes that are useful outside
riscv64 support.

Validation

I validated the series with the following checks:

  • For every commit in the series:

    • make ARCH=aarch64 all && make check
  • From the commit which introduces riscv64 architecture support onward:

    • make ARCH=riscv64 all && make check
  • Final tree:

  • RISC-V integration testing:

    • Full Linux 6.12.95 riscv64 integration test run completed successfully on native
      riscv64 hardware.
    • Test environment:
      • distro: Debian GNU/Linux 13 (trixie), DEBIAN_VERSION_FULL=13.2
      • compiler: GCC 14.2.0, riscv64-linux-gnu, Debian 14.2.0-19+byted1
      • linker: GNU ld 2.44
    • The run included the newly added Linux 6.12.95 test set and RISC-V-specific coverage
      such as syscall wrapper handling, special section handling, static keys, and skip-
      vmlinux-final-link behavior.

Notes

This PR is intentionally marked as Draft until dynup/kpatch-unit-test-objs#58 is
merged and the submodule pointer is refreshed to the final upstream commit.

qiruibd added 26 commits October 5, 2026 11:38
The _error_injection_whitelist section contains pointers to functions
annotated with ALLOW_ERROR_INJECTION().  Symbol indices can differ between
original and patched objects even when the content is semantically
unchanged.

Ignore this section to avoid false CHANGED detection.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
…tion

The string offset into .kpatch.ignore.sections must be computed as
sym->st_value + rela->addend, not just rela->addend.  Using addend alone is
only correct when the relocation references a section symbol (STT_SECTION,
where st_value is 0).  When the relocation references a regular symbol with
a non-zero st_value, the offset is wrong and ignored sections can fail
replacement symbol lookup.

On x86 and ARM64 this happens to work because GCC emits section symbols for
these relocations.  On RISC-V, GCC emits regular symbols with non-zero
st_value, exposing the bug.

This matches the pattern used for .modinfo string lookups in kpatch-elf.c
(kpatch_create_rela_list).

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Use modinfo -F name when .gnu.linkonce.this_module does not provide a
module name.

This keeps load and unload handling working for modules whose build does
not leave the module name in that section string.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Kernels built with CONFIG_PRINTK_CALLER prepend a caller-id prefix to each
dmesg line, so the marker written to /dev/kmsg does not match the rendered
line read back from dmesg --notime.

Capture the actual rendered dmesg line after writing the marker and use it
for exact matching in new_dmesg(). Fall back to suffix matching when
recovering the line so the prefix does not interfere, and fail early if the
marker cannot be recovered from the printk buffer.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
The LLD variable was unconditionally derived as ${CROSS_COMPILE}ld.lld,
which only exists when the cross-toolchain ships a prefixed ld.lld.  Many
cross-toolchains (and native builds) provide only the unprefixed ld.lld,
so kpatch-build could not locate the linker there.

Allow LLD to be overridden via the environment; otherwise prefer the
prefixed ${CROSS_COMPILE}ld.lld when it exists and fall back to the
unprefixed ld.lld.  This makes cross-builds work on toolchains that do
not ship a prefixed lld.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Add RISCV64 ELF architecture handling and make the build system accept
riscv64 targets.

Map kpatch's riscv64 architecture name to the kernel ARCH=riscv value, skip
RISC-V VDSO objects, and pass -fPIC for RISC-V kernel object builds.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
RISC-V kernels use -fpatchable-function-entry to reserve NOPs at function
entries for ftrace patching.

Detect 2-byte C.NOP and 4-byte regular NOP padding, use the detected
padding for symbol bundling, and create __mcount_loc or
__patchable_function_entries callsite sections for RISC-V functions.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
RISC-V uses ELF mapping symbols and compiler-generated local labels which
can be renamed or moved between builds.

Ignore unstable local symbols during symbol correlation and normalize
RISC-V local-label relocations in text and function-local .rodata sections
to section symbols.

This also generalizes local-label handling beyond RISC-V.  AArch64 now
ignores .L* local labels (except .LC*, which point to string literals and
are handled by kpatch_include_standard_elements()) during symbol
correlation and section-symbol replacement; previously only $d/$x mapping
symbols were ignored.  LoongArch local-label normalization is now scoped
to text sections and .rodata.*; previously it applied to all sections,
including special sections like __jump_table, __ex_table and .alternative,
where normalizing local labels to section symbols could corrupt field
offsets.  A missing section symbol is now created on demand.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
The insn_is_load_immediate() helper detects instructions that load an
immediate value into a register, which is how the compiler embeds __LINE__
in WARN() and might_sleep() macros.  When only the line number differs
between patched and original code, kpatch can safely ignore the change as a
false positive.

On RISC-V, __LINE__ can be loaded with a 32-bit addi encoding or with the
16-bit C.li compressed encoding when the C extension is enabled.  Detect
both forms for the syscall argument registers used by the kernel.

Previously RISCV64 fell through with "to be done", causing
kpatch_line_macro_change_only() to return false for RISC-V and produce
false positive CHANGED sections.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Add RISCV64 to the generic special section architecture mask and ignore
patchable function entry sections for RISC-V objects.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
RISC-V uses .alternative instead of the generic .altinstructions section
for alternative instruction patching.

Register it as a special section and teach the build helper to read
alt_entry size data from DWARF so altinstructions_group_size() can process
RISC-V entries.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
RISC-V jump entries use paired ADD/SUB relocations, producing six
relocations per entry instead of the standard three.

Detect that format, select the code and key relocations from the ADD
entries, and reject unsafe unexported vmlinux keys before they can be
partially converted to livepatch relocations.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
RISC-V special sections encode self-relative fields with paired
R_RISCV_ADD/SUB relocations.  The SUB half can reference a local anchor
symbol whose st_value is the field offset in the base section.

When kpatch compacts .alternative, __jump_table, __bug_table, or
__ex_table, move retained in-section anchors with their groups and reject
any anchor left outside the regenerated section.  This keeps the generic
relocation range check meaningful instead of bypassing bad in-section
anchors later.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Identify RISC-V HI20/LO12 paired relocations that need special livepatch
handling and record them in the intermediate metadata.

Mark paired LO12 relocations with riscv_paired_lo12 and set the local flag
on intermediate relocations so create-klp-module can emit the correct KLP
relocation type.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Consume the intermediate relocation metadata emitted by create-diff-object
and generate livepatch relocation entries for RISC-V paired HI20/LO12
sequences. Create KLP data slots, local anchors, normalize simple
addi-based LO12 loads to direct ld instructions, and remove linker-only
RISC-V relocations that have no runtime counterpart.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Extend patch_riscv_lo12_load() to handle PC-relative load instructions (ld,
lw, etc.) whose KLP data slot contains the symbol address rather than its
value.

For these loads an extra dereference is needed. Generate an out-of-line
trampoline that loads the address from the slot and then dereferences it,
redirecting the original AUIPC/LO12 pair through the trampoline with
AUIPC/JALR.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
kpatch_check_relocations() verifies that relocation targets fall within the
target section, but it only checked rela->sym->sec before reading
rela->sym->sec->data->d_size.  Some relocation targets have a valid section
object but no materialized data buffer, such as NOBITS/.bss or sections
omitted from the output ELF.  For those targets, sec->data is NULL, so the
range check dereferenced NULL and terminated kpatch-build before it could
produce a patch module.

There is no section data size against which to validate these targets. Skip
the range check when sec->data is absent, while leaving relocation
validation unchanged for materialized sections.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Debug relocation sections can still reference symbols from sections which
are kept in the output object.  Mark those symbols as included before
pruning debug relocations to unchanged sections.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
RISC-V uses __riscv_sys_* naming for syscall entry points, unlike other
architectures that use sys_* directly.

Add the RISC-V specific __KPATCH_SYSCALL_DEFINEx macro that generates the
matching __riscv_sys_*, __se_sys_*, and __kpatch_do_sys_* symbols for the
kernel syscall wrapper conventions.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Add --skip-vmlinux-final-link for riscv64 builds. In this mode, build the
original and patched trees through vmlinux.o and modpost instead of running
the final vmlinux link.

Use vmlinux.symvers as the symbol version source. Before the external
livepatch module build, copy vmlinux.symvers to Module.symvers because the
module build expects the kernel tree file name.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Limit --skip-vmlinux-final-link to inputs whose effects can be verified as
vmlinux-only. Reject custom targets and out-of-tree modules, reject patches
touching non-C sources, and reject .c files or changed objects that resolve
to module objects.

Preserve the pre-build Module.symvers state, including the case where the
file was absent, while the skip-link flow temporarily replaces it with
vmlinux.symvers. Also compare original and patched vmlinux.symvers content
and fail with a cached diff if symbol versions change.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Add a RISC-V-only integration test for the vmlinux-only boundary of
--skip-vmlinux-final-link.

The test uses an XFS in-tree module source, verifies that kpatch-build
rejects it before the patched build, and checks that Module.symvers is
restored after the expected failure. Other architectures and configurations
where XFS is not modular are skipped.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Add pre-built riscv64 test objects for the unit test cases so the RISC-V
unit test target has matching fixture data.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Add riscv64 to the unit test architecture list and skip RISC-V boot objects
in difftree, matching the existing generated-object exclusions for other
architectures.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Add a linux-6.12.95 integration test directory containing the standard
livepatch scenario fixtures (data-new, new-function, new-globals,
shadow-newpid, special-static, macro-callbacks, gcc-static-local-var-6,
syscall, symvers-disagreement-FAIL, warn-detect-FAIL, multiple) and
their *-LOADED.test runtime checks, mirroring the set already used under
existing kernel-version directories such as linux-6.17.0 and amzn-2023.

This lets the integration suite run against the 6.12.95 stable kernel
baseline.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
assert_num_funcs used the letter printed by nm as a proxy for the ELF
symbol type.  That is not reliable on RISC-V: create-diff-object emits
local STT_NOTYPE .Lkpatch_riscv_hi20_* anchors for paired HI20/LO12
relocations, and nm versions which expose special symbols print those
text-section anchors as lowercase t.  The same object can therefore pass
or fail solely because of the installed binutils version or nm options.

Count symbols which objdump explicitly marks as functions and which are
defined in .text or .text.* instead.  Requiring the ELF STT_FUNC type
excludes the RISC-V relocation anchors, while restricting the section
preserves the assertion's original purpose of checking patch text rather
than executable dependency sections such as .init.text.  Newly added helper
functions remain covered because they are STT_FUNC symbols in .text.*.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
@qiruibd
qiruibd marked this pull request as draft October 6, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant