]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
x86: Handle KCOV __init vs inline mismatches
authorKees Cook <kees@kernel.org>
Thu, 24 Jul 2025 05:50:26 +0000 (22:50 -0700)
committerKees Cook <kees@kernel.org>
Thu, 24 Jul 2025 23:55:11 +0000 (16:55 -0700)
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>
arch/x86/include/asm/acpi.h
arch/x86/include/asm/realmode.h
arch/x86/kernel/kvm.c
arch/x86/mm/init_64.c
include/linux/acpi.h
include/linux/bootconfig.h
include/linux/efi.h
include/linux/memblock.h
include/linux/smp.h
kernel/kexec_handover.c

index 5ab1a4598d00bc2d5534cda504c397d6d2f046a1..a03aa6f999d1587a15273e871e5f9e72c2d7d8d4 100644 (file)
@@ -158,13 +158,13 @@ static inline bool acpi_has_cpu_in_madt(void)
 }
 
 #define ACPI_HAVE_ARCH_SET_ROOT_POINTER
-static inline void acpi_arch_set_root_pointer(u64 addr)
+static __always_inline void acpi_arch_set_root_pointer(u64 addr)
 {
        x86_init.acpi.set_root_pointer(addr);
 }
 
 #define ACPI_HAVE_ARCH_GET_ROOT_POINTER
-static inline u64 acpi_arch_get_root_pointer(void)
+static __always_inline u64 acpi_arch_get_root_pointer(void)
 {
        return x86_init.acpi.get_root_pointer();
 }
index f607081a022abe433b9b65132ec10ccaa11f3f96..e406a1e92c6301b38908dc1419169bb5848df0be 100644 (file)
@@ -78,7 +78,7 @@ extern unsigned char secondary_startup_64[];
 extern unsigned char secondary_startup_64_no_verify[];
 #endif
 
-static inline size_t real_mode_size_needed(void)
+static __always_inline size_t real_mode_size_needed(void)
 {
        if (real_mode_header)
                return 0;       /* already allocated. */
index 921c1c783bc187dd3a239bf0c1e0e0f45695586c..8ae750cde0c6576aac08e89aad60dd9b3fd3a210 100644 (file)
@@ -420,7 +420,7 @@ static u64 kvm_steal_clock(int cpu)
        return steal;
 }
 
-static inline void __set_percpu_decrypted(void *ptr, unsigned long size)
+static inline __init void __set_percpu_decrypted(void *ptr, unsigned long size)
 {
        early_set_memory_decrypted((unsigned long) ptr, size);
 }
index ee66fae9ebcc34a5c75a7bbad7c8fed04d0bf153..c02029cd27e1ba8d32c633a360062f72062eb2be 100644 (file)
@@ -806,7 +806,7 @@ kernel_physical_mapping_change(unsigned long paddr_start,
 }
 
 #ifndef CONFIG_NUMA
-static inline void x86_numa_init(void)
+static __always_inline void x86_numa_init(void)
 {
        memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
 }
index f102c0fe34318fd4070d9c9d10ecdc897d3ad8b9..fc7f5e0390745f9f833c5f70b7ed04842c91dafd 100644 (file)
@@ -759,13 +759,13 @@ int acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem, int *timer_count)
 #endif
 
 #ifndef ACPI_HAVE_ARCH_SET_ROOT_POINTER
-static inline void acpi_arch_set_root_pointer(u64 addr)
+static __always_inline void acpi_arch_set_root_pointer(u64 addr)
 {
 }
 #endif
 
 #ifndef ACPI_HAVE_ARCH_GET_ROOT_POINTER
-static inline u64 acpi_arch_get_root_pointer(void)
+static __always_inline u64 acpi_arch_get_root_pointer(void)
 {
        return 0;
 }
index 3f4b4ac527ca28c66119cf00fc13083633ec80a3..25df9260d206da38063c6343514f99b78d6b9e7e 100644 (file)
@@ -290,7 +290,7 @@ int __init xbc_get_info(int *node_size, size_t *data_size);
 /* XBC cleanup data structures */
 void __init _xbc_exit(bool early);
 
-static inline void xbc_exit(void)
+static __always_inline void xbc_exit(void)
 {
        _xbc_exit(false);
 }
index 7d63d1d75f22f20bccdcb82c8aaac967eba35870..e3776d9cad07105cba14e700b5c63ffb577b6101 100644 (file)
@@ -1334,7 +1334,7 @@ struct linux_efi_initrd {
 
 bool xen_efi_config_table_is_usable(const efi_guid_t *guid, unsigned long table);
 
-static inline
+static __always_inline
 bool efi_config_table_is_usable(const efi_guid_t *guid, unsigned long table)
 {
        if (!IS_ENABLED(CONFIG_XEN_EFI))
index bb19a253422466a0dba838876409fc051e9a8da4..b96746376e17886cacd3250ecebd09b7243b2687 100644 (file)
@@ -463,7 +463,7 @@ static inline void *memblock_alloc_raw(phys_addr_t size,
                                          NUMA_NO_NODE);
 }
 
-static inline void *memblock_alloc_from(phys_addr_t size,
+static __always_inline void *memblock_alloc_from(phys_addr_t size,
                                                phys_addr_t align,
                                                phys_addr_t min_addr)
 {
index f1aa0952e8c30b47b58ffcda4757d137c1790342..84e948eb1c20f63bcd183089d1eeb5bb6fce552d 100644 (file)
@@ -221,7 +221,7 @@ static inline void wake_up_all_idle_cpus(void) {  }
 
 #ifdef CONFIG_UP_LATE_INIT
 extern void __init up_late_init(void);
-static inline void smp_init(void) { up_late_init(); }
+static __always_inline void smp_init(void) { up_late_init(); }
 #else
 static inline void smp_init(void) { }
 #endif
index 69b953551677c81930c798c4983b514691d33cfa..f3f6bfe43d476e059751198d3e5ca883aeb216ec 100644 (file)
@@ -305,8 +305,8 @@ err_free:
        return -ENOMEM;
 }
 
-static void deserialize_bitmap(unsigned int order,
-                              struct khoser_mem_bitmap_ptr *elm)
+static void __init deserialize_bitmap(unsigned int order,
+                                     struct khoser_mem_bitmap_ptr *elm)
 {
        struct kho_mem_phys_bits *bitmap = KHOSER_LOAD_PTR(elm->bitmap);
        unsigned long bit;