In application programming, static
variables are stored in .BSS
section. And unlike local variables they're not de allocated on function return or something similar to global variables.
In Linux kernel modules, functions can be tagged with __init
attribute in Linux and code in .text
of such functions will be removed, once they're executed.
Let's say there's a function with __init
and has static
local variables; Will those static
local's be de allocated from .BSS
section along with the function from .text
section?
Yes, of course there might not be any use (mention if you find one) of declaring a static
variable in an __init
function, but I want to understand behind the scenes.
If something is defined as static
, it must stay alive for the entire lifetime of the associated unit. The only thing that happens is that you will not be able to reference the object by its original name anywhere outside the function in which it was declared. Therefore, if you don't save a reference to the object somewhere else, the object will still be available, but you will have lost access to it (this could be considered a memory leak).
The only exception when talking about kernel code is the __initdata
macro, that will put variables in a specific section (.init.data
) and discard them when the initialization is done (just like .init
). In such case, the variable will be gone even if defined static
, and references will become invalid. This is useful if you need some kind of complex (and large) structure only for initialization purposes and you want to save space by discarding it after using it in your init function.
Here's a working example:
// SPDX-License-Identifier: GPL-3.0
#include <linux/init.h> // module_{init,exit}()
#include <linux/module.h> // THIS_MODULE, MODULE_VERSION, ...
#include <linux/kernel.h> // printk(), pr_*()
#ifdef pr_fmt
#undef pr_fmt
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
static unsigned *global_ptr;
static unsigned global_var;
static int global_initdata_var __initdata;
static int __init my_init(void)
{
static unsigned local_var = 123;
static unsigned local_initdata_var __initdata = 456;
global_ptr = &local_var;
global_var = local_initdata_var;
return global_initdata_var;
}
static void __exit my_exit(void)
{
pr_info("%u %u\n", *global_ptr , global_var);
}
module_init(my_init);
module_exit(my_exit);
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("Test module.");
MODULE_AUTHOR("Marco Bonelli");
MODULE_LICENSE("GPL");
Looking into the .ko
file with objdump
after compiling the above shows:
local_var
defined inside the init function in the .data
section (because it was explicitly initialized to 123
).local_initdata_var
and global_initdata_var
in the .init.data
section (because of __initdata
), regardless of where they were defined..bss
section./ # objdump -j .init.data -j .data -j .bss -D static_init.ko
static_init.ko: file format elf64-littleaarch64
Disassembly of section .data:
0000000000000000 <local_var.20642>:
0: 0000007b .word 0x0000007b
Disassembly of section .init.data:
0000000000000000 <local_initdata_var.20643>:
0: 000001c8 .word 0x000001c8
0000000000000004 <global_initdata_var>:
4: 00000000 .word 0x00000000
Disassembly of section .bss:
0000000000000000 <global_ptr>:
...
0000000000000008 <global_var>:
8: 00000000 .word 0x00000000
Result of inserting/removing the module:
/ # insmod static_init.ko
/ # cat /proc/kallsyms | grep static_init
ffff800011ad9768 b static_init_done.7337
ffff800008ca0000 t $x [static_init]
ffff800008ca0000 t my_exit [static_init]
ffff800008ca2000 d $d [static_init]
ffff800008ca2000 d local_var.20642 [static_init]
ffff800008ca2348 b $d [static_init]
ffff800008ca2348 b global_ptr [static_init]
ffff800008ca2350 b global_var [static_init]
ffff800008ca1028 r $d [static_init]
ffff800008ca2040 d $d [static_init]
ffff800008ca1040 r $d [static_init]
ffff800008ca1040 r _note_6 [static_init]
ffff800008ca2040 d __this_module [static_init]
ffff800008ca0000 t cleanup_module [static_init]
/ # rmmod static_init
[ 12.155152] static_init: 123 456
/ #
As you can see, local_var
is still there even after inserting the module, and is marked as d
(local data symbol), while variables defined with __initdata
(no matter where) are no longer there.