Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86: Handle KCOV __init vs inline mismatches

GCC appears to have kind of fragile inlining heuristics, in the
sense that it can change whether or not it inlines something based on
optimizations. It looks like the kcov instrumentation being added (or in
this case, removed) from a function changes the optimization results,
and some functions marked "inline" are _not_ inlined. In that case,
we end up with __init code calling a function not marked __init, and we
get the build warnings I'm trying to eliminate in the coming patch that
adds __no_sanitize_coverage to __init functions:

WARNING: modpost: vmlinux: section mismatch in reference: xbc_exit+0x8 (section: .text.unlikely) -> _xbc_exit (section: .init.text)
WARNING: modpost: vmlinux: section mismatch in reference: real_mode_size_needed+0x15 (section: .text.unlikely) -> real_mode_blob_end (section: .init.data)
WARNING: modpost: vmlinux: section mismatch in reference: __set_percpu_decrypted+0x16 (section: .text.unlikely) -> early_set_memory_decrypted (section: .init.text)
WARNING: modpost: vmlinux: section mismatch in reference: memblock_alloc_from+0x26 (section: .text.unlikely) -> memblock_alloc_try_nid (section: .init.text)
WARNING: modpost: vmlinux: section mismatch in reference: acpi_arch_set_root_pointer+0xc (section: .text.unlikely) -> x86_init (section: .init.data)
WARNING: modpost: vmlinux: section mismatch in reference: acpi_arch_get_root_pointer+0x8 (section: .text.unlikely) -> x86_init (section: .init.data)
WARNING: modpost: vmlinux: section mismatch in reference: efi_config_table_is_usable+0x16 (section: .text.unlikely) -> xen_efi_config_table_is_usable (section: .init.text)

This problem is somewhat fragile (though using either __always_inline
or __init will deterministically solve it), but we've tripped over
this before with GCC and the solution has usually been to just use
__always_inline and move on.

For x86 this means forcing several functions to be inline with
__always_inline.

Link: https://lore.kernel.org/r/20250724055029.3623499-2-kees@kernel.org
Signed-off-by: Kees Cook <kees@kernel.org>

Kees Cook 8245d47c 65c43090

+13 -13
+2 -2
arch/x86/include/asm/acpi.h
··· 158 158 } 159 159 160 160 #define ACPI_HAVE_ARCH_SET_ROOT_POINTER 161 - static inline void acpi_arch_set_root_pointer(u64 addr) 161 + static __always_inline void acpi_arch_set_root_pointer(u64 addr) 162 162 { 163 163 x86_init.acpi.set_root_pointer(addr); 164 164 } 165 165 166 166 #define ACPI_HAVE_ARCH_GET_ROOT_POINTER 167 - static inline u64 acpi_arch_get_root_pointer(void) 167 + static __always_inline u64 acpi_arch_get_root_pointer(void) 168 168 { 169 169 return x86_init.acpi.get_root_pointer(); 170 170 }
+1 -1
arch/x86/include/asm/realmode.h
··· 78 78 extern unsigned char secondary_startup_64_no_verify[]; 79 79 #endif 80 80 81 - static inline size_t real_mode_size_needed(void) 81 + static __always_inline size_t real_mode_size_needed(void) 82 82 { 83 83 if (real_mode_header) 84 84 return 0; /* already allocated. */
+1 -1
arch/x86/kernel/kvm.c
··· 420 420 return steal; 421 421 } 422 422 423 - static inline void __set_percpu_decrypted(void *ptr, unsigned long size) 423 + static inline __init void __set_percpu_decrypted(void *ptr, unsigned long size) 424 424 { 425 425 early_set_memory_decrypted((unsigned long) ptr, size); 426 426 }
+1 -1
arch/x86/mm/init_64.c
··· 806 806 } 807 807 808 808 #ifndef CONFIG_NUMA 809 - static inline void x86_numa_init(void) 809 + static __always_inline void x86_numa_init(void) 810 810 { 811 811 memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0); 812 812 }
+2 -2
include/linux/acpi.h
··· 759 759 #endif 760 760 761 761 #ifndef ACPI_HAVE_ARCH_SET_ROOT_POINTER 762 - static inline void acpi_arch_set_root_pointer(u64 addr) 762 + static __always_inline void acpi_arch_set_root_pointer(u64 addr) 763 763 { 764 764 } 765 765 #endif 766 766 767 767 #ifndef ACPI_HAVE_ARCH_GET_ROOT_POINTER 768 - static inline u64 acpi_arch_get_root_pointer(void) 768 + static __always_inline u64 acpi_arch_get_root_pointer(void) 769 769 { 770 770 return 0; 771 771 }
+1 -1
include/linux/bootconfig.h
··· 290 290 /* XBC cleanup data structures */ 291 291 void __init _xbc_exit(bool early); 292 292 293 - static inline void xbc_exit(void) 293 + static __always_inline void xbc_exit(void) 294 294 { 295 295 _xbc_exit(false); 296 296 }
+1 -1
include/linux/efi.h
··· 1334 1334 1335 1335 bool xen_efi_config_table_is_usable(const efi_guid_t *guid, unsigned long table); 1336 1336 1337 - static inline 1337 + static __always_inline 1338 1338 bool efi_config_table_is_usable(const efi_guid_t *guid, unsigned long table) 1339 1339 { 1340 1340 if (!IS_ENABLED(CONFIG_XEN_EFI))
+1 -1
include/linux/memblock.h
··· 463 463 NUMA_NO_NODE); 464 464 } 465 465 466 - static inline void *memblock_alloc_from(phys_addr_t size, 466 + static __always_inline void *memblock_alloc_from(phys_addr_t size, 467 467 phys_addr_t align, 468 468 phys_addr_t min_addr) 469 469 {
+1 -1
include/linux/smp.h
··· 221 221 222 222 #ifdef CONFIG_UP_LATE_INIT 223 223 extern void __init up_late_init(void); 224 - static inline void smp_init(void) { up_late_init(); } 224 + static __always_inline void smp_init(void) { up_late_init(); } 225 225 #else 226 226 static inline void smp_init(void) { } 227 227 #endif
+2 -2
kernel/kexec_handover.c
··· 305 305 return -ENOMEM; 306 306 } 307 307 308 - static void deserialize_bitmap(unsigned int order, 309 - struct khoser_mem_bitmap_ptr *elm) 308 + static void __init deserialize_bitmap(unsigned int order, 309 + struct khoser_mem_bitmap_ptr *elm) 310 310 { 311 311 struct kho_mem_phys_bits *bitmap = KHOSER_LOAD_PTR(elm->bitmap); 312 312 unsigned long bit;