转自:http://www.cnblogs.com/lifexy/p/7089873.html

先来分析一个简单的.lds链接脚本


例1,假如现在有head.c init.c nand.c main.c这4个文件:

1.1 首先创建链接脚本nand.lds:

1 SECTIONS {
2 firtst 0x00000000 : { head.o init.o nand.o}
3 second 0x30000000 : AT(4096) { main.o }
4
}

SECTIONS { ... }                  用来描述输出文件的内存布局。

这个脚本里规定了两个段,firtst和cecond

0x00000000   0x30000000   

表示链接地址或运行地址,指程序在SRAM、SDRAM实际运行的地址,也就是使PC等于这个地址。

这里指head.o init.o nand.o的加载地址为0,运行地址在0x00000000,main.o运行地址在0x30000000

AT(4096)    

表示加载地址或存储地址,指程序编译后存放的地址,一般存在ROM、FLASH中,也就是运行这个指令时,会先将4096地址~(4096+2048)地址处的内容复制到0x30000000处运行(因为已经初始化了SDRAM以及Nand Flash)。

这里指main.o的加载地址为Nand Flash里的地址4096,运行地址在SDRAM里的地址  0x30000000。

1.2 制作Makefile

objs := head.o init.o nand.o main.o

nand.bin : $(objs)  
arm-linux-ld -Tnand.lds -o nand_elf $^
arm-linux-objcopy -O binary -S nand_elf $@
arm-linux-objdump -D -m arm nand_elf > nand.dis %.o:%.c
arm-linux-gcc -Wall -c -O2 -o $@ $< %.o:%.S
arm-linux-gcc -Wall -c -O2 -o $@ $< clean:
rm -f nand.dis nand.bin nand_elf *.o

其中 objs 是代表的一个变量,表示obj文件,也可以是objects, OBJECTS, objs, OBJS, obj, 或是 OBJ,后面就可以使用$(objs)来使用这个变量了。

$@               目标文件

$^                 所有的依赖文件

$<                 第一个依赖文件

例如: arm-linux-ld -Tnand.lds -o nand_elf $^          <<——  等价于  ——>>    arm-linux-ld  -o nand_elf  head.o init.o nand.o main.o

%.o:%.c                  表示所有的.o文件,依赖于对应的.c文件

%.o:%.S                  表示所有的.o文件,依赖于对应的.S文件


当有多个.o文件时,这时候.lds链接脚本 又该如何安排它们在可执行文件中的顺序?

这里就需要将多个目标文件的.text、.data和.bss等段链接在一起而链接脚本文件是告诉链接器从什么地址开始放置这些段

  • .text:代码段,存放程序执行代码的一块内存
  • .data:读/写数据段,存放已初始的全局变量或静态变量的一块内存
  • .rodata:只读数据段,存放只读数据段,比如全局const变量和#define定义的变量
  • .bss:存放未初始化的全局变量或静态变量,这里的变量存放只是用来预留位置,并不占用空间

常用命令:

ENTRY(SYMBOL);将SYMBOL的值设置成入口地址。一般设置为_start。

OUTPUT(FILENAME); 定义输出文件的名字。可以用它来指定默认的输出文件名称。当然我们一般都用手动-o进行指定,如果我们没有进行手动指定的话,输出文件名称就以这个FILENAME为输出文件名。

STARTUP(filename);指定filename为第一个输入文件。

OUTPUT_FORMAT(default, big, little);定义3种输出文件的格式。若有命令行选项-EB(大端),则使用第二个输出格式,有命令行指定-EL(小端),则使用第三个格式。否则使用默认的default输出格式。

OUT_ARCH(arch);设置输出文件的体系架构

SECTIONS :最重要的,最基本的,也是最主要的命令,它告诉链接器如何把输入文件的各个section输出到目标文件中的各个section中去。


例2:分析 board/100ask24x0/u-boot.lds链接脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
OUTPUT_ARCH(arm)                                //设置输出文件的体系架构。
ENTRY(_start)                                   //将_start这个全局符号设置成入口地址。
SECTIONS                                        //输出文件内容布局
{
    . = 0x00000000;                            //指定地址0x00000000
 
    . = ALIGN(4);                             //代码以4字节对齐
    .text      :                                //指定.text section段(位于0x00000000)   
    {
      cpu/arm920t/start.o   (.text)          //添加第一个目标文件: cpu/arm920t/start.o里面的.text代码段
          board/100ask24x0/boot_init.o (.text)   //添加第二个目标文件: board/100ask24x0/boot_init.o里面的.text代码段
      *(.text)                               // *(.text) 表示添加剩下的全部文件的.text代码段
    }
 
    . = ALIGN(4);
    .rodata : { *(.rodata) }        //指定.rodata section段(位于0x00000000+.text section),将所有的.rodata只读数据段合并成一个.rodata只读数据段 
 
    . = ALIGN(4);
    .data : { *(.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段,所有的u-boot命令相关的定义都放在这个位置
    __u_boot_cmd_end = .;              //  u_boot_cmd段结束位置
 
    . = ALIGN(4);
    __bss_start = .;                   //把__bss_start赋值为当前位置,即bss段的开始位置
    .bss : { *(.bss) }                 //指定bss段,这里NOLOAD的意思是这段不需装载,仅在执行域中才会有这段
    _end = .;                          //把_end赋值为当前位置,即bss段的结束位置
}

  


有什么不懂的或有误的地方欢迎指出,非常感谢

版权声明:本文为博主原创文章,未经博主允许不得转载。

随机推荐

  1. 【转】史上最浅显易懂的Git教程!

    之前一直在找git的学习教程,网上搜到很多,但是大多数写的都非常简单或者混乱,你知道技术男的思维就是以为他抛一个专业术语出来,以为你都懂……或者简单写两句,插个图,他觉得他懂了,你也能懂,事实上初学者 ...

  2. php 随机密码和盐 来自wordpress

    生成随机密码或盐. Generate keys and salts using secure CSPRNG $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJ ...

  3. C++解析(14):静态成员变量与静态成员函数

    0.目录 1.静态成员变量 2.静态成员函数 3.小结 1.静态成员变量 成员变量的回顾: 通过对象名能够访问public成员变量 每个对象的成员变量都是专属的 成员变量不能在对象之间共享 新的需求: ...

  4. list的4种遍历方式

    import java.util.ArrayList;import java.util.Iterator;import java.util.List; import com.hbut.domain.P ...

  5. 【SYZOJ279】滑稽♂树(树套树)

    [SYZOJ279]滑稽♂树(树套树) 题面 SYZOJ CJOJ 题目描述 zzsyz实验楼里面种了一棵滑稽树,只有滑稽之力达到大乘期的oier才能看到.虽然我们看不到,但是还是知道一些信息: 这真 ...

  6. spark(四)

    一. spark 2  版本 相对于以前版本的变化 spark core  : Accumulators (累加器):性能更好,页面上也可以看到累加器的信息 spark sql: 1. 2.DataS ...

  7. Hive(一)基础知识

    一.Hive的基本概念 (安装的是Apache hive 1.2.1) 1.hive简介 Hive 是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表, 并提供类 SQ ...

  8. 解题:AHOI 2013 作业

    题面 emmm......我把莫队扔到了杂题里,因为感觉局限挺大的=.= 这题是莫队维护信息+分块查询答案,都是两者的基本操作,复杂度$O(m$ $sqrt(n)+n$ $sqrt(m))$ 所以为啥 ...

  9. python并行编程学习之绪论

    计算机科学的研究,不仅应该涵盖计算处理所基于的原理,还因该反映这些领域目前的知识状态.当今,计算机技术要求来自计算机科学所有分支的专业人员理解计算机处理的基础的关键,在于知道软件和硬件在所有层面上的交 ...

  10. 为Azure Web Site 添加ADFS验证支持之二 在代码里使用ADFS

    下面我们来创建一个MVC 5.0的ASP.Net程序,并且将它部署到Azure Web Site上 通过Visual Studio 2015创建Web Project 在选择ASP.net模板的地方, ...