objtool/arm64: Port klp-build to arm64
Josh Poimboeuf
maintainerv4 cover objtool/arm64: Port klp-build to arm64
Based on tip/objtool/core + the following fixes:
- https://lore.kernel.org/[email protected]
- https://lore.kernel.org/ed4fe1f95071897859ec7fbe9176246cbd4962bf.1786138806.git.jpoimboe@kernel.org
- https://lore.kernel.org/1b5ccfa8095bdb1277f84af1c2c2e2205aca03ae.1785992188.git.jpoimboe@kernel.org
The full set (including the above fixes) can be found on the following branch:
git://git.kernel.org/pub/scm/linux/kernel/git/jpoimboe/linux.git klp-build-arm64
v4:
- Replace "objtool: Allow empty alternatives" with "arm64: Remove unnecessary empty alternatives" [Peter]
- Add "objtool/klp: Fix .kcfi_traps special section extraction" [Joe]
- Fix vmlinux.o objtool options leaking in from Makefile.lib [Sashiko]
- Tighten jump-to-end-of-function check [Sashiko]
- Drop unneeded linux/kconfig.h include [Sashiko]
- Fix bisectability issue with is_mapping_sym()/is_data_mapping_sym() [Sashiko]
- Add missing ALLOW_ERROR_INJECTION() to arm64 syscall macro [Sashiko]
v3: https://lore.kernel.org/[email protected]
- Too many changes to list. Did a lot of testing and fixed a bunch of issues (many of which have already been merged in tip/objtool/core).
v2: https://lore.kernel.org/[email protected]
- patches 1-2 were merged, rebase on tip/master
- improve commit message for "objtool: Extricate checksum calculation from validate_branch()"
- add review tags
v1: https://lore.kernel.org/[email protected]
Port objtool and the klp-build tooling (for building livepatch modules) to arm64.
Note this doesn't bring all the objtool bells and whistles to arm64, nor any of the CFG reverse engineering. This only adds the bare minimum needed for 'objtool --checksum'.
And note that objtool still doesn't get enabled at all for normal arm64 kernel builds, so this doesn't affect any users other than those running klp-build directly.
Josh Poimboeuf (22):
objtool/klp: Fix .kcfi_traps special section extraction
klp-build: Reject patches to init/*.c
arm64: Annotate intra-function calls
arm64: Fix EFI linking with -fdata-sections
arm64: Rename TRAMP_VALIAS -> TRAMP_VALIAS_ASM in asm-offsets
arm64: vdso: Discard .discard.* sections
arm64: Annotate special section entries
arm64: Remove unnecessary empty alternatives
crypto: arm64: Move data to .rodata
objtool: Allow setting --mnop without --mcount
kbuild: Only run objtool if there is at least one command
objtool: Ignore jumps to the end of the function for checksum runs
objtool: Refactor elf_add_data() to use a growable data buffer
objtool: Reuse string references
objtool: Prevent kCFI hashes from being decoded as instructions objtool/klp: Add arm64 support for prefix/PFE detection objtool/klp: Filter arm64 mapping symbols in find_symbol_by_offset() objtool/klp: Don't correlate arm64 mapping symbols objtool/klp: Clone inline alternative replacements objtool/klp: Introduce objtool for arm64
klp-build: Support cross-compilation
klp-build: Add arm64 syscall patching macro
arch/arm64/Kconfig | 2 + arch/arm64/include/asm/alternative-macros.h | 27 +- arch/arm64/include/asm/asm-bug.h | 2 + arch/arm64/include/asm/asm-extable.h | 21 +- arch/arm64/include/asm/assembler.h | 4 +- arch/arm64/include/asm/jump_label.h | 2 + arch/arm64/kernel/asm-offsets.c | 7 +- arch/arm64/kernel/entry.S | 10 +- arch/arm64/kernel/proton-pack.c | 12 +- arch/arm64/kernel/vdso/vdso.lds.S | 1 + arch/arm64/kernel/vmlinux.lds.S | 2 +- arch/x86/boot/startup/Makefile | 2 +- include/linux/annotate.h | 14 +- include/linux/livepatch_helpers.h | 20 ++ include/linux/objtool_types.h | 1 + lib/crypto/arm64/sha2-armv8.pl | 18 +- scripts/Makefile.build | 4 +- scripts/Makefile.lib | 52 ++-- scripts/Makefile.vmlinux_o | 18 +- scripts/livepatch/klp-build | 24 +- tools/include/linux/objtool_types.h | 1 + tools/objtool/Makefile | 4 + tools/objtool/arch/arm64/Build | 2 + tools/objtool/arch/arm64/decode.c | 177 ++++++++++++ .../arch/arm64/include/arch/cfi_regs.h | 11 + tools/objtool/arch/arm64/include/arch/elf.h | 15 ++ .../objtool/arch/arm64/include/arch/special.h | 21 ++ tools/objtool/arch/arm64/special.c | 30 +++ tools/objtool/arch/x86/include/arch/elf.h | 2 + tools/objtool/builtin-check.c | 5 - tools/objtool/check.c | 52 ++-- tools/objtool/elf.c | 170 +++++++----- tools/objtool/include/objtool/elf.h | 48 +++- tools/objtool/klp-diff.c | 254 ++++++++++++++++-- tools/objtool/klp-symid.c | 2 +- 35 files changed, 843 insertions(+), 194 deletions(-) create mode 100644 tools/objtool/arch/arm64/Build create mode 100644 tools/objtool/arch/arm64/decode.c create mode 100644 tools/objtool/arch/arm64/include/arch/cfi_regs.h create mode 100644 tools/objtool/arch/arm64/include/arch/elf.h create mode 100644 tools/objtool/arch/arm64/include/arch/special.h create mode 100644 tools/objtool/arch/arm64/special.c
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 1/22 objtool/klp: Fix .kcfi_traps special section extraction
create_fake_symbols() creates a symbol per entry for special sections. It does so in two steps: first for the sections which have ANNOTATE_DATA_SPECIAL annotations, then for the rest, using entsize or the reloc count to infer the entry size. The second step skips the sections already handled by the first one by looking for a symbol at offset 0.
That heuristic is too fuzzy: with Clang and CONFIG_CFI, it misfires on .kcfi_traps because Clang emits a .Ltmp* assembler-local label at the start of the section, so no symbols are created and clone_special_sections() extracts nothing. klp-build still reports SUCCESS, but the livepatch module has no __kcfi_traps section and the traps for the patched functions are lost.
Look for the actual fake symbols created by the first step instead.
--- tools/objtool/include/objtool/elf.h | 1 + tools/objtool/klp-diff.c | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-)
tools/objtool/include/objtool/elf.h +1 -0
@@ -97,6 +97,7 @@ struct symbol { u8 included : 1; u8 klp : 1; u8 dont_correlate : 1; + u8 fake : 1;struct list_head pv_target;struct reloc *relocs;struct section *group_sec;
tools/objtool/klp-diff.c +24 -2
@@ -1629,6 +1629,7 @@ static int create_fake_symbol(struct elf *elf, struct section *sec, unsigned long offset, size_t size) { char name[SYM_NAME_LEN]; +struct symbol *sym;unsigned int type;static int ctr;char *c;
@@ -1645,7 +1646,24 @@ static int create_fake_symbol(struct elf *elf, struct section *sec,* while still allowing objdump to disassemble it. */ type =is_text_sec (sec) ?STT_NOTYPE :STT_OBJECT ; -return elf_create_symbol (elf, name, sec,STB_LOCAL , type, offset, size) ?0 :-1 ; + + sym =elf_create_symbol (elf, name, sec,STB_LOCAL , type, offset, size); +if (!sym) +return -1 ; + + sym->fake =1 ; +return 0 ; +} + +static bool has_fake_symbols (struct section *sec) +{ +struct symbol *sym; + +sec_for_each_sym (sec, sym) +if (sym->fake) +return true; + +return false; }/*
@@ -1737,7 +1755,11 @@ static int create_fake_symbols(struct elf *elf)unsigned int entry_size;unsigned long offset; -if (!is_special_section (sec) ||find_symbol_by_offset (sec,0 )) +if (!is_special_section (sec)) +continue ; + +/* Skip sections already handled by step 1 above */ +if (has_fake_symbols (sec))continue ;if (!sec->rsec) {
Signature · 1 line
2.54.0
Re: [PATCH v4 01/22] objtool/klp: Fix .kcfi_traps special section extraction
Quoted 15 lines · Josh Poimboeuf
create_fake_symbols()creates a symbol per entry for special sections. It does so in two steps: first for the sections which haveANNOTATE_DATA_SPECIALannotations, then for the rest, using entsize or the reloc count to infer the entry size. The second step skips the sections already handled by the first one by looking for a symbol at offset 0.That heuristic is too fuzzy: with Clang and
CONFIG_CFI, it misfires on .kcfi_traps because Clang emits a .Ltmp* assembler-local label at the start of the section, so no symbols are created andclone_special_sections()extracts nothing. klp-build still reports SUCCESS, but the livepatch module has no__kcfi_trapssection and the traps for the patched functions are lost.
Quoted 6 lines
Look for the actual fake symbols created by the first step instead.
Fixes da4326573ae8d ("objtool/klp: Fix kCFI trap handling")Reported-by Joe Lawrence <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>
[tip: objtool/core] objtool/klp: Fix .kcfi_traps special section extraction
In reply to Josh PoimboeufThe following commit has been merged into the objtool/core branch of tip:
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: 7df1638df97b2aaaff4731b72d4940053257c952 Gitweb: https://git.kernel.org/tip/7df1638df97b2aaaff4731b72d4940053257c952 Author: Josh Poimboeuf <[email protected]> AuthorDate: Sat, 08 Aug 2026 16:17:05 -07:00 Committer: Josh Poimboeuf <[email protected]> CommitterDate: Wed, 12 Aug 2026 13:52:07 -07:00
objtool/klp: Fix .kcfi_traps special section extraction
create_fake_symbols() creates a symbol per entry for special sections. It does so in two steps: first for the sections which have ANNOTATE_DATA_SPECIAL annotations, then for the rest, using entsize or the reloc count to infer the entry size. The second step skips the sections already handled by the first one by looking for a symbol at offset 0.
That heuristic is too fuzzy: with Clang and CONFIG_CFI, it misfires on .kcfi_traps because Clang emits a .Ltmp* assembler-local label at the start of the section, so no symbols are created and clone_special_sections() extracts nothing. klp-build still reports SUCCESS, but the livepatch module has no __kcfi_traps section and the traps for the patched functions are lost.
Look for the actual fake symbols created by the first step instead.
--- tools/objtool/include/objtool/elf.h | 1 + tools/objtool/klp-diff.c | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-)
tools/objtool/include/objtool/elf.h +1 -0
@@ -97,6 +97,7 @@ struct symbol { u8 included : 1; u8 klp : 1; u8 dont_correlate : 1; + u8 fake : 1;struct list_head pv_target;struct reloc *relocs;struct section *group_sec;
tools/objtool/klp-diff.c +24 -2
@@ -1630,6 +1630,7 @@ static int create_fake_symbol(struct elf *elf, struct section *sec, unsigned long offset, size_t size) { char name[SYM_NAME_LEN]; +struct symbol *sym;unsigned int type;static int ctr;char *c;
@@ -1646,7 +1647,24 @@ static int create_fake_symbol(struct elf *elf, struct section *sec,* while still allowing objdump to disassemble it. */ type =is_text_sec (sec) ?STT_NOTYPE :STT_OBJECT ; -return elf_create_symbol (elf, name, sec,STB_LOCAL , type, offset, size) ?0 :-1 ; + + sym =elf_create_symbol (elf, name, sec,STB_LOCAL , type, offset, size); +if (!sym) +return -1 ; + + sym->fake =1 ; +return 0 ; +} + +static bool has_fake_symbols (struct section *sec) +{ +struct symbol *sym; + +sec_for_each_sym (sec, sym) +if (sym->fake) +return true; + +return false; }/*
@@ -1738,7 +1756,11 @@ entsize:unsigned int entry_size;unsigned long offset; -if (!is_special_section (sec) ||find_symbol_by_offset (sec,0 )) +if (!is_special_section (sec)) +continue ; + +/* Skip sections already handled by step 1 above */ +if (has_fake_symbols (sec))continue ;if (!sec->rsec) {
Josh Poimboeuf
maintainerPATCH v4 2/22 klp-build: Reject patches to init/*.c
In reply to Josh Poimboeufinit/Makefile hard-codes -fno-function-sections and -fno-data-sections, overriding the klp-build flags needed for patch generation.
Don't allow any changes to those files; being init code they aren't really patchable anyway.
--- scripts/livepatch/klp-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/livepatch/klp-build +1 -1
@@ -365,7 +365,7 @@ check_unsupported_patches() { for file in "${files[@]}"; do case "$file" in - lib/*|*/vdso/*|*/realmode/rm/*|*.S) + lib/*|*/vdso/*|*/realmode/rm/*|init/*|*.S) die "${patch}: unsupported patch to $file" ;; esac
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 3/22 arm64: Annotate intra-function calls
In reply to Josh PoimboeufIn preparation for enabling objtool on arm64, annotate intra-function calls.
--- arch/arm64/kernel/entry.S | 2 ++ arch/arm64/kernel/proton-pack.c | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-)
arch/arm64/kernel/entry.S +2 -0
@@ -10,6 +10,7 @@ #include <linux/arm-smccc.h> #include <linux/init.h> #include <linux/linkage.h> +#include <linux/annotate.h> #include <asm/alternative.h> #include <asm/assembler.h>
@@ -705,6 +706,7 @@ alternative_else_nop_endif * entry onto the return stack and using a RET instruction to * enter the full-fat kernel vectors. */ + ANNOTATE_INTRA_FUNCTION_CALL bl 2f b . 2:
arch/arm64/kernel/proton-pack.c +7 -5
@@ -25,6 +25,7 @@#include <linux/prctl.h> #include <linux/sched/task_stack.h> #include <linux/sysfs.h> +#include <linux/annotate.h> #include <asm/debug-monitors.h> #include <asm/insn.h>
@@ -246,11 +247,12 @@ static noinstr void qcom_link_stack_sanitisation(void) {u64 tmp; - asmvolatile ("mov %0, x30 \n" -".rept 16 \n" -"bl . + 4 \n" -".endr \n" -"mov x30, %0 \n" + asmvolatile ("mov %0, x30 \n" +".rept 16 \n" +ANNOTATE_INTRA_FUNCTION_CALL " \n" +"bl . + 4 \n" +".endr \n" +"mov x30, %0 \n" :"=&r" (tmp)); }
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 4/22 arm64: Fix EFI linking with -fdata-sections
In reply to Josh PoimboeufWhen building with -fdata-sections, the .init.bss section gets split up into a bunch of .init.bss.<var> sections. Make sure they get linked into .init.data.
--- arch/arm64/kernel/vmlinux.lds.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/kernel/vmlinux.lds.S +1 -1
@@ -281,7 +281,7 @@ SECTIONS INIT_CALLS CON_INITCALL INIT_RAM_FS - *(.init.altinstructions .init.bss) /* from the EFI stub */ + *(.init.altinstructions .init.bss .init.bss.*) /* from the EFI stub */ } .exit.data : { EXIT_DATA
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 5/22 arm64: Rename TRAMP_VALIAS -> TRAMP_VALIAS_ASM in asm-offsets
In reply to Josh PoimboeufRename the asm-offsets TRAMP_VALIAS macro to TRAMP_VALIAS_ASM, following the naming convention already used by PIE_E0_ASM and PIE_E1_ASM. This disambiguates the asm-offsets-generated constant from the C macro of the same name defined in fixmap.h and vectors.h.
This is needed by a later patch which adds new includes to asm-offsets.c that would otherwise conflict with the C version.
--- arch/arm64/kernel/asm-offsets.c | 2 +- arch/arm64/kernel/entry.S | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-)
arch/arm64/kernel/asm-offsets.c +1 -1
@@ -153,7 +153,7 @@ int main(void)DEFINE (ARM64_FTR_SYSVAL , offsetof(struct arm64_ftr_reg , sys_val));BLANK ();#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 -DEFINE (TRAMP_VALIAS ,TRAMP_VALIAS ); +DEFINE (TRAMP_VALIAS_ASM ,TRAMP_VALIAS );#endif #ifdef CONFIG_ARM_SDE_INTERFACE DEFINE (SDEI_EVENT_INTREGS , offsetof(struct sdei_registered_event , interrupted_regs));
arch/arm64/kernel/entry.S +4 -4
@@ -102,7 +102,7 @@ .endm .macro tramp_alias, dst, sym - .set .Lalias\@, TRAMP_VALIAS + \sym - .entry.tramp.text + .set .Lalias\@, TRAMP_VALIAS_ASM + \sym - .entry.tramp.text movz \dst, :abs_g2_s:.Lalias\@ movk \dst, :abs_g1_nc:.Lalias\@ movk \dst, :abs_g0_nc:.Lalias\@
@@ -626,10 +626,10 @@ SYM_CODE_END(ret_to_user) #ifdef CONFIG_QCOM_FALKOR_ERRATUM_1003 alternative_if ARM64_WORKAROUND_QCOM_FALKOR_E1003 /* ASID already in \tmp[63:48] */ - movk \tmp, #:abs_g2_nc:(TRAMP_VALIAS >> 12) - movk \tmp, #:abs_g1_nc:(TRAMP_VALIAS >> 12) + movk \tmp, #:abs_g2_nc:(TRAMP_VALIAS_ASM >> 12) + movk \tmp, #:abs_g1_nc:(TRAMP_VALIAS_ASM >> 12) /* 2MB boundary containing the vectors, so we nobble the walk cache */ - movk \tmp, #:abs_g0_nc:((TRAMP_VALIAS & ~(SZ_2M - 1)) >> 12) + movk \tmp, #:abs_g0_nc:((TRAMP_VALIAS_ASM & ~(SZ_2M - 1)) >> 12) isb tlbi vae1, \tmp dsb nsh
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 6/22 arm64: vdso: Discard .discard.* sections
In reply to Josh PoimboeufIn preparation for enabling objtool on arm64, add .discard.* to the vDSO's /DISCARD/ section so objtool annotations don't cause orphan section warnings or leak into the final vDSO binary.
--- arch/arm64/kernel/vdso/vdso.lds.S | 1 + 1 file changed, 1 insertion(+)
arch/arm64/kernel/vdso/vdso.lds.S +1 -0
@@ -39,6 +39,7 @@ SECTIONS /DISCARD/ : { *(.note.GNU-stack .note.gnu.property) *(.ARM.attributes) + *(.discard.*) } .note : { *(.note.*) } :text :note
Signature · 1 line
2.54.0
Re: [PATCH v4 06/22] arm64: vdso: Discard .discard.* sections
Quoted 6 lines · Josh Poimboeuf
In preparation for enabling objtool on arm64, add .discard.* to the vDSO's /DISCARD/ section so objtool annotations don't cause orphan section warnings or leak into the final vDSO binary.
Signed-off-by Josh Poimboeuf <[email protected]>
Josh Poimboeuf
maintainerPATCH v4 7/22 arm64: Annotate special section entries
In reply to Josh PoimboeufIn preparation for adding arm64 support for "objtool klp checksum/diff" to enable livepatch module generation, annotate special section entries.
This will allow objtool to determine the size and location of the entries and to extract them when needed.
A new ANNOTATE_DATA_SPECIAL_END annotation is added to mark the end of special data blocks, which is needed because arm64's replacement instructions are emitted in .text rather than .altinstr_replacement, so there's otherwise no way to determine where the last replacement block ends.
--- arch/arm64/include/asm/alternative-macros.h | 27 ++++++++++++++++----- arch/arm64/include/asm/asm-bug.h | 2 ++ arch/arm64/include/asm/asm-extable.h | 21 ++++++++++------ arch/arm64/include/asm/jump_label.h | 2 ++ arch/arm64/kernel/asm-offsets.c | 5 ++++ include/linux/annotate.h | 14 ++++++++++- include/linux/objtool_types.h | 1 + tools/include/linux/objtool_types.h | 1 + tools/objtool/klp-diff.c | 5 +++- 9 files changed, 62 insertions(+), 16 deletions(-)
arch/arm64/include/asm/alternative-macros.h +21 -6
@@ -3,11 +3,16 @@#define __ASM_ALTERNATIVE_MACROS_H#include <linux/const.h> +#include <linux/annotate.h> #include <vdso/bits.h> #include <asm/cpucaps.h> #include <asm/insn-def.h> +#ifndef COMPILE_OFFSETS +#include <asm/asm-offsets.h> +#endif +/* * Binutils 2.27.0 can't handle a 'UL' suffix on constants, so for the assembly * macros below we must use we must use `(1 << ARM64_CB_SHIFT)`.
@@ -58,15 +63,18 @@"661:\n\t" \ oldinstr"\n" \"662:\n" \ -".pushsection .altinstructions,\"a\"\n" \ +".pushsection .altinstructions,\"aM\", @progbits, " \ + __stringify(ALT_INSTR_SIZE) "\n" \ ALTINSTR_ENTRY(cpucap) \".popsection\n" \".subsection 1\n" \ +ANNOTATE_DATA_SPECIAL "\n" \"663:\n\t" \ newinstr"\n" \"664:\n\t" \".org . - (664b-663b) + (662b-661b)\n\t" \".org . - (662b-661b) + (664b-663b)\n\t" \ +ANNOTATE_DATA_SPECIAL_END "\n\t" \".previous\n" \".endif\n"
@@ -75,7 +83,8 @@"661:\n\t" \ oldinstr"\n" \"662:\n" \ -".pushsection .altinstructions,\"a\"\n" \ +".pushsection .altinstructions,\"aM\", @progbits, " \ + __stringify(ALT_INSTR_SIZE) "\n" \ ALTINSTR_ENTRY_CB(cpucap, cb) \".popsection\n" \"663:\n\t" \
@@ -102,13 +111,15 @@ .macro alternative_insn insn1, insn2, cap, enable = 1 .if \enable 661: \insn1 -662: .pushsection .altinstructions, "a" +662: .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f .popsection .subsection 1 + ANNOTATE_DATA_SPECIAL 663: \insn2 664: .org . - (664b-663b) + (662b-661b) .org . - (662b-661b) + (664b-663b) +ANNOTATE_DATA_SPECIAL_END .previous .endif .endm
@@ -137,7 +148,7 @@*/ .macro alternative_if_not cap .set .Lasm_alt_mode,0 - .pushsection .altinstructions,"a" + .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f .popsection 661:
@@ -145,17 +156,18 @@ .macro alternative_if cap .set .Lasm_alt_mode,1 - .pushsection .altinstructions,"a" + .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE altinstruction_entry 663f, 661f, \cap, 664f-663f, 662f-661f .popsection .subsection 1 .align 2 /* So GAS knows label 661 is suitably aligned */ + ANNOTATE_DATA_SPECIAL 661: .endm .macro alternative_cb cap, cb .set .Lasm_alt_mode,0 - .pushsection .altinstructions,"a" + .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE altinstruction_entry 661f, \cb, (1 << ARM64_CB_SHIFT) | \cap, 662f-661f, 0 .popsection 661:
@@ -168,7 +180,9 @@ 662: .if .Lasm_alt_mode==0 .subsection 1 + ANNOTATE_DATA_SPECIAL .else +ANNOTATE_DATA_SPECIAL_END .previous .endif 663:
@@ -182,6 +196,7 @@ .org . - (664b-663b) + (662b-661b) .org . - (662b-661b) + (664b-663b) .if .Lasm_alt_mode==0 +ANNOTATE_DATA_SPECIAL_END .previous .endif .endm
arch/arm64/include/asm/asm-bug.h +2 -0
@@ -5,6 +5,7 @@*/ #define __ASM_ASM_BUG_H +#include <linux/annotate.h> #include <asm/brk-imm.h> #ifdef CONFIG_DEBUG_BUGVERBOSE
@@ -24,6 +25,7 @@#define __BUG_ENTRY_START \ .pushsection __bug_table,"aw"; \ .align 2; \ + __ANNOTATE_DATA_SPECIAL; \ 14470: .long 14471f - .; \#define __BUG_ENTRY_END \
arch/arm64/include/asm/asm-extable.h +13 -8
@@ -5,6 +5,10 @@#include <linux/bits.h> #include <asm/gpr-num.h> +#ifndef COMPILE_OFFSETS +#include <asm/asm-offsets.h> +#endif +#define EX_TYPE_NONE 0#define EX_TYPE_BPF 1#define EX_TYPE_UACCESS_ERR_ZERO 2
@@ -29,13 +33,13 @@#ifdef __ASSEMBLER__ -#define __ASM_EXTABLE_RAW (insn, fixup, type, data) \ - .pushsection __ex_table, "a"; \ - .align 2; \ - .long ((insn) - .); \ - .long ((fixup) - .); \ - .short (type); \ - .short (data); \ +#define __ASM_EXTABLE_RAW (insn, fixup, type, data) \ + .pushsection __ex_table, "aM", @progbits, EXTABLE_SIZE; \ + .align 2; \ + .long ((insn) - .); \ + .long ((fixup) - .); \ + .short (type); \ + .short (data); \ .popsection;#define EX_DATA_REG (reg, gpr) \
@@ -82,7 +86,8 @@#include <linux/stringify.h> #define __ASM_EXTABLE_RAW (insn, fixup, type, data) \ - ".pushsection __ex_table, \"a\"\n" \ + ".pushsection __ex_table, \"aM\", @progbits, "\ + __stringify(EXTABLE_SIZE) "\n" \ ".align 2\n" \ ".long ((" insn ") - .)\n" \ ".long ((" fixup ") - .)\n" \
arch/arm64/include/asm/jump_label.h +2 -0
@@ -11,6 +11,7 @@#ifndef __ASSEMBLER__#include <linux/types.h> +#include <linux/annotate.h> #include <asm/insn.h> #define HAVE_JUMP_LABEL_BATCH
@@ -19,6 +20,7 @@#define JUMP_TABLE_ENTRY (key, label) \ ".pushsection __jump_table, \"aw\"\n\t" \ ".align 3\n\t" \ + ANNOTATE_DATA_SPECIAL "\n\t" \ ".long 1b - ., " label " - .\n\t" \ ".quad " key " - .\n\t" \ ".popsection\n\t"
arch/arm64/kernel/asm-offsets.c +5 -0
@@ -23,6 +23,8 @@#include <asm/suspend.h> #include <linux/kbuild.h> #include <linux/arm-smccc.h> +#include <asm/alternative.h> +#include <asm/extable.h> int main (void ) {
@@ -185,5 +187,8 @@ int main(void)#endif DEFINE (PIE_E0_ASM ,PIE_E0 );DEFINE (PIE_E1_ASM ,PIE_E1 ); +BLANK (); +DEFINE (ALT_INSTR_SIZE ,sizeof (struct alt_instr )); +DEFINE (EXTABLE_SIZE ,sizeof (struct exception_table_entry ));return 0 ; }
include/linux/annotate.h +13 -1
@@ -3,6 +3,7 @@#define _LINUX_ANNOTATE_H#include <linux/objtool_types.h> +#include <linux/stringify.h> #ifdef CONFIG_OBJTOOL
@@ -11,6 +12,10 @@ .long label - ., type; \ .popsection +#define __ASM_ANNOTATE_DATA (type) \ +912: \ + __ASM_ANNOTATE(.discard.annotate_data, 912b, type) +#ifndef __ASSEMBLY__#define ASM_ANNOTATE_LABEL (label, type) \
@@ -39,6 +44,9 @@#endif /* __ASSEMBLY__ */ #else /* !CONFIG_OBJTOOL */ + +#define __ASM_ANNOTATE_DATA (type) +#ifndef __ASSEMBLY__#define ASM_ANNOTATE_LABEL (label, type) ""#define ASM_ANNOTATE (type)
@@ -106,10 +114,12 @@#define ANNOTATE_NOCFI_SYM (sym) asm(ASM_ANNOTATE_LABEL(sym, ANNOTYPE_NOCFI))/* -* Annotate a special section entry. This emables livepatch module generation +* Annotate a special section entry. This enables livepatch module generation * to find and extract individual special section entries as needed. */ #define ANNOTATE_DATA_SPECIAL ASM_ANNOTATE_DATA(ANNOTYPE_DATA_SPECIAL) +#define __ANNOTATE_DATA_SPECIAL __ASM_ANNOTATE_DATA(ANNOTYPE_DATA_SPECIAL) +#define ANNOTATE_DATA_SPECIAL_END ASM_ANNOTATE_DATA(ANNOTYPE_DATA_SPECIAL_END)#else /* __ASSEMBLY__ */ #define ANNOTATE_NOENDBR ANNOTATE type=ANNOTYPE_NOENDBR
@@ -122,6 +132,8 @@#define ANNOTATE_REACHABLE ANNOTATE type=ANNOTYPE_REACHABLE#define ANNOTATE_NOCFI_SYM ANNOTATE type=ANNOTYPE_NOCFI#define ANNOTATE_DATA_SPECIAL ANNOTATE_DATA type=ANNOTYPE_DATA_SPECIAL +#define __ANNOTATE_DATA_SPECIAL __ASM_ANNOTATE_DATA(ANNOTYPE_DATA_SPECIAL) +#define ANNOTATE_DATA_SPECIAL_END ANNOTATE_DATA type=ANNOTYPE_DATA_SPECIAL_END#endif /* __ASSEMBLY__ */ #endif /* _LINUX_ANNOTATE_H */
include/linux/objtool_types.h +1 -0
@@ -68,5 +68,6 @@ struct unwind_hint {#define ANNOTYPE_NOCFI 9#define ANNOTYPE_DATA_SPECIAL 1 +#define ANNOTYPE_DATA_SPECIAL_END 2#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/include/linux/objtool_types.h +1 -0
@@ -68,5 +68,6 @@ struct unwind_hint {#define ANNOTYPE_NOCFI 9#define ANNOTYPE_DATA_SPECIAL 1 +#define ANNOTYPE_DATA_SPECIAL_END 2#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/objtool/klp-diff.c +4 -1
@@ -1727,7 +1727,10 @@ static int create_fake_symbols(struct elf *elf)*/ next_reloc = reloc;for_each_reloc_continue (sec->rsec, next_reloc) { -if (annotype (elf, sec, next_reloc) !=ANNOTYPE_DATA_SPECIAL || +unsigned int next_type =annotype (elf, sec, next_reloc); + +if ((next_type !=ANNOTYPE_DATA_SPECIAL && + next_type !=ANNOTYPE_DATA_SPECIAL_END ) || next_reloc->sym->sec != reloc->sym->sec)continue ;
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 8/22 arm64: Remove unnecessary empty alternatives
In reply to Josh PoimboeufThe code in arch/arm64/mm/cache.S creates three empty alternatives, all from calling the dcache_by_myline_op_nosync asm macro. If \op == cvau, it creates an empty alternative for ARM64_WORKAROUND_4311569.
Since orig_len == 0, the alternative patching code mostly ignores it, though it does do an unnecessary clean_dcache_range_nopatch(). It also triggers an objtool error ("empty alternative entry").
Clean it up by moving the .ifnc check outside the alternative emit.
--- arch/arm64/include/asm/assembler.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/include/asm/assembler.h +2 -2
@@ -404,13 +404,13 @@ alternative_else_nop_endif add \start, \start, \linesz cmp \start, \end b.lo .Ldcache_op\@ -alternative_if ARM64_WORKAROUND_4311569 .ifnc \op, cvau +alternative_if ARM64_WORKAROUND_4311569 mov \start, \tmp mov \tmp, xzr cbnz \start, .Ldcache_op\@ - .endif alternative_else_nop_endif + .endif _cond_uaccess_extable .Ldcache_op\@, \fixup .endm
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 9/22 crypto: arm64: Move data to .rodata
In reply to Josh PoimboeufData embedded in .text pollutes i-cache and confuses objtool and other tools that try to disassemble it. Move it to .rodata.
--- lib/crypto/arm64/sha2-armv8.pl | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
lib/crypto/arm64/sha2-armv8.pl +12 -6
@@ -207,12 +207,13 @@ $func: ___ $code.=<<___ if ($SZ==4); #ifndef __KERNEL__ + adrp x17,.LOPENSSL_armcap_P + add x17,x17,:lo12:.LOPENSSL_armcap_P # ifdef __ILP32__ - ldrsw x16,.LOPENSSL_armcap_P + ldrsw x16,[x17] # else - ldr x16,.LOPENSSL_armcap_P + ldr x16,[x17] # endif - adr x17,.LOPENSSL_armcap_P add x16,x16,x17 ldr w16,[x16] tst w16,#ARMV8_SHA256
@@ -237,7 +238,8 @@ $code.=<<___; ldp $E,$F,[$ctx,#4*$SZ] add $num,$inp,$num,lsl#`log(16*$SZ)/log(2)` // end of input ldp $G,$H,[$ctx,#6*$SZ] - adr $Ktbl,.LK$BITS + adrp $Ktbl,.LK$BITS + add $Ktbl,$Ktbl,:lo12:.LK$BITS stp $ctx,$num,[x29,#96] .Loop:
@@ -286,6 +288,7 @@ $code.=<<___; ret .size $func,.-$func +.pushsection .rodata .align 6 .type .LK$BITS,%object .LK$BITS:
@@ -365,6 +368,7 @@ $code.=<<___; #endif .asciz "SHA$BITS block transform for ARMv8, CRYPTOGAMS by <appro\@openssl.org>" .align 2 +.popsection ___ if ($SZ==4) {
@@ -385,7 +389,8 @@ sha256_block_armv8: add x29,sp,#0 ld1.32 {$ABCD,$EFGH},[$ctx] - adr $Ktbl,.LK256 + adrp $Ktbl,.LK256 + add $Ktbl,$Ktbl,:lo12:.LK256 .Loop_hw: ld1 {@MSG[0]-@MSG[3]},[$inp],#64
@@ -648,7 +653,8 @@ sha256_block_neon: mov x29, sp sub sp,sp,#16*4 - adr $Ktbl,.LK256 + adrp $Ktbl,.LK256 + add $Ktbl,$Ktbl,:lo12:.LK256 add $num,$inp,$num,lsl#6 // len to point at the end of inp ld1.8 {@X[0]},[$inp], #16
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 10/22 objtool: Allow setting --mnop without --mcount
In reply to Josh PoimboeufInstead of returning an error for --mnop without --mcount, just silently ignore it. This will help simplify kbuild's handling of objtool args.
--- tools/objtool/builtin-check.c | 5 ----- 1 file changed, 5 deletions(-)
tools/objtool/builtin-check.c +0 -5
@@ -145,11 +145,6 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])static bool opts_valid (void ) { -if (opts.mnop && !opts.mcount) { -ERROR ("--mnop requires --mcount" ); -return false; - } -if (opts.noinstr && !opts.link) {ERROR ("--noinstr requires --link" );return false;
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 11/22 kbuild: Only run objtool if there is at least one command
In reply to Josh PoimboeufSplit the objtool args into commands and options, such that if no commands have been enabled, objtool doesn't run.
This is in preparation for enabling objtool and klp-build for arm64.
--- arch/x86/boot/startup/Makefile | 2 +- scripts/Makefile.build | 4 +-- scripts/Makefile.lib | 52 ++++++++++++++++++---------------- scripts/Makefile.vmlinux_o | 18 +++++------- 4 files changed, 38 insertions(+), 38 deletions(-)
arch/x86/boot/startup/Makefile +1 -1
@@ -36,7 +36,7 @@ $(patsubst %.o,$(obj)/%.o,$(lib-y)): OBJECT_FILES_NON_STANDARD := y # relocations, even if other objtool actions are being deferred. # $(pi-objs): objtool-enabled = 1 -$(pi-objs): objtool-args = $(if $(delay-objtool),--dry-run,$(objtool-args-y)) --noabs +$(pi-objs): objtool-args = $(if $(delay-objtool),--dry-run,$(objtool-cmds-y) $(objtool-opts-y)) --noabs # # Confine the startup code by prefixing all symbols with __pi_ (for position
scripts/Makefile.build +2 -2
@@ -277,7 +277,7 @@ endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(target-stem).o)$(OBJECT_FILES_NON_STANDARD)n),$(is-kernel-object)) ifdef CONFIG_OBJTOOL -$(obj)/%.o: private objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y)) +$(obj)/%.o: private objtool-enabled = $(and $(is-standard-object),$(objtool-cmds-y),$(if $(delay-objtool),$(is-single-obj-m),y)) endif ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),)
@@ -502,7 +502,7 @@ define rule_ld_multi_m $(call cmd,gen_objtooldep) endef -$(multi-obj-m): private objtool-enabled := $(delay-objtool) +$(multi-obj-m): private objtool-enabled := $(if $(objtool-cmds-y),$(delay-objtool)) $(multi-obj-m): private part-of-module := y $(multi-obj-m): %.o: %.mod FORCE $(call if_changed_rule,ld_multi_m)
scripts/Makefile.lib +28 -24
65 lines not on this page · raw message
scripts/Makefile.vmlinux_o +7 -11
@@ -36,21 +36,17 @@ endif # For !delay-objtool + CONFIG_NOINSTR_VALIDATION, it runs on both translation # units and vmlinux.o, with the latter only used for noinstr/unret validation. -objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION)) - -ifeq ($(delay-objtool),y) -vmlinux-objtool-args-y += $(objtool-args-y) -else -vmlinux-objtool-args-$(CONFIG_OBJTOOL_WERROR) += --werror +ifneq ($(delay-objtool),y) +objtool-cmds-y = +objtool-opts-y = --link +objtool-opts-$(CONFIG_OBJTOOL_WERROR) += --werror endif -vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION) += --noinstr \ - $(if $(or $(CONFIG_MITIGATION_UNRET_ENTRY),$(CONFIG_MITIGATION_SRSO)), --unret) +objtool-cmds-$(CONFIG_NOINSTR_VALIDATION) += --noinstr \ + $(if $(or $(CONFIG_MITIGATION_UNRET_ENTRY),$(CONFIG_MITIGATION_SRSO)), --unret) # Only used for builds initiated by klp-build -vmlinux-objtool-args-$(if $(KLP_SYMIDS),y) += --klp-symids - -objtool-args = $(vmlinux-objtool-args-y) --link +objtool-cmds-$(if $(KLP_SYMIDS),y) += --klp-symids # Link of vmlinux.o used for section mismatch analysis # ---------------------------------------------------------------------------
Signature · 1 line
2.54.0
Re: [PATCH v4 11/22] kbuild: Only run objtool if there is at least one command
Quoted 10 lines · Josh Poimboeuf
Split the objtool args into commands and options, such that if no commands have been enabled, objtool doesn't run.
This is in preparation for enabling objtool and klp-build for arm64.
Reviewed-by Nathan Chancellor <[email protected]>Reviewed-by Nicolas Schier <[email protected]>Tested-by Nathan Chancellor <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>
Josh Poimboeuf
maintainerPATCH v4 12/22 objtool: Ignore jumps to the end of the function for checksum runs
In reply to Josh PoimboeufSometimes Clang arm64 code jumps to the end of the function for UB. No need to make that an error for checksum runs, which are only run manually by klp-build, and for which caring about UB is out of scope.
Such UBs are still reported for normal validate branch runs (for arches which do that).
--- tools/objtool/check.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-)
tools/objtool/check.c +21 -17
@@ -38,6 +38,22 @@ struct disas_context *objtool_disas_ctx;size_t sym_name_max_len; +static bool validate_branch_enabled (void ) +{ +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; +} +struct instruction *find_insn (struct objtool_file *file,struct section *sec,unsigned long offset) {
@@ -1595,8 +1611,12 @@ static int add_jump_destinations(struct objtool_file *file)/* * GCOV/KCOV dead code can jump to the end of * the function/section. +* +* Clang on arm64 also does this sometimes for +* undefined behavior. */ -if (file->ignore_unreachables && func && +if ((!validate_branch_enabled () || file->ignore_unreachables) && + func && dest_sec == insn->sec && dest_off == func->offset + func->len)continue ;
@@ -2586,22 +2606,6 @@ static void mark_holes(struct objtool_file *file) } } -static bool validate_branch_enabled (void ) -{ -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; -} -int decode_file (struct objtool_file *file) {arch_initial_func_cfi_state (&initial_func_cfi);
Signature · 1 line
2.54.0
Re: [PATCH v4 12/22] objtool: Ignore jumps to the end of the function for checksum runs
Quoted 9 lines · Josh Poimboeuf
Sometimes Clang arm64 code jumps to the end of the function for UB. No need to make that an error for checksum runs, which are only run manually by klp-build, and for which caring about UB is out of scope.
Such UBs are still reported for normal validate branch runs (for arches which do that).
Signed-off-by Josh Poimboeuf <[email protected]>
Josh Poimboeuf
maintainerPATCH v4 13/22 objtool: Refactor elf_add_data() to use a growable data buffer
In reply to Josh PoimboeufInstead of calling elf_newdata() for each new piece of data with its own separate buffer, keep it all in the same growable buffer so the section's entire data can be accessed if needed.
--- tools/objtool/elf.c | 123 ++++++++++++++-------------- tools/objtool/include/objtool/elf.h | 13 ++- 2 files changed, 71 insertions(+), 65 deletions(-)
tools/objtool/elf.c +60 -63
@@ -1147,9 +1147,6 @@ static int read_relocs(struct elf *elf) rsec->base->rsec = rsec; -/* nr_alloc_relocs=0: libelf owns d_buf */ - rsec->nr_alloc_relocs =0 ; - rsec->relocs =calloc (sec_num_entries (rsec),sizeof (*reloc));if (!rsec->relocs) {ERROR_GLIBC ("calloc" );
@@ -1408,7 +1405,7 @@ unsigned int elf_add_string(struct elf *elf, struct section *strtab, const charvoid *elf_add_data (struct elf *elf,struct section *sec,const void *data,size_t size) { -unsigned long offset; +unsigned long offset, size_old, size_new, alloc_size_old, alloc_size_new;Elf_Scn *s;if (!sec->sh.sh_addralign) {
@@ -1422,30 +1419,55 @@ void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_return NULL ; } - sec->data =elf_newdata (s);if (!sec->data) { -ERROR_ELF ("elf_newdata" ); -return NULL ; + sec->data =elf_newdata (s); +if (!sec->data) { +ERROR_ELF ("elf_newdata" ); +return NULL ; + } + + sec->data->d_align = sec->sh.sh_addralign; } - sec->data->d_buf =calloc (1 , size); -if (!sec->data->d_buf) { -ERROR_GLIBC ("calloc" ); -return NULL ; + size_old = sec->data->d_size; + offset =ALIGN (size_old, sec->sh.sh_addralign); + size_new = offset + size; + +if (!sec->data_overallocated) + alloc_size_old = size_old; +else + alloc_size_old =max (64UL ,roundup_pow_of_two (size_old ? :1 )); + + alloc_size_new =max (64UL ,roundup_pow_of_two (size_new ? :1 )); + +if (alloc_size_new > alloc_size_old) { +void *orig_buf = sec->data->d_buf; + + sec->data->d_buf =calloc (1 , alloc_size_new); +if (!sec->data->d_buf) { +ERROR_GLIBC ("calloc" ); +return NULL ; + } + +if (size_old) +memcpy (sec->data->d_buf, orig_buf, size_old); + +if (orig_buf && sec->data_owned) +free (orig_buf); + + sec->data_owned =1 ; + sec->data_overallocated =1 ; }if (data) -memcpy (sec->data->d_buf, data, size); - - sec->data->d_size = size; - sec->data->d_align = sec->sh.sh_addralign; - - offset =ALIGN (sec_size (sec), sec->sh.sh_addralign); - sec->sh.sh_size = offset + size; +memcpy (sec->data->d_buf + offset, data, size); +else +memset (sec->data->d_buf + offset,0 , size); + sec->data->d_size = size_new; + sec->sh.sh_size = size_new;mark_sec_changed (elf, sec, true); - -return sec->data->d_buf; +return sec->data->d_buf + offset; } struct section *elf_create_section(struct elf *elf, const char *name,
@@ -1496,6 +1518,8 @@ struct section *elf_create_section(struct elf *elf, const char *name,ERROR_GLIBC ("calloc" );return NULL ; } + + sec->data_owned =1 ; }if (!gelf_getshdr (s, &sec->sh)) {
@@ -1546,60 +1570,33 @@ static int elf_alloc_reloc(struct elf *elf, struct section *rsec)struct reloc *old_relocs, *old_relocs_end, *new_relocs;unsigned int nr_relocs_old =sec_num_entries (rsec);unsigned int nr_relocs_new = nr_relocs_old +1 ; -unsigned long nr_alloc; +unsigned long nr_alloc_old =0 , nr_alloc_new;struct symbol *sym; -if (!rsec->data) { - rsec->data =elf_newdata (elf_getscn (elf->elf, rsec->idx)); -if (!rsec->data) { -ERROR_ELF ("elf_newdata" ); -return -1 ; - } +if (!elf_add_data (elf, rsec,NULL ,elf_rela_size (elf))) +return -1 ; - rsec->data->d_align =1 ; - rsec->data->d_type =ELF_T_RELA ; - rsec->data->d_buf =NULL ; - } + rsec->data->d_type =ELF_T_RELA ; - rsec->data->d_size = nr_relocs_new *elf_rela_size (elf); - rsec->sh.sh_size = rsec->data->d_size; +if (rsec->relocs_overallocated) + nr_alloc_old =max (64UL ,roundup_pow_of_two (nr_relocs_old ? :1 )); +else + nr_alloc_old = nr_relocs_old; - nr_alloc =max (64UL ,roundup_pow_of_two (nr_relocs_new)); -if (nr_alloc <= rsec->nr_alloc_relocs) + nr_alloc_new =max (64UL ,roundup_pow_of_two (nr_relocs_new ? :1 )); + +if (nr_alloc_old == nr_alloc_new)return 0 ; -if (rsec->data->d_buf && !rsec->nr_alloc_relocs) { -void *orig_buf = rsec->data->d_buf; - -/* -* The original d_buf is owned by libelf so it can't be -* realloced. -*/ - rsec->data->d_buf =malloc (nr_alloc *elf_rela_size (elf)); -if (!rsec->data->d_buf) { -ERROR_GLIBC ("malloc" ); -return -1 ; - } -memcpy (rsec->data->d_buf, orig_buf, - nr_relocs_old *elf_rela_size (elf)); - }else { - rsec->data->d_buf =realloc (rsec->data->d_buf, - nr_alloc *elf_rela_size (elf)); -if (!rsec->data->d_buf) { -ERROR_GLIBC ("realloc" ); -return -1 ; - } - } - - rsec->nr_alloc_relocs = nr_alloc; - - old_relocs = rsec->relocs; - new_relocs =calloc (nr_alloc,sizeof (struct reloc )); + new_relocs =calloc (nr_alloc_new,sizeof (struct reloc ));if (!new_relocs) {ERROR_GLIBC ("calloc" );return -1 ; } + rsec->relocs_overallocated =1 ; + + old_relocs = rsec->relocs;if (!old_relocs) goto done;
@@ -1644,6 +1641,7 @@ static int elf_alloc_reloc(struct elf *elf, struct section *rsec) }free (old_relocs); + done: rsec->relocs = new_relocs;return 0 ;
@@ -1673,7 +1671,6 @@ struct section *elf_create_rela_section(struct elf *elf, struct section *sec,if (nr_relocs) { rsec->data->d_type =ELF_T_RELA ; - rsec->nr_alloc_relocs = nr_relocs; rsec->relocs =calloc (nr_relocs,sizeof (struct reloc ));if (!rsec->relocs) {ERROR_GLIBC ("calloc" );
tools/objtool/include/objtool/elf.h +11 -2
@@ -58,9 +58,18 @@ struct section {Elf_Data *data;const char *name;int idx; -bool _changed, text, rodata, noinstr, init, truncate; + u32 _changed : 1, + text : 1, + rodata : 1, + noinstr : 1, + init : 1, + truncate : 1, + data_owned : 1, + data_overallocated : 1, + relocs_overallocated : 1; +/* 23 bit hole */ +struct reloc *relocs; -unsigned long nr_alloc_relocs;struct section *twin; };
Signature · 1 line
2.54.0
Re: [PATCH v4 13/22] objtool: Refactor elf_add_data() to use a growable data buffer
Quoted 6 lines · Josh Poimboeuf
Instead of calling
elf_newdata()for each new piece of data with its own separate buffer, keep it all in the same growable buffer so the section's entire data can be accessed if needed.Signed-off-by Josh Poimboeuf <[email protected]>
Josh Poimboeuf
maintainerPATCH v4 14/22 objtool: Reuse string references
In reply to Josh PoimboeufFor duplicate strings, elf_add_string() just blindly adds duplicates.
That can be a problem for arm64 which often uses two consecutive instructions (and corresponding relocations) to put an address into a register, like:
d8: 90000001 adrp x1, 0 <meminfo_proc_show> d8: R_AARCH64_ADR_PREL_PG_HI21 .rodata.meminfo_proc_show.str1.8 dc: 91000021 add x1, x1, #0x0 dc: R_AARCH64_ADD_ABS_LO12_NC .rodata.meminfo_proc_show.str1.8
Referencing two different addresses in the ADRP+ADD pair would corrupt the memory access. Avoid that by detecting and reusing duplicates when cloning string relocs.
--- tools/objtool/elf.c | 29 +++++++++++++++++++++++------ tools/objtool/include/objtool/elf.h | 3 ++- tools/objtool/klp-diff.c | 4 +++- 3 files changed, 28 insertions(+), 8 deletions(-)
tools/objtool/elf.c +23 -6
@@ -1379,9 +1379,27 @@ struct elf *elf_create_file(GElf_Ehdr *ehdr, const char *name)return elf; } -unsigned int elf_add_string (struct elf *elf,struct section *strtab,const char *str) +int elf_find_string (struct elf *elf,struct section *strtab,const char *str) { -unsigned int offset; +char *d_buf; +int i; + +if (!strtab->data) +return -1 ; + + d_buf = strtab->data->d_buf; + +for (i =0 ; i < strtab->data->d_size; i +=strlen (d_buf + i) +1 ) { +if (!strcmp (d_buf + i, str)) +return i; + } + +return -1 ; +} + +int elf_add_string (struct elf *elf,struct section *strtab,const char *str) +{ +void *data;if (!strtab) strtab =find_section_by_name (elf,".strtab" );
@@ -1395,12 +1413,11 @@ unsigned int elf_add_string(struct elf *elf, struct section *strtab, const charreturn -1 ; } - offset =ALIGN (sec_size (strtab), strtab->sh.sh_addralign); - -if (!elf_add_data (elf, strtab, str,strlen (str) +1 )) + data =elf_add_data (elf, strtab, str,strlen (str) +1 ); +if (!data)return -1 ; -return offset; +return data - strtab->data->d_buf; }void *elf_add_data (struct elf *elf,struct section *sec,const void *data,size_t size)
tools/objtool/include/objtool/elf.h +2 -1
@@ -188,7 +188,8 @@ 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); -unsigned int elf_add_string (struct elf *elf,struct section *strtab,const char *str); +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); struct reloc *elf_create_reloc(struct elf *elf, struct section *sec, unsigned long offset, struct symbol *sym,
tools/objtool/klp-diff.c +3 -1
@@ -1543,7 +1543,9 @@ static int clone_reloc(struct elfs *e, struct reloc *patched_reloc,__dbg_clone ("\"%s\"" ,escape_str (str)); - addend =elf_add_string (e->out, out_sym->sec, str); + addend =elf_find_string (e->out, out_sym->sec, str); +if (addend ==-1 ) + addend =elf_add_string (e->out, out_sym->sec, str);if (addend ==-1 )return -1 ; }
Signature · 1 line
2.54.0
Re: [PATCH v4 14/22] objtool: Reuse string references
Quoted 7 lines · Josh Poimboeuf
For duplicate strings,
elf_add_string()just blindly adds duplicates.That can be a problem for arm64 which often uses two consecutive instructions (and corresponding relocations) to put an address into a register, like:
Quoted 8 lines
d8: 90000001 adrp x1, 0 <meminfo_proc_show> d8: R_AARCH64_ADR_PREL_PG_HI21 .rodata.meminfo_proc_show.str1.8 dc: 91000021 add x1, x1, #0x0 dc: R_AARCH64_ADD_ABS_LO12_NC .rodata.meminfo_proc_show.str1.8Referencing two different addresses in the ADRP+ADD pair would corrupt the memory access. Avoid that by detecting and reusing duplicates when cloning string relocs.
Signed-off-by Josh Poimboeuf <[email protected]>
With one nitpick below:
Quoted 11 lines
--- tools/objtool/elf.c | 29 +++++++++++++++++++++++------ tools/objtool/include/objtool/elf.h | 3 ++- tools/objtool/klp-diff.c | 4 +++- 3 files changed, 28 insertions(+), 8 deletions(-)tools/objtool/elf.c +0
-0
tools/objtool/elf.c struct elf *elf_create_file(GElf_Ehdr *ehdr, const char *name) · line 1383
Quoted 6 lines
tools/objtool/elf.c +1
-1@@ -1379,9 +1379,27 @@ struct elf *elf_create_file(GElf_Ehdr *ehdr, const char *name)return elf; } -unsigned int elf_add_string (struct elf *elf,struct section *strtab,const char *str) +int elf_find_string (struct elf *elf,struct section *strtab,const char *str) {
elf_find_string() returns -1 for error and positive number for addend. It is a good idea to add some comments for this behavior.
Thanks,
Song
[...]
Josh Poimboeuf
maintainerRe: [PATCH v4 14/22] objtool: Reuse string references
Quoted 6 lines · Song Liu
Review
Quoted 3 lines
(quoted diff) +1
-1-unsigned int elf_add_string(struct elf *elf, struct section *strtab, const char *str) +int elf_find_string(struct elf *elf, struct section *strtab, const char *str) {
elf_find_string()returns -1 for error and positive number for addend. It is a good idea to add some comments for this behavior.
Ok, will add a small comment above the function:
tools/objtool/elf.c +5 -0
@@ -1410,6 +1410,11 @@ int elf_find_string(struct elf *elf, struct section *strtab, const char *str)return -1 ; } +/* +* Add a static string to the strtab section. +* +* Returns positive string offset on success, -1 on error. +*/ int elf_add_string (struct elf *elf,struct section *strtab,const char *str) {void *data;
Josh Poimboeuf
maintainerPATCH v4 15/22 objtool: Prevent kCFI hashes from being decoded as instructions
In reply to Josh PoimboeufOn arm64 with CONFIG_CFI=y, Clang places a 4-byte kCFI type hash immediately before each address-taken function entry. Since these hashes are in the text section, objtool tries to decode them, leading to unpredictable results (e.g., ""unannotated intra-function call").
arm64 toolchains use mapping symbols to annotate boundaries between code and data. Use those to just mark such "instructions" as NOP so objtool ignores them.
--- tools/objtool/check.c | 14 ++++++++++++++ tools/objtool/include/objtool/elf.h | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+)
tools/objtool/check.c +14 -0
@@ -430,6 +430,8 @@ static int decode_instructions(struct objtool_file *file)for_each_sec (file->elf, sec) {struct instruction *insns =NULL ; +struct symbol *map_sym; +bool is_data = false;u8 prev_len =0 ;u8 idx =0 ;
@@ -456,6 +458,8 @@ static int decode_instructions(struct objtool_file *file)if (!strcmp (sec->name,".init.text" ) && !opts.module) sec->init = true; + map_sym = list_first_entry(&sec->symbol_list, struct symbol, list); +for (offset =0 ; offset <sec_size (sec); offset += insn->len) {if (!insns || idx ==INSN_CHUNK_MAX ) { insns =calloc (INSN_CHUNK_SIZE ,sizeof (*insn));
@@ -480,6 +484,16 @@ static int decode_instructions(struct objtool_file *file) prev_len = insn->len; +/* Use mapping symbols to skip data in text sections */ +sec_for_each_sym_from (sec, map_sym) { +if (map_sym->offset > offset) +break ; +if (is_mapping_sym (map_sym)) + is_data =is_data_mapping_sym (map_sym); + } +if (is_data) + insn->type =INSN_NOP ; +/* * By default, "ud2" is a dead end unless otherwise * annotated, because GCC 7 inserts it for certain
tools/objtool/include/objtool/elf.h +23 -0
@@ -296,6 +296,26 @@ static inline bool is_notype_sym(struct symbol *sym)return sym->type ==STT_NOTYPE ; } +/* +* ARM64 mapping symbols ($d, $x, $a, __pi_$d, etc) which mark transitions +* between code and data. +*/ +static inline bool is_mapping_sym (struct symbol *sym) +{ +return is_notype_sym (sym) &&strchr (sym->name,'$' ); +} + +static inline bool is_data_mapping_sym (struct symbol *sym) +{ +const char *dollar; + +if (!is_mapping_sym (sym)) +return false; + + dollar =strchr (sym->name,'$' ); +return dollar && dollar[1 ] =='d' ; +} +static inline bool is_global_sym (struct symbol *sym) {return sym->bind ==STB_GLOBAL ;
@@ -508,6 +528,9 @@ static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next)#define sec_for_each_sym (sec, sym) \ list_for_each_entry(sym, &sec->symbol_list, list) +#define sec_for_each_sym_from (sec, sym) \ + list_for_each_entry_from(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
Signature · 1 line
2.54.0
Song Liu
maintainerRe: [PATCH v4 15/22] objtool: Prevent kCFI hashes from being decoded as instructions
On Sat, Aug 8, 2026 at 4:18 PM Josh Poimboeuf <[email protected]> wrote:
[...]
Quoted 9 lines
tools/objtool/include/objtool/elf.h +8
-0+/* +* ARM64 mapping symbols ($d, $x, $a, __pi_$d, etc) which mark transitions +* between code and data. +*/ +static inline bool is_mapping_sym (struct symbol *sym) +{ +return is_notype_sym (sym) &&strchr (sym->name,'$' ); +}
tools/objtool/include/objtool/elf.h static inline bool is_notype_sym(struct symbol *sym) · line 316
Quoted 10 lines
tools/objtool/include/objtool/elf.h +10
-0+ +static inline bool is_data_mapping_sym (struct symbol *sym) +{ +const char *dollar; + +if (!is_mapping_sym (sym)) +return false; + + dollar =strchr (sym->name,'$' ); +return dollar && dollar[1 ] =='d' ;
nit: is_data_mapping_sym() calls strchr() twice. Maybe we can optimize it by eliminating a strchr()?
Thanks,
Song
Quoted 18 lines
tools/objtool/include/objtool/elf.h +5
-1+} +static inline bool is_global_sym (struct symbol *sym) {return sym->bind ==STB_GLOBAL ;@@ -508,6 +528,9 @@ static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next)#define sec_for_each_sym (sec, sym) \ list_for_each_entry(sym, &sec->symbol_list, list) +#define sec_for_each_sym_from (sec, sym) \ + list_for_each_entry_from(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 --2.54.0
Josh Poimboeuf
maintainerRe: [PATCH v4 15/22] objtool: Prevent kCFI hashes from being decoded as instructions
Quoted 16 lines · Song Liu
On Sat, Aug 8, 2026 at 4:18 PM Josh Poimboeuf <[email protected]> wrote:
[...]Quoted 14 lines
tools/objtool/include/objtool/elf.h +13
-0+/* +* ARM64 mapping symbols ($d, $x, $a, __pi_$d, etc) which mark transitions +* between code and data. +*/ +static inline bool is_mapping_sym (struct symbol *sym) +{ +return is_notype_sym (sym) &&strchr (sym->name,'$' ); +} + +static inline bool is_data_mapping_sym (struct symbol *sym) +{ +const char *dollar; +
Quoted 8 lines
tools/objtool/include/objtool/elf.h static inline bool is_notype_sym(struct symbol *sym) · line 316
Quoted 5 lines
tools/objtool/include/objtool/elf.h +5
-0+if (!is_mapping_sym (sym)) +return false; + + dollar =strchr (sym->name,'$' ); +return dollar && dollar[1 ] =='d' ;nit:
is_data_mapping_sym()callsstrchr()twice. Maybe we can optimize it by eliminating astrchr()?
I suppose it's a bit funky, but the compiler CSEs it, so it's harmless.
Signature · 1 line
Josh
Re: [PATCH v4 15/22] objtool: Prevent kCFI hashes from being decoded as instructions
Quoted 27 lines · Josh Poimboeuf
Quoted 16 lines · Song Liu
On Sat, Aug 8, 2026 at 4:18 PM Josh Poimboeuf <[email protected]> wrote:
[...]Quoted 14 lines
tools/objtool/include/objtool/elf.h +13
-0+/* +* ARM64 mapping symbols ($d, $x, $a, __pi_$d, etc) which mark transitions +* between code and data. +*/ +static inline bool is_mapping_sym (struct symbol *sym) +{ +return is_notype_sym (sym) &&strchr (sym->name,'$' ); +} + +static inline bool is_data_mapping_sym (struct symbol *sym) +{ +const char *dollar; +Quoted 8 lines
tools/objtool/include/objtool/elf.h static inline bool is_notype_sym(struct symbol *sym) · line 316
Quoted 5 lines
tools/objtool/include/objtool/elf.h +5
-0+if (!is_mapping_sym (sym)) +return false; + + dollar =strchr (sym->name,'$' ); +return dollar && dollar[1 ] =='d' ;nit:
is_data_mapping_sym()callsstrchr()twice. Maybe we can optimize it by eliminating astrchr()?
Quoted 1 line
I suppose it's a bit funky, but the compiler CSEs it, so it's harmless.
I see. Then this should be fine.
Thanks!
Josh Poimboeuf
maintainerPATCH v4 16/22 objtool/klp: Add arm64 support for prefix/PFE detection
In reply to Josh PoimboeufAdd arm64 support for detecting prefixed areas before functions (for kCFI or ftrace with call ops), and __patchable_function_entries (for ftrace with call ops or args).
--- tools/objtool/arch/x86/include/arch/elf.h | 2 + tools/objtool/elf.c | 13 ++ tools/objtool/include/objtool/elf.h | 2 + tools/objtool/klp-diff.c | 166 ++++++++++++++++++++-- 4 files changed, 172 insertions(+), 11 deletions(-)
tools/objtool/arch/x86/include/arch/elf.h +2 -0
@@ -10,4 +10,6 @@#define R_TEXT32 R_X86_64_PC32#define R_TEXT64 R_X86_64_PC32 +#define ARCH_HAS_PREFIX_SYMBOLS 1 +#endif /* _OBJTOOL_ARCH_ELF */
tools/objtool/elf.c +13 -0
@@ -275,6 +275,19 @@ struct symbol *find_func_containing(struct section *sec, unsigned long offset)return NULL ; } +struct symbol *find_data_mapping_sym (struct section *sec,unsigned long offset) +{ +struct rb_root_cached *tree = (struct rb_root_cached *)&sec->symbol_tree; +struct symbol *sym; + +__sym_for_each (sym, tree, offset, offset) { +if (sym->offset == offset &&is_data_mapping_sym (sym)) +return sym; + } + +return NULL ; +} +struct symbol *find_symbol_by_name (const struct elf *elf,const char *name) {struct symbol *sym;
tools/objtool/include/objtool/elf.h +2 -0
@@ -131,6 +131,7 @@ struct elf {struct list_head sections;struct list_head symbols;unsigned long num_relocs; +int pfe_offset;int symbol_bits;int symbol_name_bits;
@@ -230,6 +231,7 @@ struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsstruct reloc *find_reloc_by_dest_range (const struct elf *elf,struct section *sec,unsigned long offset,unsigned int len);struct symbol *find_func_containing (struct section *sec,unsigned long offset); +struct symbol *find_data_mapping_sym (struct section *sec,unsigned long offset);/* * Try to see if it's a whole archive (vmlinux.o or module).
tools/objtool/klp-diff.c +155 -11
257 lines not on this page · raw message
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 17/22 objtool/klp: Filter arm64 mapping symbols in find_symbol_by_offset()
In reply to Josh PoimboeufARM64 ELF objects contain $d/$x mapping symbols (STT_NOTYPE) at offset 0 in data/text sections. These aren't "real" symbols so filter them from find_symbol_by_offset(), consistent with the existing section symbol filter.
--- tools/objtool/elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/objtool/elf.c +1 -1
@@ -160,7 +160,7 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)struct symbol *sym;__sym_for_each (sym, tree, offset, offset) { -if (sym->offset == offset && !is_sec_sym (sym)) +if (sym->offset == offset && !is_sec_sym (sym) && !is_mapping_sym (sym))return sym->alias; }
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 18/22 objtool/klp: Don't correlate arm64 mapping symbols
In reply to Josh PoimboeufARM64 ELF files contain mapping symbols ($d, $x, $a, etc.) which mark transitions between code and data. There are thousands of them per object file, all sharing the same few names.
They aren't "real" symbols so there's no need to correlate them.
--- tools/objtool/klp-diff.c | 1 + 1 file changed, 1 insertion(+)
tools/objtool/klp-diff.c +1 -0
@@ -547,6 +547,7 @@ static bool dont_correlate(struct symbol *sym)is_prefix_func (sym) ||is_uncorrelated_static_local (sym) ||is_local_label (sym) || +is_mapping_sym (sym) ||is_string_sec (sym->sec) ||is_anonymous_rodata (sym) || is_initcall_sym(sym) ||
Signature · 1 line
2.54.0
Re: [PATCH v4 18/22] objtool/klp: Don't correlate arm64 mapping symbols
Quoted 8 lines · Josh Poimboeuf
ARM64 ELF files contain mapping symbols ($d, $x, $a, etc.) which mark transitions between code and data. There are thousands of them per object file, all sharing the same few names.
They aren't "real" symbols so there's no need to correlate them.
Signed-off-by Josh Poimboeuf <[email protected]>
Josh Poimboeuf
maintainerPATCH v4 19/22 objtool/klp: Clone inline alternative replacements
In reply to Josh PoimboeufUnlike 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.
--- 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(-)
tools/objtool/elf.c +5 -4
@@ -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 ;
tools/objtool/include/objtool/elf.h +5 -1
@@ -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
tools/objtool/klp-diff.c +46 -8
109 lines not on this page · raw message
tools/objtool/klp-symid.c +1 -1
@@ -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 ;
Signature · 1 line
2.54.0
Josh Poimboeuf
maintainerPATCH v4 20/22 objtool/klp: Introduce objtool for arm64
In reply to Josh PoimboeufAdd basic support for arm64 on objtool. Only "objtool klp" subcommands are currently supported.
--- arch/arm64/Kconfig | 2 + tools/objtool/Makefile | 4 + tools/objtool/arch/arm64/Build | 2 + tools/objtool/arch/arm64/decode.c | 177 ++++++++++++++++++ .../arch/arm64/include/arch/cfi_regs.h | 11 ++ tools/objtool/arch/arm64/include/arch/elf.h | 15 ++ .../objtool/arch/arm64/include/arch/special.h | 21 +++ tools/objtool/arch/arm64/special.c | 30 +++ 8 files changed, 262 insertions(+) create mode 100644 tools/objtool/arch/arm64/Build create mode 100644 tools/objtool/arch/arm64/decode.c create mode 100644 tools/objtool/arch/arm64/include/arch/cfi_regs.h create mode 100644 tools/objtool/arch/arm64/include/arch/elf.h create mode 100644 tools/objtool/arch/arm64/include/arch/special.h create mode 100644 tools/objtool/arch/arm64/special.c
arch/arm64/Kconfig +2 -0
@@ -209,9 +209,11 @@ config ARM64 select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_IOREMAP_PROT select HAVE_IRQ_TIME_ACCOUNTING + select HAVE_KLP_BUILD select HAVE_LIVEPATCH select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI + select HAVE_OBJTOOL select HAVE_PERF_EVENTS select HAVE_PERF_EVENTS_NMI if ARM64_PSEUDO_NMI select HAVE_PERF_REGS
tools/objtool/Makefile +4 -0
@@ -11,6 +11,10 @@ ifeq ($(SRCARCH),loongarch) BUILD_ORC := y endif +ifeq ($(SRCARCH),arm64) + ARCH_HAS_KLP := y +endif + ifeq ($(ARCH_HAS_KLP),y) HAVE_XXHASH = $(shell printf "$(pound)include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \ $(HOSTCC) $(HOSTCFLAGS) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n)
tools/objtool/arch/arm64/Build new file +2 -0
@@ -0,0 +1,2 @@ +objtool-y += decode.o +objtool-y += special.o
tools/objtool/arch/arm64/decode.c new file +177 -0
177 lines not on this page · raw message
tools/objtool/arch/arm64/include/arch/cfi_regs.h new file +11 -0
@@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _OBJTOOL_ARCH_CFI_REGS_H +#define _OBJTOOL_ARCH_CFI_REGS_H + +/* These aren't actually used for arm64 */ +#define CFI_BP 0 +#define CFI_SP 0 +#define CFI_RA 0 +#define CFI_NUM_REGS 2 + +#endif /* _OBJTOOL_ARCH_CFI_REGS_H */
tools/objtool/arch/arm64/include/arch/elf.h new file +15 -0
@@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _OBJTOOL_ARCH_ELF_H +#define _OBJTOOL_ARCH_ELF_H + +#define R_NONE R_AARCH64_NONE +#define R_ABS64 R_AARCH64_ABS64 +#define R_ABS32 R_AARCH64_ABS32 +#define R_DATA32 R_AARCH64_PREL32 +#define R_DATA64 R_AARCH64_PREL64 +#define R_TEXT32 R_AARCH64_PREL32 +#define R_TEXT64 R_AARCH64_PREL64 + +#define ARCH_HAS_INLINE_ALTS 1 + +#endif /* _OBJTOOL_ARCH_ELF_H */
tools/objtool/arch/arm64/include/arch/special.h new file +21 -0
@@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _OBJTOOL_ARCH_SPECIAL_H +#define _OBJTOOL_ARCH_SPECIAL_H + +#define EX_ENTRY_SIZE 12 +#define EX_ORIG_OFFSET 0 +#define EX_NEW_OFFSET 4 + +#define JUMP_ENTRY_SIZE 16 +#define JUMP_ORIG_OFFSET 0 +#define JUMP_NEW_OFFSET 4 +#define JUMP_KEY_OFFSET 8 + +#define ALT_ENTRY_SIZE 12 +#define ALT_ORIG_OFFSET 0 +#define ALT_NEW_OFFSET 4 +#define ALT_FEATURE_OFFSET 8 +#define ALT_ORIG_LEN_OFFSET 10 +#define ALT_NEW_LEN_OFFSET 11 + +#endif /* _OBJTOOL_ARCH_SPECIAL_H */
tools/objtool/arch/arm64/special.c new file +30 -0
@@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include <objtool/special.h> + +/* +* On arm64 a zero-length replacement means the alternative has a callback, +* whose address is stored in the replacement offset. It must be preserved. +*/ +bool arch_alt_ignore_new_reloc (struct section *sec,unsigned long offset) +{ +return false; +} + +bool arch_support_alt_relocation (struct special_alt *special_alt, +struct instruction *insn, +struct reloc *reloc) +{ +return true; +} + +struct reloc *arch_find_switch_table (struct objtool_file *file, +struct instruction *insn, +unsigned long *table_size) +{ +return NULL ; +} + +const char *arch_cpu_feature_name (int feature_number) +{ +return NULL ; +}
Signature · 1 line
2.54.0
Re: [PATCH v4 20/22] objtool/klp: Introduce objtool for arm64
Quoted 5 lines · Josh Poimboeuf
Add basic support for arm64 on objtool. Only "objtool klp" subcommands are currently supported.
Signed-off-by Josh Poimboeuf <[email protected]>
Josh Poimboeuf
maintainerPATCH v4 21/22 klp-build: Support cross-compilation
In reply to Josh PoimboeufAdd support for cross-compilation. The user must export ARCH, and either CROSS_COMPILE or LLVM as needed.
--- scripts/livepatch/klp-build | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
scripts/livepatch/klp-build +21 -1
@@ -435,6 +435,25 @@ validate_patches() { revert_patches } +cross_compile_init() { + if [[ -v LLVM && -n "$LLVM" ]]; then + local prefix="" + local suffix="" + + if [[ "$LLVM" == */ ]]; then + # LLVM=/path/to/bin/ + prefix="$LLVM" + elif [[ "$LLVM" == -* ]]; then + # LLVM=-14 + suffix="$LLVM" + fi + + OBJCOPY="${prefix}llvm-objcopy${suffix}" + else + OBJCOPY="${CROSS_COMPILE:-}objcopy" + fi +} + do_init() { # We're not yet smart enough to handle anything other than in-tree # builds in pwd.
@@ -465,6 +484,7 @@ do_init() { validate_config set_module_name set_kernelversion + cross_compile_init } # Refresh the patch hunk headers, specifically the line numbers and counts.
@@ -881,7 +901,7 @@ build_patch_module() { cp -f "$kmod_file" "$kmod_file.orig" # Work around issue where slight .config change makes corrupt BTF - objcopy --remove-section=.BTF "$kmod_file" + "$OBJCOPY" --remove-section=.BTF "$kmod_file" # Fix (and work around) linker wreckage for klp syms / relocs "$OBJTOOL" klp post-link "$kmod_file" || die "objtool klp post-link failed"
Signature · 1 line
2.54.0
Re: [PATCH v4 21/22] klp-build: Support cross-compilation
Quoted 5 lines · Josh Poimboeuf
Add support for cross-compilation. The user must export ARCH, and either
CROSS_COMPILEor LLVM as needed.Signed-off-by Josh Poimboeuf <[email protected]>
Josh Poimboeuf
maintainerPATCH v4 22/22 klp-build: Add arm64 syscall patching macro
In reply to Josh PoimboeufAdd arm64 support for KLP_SYSCALL_DEFINEx(), mirroring the arm64 __SYSCALL_DEFINEx() pattern from arch/arm64/include/asm/syscall_wrapper.h.
--- include/linux/livepatch_helpers.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
include/linux/livepatch_helpers.h +20 -0
@@ -72,6 +72,26 @@ } \ static inline long __klp_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) +#elif defined(CONFIG_ARM64 ) + +#define __KLP_SYSCALL_DEFINEx (x, name, ...) \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ + static inline long __klp_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + asmlinkage long __arm64_sys##name(const struct pt_regs *regs); \ + ALLOW_ERROR_INJECTION(__arm64_sys##name, ERRNO); \ + asmlinkage long __arm64_sys##name(const struct pt_regs *regs) \ + { \ + return __se_sys##name(SC_ARM64_REGS_TO_ARGS(x,__VA_ARGS__));\ + } \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ + { \ + long ret = __klp_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ + return ret; \ + } \ + static inline long __klp_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) +#endif #endif /* _LINUX_LIVEPATCH_HELPERS_H */
Signature · 1 line
2.54.0
Re: [PATCH v4 22/22] klp-build: Add arm64 syscall patching macro
Quoted 5 lines · Josh Poimboeuf
Add arm64 support for
KLP_SYSCALL_DEFINEx(), mirroring the arm64__SYSCALL_DEFINEx()pattern fromarch/arm64/include/asm/syscall_wrapper.h.Signed-off-by Josh Poimboeuf <[email protected]>