转自: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段起始的后面去了.