zoukankan      html  css  js  c++  java
  • uboot中.lds连接脚本文件的分析

    标题:u-boot中.lds连接脚本文件的分析
    2008-03-14 14:03:31
    对于.lds文件,它定义了整个程序编译之后的连接过程,决定了一个可执行程序的各个段的存储位置。虽然现在我还没怎么用它,但感觉还是挺重要的,有必要了解一下。
    先看一下GNU官方网站上对.lds文件形式的完整描述:
    SECTIONS {
    ...
    secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
    { contents } >region :phdr =fill
    ...
    }
    secname和contents是必须的,其他的都是可选的。下面挑几个常用的看看:
    1、secname:段名
    2、contents:决定哪些内容放在本段,可以是整个目标文件,也可以是目标文件中的某段(代码段、数据段等)
    3、start:本段连接(运行)的地址,如果没有使用AT(ldadr),本段存储的地址也是start。GNU网站上说start可以用任意一种描述地址的符号来描述。
    4、AT(ldadr):定义本段存储(加载)的地址。
    看一个简单的例子:(摘自《2410完全开发》)
    /* nand.lds */
    SECTIONS {
    firtst 0x00000000 : { head.o init.o }
    second 0x30000000 : AT(4096) { main.o }
    }
    以上,head.o放在0x00000000地址开始处,init.o放在head.o后面,他们的运行地址也是0x00000000,即连接和存储地址相同(没有AT指定);main.o放在4096(0x1000,是AT指定的,存储地址)开始处,但是它的运行地址在0x30000000,运行之前需要从0x1000(加载处)复制到0x30000000(运行处),此过程也就用到了读取Nand flash。
    这就是存储地址和连接(运行)地址的不同,称为加载时域和运行时域,可以在.lds连接脚本文件中分别指定。
    编写好的.lds文件,在用arm-linux-ld连接命令时带-Tfilename来调用执行,如
    arm-linux-ld –Tnand.lds x.o y.o –o xy.o。也用-Ttext参数直接指定连接地址,如
    arm-linux-ld –Ttext 0x30000000 x.o y.o –o xy.o。

    既然程序有了两种地址,就涉及到一些跳转指令的区别,这里正好写下来,以后万一忘记了也可查看,以前不少东西没记下来现在忘得差不多了。。。
    ARM汇编中,常有两种跳转方法:b跳转指令、ldr指令向PC赋值。
    我自己经过归纳如下:
    (1) b step1 :b跳转指令是相对跳转,依赖当前PC的值,偏移量是通过该指令本身的bit[23:0]算出来的,这使得使用b指令的程序不依赖于要跳到的代码的位置,只看指令本身。
    (2) ldr pc, =step1 :该指令是从内存中的某个位置(step1)读出数据并赋给PC,同样依赖当前PC的值,但是偏移量是那个位置(step1)的连接地址(运行时的地址),所以可以用它实现从Flash到RAM的程序跳转。
    (3) 此外,有必要回味一下adr伪指令,U-boot中那段relocate代码就是通过adr实现当前程序是在RAM中还是flash中。仍然用我当时的注释:
    relocate: /* 把U-Boot重新定位到RAM */
    adr r0, _start /* r0是代码的当前位置 */
    /* adr伪指令,汇编器自动通过当前PC的值算出 如果执行到_start时PC的值,放到r0中
    当此段在flash中执行时r0 = _start = 0;当此段在RAM中执行时_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x33F80000,即u-boot在把代码拷贝到RAM中去执行的代码段的开始) */
    ldr r1, _TEXT_BASE /* 测试判断是从Flash启动,还是RAM */
    /* 此句执行的结果r1始终是0x33FF80000,因为此值是又编译器指定的(ads中设置,或-D设置编译器参数) */
    cmp r0, r1 /* 比较r0和r1,调试的时候不要执行重定位 */


    下面,结合u-boot.lds看看一个正式的连接脚本文件。这个文件的基本功能还能看明白,虽然上面分析了好多,但其中那些GNU风格的符号还是着实让我感到迷惑,好菜啊,怪不得连被3家公司鄙视,自己鄙视自己。。。
    OUTPUT_FORMAT("elf32­littlearm", "elf32­littlearm", "elf32­littlearm")
    ;指定输出可执行文件是elf格式,32位ARM指令,小端
    OUTPUT_ARCH(arm)
    ;指定输出可执行文件的平台为ARM
    ENTRY(_start)
    ;指定输出可执行文件的起始代码段为_start.
    SECTIONS
    {
    . = 0x00000000 ; 从0x0位置开始
    . = ALIGN(4) ; 代码以4字节对齐
    .text : ;指定代码段
    {
    cpu/arm920t/start.o (.text) ; 代码的第一个代码部分
    *(.text) ;其它代码部分
    }
    . = ALIGN(4)
    .rodata : { *(.rodata) } ;指定只读数据段
    . = ALIGN(4);
    .data : { *(.data) } ;指定读/写数据段
    . = ALIGN(4);
    .got : { *(.got) } ;指定got段, got段式是uboot自定义的一个段, 非标准段
    __u_boot_cmd_start = . ;把__u_boot_cmd_start赋值为当前位置, 即起始位置
    .u_boot_cmd : { *(.u_boot_cmd) } ;指定u_boot_cmd段, uboot把所有的uboot命令放在该段.
    __u_boot_cmd_end = .;把__u_boot_cmd_end赋值为当前位置,即结束位置
    . = ALIGN(4);
    __bss_start = .; 把__bss_start赋值为当前位置,即bss段的开始位置
    .bss : { *(.bss) }; 指定bss段
    _end = .; 把_end赋值为当前位置,即bss段的结束位置
    }

     原文地址:http://lionwq.spaces.eepw.com.cn/articles/article/item/18928

  • 相关阅读:
    【Java EE 学习 36】【struts2】【struts2系统验证】【struts2 ognl值栈】【struts2 ongl标签】【struts2 UI标签】【struts2模型驱动和令牌机制】
    【Java EE 学习 35 下】【struts2】【struts2文件上传】【struts2自定义拦截器】【struts2手动验证】
    【Java EE 学习 35 上】【strus2】【类型转换器】【struts2和Servlet API解耦】【国际化问题】【资源文件乱码问题已经解决】
    【Java EE 学习 34】【struts2学习第一天】
    【JavaScript中的正则表达式】
    【Java EE 学习 33 下】【validate表单验证插件】
    【Java EE 学习 33 上】【JQuery样式操作】【JQuery中的Ajax操作】【JQuery中的XML操作】
    【Java EE 学习 32 下】【JQuery】【JQuey中的DOM操作】
    【Java EE 学习 32 上】【JQuery】【选择器】
    【Java EE 学习 31】【JavaScript基础增强】【Ajax基础】【Json基础】
  • 原文地址:https://www.cnblogs.com/lihaiping/p/uboot.html
Copyright © 2011-2022 走看看