__init函数中的本地静态标识符会发生什么情况



在应用程序编程中,static存储在.BSS部分。与局部变量不同,它们不会在函数返回或类似于全局变量的情况下被取消分配。


在Linux中,函数可以标记为__init属性,并且这些函数的.text中的代码将被删除,一旦执行


假设有一个函数具有__init,并且具有static局部变量;这些static本地的会和.text部分的函数一起从.BSS部分中取消分配吗

是的,当然,在__init函数中声明static变量可能没有任何用处,但我想了解幕后情况。

如果某个东西被定义为static,它必须在相关单元的整个生命周期内保持活动。唯一会发生的事情是,您将无法在声明对象的函数之外的任何位置通过其原始名称引用对象。因此,如果您不将对该对象的引用保存到其他地方,该对象仍然可用,但您将失去对它的访问权限(这可能被视为内存泄漏(。

当谈到内核代码时,唯一的例外是__initdata宏,它将把变量放在特定的部分(.init.data(中,并在初始化完成时丢弃它们(就像.init一样(。在这种情况下,即使定义了static,变量也将消失,并且引用将变为无效。如果您只出于初始化目的而需要某种复杂(大型(结构,并且您希望在init函数中使用它后丢弃它来节省空间,那么这将非常有用。

下面是一个工作示例:

// 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 %un", *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");

编译以上内容后,使用objdump查看.ko文件显示:

  • local_var.data部分的init函数中定义(因为它被显式初始化为123(
  • .init.data部分中的local_initdata_var global_initdata_var(因为__initdata(,而不管它们在哪里定义
  • .bss部分中的全局非显式初始化变量
/ # 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

插入/移除模块的结果:

/ # 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
/ #

正如您所看到的,即使在插入模块之后,local_var仍然存在,并且被标记为d(本地数据符号(,而用__initdata定义的变量(无论在哪里(不再存在。

相关内容

最新更新