SECTIONS
{. = 0x10000;
.text : { *(.text) }
. = 0x8000000;
.data : { *(.data) }
.bss : { *(.bss) }
} SECTIONS是LS语法中的关键command,它用来描述输出文件的内存布局。例如上例中就含text/data/bss三个部分(实际上text/data/bss才是段,但是SECTIONS这个词在LS中是一个command,希望各位看官要明白)。 .=0x10000; 其中的.非常关键,它代表location counter(LC)。意思是.text段的开始设置在0x10000处。这个LC应该指的是LMA,但大多数情况下VMA=LMA。 .text:{*(.text)},这个表示输出文件的.text段内容由所有输入文件(*)的.text段组成。组成顺序就是ld命令中输入文件的顺序,例如1.obj,2.obj...... 此后,由来了一个.=0x800000000;。如果没有这个赋值的,那么LC应该等于0x10000+sizeof(text段),即LC如果不强制指定的话,它默认就是上一次的LC+中间section的长度。还好,这里强制指定LC=0X800000000.表明后面的.data段的开始位于这个地址。 .data和后面的.bss表示分别有输入文件的.data和.bss段构成。
你看,我们从这个LC文件中学到了什么?
恩,我们可以任意设置各个段的LMA值。当然,绝大部分情况,我们不需要有自己的LS来控制输出文件的内存布局。不过LK(linux kernel)可不一样了......
四 霸王硬上弓---vmlinux.lds.S分析
OK,有了上面的基础知识,下面我们霸王硬上弓,直接分析arch/arm/kernel/vmlinux.lds.S.虽然最终链接用的是vmlinux.lds,但是那个文件
由vmlinux.lds.S(这是一个汇编文件)得到,
arm-linux-gcc -E -Wp,-MD,arch/arm/kernel/.vmlinux.lds.d -nostdinc ...... -D__KERNEL__ -mlittle-endian ......
-DTEXT_OFFSET=0x00008000 -P -C -Uarm -D__ASSEMBLY__ -o arch/arm/kernel/vmlinux.lds arch/arm/kernel/vmlinux.lds.S
所以,我们直接分析vmlinux.lds好了。
/*
一堆注释,这里就不再贴上了,另外,增加//号做为注释标识
* Convert a physical address to a Page Frame Number and back
*/
//OUTPUT_ARCH是LS语法中的COMMAND,用来指定输出文件的machine arch。objdump -f可查询所有支持的machine。另外
//这些东西涉及到一种叫BFD的。各位看官可以自己搜索下BFD的内容。
//下面这 表示输出文件基于ARM架构
OUTPUT_ARCH(arm)
//ENTRY也是一个command,用来设置入口点。这里表示入口点是stext 。根据LD的描述,入口点的意思就是程序运行的第一条指令。内核是一个模块,大家把他想象
//成一个运行在硬件上的大程序就可以了。而我们的程序又是运行在内核至上的。比较下Java虚拟机以及运行在其上的Java程序吧......
ENTRY(stext)
//设置jiffies为jiffies_64
jiffies = jiffies_64;
//定义输出文件的段
SECTIONS
{
//设置location count为0xc0008000,这个好理解吧?内核运行的地址全在C0000000以上
. = 0xC0000000 + 0x00008000;
//定义一个.text.head段,由输入文件中所有.text.head段组成
/*
LS语法中,关于seciton的定义如下:
section [address] [(type)] :
[AT(lma)] [ALIGN(section_align)]
[SUBALIGN(subsection_align)]
[constraint]
{
output-section-command
output-section-command
...
} [>region] [AT>lma_region] [:phdr :phdr ...] [=fillexp]
其中,address为VMA,而AT命令中的为LMA。一般情况,address不会设置,所以它默认等于当前的location counter
*/
.text.head : {
/*这个非常关键,咱们在内核代码中经常能看到一些变量声明,例如extern int __stext,但是却找不到在哪定义的
其实这些都是在lds文件中定义的。这里得说一下编译链接相关的小知识。咱们这知道大概即可,具体内容可以自己深入研究
假设C代码中定义一个变量 int x = 0;那么
1 编译器首先会分配一块内存,用来存储该变量的值
2 编译器在程序的symbol表中,创建一项,用来存储这个变量的地址