好的朋友已经做过好多年的arm开发,却对底层的编译链接逻辑很少接触,主要原因在于现在大多数应用层的开发不需要从裸板开始,工程师只需要在应用层面开发即可,但是,如果牵涉到较多的硬件改造或系统重构,就需要对整个系统底层进行调整,lds文件的修改将在所难免。
为什么要用到lds链接脚本?
首先lds链接脚本的作用就是将许多源文件编译后生成的目标文件*.o,在各个段链接在一起,通过此文件,告诉链接器这些各个段存放的地址先后顺序,它定义了整个程序编译之后的连接过程,决定了一个可执行程序的各个段的存储位置。
lds文件语法结构
lds文件的的语法定义,详见GNU官方网站,文件类型为文本文件,
主要伪代码有:
OUTPUT_FORMAT :指定输出文件格式
OUTPUT_ARCH:指定输出可执行文件运行处理器平台
ENTRY:指定程序入口位置
ALIGN; 代码对齐方式
SENCTIONS:定义段,为主要单元,sections的形式为:
SECTIONS {
…
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
{ contents } >region :phdr =fill
…
}
其中secname和contents是必须的,其他都是可选的。说明如下:
1、secname:段名
2、contents:段内容,可以是整个目标文件,也可以是目标文件中的某些段(代码段、数据段等)
3、start:本段连接(运行)的地址,如果没有使用AT(ldadr),本段存储的地址也是start。
4、AT(ldadr):本段存储(加载)的地址。
lds文件实例解析
OUTPUT_FORMAT(“elf32-littlearm”, “elf32-littlearm”, “elf32-littlearm”)
;指定输出可执行文件是elf格式,32位ARM指令,小端
OUTPUT_ARCH(arm);指定输出可执行文件的平台为ARM处理器平台
ENTRY(_start);指定输出可执行文件的起始代码段为_start.
MEMORY
{
RAM (xrw) : ORIGIN = 0x00000000, LENGTH = 8M
SRAM (xrw) : ORIGIN = 0x30000000, LENGTH = 16K
}
SECTIONS
{
. = 0x00000000; //指定当前的链接地址=0x00000000
. = ALIGN(4);; 代码以4字节对齐
.text :
{
./bsp/boot.o (.text*);//添加第一个目标文件
./bsp/src/*.o(.text*); //添加第二个目标文件
./bsp/lib/*.o(.text*); //添加第三个目标文件
./freertos/*.o(.text*);
./freertos/portable/hd996/*.o(.text*);
}
. = ALIGN(4);
.rodata : ;指定只读数据段
{
*(.rodata*);
*(.rel*);
}
. = ALIGN(4);
.data : ;指定读/写数据段
{
*(.data*);
*(.fastcode);
*(.fastcode.*);
}
. = ALIGN(4);
__bss_start = .;//把__bss_start赋值为当前地址位置,即bss段的开始位置
.bss :
{
*(.bss*);
*(COMMON);//指定bss段,里面存放未被使用的变量
}
_end = .; //把_end赋值为当前地址位置,即bss段的结束位置
}