所有创建可执行文件的最后一步就是链接。它是由ld或者是用gcc间接调用ld来完成的。它主要任务和把外部库和应用程序的目标代码放到text段正确位置。以及创建程序中其它段(如data/bss段)。
标准C程序的链接是一般是固定的。它是ld调用一个缺省的链接脚本来完成的。因此对于一般的应用开发者,几乎感觉不到ld以及链接脚本的存在。
但是如果在一些特殊情况下,主要是底层非操作系统程序。里面很多代码,特别是汇编代码。必须要链接到指定的位置。而且这个时候的程序入口不一定也不是main了。这种情况在bootloader,Linux内核以及裸机程序(非操作系统的程序,bootloader可以看成这类程序一个特例)。这时,你就要手工编写lds文件了。
一.lds格式
---------------------------------------------------------------
lds的格式非常复杂,但是常用就是那几句。因此我们可以用下面一个比较通用的模板来解释.
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") OUTPUT_ARCH("arm") ENTRY(_start) SECTIONS { . = 0x30000000; .text : { *(.text)} . = ALIGN(2); .data : { *(.data)} } |
OUTPUT_FORMAT表示输出格式。其中有三个参数,第一个是指默认的输出格式。第二是指ld命令行参数使用-EB'输出的格式。第三个是指使用-EL时输出的格式
elf32-littlearm 表示ELF可执行文件格式,小端字节序和ARM体系结构.
OUTPUT_ARCH 表示输出的体系结构,这里是ARM
ENTRY(_start) 表示执行的入口符号。它可以是汇编的代码段标签,或者C语言的函数,这里表示使用函数_start作为入口。
SECTIONS 是表示各段的分布描述.
. = 0x30000000; 表示程序起始地址
.text : { *(.text)}
.text:表示代码段的描述,{}中。 *(.text)总是最后一句表示.text缺省的描述.
另一个.text实例
.text : {
cpu/arm920t/start.o (.text) ; 代码的第一个代码部分
*(.text) ;其它代码部分
}
. = ALIGN(2); 表示接下来部分采用2对齐
.data : { *(.data)} 数据库缺省描述
类似还有 .bss .got 和.rodata 段。
对lds的详细解翻译可以参见
GNU-ld链接脚本浅析 http://www.cublog.cn/u/13991/showart_177822.html
二.lds的使用
-------------------------------------------------
用-T参数可以把lds脚本传给ld
ld -T your.lds -o elf_name
上句表根据your.lds来链接出elf可执行文件 elf_name
在底层开发里,下载到内存或Nand Flash的,还得多得用objcopy一步格式转换,以ARM为例.它需要用arm-linux-objcopy来转换
arm-linux-objcopy elf_name -I elf32-littlearm -O binary -o bin_name
表示把elf格式的elf_name变成二进制的bin_name