转自:http://www.lslnet.com/linux/dosc1/37/linux-274260.htm
http://shiluo.110.blog.163.com/blog/static/573873201005103526936/
vmlinux.lds.S用于对ld的输出进行组版,这个文件的格式在ld.info手册中有详细的说明。vmlinux.lds.S的主要目的是对输出文件中段进行排序,并定义相关的符号名,以下是简要注释。
/* ld script to make i386 Linux kernel
* Written by Martin Mares ;
*/
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386) /* 输出格式 */
ENTRY(_start) /* 定义_start作为入口点 */
SECTIONS
{
. = PAGE_OFFSET_RAW + 0x100000; /* 定义当前段的偏移量(.代表当前计数器) */
_text = .; /* 定义符号_text为当前位置 */
.text : { /* 定义段.text (": {"是段定义符)*/
*(.text) /* 将所有输入文件中.text段合并到这里 */
*(.fixup) /* 将所有输入文件中的.fixup段合并到这里 */
*(.gnu.warning) /* 将所有输入文件中的.gnu.warning段合并到这里 */
} = 0x9090 /* 合并中的空隙用0x9090填充 */
/* 以下的语法含义可以类推 */
.text.lock : { *(.text.lock) } /* out-of-line lock text */
.rodata : { *(.rodata) }
.kstrtab : { *(.kstrtab) }
. = ALIGN(16); /* Exception table */
__start___ex_table = .; /* 定义__start_ex_table符号为当前位置 */
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
__start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
_etext = .; /* End of text section */
.data : { /* Data */
*(.data)
CONSTRUCTORS /* 将C++的构造函数指针段合并到这里 */
}
_edata = .; /* End of data section */
. = ALIGN(8192); /* init_task */
.data.init_task : { *(.data.init_task) }
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
. = ALIGN(4096); /* 输出计数器在页边界上对齐 */
__init_end = .;
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
. = ALIGN(4096);
.data.page_aligned : { *(.data.idt) }
__bss_start = .; /* BSS */
.bss : {
*(.bss)
}
_end = . ;
/* Stabs debugging sections. */
.stab 0 : { *(.stab) } /* 0 是段属性,代表段的起始地址 */
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
以下是用"objdump --headers vmlinux"得到的组版结果:
vmlinux: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0009ccb8 c0100000 c0100000 00001000 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .text.lock 00000622 c019ccc0 c019ccc0 0009dcc0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .rodata 0000f4ab c019d2e4 c019d2e4 0009e2e4 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .kstrtab 00002d9c c01ac78f c01ac78f 000ad78f 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 __ex_table 00000ba8 c01af530 c01af530 000b0530 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 __ksymtab 00001870 c01b00d8 c01b00d8 000b10d8 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .data 000133c0 c01b1950 c01b1950 000b2950 2**4
CONTENTS, ALLOC, LOAD, DATA
7 .data.init_task 00002000 c01c6000 c01c6000 000c6000 2**2
CONTENTS, ALLOC, LOAD, DATA
8 .text.init 0000868e c01c8000 c01c8000 000c8000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
9 .data.init 00003220 c01d0690 c01d0690 000d0690 2**2
CONTENTS, ALLOC, LOAD, DATA
10 .data.cacheline_aligned 00001c20 c01d4000 c01d4000 000d4000 2**2
CONTENTS, ALLOC, LOAD, DATA
11 .data.page_aligned 00000800 c01d6000 c01d6000 000d6000 2**2
CONTENTS, ALLOC, LOAD, DATA
12 .bss 0001f324 c01d6800 c01d6800 000d6800 2**4
ALLOC
13 .comment 000011d0 00000000 00000000 000d6800 2**0
CONTENTS, READONLY
14 .note 000011d0 000011d0 000011d0 000d79d0 2**0
CONTENTS, READONLY
ENTRY(_start)
7 SECTIONS
8 {
9 . = 0xC0000000 + 0x100000;
10 _text = .; /* Text and read-only data */
11 .text : {
.data: { *(.data) }
.bss: { *(.bss) }
}
其中,ENTRY(_start)指明程序的入口点:_start标号;.=0xC0000000 + 0x100000指明目标代码的起始地址.text : { ....}表示从该位置开始放置所有目标文件的代码段,里面又分几个小区段.又如
__start___ex_table = .;
24 __ex_table : { *(__ex_table) }
25 __stop___ex_table = .;
则你可以在__copy_user()宏定义中看见
".section .fixup,\"ax\"\n" \
264 "3: lea 0(%3,%0,4),%0\n" \
265 " jmp 2b\n" \
266 ".previous\n" \
267 ".section __ex_table,\"a\"\n" \
268 " .align 4\n" \
269 " .long 0b,3b\n" \
270 " .long 1b,2b\n"
这就告诉ld把这些部分要放入相应的区段中.这每个区段都有不同的特性或者说用意.比如这个__start___ex_table,可以把它看成异常段的入口地址,在/arch/i386/mm/extable.c可以看见
10 extern const struct exception_table_entry __start___ex_table[];
11 extern const struct exception_table_entry __stop___ex_table[];
这两个地址会根据vmlinux.lds设置好地址.
当异常发生时,内核的异常响应会从这里开始搜索search_exception_table(unsigned long addr)看能不能找到相应的异常处理办法.
另外像
9 . = 0xC0000000 + 0x100000;
10 _text = .;
表示_text=0xC0000000+0x100000
....(接者往下走...)
22 . = ALIGN(16); /* Exception table */
23 __start___ex_table = .;
24 __ex_table : { *(__ex_table) }
25 __stop___ex_table = .;
26
22行表示.(.是current
location counter)必需要对齐,如果没有这行的话会有隐患.想像没有22行的话
27 __start___ksymtab = .; /* Kernel symbol table */
28 __ksymtab : { *(__ksymtab) }
29 __stop___ksymtab = .;
30 __start___kallsyms = .; /* All kernel symbols */
31 __kallsyms : { *(__kallsyms) }
32 __stop___kallsyms = .;
28行__ksymtab段开始位置一般会对齐而 __start___ksymtab这个指针指向.,如果这个.没有sufficiently aligned before那么有可能__start___ksymtab就指向__ksymtab段起始的后面去了.