Issue
In Linux 5.4.21 source code, I put
#pragma GCC push_options
#pragma GCC optimize ("O0")
and
#pragma GCC pop_options
around the function static int __init gic_init_bases
in the file /drivers/irqchip/irq-gic-v3.c
.
When I build it, I get this warning message (section mismatch). I later found it is actually the #pragma GCC optimize ("O0")
line that is causing it.
CALL scripts/atomic/check-atomics.sh
CALL scripts/checksyscalls.sh
CHK include/generated/compile.h
CC arch/arm64/kernel/irq.o
CC arch/arm64/kernel/setup.o
CC drivers/irqchip/irq-gic-v3.o
AS arch/arm64/kernel/head.o
AR arch/arm64/kernel/built-in.a
AR arch/arm64/built-in.a
AR drivers/irqchip/built-in.a
AR drivers/built-in.a
GEN .version
CHK include/generated/compile.h
UPD include/generated/compile.h
CC init/version.o
AR init/built-in.a
LD vmlinux.o
MODPOST vmlinux.o
WARNING: vmlinux.o(.text+0x227cc0): Section mismatch in reference from the function gic_smp_init() to the function .init.text:set_smp_cross_call()
The function gic_smp_init() references
the function __init set_smp_cross_call().
This is often because gic_smp_init lacks a __init
annotation or the annotation of set_smp_cross_call is wrong.
MODINFO modules.builtin.modinfo
LD .tmp_vmlinux1
KSYM .tmp_kallsyms1.o
LD .tmp_vmlinux2
KSYM .tmp_kallsyms2.o
LD vmlinux
SORTEX vmlinux
SYSMAP System.map
OBJCOPY arch/arm64/boot/Image
Function call chain is like this: gic_init_bases -> gic_smp_init() -> set_smp_cross_call
(currently CONFIG_SMP=y
). The message seems to say set_smp_cross_call
is annotated with __init
(meaning it is placed in .init.text
), but gic_smp_init
is not.
Without the #pragma
debug setting, there was not warning of this kind. I'm not sure if I can just add add __init
to gic_smp_init()
(or remove _init
from set_smp_cross_call
). What is the correct method to fix it?
If I add __init
to gic_smp_init
, this warning goes away, but I think this will make the function be removed after initialization (which is ok maybe?).
Solution
TL;DR: gic_smp_init()
should be annotated with __init
.
Update: this was fixed in kernel v5.8, here's the relevant commit.
Looks to me like you found a bug: gic_smp_init()
is only called by __init gic_init_bases()
, so it has no real reason to not be annotated with __init
too. The function set_smp_cross_call()
is annotated with __init
, so callers should also be annotated with __init
.
If you compile with optimizations (without the pragma) this inconsistency disappears because the compiler simply inlines the entire body of gic_smp_init()
into gic_init_bases()
: the call chain is then just gic_init_bases -> set_smp_cross_call
and everything is fine since they are both annotated __init
. However, when you disable optimizations (#pragma GCC optimize ("O0")
) the compiler no longer inlines the call to gic_smp_init()
, which stays on its own as an actual function, and the inconsistency reveals itself.
The authors of the module probably missed the __init
annotation of set_smp_cross_call()
, or the annotation was added later and nobody noticed it also needed to be "propagated" in that driver code.
There also seems to be an inconsistency between the annotations for set_smp_cross_call()
: in the C files (/arch/{arm,arm64}/kernel/smp.c
) it is annotated with __init
, while in the header files (/arch/{arm,arm64}/include/asm/smp.h
) it is not. The latter instances should probably be annotated too as the doc-comment for the __init
macro suggests:
* If the function has a prototype somewhere, you can also add
* __init between closing brace of the prototype and semicolon:
*
* extern int initialize_foobar_device(int, int, int) __init;
Answered By - Marco Bonelli Answer Checked By - Willingham (WPSolving Volunteer)