* [PATCH v2 19/53] objtool/klp: Fix pointer comparisons for rodata objects
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
klp-diff treats all rodata as uncorrelated, so any reference to it uses
a duplicated copy rather than using a KLP reloc.
For the contents of the data itself, a duplicated copy is fine.
However, pointer comparisons (e.g., f->f_op == &foo_ops) are broken.
Fix it by correlating non-anonymous rodata objects.
Also, use a new find_symbol_containing_inclusive() helper for matching
the end of a symbol so bounds calculations don't get broken, for the
case where an array or other symbol's ending address is used as part of
a bounds calculation.
While these are really two distinct changes, they need to be done in the
same patch so as to avoid introducing bisection regressions.
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/elf.c | 14 ++++++++++++++
tools/objtool/include/objtool/elf.h | 1 +
tools/objtool/klp-diff.c | 15 +++++++++++++--
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 87c6e00749c6..5a20dab683dd 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -207,6 +207,20 @@ struct symbol *find_symbol_containing(const struct section *sec, unsigned long o
return sym ? sym->alias : NULL;
}
+/*
+ * Also match the symbol end address which can be used for a bounds comparison.
+ */
+struct symbol *find_symbol_containing_inclusive(const struct section *sec,
+ unsigned long offset)
+{
+ struct symbol *sym = find_symbol_containing(sec, offset);
+
+ if (!sym && offset)
+ sym = find_symbol_containing(sec, offset - 1);
+
+ return sym;
+}
+
/*
* Returns size of hole starting at @offset.
*/
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index ab5f7017ec34..8a543cea43b9 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -211,6 +211,7 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *name);
struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
+struct symbol *find_symbol_containing_inclusive(const struct section *sec, unsigned long offset);
int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 78633c9b68eb..bf37c652188b 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -386,6 +386,7 @@ static bool dont_correlate(struct symbol *sym)
is_uncorrelated_static_local(sym) ||
is_local_label(sym) ||
is_string_sec(sym->sec) ||
+ (is_rodata_sec(sym->sec) && !is_object_sym(sym)) ||
is_initcall_sym(sym) ||
is_addressable_sym(sym) ||
is_special_section(sym->sec) ||
@@ -979,7 +980,7 @@ static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *reloc)
goto found_sym;
/* No dedicated section; find the symbol manually */
- sym = find_symbol_containing(sec, arch_adjusted_addend(reloc));
+ sym = find_symbol_containing_inclusive(sec, arch_adjusted_addend(reloc));
if (!sym) {
/*
* This is presumably an .altinstr_replacement section which is
@@ -988,6 +989,17 @@ static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *reloc)
if (!sec_size(sec))
return 1;
+ /*
+ * .rodata is a mixed bag of named objects and anonymous data.
+ *
+ * Convert section symbol references to named object symbols
+ * when possible, to preserve pointer identity for const
+ * structs like file_operations. Otherwise a section symbol is
+ * fine.
+ */
+ if (is_rodata_sec(sec))
+ return 0;
+
/*
* This can happen for special section references to weak code
* whose symbol has been stripped by the linker.
@@ -1009,7 +1021,6 @@ static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *reloc)
static bool is_uncorrelated_section(struct section *sec)
{
return is_string_sec(sec) ||
- strstarts(sec->name, ".rodata") ||
strstarts(sec->name, ".data..Lubsan") || /* GCC */
strstarts(sec->name, ".data..L__unnamed_"); /* Clang */
}
--
2.53.0
^ permalink raw reply related
* [PATCH v2 20/53] objtool/klp: Don't correlate .rodata.cst* constant pool objects
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Clang aggregates UBSAN type descriptors into shared anonymous
.data..L__unnamed_* sections. This data is used by UBSAN trap handlers.
When a changed function has an UBSAN bounds check, klp-diff clones the
entire UBSAN data section associated with the TU. Relocations within
the cloned section that reference named rodata objects in .rodata.cst*
(like 'exponent', 'pirq_ali_set.irqmap') become KLP relocations because
those objects now get correlated.
That results in a .klp.rela.vmlinux..data section which can easily have
thousands of KLP relocs, most of which are completely superfluous, used
by functions which aren't cloned to the patch module.
The .rodata.cst* sections are SHF_MERGE constant pool sections
containing small fixed-size data (lookup tables, bitmasks) that is only
read by value. Pointer identity is never relevant for these objects, so
correlating them is unnecessary.
Exclude .rodata.cst* objects from correlation so they get cloned as
local data instead of generating KLP relocations.
It might be possible to someday treat UBSAN data sections as special
sections, and only extract the few needed entries. But this works for
now.
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/klp-diff.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index bf37c652188b..ca87bcb9afa3 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -372,6 +372,21 @@ static bool is_initcall_sym(struct symbol *sym)
strstarts(sym->name, "__initstub__");
}
+/*
+ * Some .rodata is anonymous and can't be correlated due to there being no
+ * symbol names.
+ *
+ * The .rodata.cst* sections aren't technically anonymous, they're SHF_MERGE
+ * constant pool sections containing small fixed-size data (lookup tables,
+ * bitmasks) which are only read by value, so pointer equivalence isn't needed.
+ * They are typically referenced by UBSAN data sections.
+ */
+static bool is_anonymous_rodata(struct symbol *sym)
+{
+ return is_rodata_sec(sym->sec) &&
+ (!is_object_sym(sym) || strstarts(sym->sec->name, ".rodata.cst"));
+}
+
/*
* These symbols should never be correlated, so their local patched versions
* are used instead of linking to the originals.
@@ -386,7 +401,7 @@ static bool dont_correlate(struct symbol *sym)
is_uncorrelated_static_local(sym) ||
is_local_label(sym) ||
is_string_sec(sym->sec) ||
- (is_rodata_sec(sym->sec) && !is_object_sym(sym)) ||
+ is_anonymous_rodata(sym) ||
is_initcall_sym(sym) ||
is_addressable_sym(sym) ||
is_special_section(sym->sec) ||
--
2.53.0
^ permalink raw reply related
* [PATCH v2 21/53] objtool/klp: Fix reloc corruption in convert_reloc_sym_to_secsym()
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Use the section symbol's index instead of the old symbol's index when
updating the ELF relocation entry in convert_reloc_sym_to_secsym().
Found by Sashiko review.
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/klp-diff.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index ca87bcb9afa3..463b6daa5234 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -975,7 +975,7 @@ static int convert_reloc_sym_to_secsym(struct elf *elf, struct reloc *reloc)
return -1;
reloc->sym = sec->sym;
- set_reloc_sym(elf, reloc, sym->idx);
+ set_reloc_sym(elf, reloc, sec->sym->idx);
set_reloc_addend(elf, reloc, sym->offset + reloc_addend(reloc));
return 0;
}
--
2.53.0
^ permalink raw reply related
* [PATCH v2 22/53] objtool: Fix reloc hash collision in find_reloc_by_dest_range()
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
In find_reloc_by_dest_range(), hash collisions can cause a high-offset
relocation to appear when probing a low-offset hash bucket.
Only return early when the best match found so far genuinely belongs to
the current bucket (its offset is within the bucket's stride range).
Otherwise, continue scanning later buckets which may contain
lower-offset matches.
This ensures the first reloc in the range gets returned.
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Fixes: 74b873e49d92 ("objtool: Optimize find_rela_by_dest_range()")
Acked-by: Song Liu <song@kernel.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/elf.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 5a20dab683dd..f41280e454ca 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -315,8 +315,9 @@ struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *nam
return NULL;
}
+/* If there are multiple matches, return the first one in the range */
struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
- unsigned long offset, unsigned int len)
+ unsigned long offset, unsigned int len)
{
struct reloc *reloc, *r = NULL;
struct section *rsec;
@@ -338,11 +339,11 @@ struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *se
r = reloc;
}
}
- if (r)
+ if (r && (reloc_offset(r) & OFFSET_STRIDE_MASK) == o)
return r;
}
- return NULL;
+ return r;
}
struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset)
--
2.53.0
^ permalink raw reply related
* [PATCH v2 23/53] klp-build: Fix hang on out-of-date .config
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
If .config is out of date with the kernel source, 'make syncconfig'
hangs while waiting for user input on new config options. Detect the
mismatch and return an error.
Fixes: 6f93f7b06810 ("livepatch/klp-build: Fix inconsistent kernel version")
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 0ad7e6631314..e19d93b78fcb 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -306,7 +306,12 @@ set_kernelversion() {
stash_file "$file"
- kernelrelease="$(cd "$SRC" && make syncconfig &>/dev/null && make -s kernelrelease)"
+ if [[ -n "$(make -s listnewconfig 2>/dev/null)" ]]; then
+ die ".config mismatch, check your .config or run 'make olddefconfig'"
+ fi
+ make syncconfig &>/dev/null || die "make syncconfig failed"
+
+ kernelrelease="$(make -s kernelrelease)"
[[ -z "$kernelrelease" ]] && die "failed to get kernel version"
sed -i "2i echo $kernelrelease; exit 0" scripts/setlocalversion
--
2.53.0
^ permalink raw reply related
* [PATCH v2 24/53] klp-build: Fix checksum comparison for changed offsets
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
The klp-build -f/--show-first-changed feature uses diff to compare
checksum log lines between original and patched objects. However, diff
compares entire lines, including the offset field. When a function is
at a different section offset, the offset field differs even though the
instruction checksum is identical, causing the wrong instruction to be
printed.
Only compare the checksum field when looking for the first changed
instruction. Also print both the original and patched offsets when they
differ.
Fixes: 78be9facfb5e ("livepatch/klp-build: Add --show-first-changed option to show function divergence")
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index e19d93b78fcb..8f0ea56f2640 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -727,13 +727,29 @@ diff_checksums() {
)
for func in ${funcs[$file]}; do
- diff <( grep0 -E "^DEBUG: .*checksum: $func " "$orig_log" | sed "s|$ORIG_DIR/||") \
- <( grep0 -E "^DEBUG: .*checksum: $func " "$patched_log" | sed "s|$PATCHED_DIR/||") \
- | gawk '/^< DEBUG: / {
- gsub(/:/, "")
- printf "%s: %s: %s\n", $3, $5, $6
- exit
- }' || true
+ local -a orig patched
+ paste <(grep0 -E "^DEBUG: .*checksum: $func " "$orig_log") \
+ <(grep0 -E "^DEBUG: .*checksum: $func " "$patched_log") |
+ while IFS= read -r line; do
+ read -ra orig <<< "${line%%$'\t'*}"
+ read -ra patched <<< "${line#*$'\t'}"
+
+ if [[ ${#patched[@]} -eq 0 ]]; then
+ printf "%s: %s: %s (removed)\n" "${orig[1]%:}" "${orig[3]}" "${orig[-2]}"
+ break
+ elif [[ ${#orig[@]} -eq 0 ]]; then
+ printf "%s: %s: %s (added)\n" "${patched[1]%:}" "${patched[3]}" "${patched[-2]}"
+ break
+ fi
+
+ [[ "${orig[-1]}" == "${patched[-1]}" ]] && continue
+
+ printf "%s: %s: %s" "${orig[1]%:}" "${orig[3]}" "${orig[-2]}"
+ [[ "${orig[-2]}" != "${patched[-2]}" ]] && \
+ printf " (patched: %s)" "${patched[-2]}"
+ printf "\n"
+ break
+ done || true
done
done
}
--
2.53.0
^ permalink raw reply related
* [PATCH v2 26/53] klp-build: Validate patch file existence
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Make sure all patch files actually exist. Otherwise there can be
confusing errors later.
Acked-by: Song Liu <song@kernel.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 68d61b72f39a..13709d20e295 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -157,6 +157,7 @@ process_args() {
local short
local long
local args
+ local patch
short="hfj:o:vdS:T"
long="help,show-first-changed,jobs:,output:,no-replace,verbose,debug,short-circuit:,keep-tmp"
@@ -235,6 +236,10 @@ process_args() {
KEEP_TMP="$keep_tmp"
PATCHES=("$@")
+
+ for patch in "${PATCHES[@]}"; do
+ [[ -f "$patch" ]] || die "$patch doesn't exist"
+ done
}
# temporarily disable xtrace for especially verbose code
--
2.53.0
^ permalink raw reply related
* [PATCH v2 25/53] klp-build: Don't use errexit
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
The errtrace option (combined with the ERR trap) already serves the same
function (and more) as errexit, so errexit is redundant. And it has
more pitfalls. Remove it.
Acked-by: Song Liu <song@kernel.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 8f0ea56f2640..68d61b72f39a 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -3,7 +3,7 @@
#
# Build a livepatch module
-# shellcheck disable=SC1090,SC2155
+# shellcheck disable=SC1090,SC2155,SC2164
if (( BASH_VERSINFO[0] < 4 || \
(BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] < 4) )); then
@@ -11,13 +11,12 @@ if (( BASH_VERSINFO[0] < 4 || \
exit 1
fi
-set -o errexit
set -o errtrace
set -o pipefail
set -o nounset
# Allow doing 'cmd | mapfile -t array' instead of 'mapfile -t array < <(cmd)'.
-# This helps keep execution in pipes so pipefail+errexit can catch errors.
+# This helps keep execution in pipes so pipefail+ERR trap can catch errors.
shopt -s lastpipe
unset DEBUG_CLONE DIFF_CHECKSUM SKIP_CLEANUP XTRACE
--
2.53.0
^ permalink raw reply related
* [PATCH v2 27/53] klp-build: Suppress excessive fuzz output by default
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
When a patch applies with fuzz, the detailed output from the patch tool
can be very noisy, especially for big patches.
Suppress the fuzz details by default, while keeping the "applied with
fuzz" warning. The noise can be restored with '--verbose'.
Acked-by: Song Liu <song@kernel.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 13709d20e295..dc2c5c33d1db 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -19,12 +19,11 @@ set -o nounset
# This helps keep execution in pipes so pipefail+ERR trap can catch errors.
shopt -s lastpipe
-unset DEBUG_CLONE DIFF_CHECKSUM SKIP_CLEANUP XTRACE
+unset DEBUG_CLONE DIFF_CHECKSUM SKIP_CLEANUP VERBOSE XTRACE
REPLACE=1
SHORT_CIRCUIT=0
JOBS="$(getconf _NPROCESSORS_ONLN)"
-VERBOSE="-s"
shopt -o xtrace | grep -q 'on' && XTRACE=1
# Avoid removing the previous $TMP_DIR until args have been fully processed.
@@ -194,7 +193,7 @@ process_args() {
shift
;;
-v | --verbose)
- VERBOSE="V=1"
+ VERBOSE=1
shift
;;
-d | --debug)
@@ -381,7 +380,7 @@ apply_patch() {
echo "$output" >&2
die "$patch did not apply"
elif [[ "$output" =~ $drift_regex ]]; then
- echo "$output" >&2
+ [[ -v VERBOSE ]] && echo "$output" >&2
warn "${patch} applied with fuzz"
fi
@@ -544,7 +543,11 @@ build_kernel() {
#
cmd+=("KBUILD_MODPOST_WARN=1")
- cmd+=("$VERBOSE")
+ if [[ -v VERBOSE ]]; then
+ cmd+=("V=1")
+ else
+ cmd+=("-s")
+ fi
cmd+=("-j$JOBS")
cmd+=("KCFLAGS=-ffunction-sections -fdata-sections")
cmd+=("OBJTOOL_ARGS=${objtool_args[*]}")
@@ -805,7 +808,11 @@ build_patch_module() {
[[ $REPLACE -eq 0 ]] && cflags+=("-DKLP_NO_REPLACE")
cmd=("make")
- cmd+=("$VERBOSE")
+ if [[ -v VERBOSE ]]; then
+ cmd+=("V=1")
+ else
+ cmd+=("-s")
+ fi
cmd+=("-j$JOBS")
cmd+=("--directory=.")
cmd+=("M=$KMOD_DIR")
--
2.53.0
^ permalink raw reply related
* [PATCH v2 29/53] klp-build: Reject patches to vDSO
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
vDSO code runs in userspace and can't be livepatched. Such patches also
cause spurious "new function" errors due to generated files like
vdso*-image.c having unstable line numbers across builds.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 9970e1f274ef..a70d48d98453 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -357,7 +357,7 @@ check_unsupported_patches() {
for file in "${files[@]}"; do
case "$file" in
- lib/*|*.S)
+ lib/*|*/vdso/*|*.S)
die "${patch}: unsupported patch to $file"
;;
esac
--
2.53.0
^ permalink raw reply related
* [PATCH v2 28/53] klp-build: Fix patch cleanup on interrupt
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
If a build error occurs and the user hits Ctrl-C while a large patch is
being reverted during cleanup, the cleanup EXIT trap gets re-triggered
and tries to re-revert the already partially-reverted patch. That
causes 'patch -R' to repeatedly prompt
"Unreversed patch detected! Ignore -R? [n]"
for each already-reverted hunk, with no way to break out.
Fix it by adding '--force' to the patch revert command in
revert_patch(), which causes it to silently ignore already-reverted
hunks. And ignore errors, as the cleanup is always best-effort.
For similar reasons, add to APPLIED_PATCHES before (rather than after)
applying the patch in apply_patch() so an interrupted apply will also
get cleaned up.
Fixes: d36a7343f4ba ("livepatch/klp-build: switch to GNU patch and recountdiff")
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index dc2c5c33d1db..9970e1f274ef 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -384,15 +384,15 @@ apply_patch() {
warn "${patch} applied with fuzz"
fi
- patch -d "$SRC" -p1 --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" --silent < "$patch"
APPLIED_PATCHES+=("$patch")
+ patch -d "$SRC" -p1 --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" --silent < "$patch"
}
revert_patch() {
local patch="$1"
local tmp=()
- patch -d "$SRC" -p1 -R --silent --no-backup-if-mismatch -r /dev/null < "$patch"
+ patch -d "$SRC" -p1 -R --force --no-backup-if-mismatch -r /dev/null &> /dev/null < "$patch" || true
for p in "${APPLIED_PATCHES[@]}"; do
[[ "$p" == "$patch" ]] && continue
--
2.53.0
^ permalink raw reply related
* [PATCH v2 31/53] klp-build: Print "objtool klp diff" command in verbose mode
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Print the full objtool command line when '--verbose' is given to help
with debugging.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 1 +
1 file changed, 1 insertion(+)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 2bb35de5db75..355345aa94d2 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -681,6 +681,7 @@ diff_objects() {
(
cd "$ORIG_DIR"
+ [[ -v VERBOSE ]] && echo "${cmd[@]}"
"${cmd[@]}" \
1> >(tee -a "$log") \
2> >(tee -a "$log" | "${filter[@]}" >&2) || \
--
2.53.0
^ permalink raw reply related
* [PATCH v2 30/53] klp-build: Reject patches to realmode
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Realmode code is compiled as a separate 16-bit binary and embedded into
the kernel image via rmpiggy.S. It can't be livepatched.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index a70d48d98453..2bb35de5db75 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -357,7 +357,7 @@ check_unsupported_patches() {
for file in "${files[@]}"; do
case "$file" in
- lib/*|*/vdso/*|*.S)
+ lib/*|*/vdso/*|*/realmode/rm/*|*.S)
die "${patch}: unsupported patch to $file"
;;
esac
--
2.53.0
^ permalink raw reply related
* [PATCH v2 32/53] klp-build: Remove redundant SRC and OBJ variables
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
SRC and OBJ are both set to $(pwd) and are always identical. The script
already enforces that klp-build runs from the kernel root directory, and
builds are done in-place, making these variables unnecessary.
Suggested-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 67 ++++++++++++++++---------------------
1 file changed, 28 insertions(+), 39 deletions(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 355345aa94d2..34a46bafdaec 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -33,11 +33,9 @@ SCRIPT="$(basename "$0")"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FIX_PATCH_LINES="$SCRIPT_DIR/fix-patch-lines"
-SRC="$(pwd)"
-OBJ="$(pwd)"
-
-CONFIG="$OBJ/.config"
-TMP_DIR="$OBJ/klp-tmp"
+OBJTOOL="$PWD/tools/objtool/objtool"
+CONFIG="$PWD/.config"
+TMP_DIR="$PWD/klp-tmp"
ORIG_DIR="$TMP_DIR/orig"
PATCHED_DIR="$TMP_DIR/patched"
@@ -88,7 +86,7 @@ declare -a STASHED_FILES
stash_file() {
local file="$1"
- local rel_file="${file#"$SRC"/}"
+ local rel_file="${file#"$PWD"/}"
[[ ! -e "$file" ]] && die "no file to stash: $file"
@@ -102,7 +100,7 @@ restore_files() {
local file
for file in "${STASHED_FILES[@]}"; do
- mv -f "$STASH_DIR/$file" "$SRC/$file" || warn "can't restore file: $file"
+ mv -f "$STASH_DIR/$file" "$PWD/$file" || warn "can't restore file: $file"
done
STASHED_FILES=()
@@ -304,7 +302,7 @@ set_module_name() {
# Hardcode the value printed by the localversion script to prevent patch
# application from appending it with '+' due to a dirty working tree.
set_kernelversion() {
- local file="$SRC/scripts/setlocalversion"
+ local file="$PWD/scripts/setlocalversion"
local kernelrelease
stash_file "$file"
@@ -375,7 +373,7 @@ apply_patch() {
[[ ! -f "$patch" ]] && die "$patch doesn't exist"
status=0
- output=$(patch -d "$SRC" -p1 --dry-run --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" < "$patch" 2>&1) || status=$?
+ output=$(patch -p1 --dry-run --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" < "$patch" 2>&1) || status=$?
if [[ "$status" -ne 0 ]]; then
echo "$output" >&2
die "$patch did not apply"
@@ -385,14 +383,14 @@ apply_patch() {
fi
APPLIED_PATCHES+=("$patch")
- patch -d "$SRC" -p1 --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" --silent < "$patch"
+ patch -p1 --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" --silent < "$patch"
}
revert_patch() {
local patch="$1"
local tmp=()
- patch -d "$SRC" -p1 -R --force --no-backup-if-mismatch -r /dev/null &> /dev/null < "$patch" || true
+ patch -p1 -R --force --no-backup-if-mismatch -r /dev/null &> /dev/null < "$patch" || true
for p in "${APPLIED_PATCHES[@]}"; do
[[ "$p" == "$patch" ]] && continue
@@ -430,8 +428,7 @@ validate_patches() {
do_init() {
# We're not yet smart enough to handle anything other than in-tree
# builds in pwd.
- [[ ! "$SRC" -ef "$SCRIPT_DIR/../.." ]] && die "please run from the kernel root directory"
- [[ ! "$OBJ" -ef "$SCRIPT_DIR/../.." ]] && die "please run from the kernel root directory"
+ [[ ! "$PWD" -ef "$SCRIPT_DIR/../.." ]] && die "please run from the kernel root directory"
(( SHORT_CIRCUIT <= 1 )) && rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"
@@ -462,11 +459,11 @@ refresh_patch() {
get_patch_output_files "$patch" | mapfile -t output_files
# Copy orig source files to 'a'
- ( cd "$SRC" && echo "${input_files[@]}" | xargs cp --parents --target-directory="$tmpdir/a" )
+ echo "${input_files[@]}" | xargs cp --parents --target-directory="$tmpdir/a"
# Copy patched source files to 'b'
apply_patch "$patch" "--silent"
- ( cd "$SRC" && echo "${output_files[@]}" | xargs cp --parents --target-directory="$tmpdir/b" )
+ echo "${output_files[@]}" | xargs cp --parents --target-directory="$tmpdir/b"
revert_patch "$patch"
# Diff 'a' and 'b' to make a clean patch
@@ -510,10 +507,7 @@ clean_kernel() {
cmd+=("-j$JOBS")
cmd+=("clean")
- (
- cd "$SRC"
- "${cmd[@]}"
- )
+ "${cmd[@]}"
}
build_kernel() {
@@ -554,12 +548,10 @@ build_kernel() {
cmd+=("vmlinux")
cmd+=("modules")
- (
- cd "$SRC"
- "${cmd[@]}" \
- 1> >(tee -a "$log") \
- 2> >(tee -a "$log" | grep0 -v "modpost.*undefined!" >&2)
- ) || die "$build kernel build failed"
+ "${cmd[@]}" \
+ 1> >(tee -a "$log") \
+ 2> >(tee -a "$log" | grep0 -v "modpost.*undefined!" >&2) \
+ || die "$build kernel build failed"
}
find_objects() {
@@ -567,9 +559,9 @@ find_objects() {
# Find root-level vmlinux.o and non-root-level .ko files,
# excluding klp-tmp/ and .git/
- find "$OBJ" \( -path "$TMP_DIR" -o -path "$OBJ/.git" -o -regex "$OBJ/[^/][^/]*\.ko" \) -prune -o \
+ find "$PWD" \( -path "$TMP_DIR" -o -path "$PWD/.git" -o -regex "$PWD/[^/][^/]*\.ko" \) -prune -o \
-type f "${opts[@]}" \
- \( -name "*.ko" -o -path "$OBJ/vmlinux.o" \) \
+ \( -name "*.ko" -o -path "$PWD/vmlinux.o" \) \
-printf '%P\n'
}
@@ -585,7 +577,7 @@ copy_orig_objects() {
xtrace_save "copying orig objects"
for _file in "${files[@]}"; do
local rel_file="${_file/.ko/.o}"
- local file="$OBJ/$rel_file"
+ local file="$PWD/$rel_file"
local orig_file="$ORIG_DIR/$rel_file"
local orig_dir="$(dirname "$orig_file")"
@@ -618,7 +610,7 @@ copy_patched_objects() {
xtrace_save "copying changed objects"
for _file in "${files[@]}"; do
local rel_file="${_file/.ko/.o}"
- local file="$OBJ/$rel_file"
+ local file="$PWD/$rel_file"
local orig_file="$ORIG_DIR/$rel_file"
local patched_file="$PATCHED_DIR/$rel_file"
local patched_dir="$(dirname "$patched_file")"
@@ -663,7 +655,7 @@ diff_objects() {
mkdir -p "$(dirname "$out_file")"
- cmd=("$SRC/tools/objtool/objtool")
+ cmd=("$OBJTOOL")
cmd+=("klp")
cmd+=("diff")
(( ${#opts[@]} > 0 )) && cmd+=("${opts[@]}")
@@ -716,7 +708,7 @@ diff_checksums() {
fi
done
- cmd=("$SRC/tools/objtool/objtool")
+ cmd=("$OBJTOOL")
cmd+=("--checksum")
cmd+=("--link")
cmd+=("--dry-run")
@@ -774,7 +766,7 @@ build_patch_module() {
rm -rf "$KMOD_DIR"
mkdir -p "$KMOD_DIR"
- cp -f "$SRC/scripts/livepatch/init.c" "$KMOD_DIR"
+ cp -f "$SCRIPT_DIR/init.c" "$KMOD_DIR"
echo "obj-m := $NAME.o" > "$makefile"
echo -n "$NAME-y := init.o" >> "$makefile"
@@ -820,12 +812,9 @@ build_patch_module() {
cmd+=("KCFLAGS=${cflags[*]}")
# Build a "normal" kernel module with init.c and the diffed objects
- (
- cd "$SRC"
- "${cmd[@]}" \
- 1> >(tee -a "$log") \
- 2> >(tee -a "$log" >&2)
- )
+ "${cmd[@]}" \
+ 1> >(tee -a "$log") \
+ 2> >(tee -a "$log" >&2)
kmod_file="$KMOD_DIR/$NAME.ko"
@@ -836,7 +825,7 @@ build_patch_module() {
objcopy --remove-section=.BTF "$kmod_file"
# Fix (and work around) linker wreckage for klp syms / relocs
- "$SRC/tools/objtool/objtool" klp post-link "$kmod_file" || die "objtool klp post-link failed"
+ "$OBJTOOL" klp post-link "$kmod_file" || die "objtool klp post-link failed"
cp -f "$kmod_file" "$OUTFILE"
}
--
2.53.0
^ permalink raw reply related
* [PATCH v2 33/53] objtool/klp: Don't set sym->file for section symbols
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Section symbols aren't grouped after their corresponding FILE symbols.
Their sym->file should really be NULL rather than whatever random FILE
happened to be last.
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/elf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index f41280e454ca..d9cee8d5d9e8 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -649,7 +649,7 @@ static int read_symbols(struct elf *elf)
if (is_file_sym(sym))
file = sym;
- else if (sym->bind == STB_LOCAL)
+ else if (sym->bind == STB_LOCAL && !is_sec_sym(sym))
sym->file = file;
}
--
2.53.0
^ permalink raw reply related
* [PATCH v2 34/53] objtool: Include libsubcmd headers directly from source tree
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Instead of installing libsubcmd headers to a build output directory and
including from there, include directly from tools/lib/ where they
already exist. This fixes clangd indexing which otherwise can't find
libsubcmd headers.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
index b71d1886022e..a4484fd22a96 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -58,7 +58,7 @@ INCLUDES := -I$(srctree)/tools/include \
-I$(srctree)/tools/arch/$(SRCARCH)/include \
-I$(srctree)/tools/objtool/include \
-I$(srctree)/tools/objtool/arch/$(SRCARCH)/include \
- -I$(LIBSUBCMD_OUTPUT)/include
+ -I$(srctree)/tools/lib
OBJTOOL_CFLAGS := -std=gnu11 -fomit-frame-pointer -O2 -g $(WARNINGS) \
$(INCLUDES) $(LIBELF_FLAGS) $(LIBXXHASH_CFLAGS) $(HOSTCFLAGS)
@@ -135,7 +135,7 @@ $(LIBSUBCMD): fixdep $(LIBSUBCMD_OUTPUT) FORCE
$(Q)$(MAKE) -C $(LIBSUBCMD_DIR) O=$(LIBSUBCMD_OUTPUT) \
DESTDIR=$(LIBSUBCMD_OUTPUT) prefix= subdir= \
$(HOST_OVERRIDES) EXTRA_CFLAGS="$(OBJTOOL_CFLAGS)" \
- $@ install_headers
+ $@
$(LIBSUBCMD)-clean:
$(call QUIET_CLEAN, libsubcmd)
--
2.53.0
^ permalink raw reply related
* [PATCH v2 35/53] objtool/klp: Create empty checksum sections for function-less object files
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
If an object file has no functions, objtool has nothing to checksum, so
it doesn't create the .discard.sym_checksum symbol.
Then when 'objtool klp diff' reads symbol checksums, it errors out due
to the missing .discard.sym_checksum section.
Instead, just create an empty checksum section to signal to
read_sym_checksums() that the file has been processed.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/check.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index e7579c4e46dc..f020f21f94a7 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1044,9 +1044,6 @@ static int create_sym_checksum_section(struct objtool_file *file)
if (sym->csum.checksum)
idx++;
- if (!idx)
- return 0;
-
sec = elf_create_section_pair(file->elf, ".discard.sym_checksum", entsize,
idx, idx);
if (!sec)
--
2.53.0
^ permalink raw reply related
* [PATCH v2 36/53] objtool/klp: Handle Clang .data..Lanon anonymous data sections
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Clang generates anonymous data sections named .data..Lanon.<hash>.
These need section-symbol references in the same way as .data..Lubsan
(GCC) and .data..L__unnamed_ (Clang UBSAN) sections. Without this,
convert_reloc_sym() fails when processing relocations that reference
these sections.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/klp-diff.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 463b6daa5234..7e58ef36f805 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1030,14 +1030,15 @@ static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *reloc)
}
/*
- * Sections with anonymous or uncorrelated data (strings, UBSAN data)
- * need section symbol references.
+ * Sections with anonymous or uncorrelated data (strings, UBSAN data, Clang
+ * anonymous constants) need section symbol references.
*/
static bool is_uncorrelated_section(struct section *sec)
{
return is_string_sec(sec) ||
strstarts(sec->name, ".data..Lubsan") || /* GCC */
- strstarts(sec->name, ".data..L__unnamed_"); /* Clang */
+ strstarts(sec->name, ".data..L__unnamed_") || /* Clang */
+ strstarts(sec->name, ".data..Lanon."); /* Clang */
}
/*
--
2.53.0
^ permalink raw reply related
* [PATCH v2 37/53] objtool: Add is_alias_sym() helper
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Improve readability with a new is_alias_sym() helper.
No functional changes intended.
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/check.c | 6 +++---
tools/objtool/include/objtool/elf.h | 5 +++++
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index f020f21f94a7..6c94eb32c090 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -491,7 +491,7 @@ static int decode_instructions(struct objtool_file *file)
return -1;
}
- if (func->embedded_insn || func->alias != func)
+ if (func->embedded_insn || is_alias_sym(func))
continue;
if (!find_insn(file, sec, func->offset)) {
@@ -2229,7 +2229,7 @@ static int add_jump_table_alts(struct objtool_file *file)
return 0;
for_each_sym(file->elf, func) {
- if (!is_func_sym(func) || func->alias != func)
+ if (!is_func_sym(func) || is_alias_sym(func))
continue;
mark_func_jump_tables(file, func);
@@ -4523,7 +4523,7 @@ static int validate_symbol(struct objtool_file *file, struct section *sec,
return 1;
}
- if (sym->pfunc != sym || sym->alias != sym)
+ if (sym->pfunc != sym || is_alias_sym(sym))
return 0;
insn = find_insn(file, sec, sym->offset);
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 8a543cea43b9..ccc72a692d9a 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -298,6 +298,11 @@ static inline bool is_local_sym(struct symbol *sym)
return sym->bind == STB_LOCAL;
}
+static inline bool is_alias_sym(struct symbol *sym)
+{
+ return sym->alias != sym;
+}
+
static inline bool is_prefix_func(struct symbol *sym)
{
return sym->prefix;
--
2.53.0
^ permalink raw reply related
* [PATCH v2 38/53] objtool: Add is_cold_func() helper
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Add an is_cold_func() helper. No functional changes intended.
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/check.c | 6 +++---
tools/objtool/include/objtool/elf.h | 5 +++++
tools/objtool/klp-diff.c | 3 ++-
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 6c94eb32c090..93a054adf209 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2614,7 +2614,7 @@ static void mark_holes(struct objtool_file *file)
if (insn->jump_dest) {
struct symbol *dest_func = insn_func(insn->jump_dest);
- if (dest_func && dest_func->cold)
+ if (dest_func && is_cold_func(dest_func))
dest_func->ignore = true;
}
}
@@ -4422,8 +4422,8 @@ static int create_prefix_symbol(struct objtool_file *file, struct symbol *func)
char name[SYM_NAME_LEN];
struct cfi_state *cfi;
- if (!is_func_sym(func) || is_prefix_func(func) ||
- func->cold || func->static_call_tramp)
+ if (!is_func_sym(func) || is_prefix_func(func) || is_cold_func(func) ||
+ func->static_call_tramp)
return 0;
if ((strlen(func->name) + sizeof("__pfx_") > SYM_NAME_LEN)) {
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index ccc72a692d9a..e452784df702 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -308,6 +308,11 @@ static inline bool is_prefix_func(struct symbol *sym)
return sym->prefix;
}
+static inline bool is_cold_func(struct symbol *sym)
+{
+ return sym->cold;
+}
+
static inline bool is_reloc_sec(struct section *sec)
{
return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 7e58ef36f805..8728dda1e08c 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1709,7 +1709,8 @@ static int create_klp_sections(struct elfs *e)
unsigned long sympos;
void *func_data;
- if (!is_func_sym(sym) || sym->cold || !sym->clone || !sym->clone->changed)
+ if (!is_func_sym(sym) || is_cold_func(sym) ||
+ !sym->clone || !sym->clone->changed)
continue;
/* allocate klp_func_ext */
--
2.53.0
^ permalink raw reply related
* [PATCH v2 39/53] objtool/klp: Extricate checksum calculation from validate_branch()
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
In preparation for porting the checksum code to other arches, make its
functionality independent from the CFG reverse engineering code.
Move it into a standalone calculate_checksums() function which iterates
all functions and instructions directly, rather than being called inline
from do_validate_branch().
Since checksum_update_insn() is no longer called during CFG traversal,
it needs to manually iterate the alternatives.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/check.c | 106 +++++++++++++++++------
tools/objtool/include/objtool/checksum.h | 6 +-
2 files changed, 80 insertions(+), 32 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 93a054adf209..f019e1f06780 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1350,10 +1350,7 @@ static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *i
{
struct reloc *reloc;
- if (insn->no_reloc)
- return NULL;
-
- if (!file)
+ if (!file || insn->no_reloc || insn->fake)
return NULL;
reloc = find_reloc_by_dest_range(file->elf, insn->sec,
@@ -2622,9 +2619,17 @@ static void mark_holes(struct objtool_file *file)
static bool validate_branch_enabled(void)
{
- return opts.stackval ||
- opts.orc ||
- opts.uaccess ||
+ return opts.stackval ||
+ opts.orc ||
+ opts.uaccess;
+}
+
+static bool alts_needed(void)
+{
+ return validate_branch_enabled() ||
+ opts.noinstr ||
+ opts.hack_jump_label ||
+ opts.disas ||
opts.checksum;
}
@@ -2658,7 +2663,7 @@ static int decode_sections(struct objtool_file *file)
* Must be before add_jump_destinations(), which depends on 'func'
* being set for alternatives, to enable proper sibling call detection.
*/
- if (validate_branch_enabled() || opts.noinstr || opts.hack_jump_label || opts.disas) {
+ if (alts_needed()) {
if (add_special_section_alts(file))
return -1;
}
@@ -3654,6 +3659,7 @@ static bool skip_alt_group(struct instruction *insn)
return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC;
}
+#ifdef BUILD_KLP
static int checksum_debug_init(struct objtool_file *file)
{
char *dup, *s;
@@ -3701,8 +3707,10 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func,
struct instruction *insn)
{
struct reloc *reloc = insn_reloc(file, insn);
+ struct alternative *alt;
unsigned long offset;
struct symbol *sym;
+ static bool in_alt;
if (insn->fake)
return;
@@ -3715,7 +3723,7 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func,
if (call_dest)
checksum_update(func, insn, call_dest->demangled_name,
strlen(call_dest->demangled_name));
- return;
+ goto alts;
}
sym = reloc->sym;
@@ -3726,21 +3734,78 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func,
str = sym->sec->data->d_buf + sym->offset + offset;
checksum_update(func, insn, str, strlen(str));
- return;
+ goto alts;
}
if (is_sec_sym(sym)) {
sym = find_symbol_containing(reloc->sym->sec, offset);
if (!sym)
- return;
+ goto alts;
offset -= sym->offset;
}
checksum_update(func, insn, sym->demangled_name, strlen(sym->demangled_name));
checksum_update(func, insn, &offset, sizeof(offset));
+
+alts:
+ for (alt = insn->alts; alt; alt = alt->next) {
+ struct alt_group *alt_group = alt->insn->alt_group;
+
+ /* Prevent __ex_table recursion, e.g. LOAD_SEGMENT() */
+ if (in_alt)
+ break;
+ in_alt = true;
+
+ checksum_update(func, insn, &alt->type, sizeof(alt->type));
+
+ if (alt_group && alt_group->orig_group) {
+ struct instruction *alt_insn;
+
+ checksum_update(func, insn, &alt_group->feature, sizeof(alt_group->feature));
+
+ for (alt_insn = alt->insn; alt_insn; alt_insn = next_insn_same_sec(file, alt_insn)) {
+ checksum_update_insn(file, func, alt_insn);
+ if (!alt_group->last_insn || alt_insn == alt_group->last_insn)
+ break;
+ }
+ } else {
+ checksum_update_insn(file, func, alt->insn);
+ }
+
+ in_alt = false;
+ }
}
+static int calculate_checksums(struct objtool_file *file)
+{
+ struct instruction *insn;
+ struct symbol *func;
+
+ if (checksum_debug_init(file))
+ return -1;
+
+ for_each_sym(file->elf, func) {
+ /*
+ * Skip cold subfunctions and aliases: they share the
+ * parent's checksum via func_for_each_insn() which
+ * follows func->cfunc into the cold subfunction.
+ */
+ if (!is_func_sym(func) || is_cold_func(func) ||
+ is_alias_sym(func) || !func->len)
+ continue;
+
+ checksum_init(func);
+
+ func_for_each_insn(file, func, insn)
+ checksum_update_insn(file, func, insn);
+
+ checksum_finish(func);
+ }
+ return 0;
+}
+#endif /* BUILD_KLP */
+
static int validate_branch(struct objtool_file *file, struct symbol *func,
struct instruction *insn, struct insn_state state);
static int do_validate_branch(struct objtool_file *file, struct symbol *func,
@@ -4022,9 +4087,6 @@ static int do_validate_branch(struct objtool_file *file, struct symbol *func,
insn->trace = 0;
next_insn = next_insn_to_validate(file, insn);
- if (opts.checksum && func && insn->sec)
- checksum_update_insn(file, func, insn);
-
if (func && insn_func(insn) && func != insn_func(insn)->pfunc) {
/* Ignore KCFI type preambles, which always fall through */
if (is_prefix_func(func))
@@ -4090,9 +4152,6 @@ static int validate_unwind_hint(struct objtool_file *file,
struct symbol *func = insn_func(insn);
int ret;
- if (opts.checksum)
- checksum_init(func);
-
ret = validate_branch(file, func, insn, *state);
if (ret)
BT_INSN(insn, "<=== (hint)");
@@ -4535,9 +4594,6 @@ static int validate_symbol(struct objtool_file *file, struct section *sec,
func = insn_func(insn);
- if (opts.checksum)
- checksum_init(func);
-
if (opts.trace && !fnmatch(opts.trace, sym->name, 0)) {
trace_enable();
TRACE("%s: validation begin\n", sym->name);
@@ -4550,9 +4606,6 @@ static int validate_symbol(struct objtool_file *file, struct section *sec,
TRACE("%s: validation %s\n\n", sym->name, ret ? "failed" : "end");
trace_disable();
- if (opts.checksum)
- checksum_finish(func);
-
return ret;
}
@@ -5007,10 +5060,6 @@ int check(struct objtool_file *file)
cfi_hash_add(&init_cfi);
cfi_hash_add(&func_cfi);
- ret = checksum_debug_init(file);
- if (ret)
- goto out;
-
ret = decode_sections(file);
if (ret)
goto out;
@@ -5101,6 +5150,9 @@ int check(struct objtool_file *file)
warnings += check_abs_references(file);
if (opts.checksum) {
+ ret = calculate_checksums(file);
+ if (ret)
+ goto out;
ret = create_sym_checksum_section(file);
if (ret)
goto out;
diff --git a/tools/objtool/include/objtool/checksum.h b/tools/objtool/include/objtool/checksum.h
index 0bd16fe9168b..3f25df90305d 100644
--- a/tools/objtool/include/objtool/checksum.h
+++ b/tools/objtool/include/objtool/checksum.h
@@ -33,11 +33,7 @@ static inline void checksum_finish(struct symbol *func)
#else /* !BUILD_KLP */
-static inline void checksum_init(struct symbol *func) {}
-static inline void checksum_update(struct symbol *func,
- struct instruction *insn,
- const void *data, size_t size) {}
-static inline void checksum_finish(struct symbol *func) {}
+static inline int calculate_checksums(struct objtool_file *file) { return -ENOSYS; }
#endif /* !BUILD_KLP */
--
2.53.0
^ permalink raw reply related
* [PATCH v2 40/53] objtool: Consolidate file decoding into decode_file()
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
decode_sections() relies on CFI and cfi_hash initialization done
separately in check(), making it unusable outside of check().
Consolidate the initialization into decode_sections() and rename it to
decode_file(), and make it global along with free_insns() and
insn_reloc() for use by other objtool components -- namely, the checksum
code which will be moving to another file.
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/check.c | 36 +++++++++++++--------------
tools/objtool/include/objtool/check.h | 5 ++++
2 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index f019e1f06780..49171ddc6f54 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1346,7 +1346,7 @@ __weak bool arch_is_embedded_insn(struct symbol *sym)
return false;
}
-static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
+struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
{
struct reloc *reloc;
@@ -2633,8 +2633,21 @@ static bool alts_needed(void)
opts.checksum;
}
-static int decode_sections(struct objtool_file *file)
+int decode_file(struct objtool_file *file)
{
+ arch_initial_func_cfi_state(&initial_func_cfi);
+ init_cfi_state(&init_cfi);
+ init_cfi_state(&func_cfi);
+ set_func_state(&func_cfi);
+ init_cfi_state(&force_undefined_cfi);
+ force_undefined_cfi.force_undefined = true;
+
+ if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3)))
+ return -1;
+
+ cfi_hash_add(&init_cfi);
+ cfi_hash_add(&func_cfi);
+
file->klp = is_livepatch_module(file);
mark_rodata(file);
@@ -4998,7 +5011,7 @@ struct insn_chunk {
* which can trigger more allocations for .debug_* sections whose data hasn't
* been read yet.
*/
-static void free_insns(struct objtool_file *file)
+void free_insns(struct objtool_file *file)
{
struct instruction *insn;
struct insn_chunk *chunks = NULL, *chunk;
@@ -5045,22 +5058,7 @@ int check(struct objtool_file *file)
objtool_disas_ctx = disas_ctx;
}
- arch_initial_func_cfi_state(&initial_func_cfi);
- init_cfi_state(&init_cfi);
- init_cfi_state(&func_cfi);
- set_func_state(&func_cfi);
- init_cfi_state(&force_undefined_cfi);
- force_undefined_cfi.force_undefined = true;
-
- if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) {
- ret = -1;
- goto out;
- }
-
- cfi_hash_add(&init_cfi);
- cfi_hash_add(&func_cfi);
-
- ret = decode_sections(file);
+ ret = decode_file(file);
if (ret)
goto out;
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index 5f2f77bd9b41..6489e52ea2f2 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -155,6 +155,11 @@ struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruc
insn && insn->offset < sym->offset + sym->len; \
insn = next_insn_same_sec(file, insn))
+struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn);
+
+int decode_file(struct objtool_file *file);
+void free_insns(struct objtool_file *file);
+
const char *objtool_disas_insn(struct instruction *insn);
extern size_t sym_name_max_len;
--
2.53.0
^ permalink raw reply related
* [PATCH v2 41/53] objtool/klp: Add "objtool klp checksum" subcommand
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Move the checksum functionality out of the main objtool command into a
new "objtool klp checksum" subcommand.
This has the benefit of making the code (and the patch generation
process itself) more modular.
For bisectability, both "objtool --checksum" and "objtool klp checksum"
work for now. The former will be removed after klp-build has been
converted to use the new subcommand.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/Build | 2 +-
tools/objtool/builtin-klp.c | 1 +
tools/objtool/check.c | 205 +-----------------
tools/objtool/include/objtool/check.h | 6 +
tools/objtool/include/objtool/checksum.h | 4 +
tools/objtool/include/objtool/klp.h | 1 +
tools/objtool/klp-checksum.c | 253 +++++++++++++++++++++++
tools/objtool/klp-diff.c | 2 +-
8 files changed, 269 insertions(+), 205 deletions(-)
create mode 100644 tools/objtool/klp-checksum.c
diff --git a/tools/objtool/Build b/tools/objtool/Build
index 600da051af12..93a37b0dfd31 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -12,7 +12,7 @@ objtool-$(BUILD_DISAS) += disas.o
objtool-$(BUILD_DISAS) += trace.o
objtool-$(BUILD_ORC) += orc_gen.o orc_dump.o
-objtool-$(BUILD_KLP) += builtin-klp.o klp-diff.o klp-post-link.o
+objtool-$(BUILD_KLP) += builtin-klp.o klp-checksum.o klp-diff.o klp-post-link.o
objtool-y += libstring.o
objtool-y += libctype.o
diff --git a/tools/objtool/builtin-klp.c b/tools/objtool/builtin-klp.c
index 56d5a5b92f72..58c3b9bda3eb 100644
--- a/tools/objtool/builtin-klp.c
+++ b/tools/objtool/builtin-klp.c
@@ -13,6 +13,7 @@ struct subcmd {
};
static struct subcmd subcmds[] = {
+ { "checksum", "Generate per-function checksums", cmd_klp_checksum, },
{ "diff", "Generate binary diff of two object files", cmd_klp_diff, },
{ "post-link", "Finalize klp symbols/relocs after module linking", cmd_klp_post_link, },
};
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 49171ddc6f54..3e5d335d0e29 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -64,8 +64,8 @@ struct instruction *next_insn_same_sec(struct objtool_file *file,
return insn;
}
-static struct instruction *next_insn_same_func(struct objtool_file *file,
- struct instruction *insn)
+struct instruction *next_insn_same_func(struct objtool_file *file,
+ struct instruction *insn)
{
struct instruction *next = next_insn_same_sec(file, insn);
struct symbol *func = insn_func(insn);
@@ -113,10 +113,6 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file,
for_each_sec(file->elf, __sec) \
sec_for_each_insn(file, __sec, insn)
-#define func_for_each_insn(file, func, insn) \
- for (insn = find_insn(file, func->sec, func->offset); \
- insn; \
- insn = next_insn_same_func(file, insn))
#define sym_for_each_insn(file, sym, insn) \
for (insn = find_insn(file, sym->sec, sym->offset); \
@@ -1023,56 +1019,6 @@ static int create_direct_call_sections(struct objtool_file *file)
return 0;
}
-#ifdef BUILD_KLP
-static int create_sym_checksum_section(struct objtool_file *file)
-{
- struct section *sec;
- struct symbol *sym;
- unsigned int idx = 0;
- struct sym_checksum *checksum;
- size_t entsize = sizeof(struct sym_checksum);
-
- sec = find_section_by_name(file->elf, ".discard.sym_checksum");
- if (sec) {
- if (!opts.dryrun)
- WARN("file already has .discard.sym_checksum section, skipping");
-
- return 0;
- }
-
- for_each_sym(file->elf, sym)
- if (sym->csum.checksum)
- idx++;
-
- sec = elf_create_section_pair(file->elf, ".discard.sym_checksum", entsize,
- idx, idx);
- if (!sec)
- return -1;
-
- idx = 0;
- for_each_sym(file->elf, sym) {
- if (!sym->csum.checksum)
- continue;
-
- if (!elf_init_reloc(file->elf, sec->rsec, idx, idx * entsize,
- sym, 0, R_TEXT64))
- return -1;
-
- checksum = (struct sym_checksum *)sec->data->d_buf + idx;
- checksum->addr = 0; /* reloc */
- checksum->checksum = sym->csum.checksum;
-
- mark_sec_changed(file->elf, sec, true);
-
- idx++;
- }
-
- return 0;
-}
-#else
-static int create_sym_checksum_section(struct objtool_file *file) { return -EINVAL; }
-#endif
-
/*
* Warnings shouldn't be reported for ignored functions.
*/
@@ -3672,153 +3618,6 @@ static bool skip_alt_group(struct instruction *insn)
return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC;
}
-#ifdef BUILD_KLP
-static int checksum_debug_init(struct objtool_file *file)
-{
- char *dup, *s;
-
- if (!opts.debug_checksum)
- return 0;
-
- dup = strdup(opts.debug_checksum);
- if (!dup) {
- ERROR_GLIBC("strdup");
- return -1;
- }
-
- s = dup;
- while (*s) {
- bool found = false;
- struct symbol *sym;
- char *comma;
-
- comma = strchr(s, ',');
- if (comma)
- *comma = '\0';
-
- for_each_sym_by_name(file->elf, s, sym) {
- if (!is_func_sym(sym))
- continue;
- sym->debug_checksum = 1;
- found = true;
- }
-
- if (!found)
- WARN("--debug-checksum: can't find '%s'", s);
-
- if (!comma)
- break;
-
- s = comma + 1;
- }
-
- free(dup);
- return 0;
-}
-
-static void checksum_update_insn(struct objtool_file *file, struct symbol *func,
- struct instruction *insn)
-{
- struct reloc *reloc = insn_reloc(file, insn);
- struct alternative *alt;
- unsigned long offset;
- struct symbol *sym;
- static bool in_alt;
-
- if (insn->fake)
- return;
-
- checksum_update(func, insn, insn->sec->data->d_buf + insn->offset, insn->len);
-
- if (!reloc) {
- struct symbol *call_dest = insn_call_dest(insn);
-
- if (call_dest)
- checksum_update(func, insn, call_dest->demangled_name,
- strlen(call_dest->demangled_name));
- goto alts;
- }
-
- sym = reloc->sym;
- offset = arch_insn_adjusted_addend(insn, reloc);
-
- if (is_string_sec(sym->sec)) {
- char *str;
-
- str = sym->sec->data->d_buf + sym->offset + offset;
- checksum_update(func, insn, str, strlen(str));
- goto alts;
- }
-
- if (is_sec_sym(sym)) {
- sym = find_symbol_containing(reloc->sym->sec, offset);
- if (!sym)
- goto alts;
-
- offset -= sym->offset;
- }
-
- checksum_update(func, insn, sym->demangled_name, strlen(sym->demangled_name));
- checksum_update(func, insn, &offset, sizeof(offset));
-
-alts:
- for (alt = insn->alts; alt; alt = alt->next) {
- struct alt_group *alt_group = alt->insn->alt_group;
-
- /* Prevent __ex_table recursion, e.g. LOAD_SEGMENT() */
- if (in_alt)
- break;
- in_alt = true;
-
- checksum_update(func, insn, &alt->type, sizeof(alt->type));
-
- if (alt_group && alt_group->orig_group) {
- struct instruction *alt_insn;
-
- checksum_update(func, insn, &alt_group->feature, sizeof(alt_group->feature));
-
- for (alt_insn = alt->insn; alt_insn; alt_insn = next_insn_same_sec(file, alt_insn)) {
- checksum_update_insn(file, func, alt_insn);
- if (!alt_group->last_insn || alt_insn == alt_group->last_insn)
- break;
- }
- } else {
- checksum_update_insn(file, func, alt->insn);
- }
-
- in_alt = false;
- }
-}
-
-static int calculate_checksums(struct objtool_file *file)
-{
- struct instruction *insn;
- struct symbol *func;
-
- if (checksum_debug_init(file))
- return -1;
-
- for_each_sym(file->elf, func) {
- /*
- * Skip cold subfunctions and aliases: they share the
- * parent's checksum via func_for_each_insn() which
- * follows func->cfunc into the cold subfunction.
- */
- if (!is_func_sym(func) || is_cold_func(func) ||
- is_alias_sym(func) || !func->len)
- continue;
-
- checksum_init(func);
-
- func_for_each_insn(file, func, insn)
- checksum_update_insn(file, func, insn);
-
- checksum_finish(func);
- }
- return 0;
-}
-#endif /* BUILD_KLP */
-
static int validate_branch(struct objtool_file *file, struct symbol *func,
struct instruction *insn, struct insn_state state);
static int do_validate_branch(struct objtool_file *file, struct symbol *func,
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index 6489e52ea2f2..eea64728d39b 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -144,6 +144,12 @@ struct instruction *find_insn(struct objtool_file *file,
struct section *sec, unsigned long offset);
struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruction *insn);
+struct instruction *next_insn_same_func(struct objtool_file *file, struct instruction *insn);
+
+#define func_for_each_insn(file, func, insn) \
+ for (insn = find_insn(file, func->sec, func->offset); \
+ insn; \
+ insn = next_insn_same_func(file, insn))
#define sec_for_each_insn(file, _sec, insn) \
for (insn = find_insn(file, _sec, 0); \
diff --git a/tools/objtool/include/objtool/checksum.h b/tools/objtool/include/objtool/checksum.h
index 3f25df90305d..be4eb7dfe6f2 100644
--- a/tools/objtool/include/objtool/checksum.h
+++ b/tools/objtool/include/objtool/checksum.h
@@ -31,9 +31,13 @@ static inline void checksum_finish(struct symbol *func)
}
}
+int calculate_checksums(struct objtool_file *file);
+int create_sym_checksum_section(struct objtool_file *file);
+
#else /* !BUILD_KLP */
static inline int calculate_checksums(struct objtool_file *file) { return -ENOSYS; }
+static inline int create_sym_checksum_section(struct objtool_file *file) { return -EINVAL; }
#endif /* !BUILD_KLP */
diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h
index e32e5e8bc631..6f60cf05db86 100644
--- a/tools/objtool/include/objtool/klp.h
+++ b/tools/objtool/include/objtool/klp.h
@@ -29,6 +29,7 @@ struct klp_reloc {
u32 type;
};
+int cmd_klp_checksum(int argc, const char **argv);
int cmd_klp_diff(int argc, const char **argv);
int cmd_klp_post_link(int argc, const char **argv);
diff --git a/tools/objtool/klp-checksum.c b/tools/objtool/klp-checksum.c
new file mode 100644
index 000000000000..e4a910f3211c
--- /dev/null
+++ b/tools/objtool/klp-checksum.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
+#include <subcmd/parse-options.h>
+
+#include <objtool/arch.h>
+#include <objtool/builtin.h>
+#include <objtool/check.h>
+#include <objtool/elf.h>
+#include <objtool/klp.h>
+#include <objtool/objtool.h>
+#include <objtool/warn.h>
+#include <objtool/checksum.h>
+
+static int checksum_debug_init(struct objtool_file *file)
+{
+ char *dup, *s;
+
+ if (!opts.debug_checksum)
+ return 0;
+
+ dup = strdup(opts.debug_checksum);
+ if (!dup) {
+ ERROR_GLIBC("strdup");
+ return -1;
+ }
+
+ s = dup;
+ while (*s) {
+ bool found = false;
+ struct symbol *sym;
+ char *comma;
+
+ comma = strchr(s, ',');
+ if (comma)
+ *comma = '\0';
+
+ for_each_sym_by_name(file->elf, s, sym) {
+ if (!is_func_sym(sym))
+ continue;
+ sym->debug_checksum = 1;
+ found = true;
+ }
+
+ if (!found)
+ WARN("--debug-checksum: can't find '%s'", s);
+
+ if (!comma)
+ break;
+
+ s = comma + 1;
+ }
+
+ free(dup);
+ return 0;
+}
+
+static void checksum_update_insn(struct objtool_file *file, struct symbol *func,
+ struct instruction *insn)
+{
+ struct reloc *reloc = insn_reloc(file, insn);
+ struct alternative *alt;
+ unsigned long offset;
+ struct symbol *sym;
+ static bool in_alt;
+
+ if (insn->fake)
+ return;
+
+ checksum_update(func, insn, insn->sec->data->d_buf + insn->offset, insn->len);
+
+ if (!reloc) {
+ struct symbol *call_dest = insn_call_dest(insn);
+
+ if (call_dest)
+ checksum_update(func, insn, call_dest->demangled_name,
+ strlen(call_dest->demangled_name));
+ goto alts;
+ }
+
+ sym = reloc->sym;
+ offset = arch_insn_adjusted_addend(insn, reloc);
+
+ if (is_string_sec(sym->sec)) {
+ char *str;
+
+ str = sym->sec->data->d_buf + sym->offset + offset;
+ checksum_update(func, insn, str, strlen(str));
+ goto alts;
+ }
+
+ if (is_sec_sym(sym)) {
+ sym = find_symbol_containing(reloc->sym->sec, offset);
+ if (!sym)
+ goto alts;
+
+ offset -= sym->offset;
+ }
+
+ checksum_update(func, insn, sym->demangled_name, strlen(sym->demangled_name));
+ checksum_update(func, insn, &offset, sizeof(offset));
+
+alts:
+ for (alt = insn->alts; alt; alt = alt->next) {
+ struct alt_group *alt_group = alt->insn->alt_group;
+
+ /* Prevent __ex_table recursion, e.g. LOAD_SEGMENT() */
+ if (in_alt)
+ break;
+ in_alt = true;
+
+ checksum_update(func, insn, &alt->type, sizeof(alt->type));
+
+ if (alt_group && alt_group->orig_group) {
+ struct instruction *alt_insn;
+
+ checksum_update(func, insn, &alt_group->feature, sizeof(alt_group->feature));
+
+ for (alt_insn = alt->insn; alt_insn; alt_insn = next_insn_same_sec(file, alt_insn)) {
+ checksum_update_insn(file, func, alt_insn);
+ if (!alt_group->last_insn || alt_insn == alt_group->last_insn)
+ break;
+ }
+ } else {
+ checksum_update_insn(file, func, alt->insn);
+ }
+
+ in_alt = false;
+ }
+}
+
+int calculate_checksums(struct objtool_file *file)
+{
+ struct instruction *insn;
+ struct symbol *func;
+
+ if (checksum_debug_init(file))
+ return -1;
+
+ for_each_sym(file->elf, func) {
+ /*
+ * Skip cold subfunctions and aliases: they share the
+ * parent's checksum via func_for_each_insn() which
+ * follows func->cfunc into the cold subfunction.
+ */
+ if (!is_func_sym(func) || is_cold_func(func) ||
+ is_alias_sym(func) || !func->len)
+ continue;
+
+ checksum_init(func);
+
+ func_for_each_insn(file, func, insn)
+ checksum_update_insn(file, func, insn);
+
+ checksum_finish(func);
+ }
+ return 0;
+}
+
+int create_sym_checksum_section(struct objtool_file *file)
+{
+ struct section *sec;
+ struct symbol *sym;
+ unsigned int idx = 0;
+ struct sym_checksum *checksum;
+ size_t entsize = sizeof(struct sym_checksum);
+
+ sec = find_section_by_name(file->elf, ".discard.sym_checksum");
+ if (sec) {
+ if (!opts.dryrun)
+ WARN("file already has .discard.sym_checksum section, skipping");
+
+ return 0;
+ }
+
+ for_each_sym(file->elf, sym)
+ if (sym->csum.checksum)
+ idx++;
+
+ sec = elf_create_section_pair(file->elf, ".discard.sym_checksum", entsize,
+ idx, idx);
+ if (!sec)
+ return -1;
+
+ idx = 0;
+ for_each_sym(file->elf, sym) {
+ if (!sym->csum.checksum)
+ continue;
+
+ if (!elf_init_reloc(file->elf, sec->rsec, idx, idx * entsize,
+ sym, 0, R_TEXT64))
+ return -1;
+
+ checksum = (struct sym_checksum *)sec->data->d_buf + idx;
+ checksum->addr = 0; /* reloc */
+ checksum->checksum = sym->csum.checksum;
+
+ mark_sec_changed(file->elf, sec, true);
+
+ idx++;
+ }
+
+ return 0;
+}
+
+static const char * const klp_checksum_usage[] = {
+ "objtool klp checksum [<options>] file.o",
+ NULL,
+};
+
+int cmd_klp_checksum(int argc, const char **argv)
+{
+ struct objtool_file *file;
+ int ret;
+
+ const struct option options[] = {
+ OPT_STRING(0, "debug-checksum", &opts.debug_checksum, "funcs", "enable checksum debug output"),
+ OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, options, klp_checksum_usage, 0);
+ if (argc != 1)
+ usage_with_options(klp_checksum_usage, options);
+
+ opts.checksum = true;
+
+ objname = argv[0];
+
+ file = objtool_open_read(objname);
+ if (!file)
+ return 1;
+
+ ret = decode_file(file);
+ if (ret)
+ goto out;
+
+ ret = calculate_checksums(file);
+ if (ret)
+ goto out;
+
+ ret = create_sym_checksum_section(file);
+
+out:
+ free_insns(file);
+
+ if (ret)
+ return ret;
+
+ if (!opts.dryrun && file->elf->changed && elf_write(file->elf))
+ return 1;
+
+ return elf_close(file->elf);
+}
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 8728dda1e08c..95359ad336bb 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -166,7 +166,7 @@ static int read_sym_checksums(struct elf *elf)
sec = find_section_by_name(elf, ".discard.sym_checksum");
if (!sec) {
- ERROR("'%s' missing .discard.sym_checksum section, file not processed by 'objtool --checksum'?",
+ ERROR("'%s' missing .discard.sym_checksum section, file not processed by 'objtool klp checksum'?",
elf->name);
return -1;
}
--
2.53.0
^ permalink raw reply related
* [PATCH v2 42/53] klp-build: Use "objtool klp checksum" subcommand
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
Use the new "objtool klp checksum" subcommand instead of injecting
--checksum into every objtool invocation via OBJTOOL_ARGS during the
kernel build.
This decouples checksum generation from the build, running it in
separate post-build passes, making the code (and the patch generation
pipeline itself) more modular.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 93 +++++++++++++++++++++++++------------
1 file changed, 64 insertions(+), 29 deletions(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 34a46bafdaec..8a4b268261a6 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -37,10 +37,12 @@ OBJTOOL="$PWD/tools/objtool/objtool"
CONFIG="$PWD/.config"
TMP_DIR="$PWD/klp-tmp"
-ORIG_DIR="$TMP_DIR/orig"
-PATCHED_DIR="$TMP_DIR/patched"
-DIFF_DIR="$TMP_DIR/diff"
-KMOD_DIR="$TMP_DIR/kmod"
+ORIG_DIR="$TMP_DIR/1-orig"
+PATCHED_DIR="$TMP_DIR/2-patched"
+ORIG_CSUM_DIR="$TMP_DIR/3-checksum-orig"
+PATCHED_CSUM_DIR="$TMP_DIR/3-checksum-patched"
+DIFF_DIR="$TMP_DIR/4-diff"
+KMOD_DIR="$TMP_DIR/5-kmod"
STASH_DIR="$TMP_DIR/stash"
TIMESTAMP="$TMP_DIR/timestamp"
@@ -136,10 +138,11 @@ Options:
Advanced Options:
-d, --debug Show symbol/reloc cloning decisions
-S, --short-circuit=STEP Start at build step (requires prior --keep-tmp)
- 1|orig Build original kernel (default)
- 2|patched Build patched kernel
- 3|diff Diff objects
- 4|kmod Build patch module
+ 1|orig Build original kernel (default)
+ 2|patched Build patched kernel
+ 3|checksum Generate checksums
+ 4|diff Diff objects
+ 5|kmod Build patch module
-T, --keep-tmp Preserve tmp dir on exit
EOF
@@ -203,10 +206,11 @@ process_args() {
[[ ! -d "$TMP_DIR" ]] && die "--short-circuit requires preserved klp-tmp dir"
keep_tmp=1
case "$2" in
- 1 | orig) SHORT_CIRCUIT=1; ;;
- 2 | patched) SHORT_CIRCUIT=2; ;;
- 3 | diff) SHORT_CIRCUIT=3; ;;
- 4 | mod) SHORT_CIRCUIT=4; ;;
+ 1 | orig) SHORT_CIRCUIT=1; ;;
+ 2 | patched) SHORT_CIRCUIT=2; ;;
+ 3 | checksum) SHORT_CIRCUIT=3; ;;
+ 4 | diff) SHORT_CIRCUIT=4; ;;
+ 5 | kmod) SHORT_CIRCUIT=5; ;;
*) die "invalid short-circuit step '$2'" ;;
esac
shift 2
@@ -513,11 +517,8 @@ clean_kernel() {
build_kernel() {
local build="$1"
local log="$TMP_DIR/build.log"
- local objtool_args=()
local cmd=()
- objtool_args=("--checksum")
-
cmd=("make")
# When a patch to a kernel module references a newly created unexported
@@ -544,7 +545,6 @@ build_kernel() {
fi
cmd+=("-j$JOBS")
cmd+=("KCFLAGS=-ffunction-sections -fdata-sections")
- cmd+=("OBJTOOL_ARGS=${objtool_args[*]}")
cmd+=("vmlinux")
cmd+=("modules")
@@ -574,7 +574,7 @@ copy_orig_objects() {
find_objects | mapfile -t files
- xtrace_save "copying orig objects"
+ xtrace_save "copying original objects"
for _file in "${files[@]}"; do
local rel_file="${_file/.ko/.o}"
local file="$PWD/$rel_file"
@@ -630,6 +630,35 @@ copy_patched_objects() {
mv -f "$TMP_DIR/build.log" "$PATCHED_DIR"
}
+# Copy .o files to a separate directory and run "objtool klp checksum" on each
+# copy. The checksums are written to a .discard.sym_checksum section.
+#
+# If match_dir is given, only process files which also exist there.
+generate_checksums() {
+ local src_dir="$1"
+ local dest_dir="$2"
+ local match_dir="${3:-}"
+ local files=()
+ local file
+
+ rm -rf "$dest_dir"
+ mkdir -p "$dest_dir"
+
+ find "$src_dir" -type f -name "*.o" | mapfile -t files
+ for file in "${files[@]}"; do
+ local rel="${file#"$src_dir"/}"
+ local dest="$dest_dir/$rel"
+
+ [[ -n "$match_dir" && ! -f "$match_dir/$rel" ]] && continue
+
+ mkdir -p "$(dirname "$dest")"
+ cp -f "$file" "$dest"
+ "$SRC/tools/objtool/objtool" klp checksum "$dest"
+ done
+
+ touch "$dest_dir/.complete"
+}
+
# Diff changed objects, writing output object to $DIFF_DIR
diff_objects() {
local log="$KLP_DIFF_LOG"
@@ -639,16 +668,16 @@ diff_objects() {
rm -rf "$DIFF_DIR"
mkdir -p "$DIFF_DIR"
- find "$PATCHED_DIR" -type f -name "*.o" | mapfile -t files
+ find "$PATCHED_CSUM_DIR" -type f -name "*.o" | mapfile -t files
[[ ${#files[@]} -eq 0 ]] && die "no changes detected"
[[ -v DEBUG_CLONE ]] && opts=("--debug")
# Diff all changed objects
for file in "${files[@]}"; do
- local rel_file="${file#"$PATCHED_DIR"/}"
+ local rel_file="${file#"$PATCHED_CSUM_DIR"/}"
local orig_file="$rel_file"
- local patched_file="$PATCHED_DIR/$rel_file"
+ local patched_file="$PATCHED_CSUM_DIR/$rel_file"
local out_file="$DIFF_DIR/$rel_file"
local filter=()
local cmd=()
@@ -672,7 +701,7 @@ diff_objects() {
fi
(
- cd "$ORIG_DIR"
+ cd "$ORIG_CSUM_DIR"
[[ -v VERBOSE ]] && echo "${cmd[@]}"
"${cmd[@]}" \
1> >(tee -a "$log") \
@@ -682,9 +711,9 @@ diff_objects() {
done
}
-# For each changed object, run objtool with --debug-checksum to get the
-# per-instruction checksums, and then diff those to find the first changed
-# instruction for each function.
+# For each changed object, run "objtool klp checksum" with --debug-checksum to
+# get the per-instruction checksums, and then diff those to find the first
+# changed instruction for each function.
diff_checksums() {
local orig_log="$ORIG_DIR/checksum.log"
local patched_log="$PATCHED_DIR/checksum.log"
@@ -709,8 +738,7 @@ diff_checksums() {
done
cmd=("$OBJTOOL")
- cmd+=("--checksum")
- cmd+=("--link")
+ cmd+=("klp" "checksum")
cmd+=("--dry-run")
for file in "${!funcs[@]}"; do
@@ -719,11 +747,11 @@ diff_checksums() {
(
cd "$ORIG_DIR"
"${cmd[@]}" "$opt" "$file" &> "$orig_log" || \
- ( cat "$orig_log" >&2; die "objtool --debug-checksum failed" )
+ ( cat "$orig_log" >&2; die "objtool klp checksum failed" )
cd "$PATCHED_DIR"
"${cmd[@]}" "$opt" "$file" &> "$patched_log" || \
- ( cat "$patched_log" >&2; die "objtool --debug-checksum failed" )
+ ( cat "$patched_log" >&2; die "objtool klp checksum failed" )
)
for func in ${funcs[$file]}; do
@@ -861,6 +889,13 @@ if (( SHORT_CIRCUIT <= 2 )); then
fi
if (( SHORT_CIRCUIT <= 3 )); then
+ status "Generating original checksums"
+ generate_checksums "$ORIG_DIR" "$ORIG_CSUM_DIR" "$PATCHED_DIR"
+ status "Generating patched checksums"
+ generate_checksums "$PATCHED_DIR" "$PATCHED_CSUM_DIR"
+fi
+
+if (( SHORT_CIRCUIT <= 4 )); then
status "Diffing objects"
diff_objects
if [[ -v DIFF_CHECKSUM ]]; then
@@ -869,7 +904,7 @@ if (( SHORT_CIRCUIT <= 3 )); then
fi
fi
-if (( SHORT_CIRCUIT <= 4 )); then
+if (( SHORT_CIRCUIT <= 5 )); then
status "Building patch module: $OUTFILE"
build_patch_module
fi
--
2.53.0
^ permalink raw reply related
* [PATCH v2 43/53] objtool/klp: Remove "objtool --checksum"
From: Josh Poimboeuf @ 2026-05-01 4:08 UTC (permalink / raw)
To: x86
Cc: linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <cover.1777575752.git.jpoimboe@kernel.org>
The checksum functionality has been moved to "objtool klp checksum"
which is now used by klp-build. Remove the now-dead --checksum and
--debug-checksum options from the default objtool command.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
scripts/livepatch/klp-build | 5 ++++-
tools/objtool/builtin-check.c | 17 +----------------
tools/objtool/check.c | 10 ----------
3 files changed, 5 insertions(+), 27 deletions(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 8a4b268261a6..f8a80ad0f829 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -275,6 +275,9 @@ validate_config() {
[[ "$CONFIG_AS_VERSION" -lt 200000 ]] && \
die "Clang assembler version < 20 not supported"
+ "$OBJTOOL" klp 2>&1 | command grep -q "not implemented" && \
+ die "objtool not built with KLP support; install xxhash-devel/libxxhash-dev (version >= 0.8) and recompile"
+
return 0
}
@@ -653,7 +656,7 @@ generate_checksums() {
mkdir -p "$(dirname "$dest")"
cp -f "$file" "$dest"
- "$SRC/tools/objtool/objtool" klp checksum "$dest"
+ "$OBJTOOL" klp checksum "$dest"
done
touch "$dest_dir/.complete"
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index b780df513715..ec7f10a5ef19 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -73,7 +73,6 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)
static const struct option check_options[] = {
OPT_GROUP("Actions:"),
- OPT_BOOLEAN(0, "checksum", &opts.checksum, "generate per-function checksums"),
OPT_BOOLEAN(0, "cfi", &opts.cfi, "annotate kernel control flow integrity (kCFI) function preambles"),
OPT_STRING_OPTARG('d', "disas", &opts.disas, "function-pattern", "disassemble functions", "*"),
OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks),
@@ -95,7 +94,6 @@ static const struct option check_options[] = {
OPT_GROUP("Options:"),
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
OPT_BOOLEAN(0, "backup", &opts.backup, "create backup (.orig) file on warning/error"),
- OPT_STRING(0, "debug-checksum", &opts.debug_checksum, "funcs", "enable checksum debug output"),
OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
@@ -165,20 +163,7 @@ static bool opts_valid(void)
return false;
}
-#ifndef BUILD_KLP
- if (opts.checksum) {
- ERROR("--checksum not supported; install xxhash-devel/libxxhash-dev (version >= 0.8) and recompile");
- return false;
- }
-#endif
-
- if (opts.debug_checksum && !opts.checksum) {
- ERROR("--debug-checksum requires --checksum");
- return false;
- }
-
- if (opts.checksum ||
- opts.disas ||
+ if (opts.disas ||
opts.hack_jump_label ||
opts.hack_noinstr ||
opts.ibt ||
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 3e5d335d0e29..ae047be919c5 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -18,7 +18,6 @@
#include <objtool/special.h>
#include <objtool/trace.h>
#include <objtool/warn.h>
-#include <objtool/checksum.h>
#include <objtool/util.h>
#include <linux/objtool_types.h>
@@ -4946,15 +4945,6 @@ int check(struct objtool_file *file)
if (opts.noabs)
warnings += check_abs_references(file);
- if (opts.checksum) {
- ret = calculate_checksums(file);
- if (ret)
- goto out;
- ret = create_sym_checksum_section(file);
- if (ret)
- goto out;
- }
-
if (opts.orc && nr_insns) {
ret = orc_create(file);
if (ret)
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox