在看android AOSP时看到这样一行代码
unsigned int __atags_pointer __initdata
__atags_pointer是Uboot传递给kernel的设备树首地址
这里定义了一个无符号整形,将用到它表示一个地址,但是后面__initdata代表什么呢?
引用内核中的宏定义__init,__initdata,_exitdata程序猿Ricky的日常干货的博客-CSDN博客
在linux内核中,我们经常会使用到一些宏定义,比如__init,__initdata,__exitdata等等。那么这些宏定义到底什么意思呢?接下来我们就来看一下。
kernel/include/linux/init.h:
我们来选择一些常用的宏定义,在路径:/vendor/nxp-opensource/kernel_imx/include/linux/init.h下,有如下代码:
50 #define __init __section(".init.text") __cold __latent_entropy __noinitretpoline __nocfi
51 #define __initdata __section(".init.data")
52 #define __initconst __section(".init.rodata")
53 #define __exitdata __section(".exit.data")
54 #define __exit_call __used __section(".exitcall.exit")
我们可以看到大多是和section相关的定义,这个段定义什么作用呢,它是为了告诉链接器应该把这个函数或者数据放置在哪个位置。一般是指放置到内核镜像的哪个位置上。内核相当于一个非常大的可执行程序,它里面包含了好多内容,我们按照分段的原则来存放这些内容。具体段的存放规则是由vmlinux.lds文件定义,它是负责把段信息告诉链接器的,当然我们也要在代码中声明属于哪个段。
通常编译器将函数放在.text 节,变量放在.data 或 .bss 节,使用 section 属性,可以让编译器将函数或变量放在指定的节中。那么例如:前面对__init 的定义便表示将它修饰的代码放在.init.text节。内核把段分的非常细致,是因为它会在运行过程中去定位相应的数据和代码,这样将更加方便处理。就像__init 修饰的所有代码都放在.init.text段,它只在启动阶段会被内核调用到,当初始化结束后就会释放这部分内存,以便充分利用内存,这个就是属于内存管理的部分了。
C代码中一般是按照这种规则来传递段信息的
__attribute__((section("section_name")))
可是上面的定义并不是如此,其实__section也是一个宏定义,我们在/vendor/nxp-opensource/kernel_imx/include/linux/compiler_attributes.h下可以看到
267 #define __section(section) __attribute__((__section__(section)))
至于汇编代码我们就都很清楚了,直接使用.section即可。