• 简单的ld链接脚本学习


    一、 链接脚本的整体认识

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

    链接脚本文件主要有什么内容呢? 为了规范,我们分为三个部分:

    1. 链接配置(可有可无)

    如一些符号变量的定义、入口地址、输出格式等

    STACK_SIZE = 0X200;
    OUTPUT_FORMAT(elf32-littlearm)
    OUTPUT_ARCH(arm)
    ENTRY(_start)
    
    1. 内存布局定义

    脚本中以MEMORY命令定义了存储空间,其中以ORIGIN定义地址空间的起始地址,LENGTH定义地址空间的长度。

    MEMORY
    {
    FLASH (rx) : ORIGIN = 0, LENGTH = 64K
    }
    
    1. 段链接定义

    脚本中以SECTIONS命令定义一些段(text、data、bss等段)链接分布。

    SECTIONS
    {
        .text :
        {
          *(.text*)
        } > FLASH
    }
    
    

    .text段即代码段,* (.text*)指示将工程中所有目标文件的.text段链接到FLASH中

    二、常用关键字、命令

    1. MEMORY命令

    使用MEMORY来定义内存如下:

    MEMORY {
    NAME1 [(ATTR)] : ORIGIN = ORIGIN1, LENGTH = LEN2
    NAME2 [(ATTR)] : ORIGIN = ORIGIN2, LENGTH = LEN2
    …
    }
    

    NAME :存储区域的名字。(自己可以随意命名)

    ATTR :定义该存储区域的属性。ATTR属性内可以出现以下7 个字符:

    • R 只读section
    • W 读/写section
    • X 可执行section
    • A 可分配的section
    • I 初始化了的section
    • L 同I
    • ! 不满足该字符之后的任何一个属性的section

    ORIGIN :关键字,区域的开始地址,可简写成org 或o

    LENGTH :关键字,区域的大小,可简写成len 或l

    MEMORY
    {
    rom (rx) : ORIGIN = 0, LENGTH = 256K
    ram (!rx) : org = 40000000, l = 4M
    }
    
    1. 定位符号‘.’的使用

    ‘.’表示当前地址,它可以被赋值也可以赋值给某个变量。
    如下为将当前地址赋值给某个变量(链接器链接是按照SECTIONS里的段顺序排列的,前面的排列完之后就能计算出当前地址)

    RAM_START = .;
    

    如下为将段存放在特定的地址中:

    SECTIONS
    {
        . = 0×10000;
        .text : 
        { 
            *(.text)
        }
        
        . = 0×8000000;
        .data : 
        { 
            *(.data) 
        }
    }
    

    “. = 0×10000;”该语句表示将当前地址设置为0x10000。如上代码中,意思是将所有目标文件的text段从0x10000地址开始存放。

    3 SECTIONS 命令

    SECTIONS基本的命令语法如下:

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

    这么多参数中,只有secname 和 contents 是必须的,即可简写成:

    SECTIONS
    {
           ...
          secname :
          { 
            contents 
          } 
          ...
    }
    

    链接脚本本质就是描述输入和输出。secname表示输出文件的段,即输出文件中有哪些段。而contents就是描述输出文件的这个段从哪些文件里抽取而来,即输入文件,一般就是目标文件之类的。
    如下,将目标文件的数据段存放在输出文件的数据段(段名自己定义,段名前后必须要有空格)

    SECTIONS
    {
           ...
          .data :
          { 
            main.o(.data)
            *(.data)
          } 
          ...
    }
    

    其中 *(.data) 表示将所有的目标的.data段链接到输出文件.datad段中, 特别注意的是,之前链接的就不会再链接,这样做的目的是可以将某些特殊的目标文件链接到地址前面。

    我们继续来讲一下其他参数。

    • start :表示将某个段强制链接到的地址。
    • AT(addr):实现存放地址和加载地址不一致的功能,AT表示在文件中存放的位置,而在内存里呢,按照普通方式存储。
    • region:这个region就是前面说的MEMORY命令定义的位置信息。
    1. PROVIDE关键字:

    该关键字定义一个(目标文件内被引用但没定义)符号。相当于定义一个全局变量,其他C文件可以引用它。

    SECTIONS
    {
        .text :
        {
            *(.text)
            _etext = .;
            PROVIDE(etext = .);
        }
    }
    

    如上,目标文件可以引用etext符号,其地址为定义为.text section之后的第一个字节的地址。C文件中引用。

    int main()
    {
        //引用该变量
        extern char  _etext;
        //...
    }
    
    1. KEEP 关键字

    在连接命令行内使用了选项–gc-sections后,连接器可能将某些它认为没用的section过滤掉,此时就有必要强制连接器保留一些特定的 section,可用KEEP()关键字达此目的。如KEEP(* (.text))或KEEP(SORT(*)(.text))

     



    作者:小王子_f27a
    链接:https://www.jianshu.com/p/42823b3b7c8e
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    20200116
    20200115
    20191214数组之四:数字不相同的完全平方数(关于数位上数字判断与sprintf)
    结构体与C++sort()函数的用法
    字符串常用函数
    sscanf用法
    螺旋矩阵
    模m的k次根
    梅森素数与完全数
    bit_reverse_swap
  • 原文地址:https://www.cnblogs.com/dylancao/p/9228885.html
Copyright © 2020-2023  润新知