使用宏 *__init* 作为前缀的函数会发生什么?
What happens with functions using macro *__init* as prefix?
根据我在 Linux OS 中阅读的有关模块初始化的信息,我了解到具有 [=18 这样的前缀的函数调用=]__init 将被放置在单个 ELF 位置。
比如我们通常这样写:
int __init module_start()
{
....
}
以便在初始化结束后可以覆盖或删除特定的 ELF 位置(如果是这样的话)?如果我们想再次使用初始化,或者如果我想重新初始化任何模块,在知道初始化例程已被删除的情况下,采用什么方法?
__init
是一个 Linux 内核宏,它有点类似于普通的 gcc __attribute__(constructor)
,还有一个额外的特点,它也被解释为一个提示,代码可以是一旦它有 运行 就被释放(仅限模块,平台相关)。在 "normal" gcc/glibc C 程序中,libc 负责调用任何 init(和 fini)函数,在内核中您需要显式使用 module_init()
(和 module_exit()
)。
来自 include/linux/init.h
:
/* These macros are used to mark some functions or
* initialized data (doesn't apply to uninitialized data)
* as `initialization' functions. The kernel can take this
* as hint that the function is used only during the initialization
* phase and free up used memory resources after
[...]
#define __init __section(.init.text) __cold notrace
有类似的宏来标记退出函数和数据。这些是 compiler/linker 说明:
__section()
将代码放在 .init.text
部分(抛弃)
__cold
指示编译器(通过 __attribute__()
不 优化调用路径,因为该函数很少被调用(一次!)
notrace
以防止 ftrace 可能出现的问题
重新调用模块初始化的一种简单方法是卸载并重新加载模块(有时对于使设备松开很有用)。
如果初始化例程的某些部分在 运行 时可能有用,则可以将它们放在标记为 __init
的 not 函数中,并且从真正的初始化中调用
功能。您可以用 __init
标记多个函数,但在 module_init()
中也必须只使用一个函数,否则您的代码不应调用此类函数。要点是模块初始化代码与设置内核 API 和初始化任何硬件或非硬件驱动程序功能一样重要(我猜这是你遇到的问题)。
另请参阅:
- http://lwn.net/Kernel/LDD3/(免费 600 多页 PDF,略有过时但未过时)第 2 章中的 "hello world" 模块涵盖了您必须了解的基础知识
- What does __init mean in the Linux kernel code?
根据我在 Linux OS 中阅读的有关模块初始化的信息,我了解到具有 [=18 这样的前缀的函数调用=]__init 将被放置在单个 ELF 位置。
比如我们通常这样写:
int __init module_start()
{
....
}
以便在初始化结束后可以覆盖或删除特定的 ELF 位置(如果是这样的话)?如果我们想再次使用初始化,或者如果我想重新初始化任何模块,在知道初始化例程已被删除的情况下,采用什么方法?
__init
是一个 Linux 内核宏,它有点类似于普通的 gcc __attribute__(constructor)
,还有一个额外的特点,它也被解释为一个提示,代码可以是一旦它有 运行 就被释放(仅限模块,平台相关)。在 "normal" gcc/glibc C 程序中,libc 负责调用任何 init(和 fini)函数,在内核中您需要显式使用 module_init()
(和 module_exit()
)。
来自 include/linux/init.h
:
/* These macros are used to mark some functions or
* initialized data (doesn't apply to uninitialized data)
* as `initialization' functions. The kernel can take this
* as hint that the function is used only during the initialization
* phase and free up used memory resources after
[...]
#define __init __section(.init.text) __cold notrace
有类似的宏来标记退出函数和数据。这些是 compiler/linker 说明:
__section()
将代码放在.init.text
部分(抛弃)__cold
指示编译器(通过__attribute__()
不 优化调用路径,因为该函数很少被调用(一次!)notrace
以防止 ftrace 可能出现的问题
重新调用模块初始化的一种简单方法是卸载并重新加载模块(有时对于使设备松开很有用)。
如果初始化例程的某些部分在 运行 时可能有用,则可以将它们放在标记为 __init
的 not 函数中,并且从真正的初始化中调用
功能。您可以用 __init
标记多个函数,但在 module_init()
中也必须只使用一个函数,否则您的代码不应调用此类函数。要点是模块初始化代码与设置内核 API 和初始化任何硬件或非硬件驱动程序功能一样重要(我猜这是你遇到的问题)。
另请参阅:
- http://lwn.net/Kernel/LDD3/(免费 600 多页 PDF,略有过时但未过时)第 2 章中的 "hello world" 模块涵盖了您必须了解的基础知识
- What does __init mean in the Linux kernel code?