From: Josh Poimboeuf <jpoimboe@kernel.org>
To: x86@kernel.org
Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org,
Peter Zijlstra <peterz@infradead.org>,
Joe Lawrence <joe.lawrence@redhat.com>,
Song Liu <song@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
linux-arm-kernel@lists.infradead.org,
Mark Rutland <mark.rutland@arm.com>,
Nathan Chancellor <nathan@kernel.org>,
Nicolas Schier <nsc@kernel.org>,
Herbert Xu <herbert@gondor.apana.org.au>,
Miroslav Benes <mbenes@suse.cz>, Petr Mladek <pmladek@suse.com>
Subject: [PATCH v4 19/22] objtool/klp: Clone inline alternative replacements
Date: Sat, 8 Aug 2026 16:17:23 -0700 [thread overview]
Message-ID: <ebbfa4c78e459a21cebfb635225c046984d86b6a.1786230311.git.jpoimboe@kernel.org> (raw)
In-Reply-To: <cover.1786230311.git.jpoimboe@kernel.org>
Unlike x86-64, arm64 places alternative replacement instructions in
.text, immediately after the affected function.
So if the replacement instructions have PC-relative branches without
relocations, their offsets relative to the function have to remain
constant.
Achieve that by cloning the function's alternative replacements
immediately after cloning the function itself.
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/elf.c | 9 ++---
tools/objtool/include/objtool/elf.h | 6 +++-
tools/objtool/klp-diff.c | 54 ++++++++++++++++++++++++-----
tools/objtool/klp-symid.c | 2 +-
4 files changed, 57 insertions(+), 14 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index f9d49325dbe0d..f6219f495efdc 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -1426,14 +1426,15 @@ int elf_add_string(struct elf *elf, struct section *strtab, const char *str)
return -1;
}
- data = elf_add_data(elf, strtab, str, strlen(str) + 1);
+ data = elf_add_data(elf, strtab, str, strlen(str) + 1, true);
if (!data)
return -1;
return data - strtab->data->d_buf;
}
-void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_t size)
+void *elf_add_data(struct elf *elf, struct section *sec, const void *data,
+ size_t size, bool align)
{
unsigned long offset, size_old, size_new, alloc_size_old, alloc_size_new;
Elf_Scn *s;
@@ -1460,7 +1461,7 @@ void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_
}
size_old = sec->data->d_size;
- offset = ALIGN(size_old, sec->sh.sh_addralign);
+ offset = ALIGN(size_old, align ? sec->sh.sh_addralign : 1);
size_new = offset + size;
if (!sec->data_overallocated)
@@ -1603,7 +1604,7 @@ static int elf_alloc_reloc(struct elf *elf, struct section *rsec)
unsigned long nr_alloc_old = 0, nr_alloc_new;
struct symbol *sym;
- if (!elf_add_data(elf, rsec, NULL, elf_rela_size(elf)))
+ if (!elf_add_data(elf, rsec, NULL, elf_rela_size(elf), true))
return -1;
rsec->data->d_type = ELF_T_RELA;
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index d33d25d7472a0..fba0a0e08f8b6 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -107,6 +107,7 @@ struct symbol {
u8 klp : 1;
u8 dont_correlate : 1;
u8 fake : 1;
+ u8 unalign : 1;
struct list_head pv_target;
struct reloc *relocs;
struct section *group_sec;
@@ -187,7 +188,7 @@ struct symbol *elf_create_symbol(struct elf *elf, const char *name,
struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec);
void *elf_add_data(struct elf *elf, struct section *sec, const void *data,
- size_t size);
+ size_t size, bool align);
int elf_find_string(struct elf *elf, struct section *strtab, const char *str);
int elf_add_string(struct elf *elf, struct section *strtab, const char *str);
@@ -533,6 +534,9 @@ static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next)
#define sec_for_each_sym_from(sec, sym) \
list_for_each_entry_from(sym, &sec->symbol_list, list)
+#define sec_for_each_sym_continue(sec, sym) \
+ list_for_each_entry_continue(sym, &sec->symbol_list, list)
+
#define sec_prev_sym(sym) \
sym->sec && sym->list.prev != &sym->sec->symbol_list ? \
list_prev_entry(sym, list) : NULL
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index d76d2f5b5acbf..841651e3ad746 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1014,8 +1014,9 @@ static int clone_sym_relocs(struct elfs *e, struct symbol *patched_sym);
static struct symbol *__clone_symbol(struct elf *elf, struct symbol *patched_sym,
bool data_too)
{
- struct section *out_sec = NULL;
unsigned long offset = 0, pfx_size = 0;
+ bool align = !patched_sym->unalign;
+ struct section *out_sec = NULL;
struct symbol *out_sym;
if (data_too && !is_undef_sym(patched_sym)) {
@@ -1041,7 +1042,7 @@ static struct symbol *__clone_symbol(struct elf *elf, struct symbol *patched_sym
}
if (!is_sec_sym(patched_sym))
- offset = ALIGN(sec_size(out_sec), out_sec->sh.sh_addralign);
+ offset = ALIGN(sec_size(out_sec), align ? out_sec->sh.sh_addralign : 1);
if (patched_sym->len || is_sec_sym(patched_sym)) {
void *data = NULL;
@@ -1059,7 +1060,7 @@ static struct symbol *__clone_symbol(struct elf *elf, struct symbol *patched_sym
else
size = patched_sym->len + pfx_size;
- if (!elf_add_data(elf, out_sec, data, size))
+ if (!elf_add_data(elf, out_sec, data, size, align))
return NULL;
offset += pfx_size;
@@ -1101,6 +1102,37 @@ static const char *sym_bind(struct symbol *sym)
}
}
+static struct symbol *clone_symbol(struct elfs *e, struct symbol *patched_sym,
+ bool data_too);
+
+/*
+ * For arm64 alternatives, the replacement instructions come immediately after
+ * the function. Clone any such blocks of instructions in place to preserve
+ * their offsets relative to the function in case they have hard-coded PC
+ * relative branches.
+ */
+static int clone_inline_alternatives(struct elfs *e, struct symbol *patched_sym)
+{
+ struct symbol *next;
+
+ if (!__is_defined(ARCH_HAS_INLINE_ALTS) || !is_func_sym(patched_sym))
+ return 0;
+
+ next = patched_sym;
+ sec_for_each_sym_continue(patched_sym->sec, next) {
+ if (next->offset < (patched_sym->offset + patched_sym->len) ||
+ is_mapping_sym(next))
+ continue;
+ if (!next->fake)
+ break;
+ next->unalign = 1;
+ if (!clone_symbol(e, next, true))
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Copy a symbol to the output object, optionally including its data and
* relocations.
@@ -1125,7 +1157,13 @@ static struct symbol *clone_symbol(struct elfs *e, struct symbol *patched_sym,
if (!__clone_symbol(e->out, patched_sym, data_too))
return NULL;
- if (data_too && clone_sym_relocs(e, patched_sym))
+ if (!data_too || is_undef_sym(patched_sym))
+ return patched_sym->clone;
+
+ if (clone_sym_relocs(e, patched_sym))
+ return NULL;
+
+ if (clone_inline_alternatives(e, patched_sym))
return NULL;
return patched_sym->clone;
@@ -1585,7 +1623,7 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc,
memset(&klp_reloc, 0, sizeof(klp_reloc));
klp_reloc.type = reloc_type(patched_reloc);
- if (!elf_add_data(e->out, klp_relocs, &klp_reloc, sizeof(klp_reloc)))
+ if (!elf_add_data(e->out, klp_relocs, &klp_reloc, sizeof(klp_reloc), true))
return -1;
/* klp_reloc.offset */
@@ -2164,7 +2202,7 @@ static int create_klp_sections(struct elfs *e)
return -1;
/* allocate klp_object_ext */
- obj_data = elf_add_data(e->out, obj_sec, NULL, obj_size);
+ obj_data = elf_add_data(e->out, obj_sec, NULL, obj_size, true);
if (!obj_data)
return -1;
@@ -2199,7 +2237,7 @@ static int create_klp_sections(struct elfs *e)
continue;
/* allocate klp_func_ext */
- func_data = elf_add_data(e->out, funcs_sec, NULL, func_size);
+ func_data = elf_add_data(e->out, funcs_sec, NULL, func_size, true);
if (!func_data)
return -1;
@@ -2345,7 +2383,7 @@ static int copy_import_ns(struct elfs *e)
}
}
- if (!elf_add_data(e->out, out_sec, import_ns, strlen(import_ns) + 1))
+ if (!elf_add_data(e->out, out_sec, import_ns, strlen(import_ns) + 1, true))
return -1;
}
diff --git a/tools/objtool/klp-symid.c b/tools/objtool/klp-symid.c
index 21d8708013aba..1934c2a1afc4d 100644
--- a/tools/objtool/klp-symid.c
+++ b/tools/objtool/klp-symid.c
@@ -95,7 +95,7 @@ int klp_create_symid_sections(struct objtool_file *file)
if (!sec)
return -1;
- symids = elf_add_data(elf, sec, NULL, nr * sizeof(struct klp_symid));
+ symids = elf_add_data(elf, sec, NULL, nr * sizeof(struct klp_symid), true);
if (!symids)
return -1;
--
2.54.0
next prev parent reply other threads:[~2026-08-08 23:19 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-08 23:17 [PATCH v4 00/22] objtool/arm64: Port klp-build to arm64 Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 01/22] objtool/klp: Fix .kcfi_traps special section extraction Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 02/22] klp-build: Reject patches to init/*.c Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 03/22] arm64: Annotate intra-function calls Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 04/22] arm64: Fix EFI linking with -fdata-sections Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 05/22] arm64: Rename TRAMP_VALIAS -> TRAMP_VALIAS_ASM in asm-offsets Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 06/22] arm64: vdso: Discard .discard.* sections Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 07/22] arm64: Annotate special section entries Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 08/22] arm64: Remove unnecessary empty alternatives Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 09/22] crypto: arm64: Move data to .rodata Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 10/22] objtool: Allow setting --mnop without --mcount Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 11/22] kbuild: Only run objtool if there is at least one command Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 12/22] objtool: Ignore jumps to the end of the function for checksum runs Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 13/22] objtool: Refactor elf_add_data() to use a growable data buffer Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 14/22] objtool: Reuse string references Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 15/22] objtool: Prevent kCFI hashes from being decoded as instructions Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 16/22] objtool/klp: Add arm64 support for prefix/PFE detection Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 17/22] objtool/klp: Filter arm64 mapping symbols in find_symbol_by_offset() Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 18/22] objtool/klp: Don't correlate arm64 mapping symbols Josh Poimboeuf
2026-08-08 23:17 ` Josh Poimboeuf [this message]
2026-08-08 23:17 ` [PATCH v4 20/22] objtool/klp: Introduce objtool for arm64 Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 21/22] klp-build: Support cross-compilation Josh Poimboeuf
2026-08-08 23:17 ` [PATCH v4 22/22] klp-build: Add arm64 syscall patching macro Josh Poimboeuf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ebbfa4c78e459a21cebfb635225c046984d86b6a.1786230311.git.jpoimboe@kernel.org \
--to=jpoimboe@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=herbert@gondor.apana.org.au \
--cc=joe.lawrence@redhat.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=live-patching@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mbenes@suse.cz \
--cc=nathan@kernel.org \
--cc=nsc@kernel.org \
--cc=peterz@infradead.org \
--cc=pmladek@suse.com \
--cc=song@kernel.org \
--cc=will@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox