u-boot.lds链接脚本分析

这段时间在读u-boot的makefile ,看到链接的时候,发现make会调用board/Samsung/smdk6410下的u-boot.lds链接脚本,于是看了点关于链接器和加载器方面的东西,所以写下来,以防以后忘了。

         在看链接脚本前,我们先来了解一些关于目标文件的知识。在我们将c源程序编译为可执行文件(如ELF)时,实际上需要先经过编译器实现预处理生成.i或者.ii文件,再由汇编器编译生成目标文件,最后由链接器将各个目标文件和各种库文件连接成可执行文件。目标文件包含如下五类信息:

         >头信息            :关于文件的整体信息,诸如代码大小,翻译成该目标文件的源文件名称和创建日期等。

         >目标代码       :  由编译器或者汇编器产生的二进制指令和数据

         >重定位信息: 目标代码中的一个位置列表,链接器在修改目标代码的地址时会对他进行调整

         >符号               :该模块中定义的全局符号,以及从其他模块导入的或者由链接器定义的符号

         >调试信息       :目标代码中与链接无关但会被调试器使用到的其他信息,包括源代码文件和行号信息,本地符号,被目标代码使用的数据结构描述信息

        

         并不是所有的目标格式都包含这几类信息,一个很有用的目标格式很少或者不包含任何信息都有可能。

         下面是以前unix下使用比较多的a.out目标文件的格式:

                                              

 

a.out header:

a.out的头部根据unix版本的不同而略有变化,BSD中的格式如下

       int   a_magic;        //幻数

           int    a_text;                        //文本段的大小

           int   a_data;                       //初始化的数据段的大小

           int   a_bss;                         //未初始化的数据段的大小

           int  a_syms;                     //符号表的大小

           int   a_entry;                     //入口点

           int   a_trsize;                     //文本重定位段的大小

           int   a_drsize;                    //数据重定位段的大小

 

text section:    存放程序代码

Data section:   存放数据

Bss section :   存放未初始化的数据,在镜像文件中,是不为bss段分配空间的,所以如果你开一个很大的全局的未初始化的数组,镜像文件的大小不会相应的变大。而只是在加载器将镜像加载进内存时,才会为bss段分配空间

         对于哪些变量放入bss段,哪些数据放入data段的文件的问题,经过测试发现,对于为初始化的静态数据都是放入bss段的,而初始化过的全局数据和静态数据是放进data段的,但未初始化的全局数据这既不在bss段中,也不在data段中,只是在符号表中有一项指向该全局变量:  

         #include<stdio.h>

         Char  a_test[0x100] ;

         Char  b_test[0x100] = {1};

         Staticchar c_test[0x100];

         Intmain(void)

         {

                   Static  char  a[0x100] ;

                   Static  char  b[0x100] = {1};

}

如以上程序中,c_test, b_test, a中的数据是存放在bss段中的,而b_test 和 b所分配的数据是存放在data段中的,用objdump 可以分析出.o文件的信息:

        

 

所以如果有朋友做裸机程序,并且用gcc编译时,定义未初始化的全局数组可能会出现问题,要小心使用。

 

介绍完目标文件的格式,我们开始切入正题:链接器。何为链接器呢,其实说的简单点就是把各个目标文件的各种段进行重新组合:



而链接脚本的作用就是程序员可以通过有限的控制命令,来指示链接器如何来进行工作:

/*输出文件的运行环境,因为我们用的是6410,是arm平台的*/

OUTPUT_ARCH(arm)

 

/*程序入口点*/

ENTRY(_start)

 

/*section命令用来设置段*/

SECTIONS

{

         /*将当前地址定位到0x00000000处,.操作符用来表示当前地址*/

         . = 0x00000000;

 

         /*将当前地址设为4个字节对齐处,即:. = (. + arg-1)&~(arg-1)*/

         . = ALIGN(4);

 

         /*定义text段,定义段的格式为:

         *SECTION[ADDRESS][(TYPE)]:[AT(LMA)]

         *{

         *       .......

         *       OUTPUT-SECTION-COMMAND

         *       OUTPUT_SECTION_COMMAND

         *       .......

         *}[>REGION][AT>LMA_REGION][:PHDR:PHDR....][=FILLEXP]

 []内的内容通常是可选的

         * SECTION: 段名,这个是必须的

         * ADDRESS: 一个表达式,用来对VMA进行设置

         * AT(LMA): 指定加载地址

         */

 

        /*

         * 定义.text段

         */  

.text      :
    {
    /*段由start.o,cpu_init.o,onenand_cp.o,nand_cp.o,movi.o中的.text段和div0.o中所有段组成*/
      cpu/s3c64xx/start.o    (.text)
      cpu/s3c64xx/s3c6410/cpu_init.o    (.text)
      cpu/s3c64xx/onenand_cp.o    (.text)
      cpu/s3c64xx/nand_cp.o    (.text)
      cpu/s3c64xx/movi.o (.text)
      *(.text)
      lib_arm/div0.o
    }
    /*.rodata段由所有输入文件的.rodata段组成*/
    . = ALIGN(4);
    .rodata : { *(.rodata) }

    /*.data段由所有输入文件的.data段组成*/
    . = ALIGN(4);
    .data : { *(.data) }

    /*.got段由所有输入文件的.
vi@linux  13:43:01
got段组成*/
    . = ALIGN(4);
    .got : { *(.got) }

    /*__u_boot_cmd_start的值被设置为了当前地址*/
    __u_boot_cmd_start = .;

    /*.u_boot_cmd段由所有文件的.u_boot_cmd段组成*/
    .u_boot_cmd : { *(.u_boot_cmd) }

    /*__u_boot_cmd_end变量的值被赋值为了当前地址*/
    __u_boot_cmd_end = .;

    /*.mmudata段由所有输入文件的.mmudata段组成 */
    . = ALIGN(4);
    .mmudata : { *(.mmudata) }

     = ALIGN(4);

    /*__bss_start变量被设置为了当前地址*/
    __bss_start = .;

    /*.bss段由所有输入文件的.bss段组成*/
    .bss : { *(.bss) }
    _end = .;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值