Chinaunix首页 | 论坛 | 博客
  • 博客访问: 177130
  • 博文数量: 43
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 451
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-28 09:10
文章分类
文章存档

2016年(43)

我的朋友

分类: 嵌入式

2016-07-15 11:40:53

 


gcc等编译器内置有缺省的连接脚本;但采用缺省脚本,则生成的目标代码需要操作系统才能加载运行。而对于uboot这种需要在操作系统前直接运行的程序,就不能使用编译器缺省脚本、而必须由我们编写连接脚本。

源代码经过编译器编译后包含如下段:

正文段text:包含程序的指令代码;

数据段data:包含固定的数据,如常量和字符串;

未初始化数据段:包含未初始化的变量、数组等。

连接器的任务是将多个编译后的文件的textdatabass等段连接在一起;而连接脚本文件就是告诉连接器从


若要指定链接脚本,采用如下方式:

1.    arm-linux-ld -o uboot.elf -T uboot.lds *.o 

2.    arm-linux-objcopy -Obinary uboot.elf uboot.bin 

 

网上查找的.lds文件形式的完整描述:

SECTIONS {
...
secname
 start BLOCK(align) (NOLOAD) : AT ( ldadr )
  {
 contents } >region :phdr =fill
...
}

secname和contents是必须的,其他的都是可选的。下面挑几个常用的看看:

1、secname:段名

2、contents:决定哪些内容放在本段,可以是整个目标文件,也可以是目标文件中的某段(代码段、数据段等)

3、start:本段连接(运行)的地址,如果没有使用ATldadr),本段存储的地址也是startGNU网站上说start可以用任意一种描述地址的符号来描述。

4、ATldadr):定义本段存储(加载)的地址。

 

一般应用程序包括 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 分别是STMTABDNYSYM类型的区段,对应为普通的和动态链

    接器的符号表。动态链接器符号表具有ALLOC属性,因为它需要在运行时被加载*/

  .dynsym        : { *(.dynsym)            }

  .dynstr        : { *(.dynstr)          }

  /*.rel.txt.rel.data.rel.rodata 每个都是RELRELA类型区段。是对应文本或数据区段的重定位信息*/

  .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,都是具有ALLOCEXECINSTR属性的PROGBITS类型区段。与.text区段相似,但分别为程序启动和终结时执行的代码。CFortran不需要这个*/

  /*但是对于具有初始和终结函数的全局数据的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,都是具有ALLOCEXECINSTR属性的PROGBITS类型区段。与.text区段相似,但分别为程序启动和终结时执行的代码。CFortran不需要这个*/

  /*但是对于具有初始和终结函数的全局数据的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 = .);

}

 

附:链接器的就是把源文件进行符号解析,把解析出来的符号和地址的进行绑定,把全局变量,函数,标号等等这些符合和地址绑定起来


 

阅读(1907) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~