分类: 嵌入式
2016-07-15 11:40:53
gcc等编译器内置有缺省的连接脚本;但采用缺省脚本,则生成的目标代码需要操作系统才能加载运行。而对于uboot这种需要在操作系统前直接运行的程序,就不能使用编译器缺省脚本、而必须由我们编写连接脚本。
源代码经过编译器编译后包含如下段:
正文段text:包含程序的指令代码;
数据段data:包含固定的数据,如常量和字符串;
未初始化数据段:包含未初始化的变量、数组等。
连接器的任务是将多个编译后的文件的text、data和bass等段连接在一起;而连接脚本文件就是告诉连接器从
若要指定链接脚本,采用如下方式:
1. arm-linux-ld -o uboot.elf -T uboot.lds *.o
2. arm-linux-objcopy -Obinary uboot.elf uboot.bin
网上查找的对.lds文件形式的完整描述:
SECTIONS
{ |
secname和contents是必须的,其他的都是可选的。下面挑几个常用的看看:
1、secname:段名
2、contents:决定哪些内容放在本段,可以是整个目标文件,也可以是目标文件中的某段(代码段、数据段等)
3、start:本段连接(运行)的地址,如果没有使用AT(ldadr),本段存储的地址也是start。GNU网站上说start可以用任意一种描述地址的符号来描述。
4、AT(ldadr):定义本段存储(加载)的地址。
一般应用程序包括 3 类标准段空间:.text 运行代段;.data 全局变量等具有初始值的数据空间;.bss暂态变量,堆栈等数据空间;
说明 2:.rodata,.got,.u_boot_cmd 等段空间由程序员设计需要而自行定义的段空间;
下面分析6500 uboot.lds文件
/* * Copyright 2004, 2007 Freescale Semiconductor. * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ /* OUTPUT_ARCH指出elf程序运行的平台是powerpc,除此之外还可以使用//OUTPUT_FORMAT指出格式,使用ENTRY指出入口点*/ OUTPUT_ARCH(powerpc) /*以下是SECTIONS定义,咋看起来有点类似于C语言中的结构体定义及赋初值, 其结构是: .成员变量 :{ 赋值内容} */ SECTIONS { .resetvec 0xFFFFFFFC : { *(.resetvec) } = 0xffff
.bootpg 0xFFFFF000 : { cpu/85XX/start.o (.bootpg) } = 0xffff
/* Read-only sections, merged into text segment: */ /* "."是指当前位置 ,此处作用是当前位置偏移SIZEOF_HEADERS */ . = + SIZEOF_HEADERS; .interp : { *(.interp) } .hash : { *(.hash) } /*.symtab和.dynsym 分别是STMTAB和DNYSYM类型的区段,对应为普通的和动态链 接器的符号表。动态链接器符号表具有ALLOC属性,因为它需要在运行时被加载*/ .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } /*.rel.txt,.rel.data和.rel.rodata 每个都是REL或RELA类型区段。是对应文本或数据区段的重定位信息*/ .rel.text : { *(.rel.text) } .rela.text : { *(.rela.text) } .rel.data : { *(.rel.data) } .rela.data : { *(.rela.data) } .rel.rodata : { *(.rel.rodata) } .rela.rodata : { *(.rela.rodata) } .rel.got : { *(.rel.got) } .rela.got : { *(.rela.got) } .rel.ctors : { *(.rel.ctors) } .rela.ctors : { *(.rela.ctors) } .rel.dtors : { *(.rel.dtors) } .rela.dtors : { *(.rela.dtors) } .rel.bss : { *(.rel.bss) } .rela.bss : { *(.rela.bss) } .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } /*.init和.fini,都是具有ALLOC和EXECINSTR属性的PROGBITS类型区段。与.text区段相似,但分别为程序启动和终结时执行的代码。C和Fortran不需要这个*/ /*但是对于具有初始和终结函数的全局数据的C++语言来说是必须的。*/ .init : { *(.init) } .plt : { *(.plt) } .text : { cpu/85XX/start.o (.text) cpu/85XX/traps.o (.text) cpu/85XX/interrupts.o (.text) cpu/85XX/cpu_init.o (.text) cpu/85XX/cpu.o (.text) drivers/net/tsec.o (.text) cpu/85XX/speed.o (.text) core/app/appmisc/dlmalloc.o (.text) core/lib/common/crc32.o (.text) core/lib/lib_ppc/extable.o (.text) core/lib/common/zlib.o (.text) *(.text) *(.fixup) *(.got1) } _etext = .; PROVIDE (etext = .); /*rodata 指定只读数据段*/ .rodata : { *(.rodata) *(.rodata1) *(.rodata.str1.4) *(.eh_frame) } /*.init和.fini,都是具有ALLOC和EXECINSTR属性的PROGBITS类型区段。与.text区段相似,但分别为程序启动和终结时执行的代码。C和Fortran不需要这个*/ /*但是对于具有初始和终结函数的全局数据的C++语言来说是必须的。*/ .fini : { *(.fini) } =0 .ctors : { *(.ctors) } .dtors : { *(.dtors) }
/* Read-write section, merged into data segment: */ . = (. + 0x00FF) & 0xFFFFFF00; _erotext = .; PROVIDE (erotext = .); .reloc : { *(.got) _GOT2_TABLE_ = .; *(.got2) _FIXUP_TABLE_ = .; *(.fixup) } __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
/*data 指定可读写数据段*/ .data : { *(.data) *(.data1) *(.sdata) *(.sdata2) *(.dynamic) CONSTRUCTORS } _edata = .; PROVIDE (edata = .);
/*把__u_boot_cmd_start赋值为当前位置, 即起始位置,_u_boot_cmd_start代码中会被用到,所以如果uboot代码中_u_boot_cmd_start改成ABC,那么此处的_u_boot_cmd_start就改成ABC*/ . = .; __u_boot_cmd_start = .; /*指定u_boot_cmd段, uboot把所有的uboot命令的定义都放在该段,因为每个命令定义等长,所以只要以__u_boot_cmd_start为起始地址进行偏移*/ /*就可以很快查找到某一个命令的定义,并依据定义的命令指针调用相应的函数进行处理用户的任务*/ .u_boot_cmd : { *(.u_boot_cmd) } /*把__u_boot_cmd_end赋值为当前位置, 即结束位置*/ __u_boot_cmd_end = .;
. = .; __start___ex_table = .; __ex_table : { *(__ex_table) } __stop___ex_table = .;
. = ALIGN(256); __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } /*256字节对齐*/ . = ALIGN(256); __init_end = .;
/*把__bss_start赋值为_当前位置, 当前位置即bss段起始位置*/ __bss_start = .; /*指定bss段,这里NOLOAD的意思是这段不需装载,仅在执行域中才会有这段*/ .bss (NOLOAD) : { *(.sbss) *(.scommon) *(.dynbss) *(.bss) *(COMMON) } /*把_end赋值为_当前位置, 当前位置即bss段结束位置*/ _end = . ; PROVIDE (end = .); } |
附:链接器的就是把源文件进行符号解析,把解析出来的符号和地址的进行绑定,把全局变量,函数,标号等等这些符合和地址绑定起来