- 一是静态编译连接进内核,在系统启动过程中进行初始化;
加载至 initcall6.init 段
- 一是编译成可动态加载的module,通过insmod动态加载重定位到内核。
加载至.gnu.linkonce.this_module段
- 这两种方式可以在Makefile中通过obj-y或obj-m选项进行选择。
- 如果函数的定义中带有__init,那么这个函数的所有代码会被放入.init.text的section中。
- 如果函数的定义中带有__initdata,那么这个函数的所有代码会被放入.init.data的section中。
/* These are for everybody 这是给每一个的.(尽管不是所有的arch会在模块中抛弃它)
(although not all archs will actually discard it in modules) */
#define __init __section(.init.text) __cold notrace
#define __initdata __section(.init.data)
#define __initconst __constsection(.init.rodata)
#define __exitdata __section(.exit.data)
#define __exit_call __used __section(.exitcall.exit)
/*
* Some architecture have tool chains which do not handle rodata attributes
* correctly. For those disable special sections for const, so that other
* architectures can annotate correctly.
*/
#ifdef CONFIG_BROKEN_RODATA
#define __constsection(x)
#else
#define __constsection(x) __section(x)
#endif
/*
* modpost check for section mismatches during the kernel build.
* A section mismatch happens when there are references from a
* code or data section to an init section (both code or data).
* The init sections are (for most archs) discarded by the kernel
* when early init has completed so all such references are potential bugs.
* For exit sections the same issue exists.
*
* The following markers are used for the cases where the reference to
* the *init / *exit section (code or data) is valid and will teach
* modpost not to issue a warning. Intended semantics is that a code or
* data tagged __ref* can reference code or data from init section without
* producing a warning (of course, no warning does not mean code is
* correct, so optimally document why the __ref is needed and why it's OK).
*
* The markers follow same syntax rules as __init / __initdata.
*/
#define __ref __section(.ref.text) noinline
#define __refdata __section(.ref.data)
#define __refconst __constsection(.ref.rodata)
/* compatibility defines */
#define __init_refok __ref
#define __initdata_refok __refdata
#define __exit_refok __ref
#ifdef MODULE
#define __exitused
#else
#define __exitused __used
#endif
#define __exit __section(.exit.text) __exitused __cold notrace
/* Used for MEMORY_HOTPLUG */
#define __meminit __section(.meminit.text) __cold notrace
#define __meminitdata __section(.meminit.data)
#define __meminitconst __constsection(.meminit.rodata)
#define __memexit __section(.memexit.text) __exitused __cold notrace
#define __memexitdata __section(.memexit.data)
#define __memexitconst __constsection(.memexit.rodata)
/* For assembly routines 汇编语言 */
#define __HEAD .section ".head.text","ax"
#define __INIT .section ".init.text","ax"
#define __FINIT .previous
#define __INITDATA .section ".init.data","aw",%progbits
#define __INITRODATA .section ".init.rodata","a",%progbits
#define __FINITDATA .previous
#define __MEMINIT .section ".meminit.text", "ax"
#define __MEMINITDATA .section ".meminit.data", "aw"
#define __MEMINITRODATA .section ".meminit.rodata", "a"
/* silence warnings when references are OK */
#define __REF .section ".ref.text", "ax"
#define __REFDATA .section ".ref.data", "aw"
#define __REFCONST .section ".ref.rodata", "a"
大多是和section相关的定义,这个段定义什么作用呢,它是为了告诉链接器应该把这个函数或者数据放置在哪个位置。一般是指放置到内核镜像的哪个位置上。内核相当于一个非常大的可执行程序,它里面包含了好多内容,我们按照分段的原则来存放这些内容。具体段的存放规则是由vmlinux.lds文件定义,它是负责把段信息告诉链接器的,当然我们也要在代码中声明属于哪个段。
通常编译器将函数放在.text 节,变量放在.data 或 .bss 节,使用 section 属性,可以让编译器将函数或变量放在指定的节中。那么例如:前面对__init 的定义便表示将它修饰的代码放在.init.text节。内核把段分的非常细致,是因为它会在运行过程中去定位相应的数据和代码,这样将更加方便处理。就像__init 修饰的所有代码都放在.init.text段,它只在启动阶段会被内核调用到,当初始化结束后就会释放这部分内存,以便充分利用内存,这个就是属于内存管理的部分了。
/* Simple shorthand for a section definition 区段定义的简单速记*/
#ifndef __section
# define __section(S) __attribute__ ((__section__(#S)))
#endif