https://blog.csdn.net/itxiebo/article/details/50937412

https://blog.csdn.net/itxiebo/article/details/50938753

[随笔]GNU linker script,ld script,GNU链接脚本

一、什么是GNU linker script?作用是什么?

.lds文件,即linker script,决定了可执行映像(image)的链接方式,以及各个段的装载地址(装载域)和执行地址(运行域)。

  1. 装载地址:运行之前各段的地址;
  2. 运行地址:运行时各段的地址。

二、对GNU linker script的简单认识

首先,完整版的官网Gnulinkerscript下载地址如下,此文件可作为参考文献使用。
http://pan.baidu.com/s/1hriLMb6

GNU官方网站上对.lds文件形式的基本描述:

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

两个必须的(secname, contents),其他optional

secname:段名,用以命名此段。

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

start:是段的重定位地址,即本段运行的地址。如果代码中有位置无关指令,程序运行时这个段必须放在这个地址上。start可以用任意一种描述地址的符号来描述。

BLOCK(align) 指定块对齐。比如,前一个段从0x30000000到0x300003F1,此处标记ALIGN(4),表示此处最小占用4Bytes,即使下一个段是紧挨这个段,那么下一个段的起始地址(也就是运行地址)为0x300003F4。

NOLOAD:告诉加载器程序运行时不加载该段到内存。

AT(ldadr):定义本段存储(加载)的地址,如果不使用这个选项,则加载地址等于运行地址,通过这个选项可以控制各段分别保存于输出文件中不同的位置。

三、.lds相关的简单实例

例:
/* nand.lds */

SECTIONS
{
    first 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(运行地址处),此过程也就需要读取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

四、常用section的定义

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

链接器:把各个目标文件的各种段进行重新组合。

最后,两个命令,先保存起来,后面有机会再实践一下。

arm-linux-objdump -h vmlinux > vmlinux.txt
    –输出linux内核段信息到vmlinux.txt文本中。
    arm-linux-objdump -f vmlinux > sec_symbol.txt
    –输出内核段信息和符号到sec_symbol.txt文本中。

本文回溯

什么是GNU linker script?作用是什么?
    对GNU linker script的简单认识,核心SECTIONS的结构分析。
    对链接器基本原理的理解。

u-boot分析 三 (u-boot.lds脚本)

目的,
了解链接器用到的脚本文件u-boot.lds。

在开始这篇博文之前,需要先了解一些GNU linker script的基本知识,可以参考博主的另外一篇分享《GNU linker script,ld script,GNU链接脚本》

在《u-boot分析 二》中,我们分析u-boot的目录结构,提及到了程序入口start.S,但在开始了解start.S之前,我们先聊聊链接器ld程序的脚本文件u-boot.lds。

下面我们就来品味一下UT4418开发板的u-boot.lds脚本,即u-boot/arch/arm/cpu/slsiap/u-boot.lds。如果读者正好需要看source code,可以参看之前的文章《u-boot分析 一》中的源码分享。

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*指定输出可执行文件是elf格式,32位ARM指令,小端*/
OUTPUT_ARCH(arm)
/*指定输出可执行文件的平台为ARM*/
ENTRY(_stext)
/*指定输出可执行文件的起始代码段为_stext*/
SECTIONS
{
/*指定可执行文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。必须使编译器知道这个地址,通常都是修改此处来完成*/
    . = 0x00000000;
    /*从0x0位置开始*/
    . = ALIGN(4);
    /*代码以4字节对齐*/
    .text :
    /*代码段*/
    {
        *(.__image_copy_start)
        /*u-boot将自己copy到RAM,此为需要copy的程序的start*/
        SOCDIR/start.o (.text*)
        /*./arch/arm/cpu/slsiap/s5p4418/start.S*/
        SOCDIR/vectors.o (.text*)
        /*./arch/arm/cpu/slsiap/s5p4418/vectors.S,异常向量表*/
        *(.text*)
        /*其他的代码段放在这里,即start.S/vector.S之后*/
    }

. = ALIGN(4);
    /*代码段结束后,有可能4bytes不对齐了,此时做好4bytes对齐,以开始后面的.rodata段*/
    .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
    /*在代码段之后,存放read only数据段*/
    . = ALIGN(4);
    /*和前面一样,4bytes对齐,以开始接下来的.data段*/
    .data : {
        *(.data*)
        /*可读写数据段*/
    }

. = ALIGN(4);
    /*和前面一样,4bytes对齐*/
    . = .;

. = ALIGN(4);
    .u_boot_list : {
        KEEP(*(SORT(.u_boot_list*)));
        /*.data段结束后,紧接着存放u-boot自有的一些function,例如u-boot command等*/
    }

. = ALIGN(4);

.image_copy_end :
    {
        *(.__image_copy_end)
        /*至此,u-boot需要自拷贝的内容结束,总结一下,包括代码段,数据段,以及u_boot_list*/
    }

.rel_dyn_start :
    /*在老的uboot中,如果我们想要uboot启动后把自己拷贝到内存中的某个地方,只要把要拷贝的地址写给TEXT_BASE即可,然后boot启动后就会把自己拷贝到TEXT_BASE内的地址处运行,在拷贝之前的代码都是相对的,不能出现绝对的跳转,否则会跑飞。在新版的uboot里(2013.07),TEXT_BASE的含义改变了。它表示用户要把这段代码加载到哪里,通常是通过串口等工具。然后搬移的时候由uboot自己计算一个地址来进行搬移。新版的uboot采用了动态链接技术,在lds文件中有__rel_dyn_start和__rel_dyn_end,这两个符号之间的区域存放着动态链接符号,只要给这里面的符号加上一定的偏移,拷贝到内存中代码的后面相应的位置处,就可以在绝对跳转中找到正确的函数。*/
    {
        *(.__rel_dyn_start)
    }

.rel.dyn : {
        *(.rel*)
        /*动态链接符存放在的段*/
    }

.rel_dyn_end :
    {
        *(.__rel_dyn_end)
        /*动态链接符段结束*/
    }

.end :
    {
        *(.__end)
    }

_image_binary_end = .;
    /*bin文件结束*/

/*
     * Deprecated: this MMU section is used by pxa at present but
     * should not be used by new boards/CPUs.
     */
    . = ALIGN(4096);
    .mmutable : {  /*for MMU*/
        *(.mmutable)
    }

/*
     * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
     * __bss_base and __bss_limit are for linker only (overlay ordering)
     */
    /*bss段的描述*/
    .bss_start (OVERLAY) : {
        KEEP(*(.__bss_start));
        __bss_base = .;
    }

.bss __bss_base (OVERLAY) : {
        *(.bss*)
         . = ALIGN(4);
         __bss_limit = .;
    }

.bss_end __bss_limit (OVERLAY) : {
        KEEP(*(.__bss_end));
    }
    /*bss段的描述结束*/
    .dynsym _image_binary_end : { *(.dynsym) }
    .dynbss : { *(.dynbss) }
    .dynstr : { *(.dynstr*) }
    .dynamic : { *(.dynamic*) }
    .plt : { *(.plt*) }
    .interp : { *(.interp*) }
    .gnu.hash : { *(.gnu.hash) }
    .gnu : { *(.gnu*) }
    .ARM.exidx : { *(.ARM.exidx*) }
    .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
}

总结一下,u-boot.lds脚本文件告诉链接器linker如何布局代码段、数据段、bss段等,已经配置了u-boot自拷贝(从flash到RAM的copy)的内容。另外,还简要的涉及了动态链接技术等。

GNU linker script,ld script,GNU链接脚本的更多相关文章

  1. 链接脚本(Linker Script)用法解析(一) 关键字SECTIONS与MEMORY

    1.MEMORY关键字用于描述一个MCU ROM和RAM的内存地址分布(Memory Map),MEMORY中所做的内存描述主要用于SECTIONS中LMA和VMA的定义. 2.SECTIONS关键字 ...

  2. 链接脚本(Linker Script)应用实例(一)使用copy table将函数载入到RAM中运行

    将函数载入到RAM中运行需要以下三个步骤: (1)用编译器命令#pragma section "<section name>" <user functions&g ...

  3. 链接脚本(Linker Script)用法解析(二) clear_table & copy_table

    可执行文件中的.bss段和.data段分别存放未赋初值的全局变量和已赋初值的全局变量,两者的特点分别为: (1).bss段:①无初值,所以不占ROM空间:②运行时存储于RAM:③默认初值为0 (2). ...

  4. ld - GNU linker (连接器)

    总览 (SYNOPSIS) ld [-o output] objfile... [-Aarchitecture] [-b input-format] [-Bstatic] [-Bdynamic] [- ...

  5. Linker Scripts3--简单的链接脚本命令1

    1.前言 这个部分我们描述了简单的链接脚本命令 2.设置entry point 程序中第一条运行的指令被称为入口点entry point,可以使用ENTRY链接脚本命令设置entry point,参数 ...

  6. Linker Scripts3--简单的链接脚本命令2-Assigning Values to Symbols

    1.前言 本章继续讲述简单脚本命令的后半部分 2.Assigning Values to Symbols 你可以给一个符号(symbol)赋值,它会把这些定义的符号放入全局符号表(symbols ta ...

  7. 简单的ld链接脚本学习

    一. 链接脚本的整体认识 什么是链接文件呢?作用是什么呢? 当编写了多个C文件时,我们将他们编译链接成一个可执行的文件,此时就需要用到链接脚本文件(ld).ld脚本主要功能就是:将多个目标文件(.o) ...

  8. [转]Linux下的lds链接脚本详解

    转载自:http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml     一. 概论 每一个链接过程都由链接脚本(lin ...

  9. Linux下的lds链接脚本基础

    转载:http://soft.chinabyte.com/os/104/12255104.shtml   今天在看uboot引导Linux部分,发现要对链接脚本深入了解,才能知道各个目标文件的内存分布 ...

随机推荐

  1. Activity和Fragment生命周期对比

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

  2. Linux内核调试方法总结之调试宏

    本文介绍的内核调试宏属于静态调试方法,通过调试宏主动触发oops从而打印出函数调用栈信息. 1) BUG_ON 查看bug处堆栈内容,主动制造oops Linux中BUG_ON,WARN_ON用于调试 ...

  3. python twisted异步将数据导入到数据库中

    from twisted.enterprise import adbapi from twisted.internet import reactor def creat_conn(): # 数据库基本 ...

  4. python-加密(base64)

    import base64 #base64也是用来加密的,但是这个是可以解密的 s = "username" byte类型print(base64.b64encode(s.enco ...

  5. 阶段1 语言基础+高级_1-3-Java语言高级_1-常用API_1_第3节 Random类_11-练习二_猜数字小游

    0到100之间的数字.猜多少次才能猜对最终的结果.大了或者小了都会告诉你. 二分法查找. 循环次数不确定用whilte true的方式去循环 前两种情况是需要重试的 把猜测的代码放在whilte循环里 ...

  6. lateral view 使用方法

    这个函数相当于拆开行变成列. 可以理解为行转列. select id,order_label from table_bx lateral view explode(split(work_order_l ...

  7. 【MM系列】SAP MM-模块物料主数据简介

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP MM-模块物料主数据简介   ...

  8. K近邻实战手写数字识别

    1.导包 import numpy as np import operator from os import listdir from sklearn.neighbors import KNeighb ...

  9. 为什么说 Babel 将推动 JavaScript 的发展【转】

    Babel是一个转换编译器,它能将 ES6 转换成可以在浏览器中运行的代码.Babel 由来自澳大利亚的开发者Sebastian McKenzie创建.他的目标是使 Babel 可以处理 ES6 的所 ...

  10. web 前端1 拾遗

    1.整体布局 三个div header body footer 2.div的居中 width:980px margin:0 auto 3.内联标签 inline #内联 无法使用高度.宽度 block ...