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


    1.前言

    这个部分我们描述了简单的链接脚本命令

    2.设置entry point

    程序中第一条运行的指令被称为入口点entry point,可以使用ENTRY链接脚本命令设置entry point,参数是一个符号名:

    ENTRY(symbol)

    有几种方法可以设置entry point,链接器会按照如下的顺序来try各种方法,只要任何一种方法成功则会停止:

    •  the ‘-e’ entry command-line option;
    •  the ENTRY(symbol) command in a linker script;
    •  the value of the symbol start, if defined;
    •  the address of the first byte of the ‘.text’ section, if present;
    •  The address 0

    3.Commands Dealing with Files

    有几种处理文件的链接脚本命令:

    •  INCLUDE filename:这里包含了链接脚本文件名

    这个文件会在当前目录搜索,或者在"-L"指定的目录搜索,可以嵌套调用INCLUDE达10级

    即: 文件1内INCLUDE文件2, 文件2内INCLUDE文件3… , 文件10内INCLUDE文件11. 那么文件11内不能再出现 INCLUDE指令了.

    可以把INCLUDE命令放到文件的最前面,也可以放到MEMORY或SECTIONS命令里面,或者放到输出section描述里面。

    •  INPUT(file, file, ...)
    • INPUT(file file ...)

    INPUT命令指导链接器在链接时包含文件,否则它们必须出现在命令行

    举例来说,如果你链接的时候总是想包含"subr.o",但是不想在每行命令行里输入,可以把‘INPUT (subr.o)’放到链接脚本里

    事实上可以把所有的输入文件放到链接脚本里,然后通过-T选项来调用链接器

    这种情况下,sysroot前缀被配置,文件名以“/”开始,被处理的脚本位于sysroot前缀,文件名将在sysroot前缀搜索。

    否则链接器将在当前目录搜索,如果没有发现,将搜索archive库搜索路径,可以参考‘-L’ in Section 2.1 [Command Line Options], page 3.

    如果使用‘INPUT (-lfile)’,则ld将转换文件名为libfile.a,与命令行参数"-l"一样

    •    GROUP(files) : 指定需要重复搜索符号定义的多个输入文件

    除了file必须是库文件以外,该命令与INPUT相似, 且file文件作为一组被ld重复扫描,直到不在有新的未定义的引用出现。

    • OUTPUT(FILENAME) : 定义输出文件的名字

    同ld的-o选项, 不过-o选项的优先级更高. 所以它可以用来定义默认的输出文件名. 如a.out

    • SEARCH_DIR(PATH) :定义搜索路径,

    同ld的-L选项, 不过由-L指定的路径要比它定义的优先被搜索。

    • STARTUP(filename) : 指定filename为第一个输入文件

    在链接过程中, 每个输入文件是有顺序的. 此命令设置文件filename为第一个输入文件。

    就象这个文件是在命令行上第一个被指定的文件一样, 如果在一个系统中,,入口点总是存在于第一个文件中,那这个就很有用。

    4.Commands Dealing with Object File Formats

    • OUTPUT_FORMAT(BFDNAME) : 设置输出文件使用的BFD格式

    同ld选项-o format BFDNAME, 不过ld选项优先级更高.

    • OUTPUT_FORMAT(DEFAULT,BIG,LITTLE) : 定义三种输出文件的格式(大小端)

    对于此命令,要在命令行中使用-EB或-EL选项来指定不同的输出文件格式

    如果'-EB'和'-EL'都没有使用, 那输出格式会是第一个参数 DEFAULT,

    如果使用了'-EB',输出格式会是第二个参数 BIG,

    如果使用了'-EL', 输出格式会是第三个参数, LITTLE.

    比如:缺省的基于 MIPS ELF 平台连接脚本使用如下命令:

    OUTPUT_formAT(elf32-bigmips, elf32-bigmips, elf32-littlemips)

    这表示缺省的输出文件格式是'elf32-bigmips', 但是当用户使用'-EL'命令行选项的时候, 输出文件就会被以`elf32-littlemips'格式创建.

    • TARGET(BFDNAME):设置输入文件的BFD格式

    同ld选项-b BFDNAME. 若使用了TARGET命令, 但未使用OUTPUT_FORMAT命令, 则最用一个TARGET命令设置的BFD格式将被作为输出文件的BFD格式.

    5. Assign alias names to memory regions

    别名可以被加到用MEMORY命令创建的存储区域.每个名称对应着最多一个存储区域

    REGION_ALIAS函数创建了存储区域region的一个别名.这使得输出section可以灵活地映射到存储区域。后面有一个例子。

    假设我们有一个具有各种存储设备的嵌入式系统的应用:

    (1)各存储设备存储特性

    易失性存储器RAM允许执行代码或存储数据;

    非易失性存储器ROM允许执行代码和数据只读访问;

    非易失性存储器ROM2,具有只读数据访问和不可运行代码的特性。

    (2)我们有四个输出sections:

      .text 程序代码

     .rodata 只读数据

     .data 可读写初始化数据

     .bss 可读写初始化数据,但数据必须被初始化为0.

    (3)目标是提供一个链接器命令文件,该文件包含定义输出sections的系统独立部分和映射输出sections到系统上有效的存储区域的系统非独立部分.我们的嵌入式系统带有三种不同的存储配置A,B和C:

    Section Variant A Variant B Variant C 
    .text RAM ROM ROM 
    .rodata RAM ROM ROM2 
    .data RAM RAM/ROM RAM/ROM2 
    .bss RAM RAM RAM 

    注:符号RAM/ROM 或 RAM/ROM2 表示这个section会被加载到相应的区域ROM 或 ROM2.请注意data section的加载地址是基于三个变量中.rodata section的末尾开始的.

    (4)基本链接器脚本处理了如下输出section.它包含了系统非独立的linkcmds.memory文件,该文件用于描述存储分布:

    INCLUDE linkcmds.memory
          
    SECTIONS
    {
        .text :
        {
            *(.text)
        } > REGION_TEXT
        .rodata :
        {
            *(.rodata)
            rodata_end = .;
        } > REGION_RODATA
        .data : AT (rodata_end)
        {
            data_start = .;
            *(.data)
        } > REGION_DATA
        data_size = SIZEOF(.data);
        data_load_start = LOADADDR(.data);
        .bss :
        {
            *(.bss)
        } > REGION_BSS
     }

    (5)现在我们需要三个不同的 linkcmds.memory 文件来定义存储区域和别名。 针对A,B和C三种的linkcmds.memory的内容如下:

    A Here everything goes into the RAM.
    这里所有的都进入到RAM
     MEMORY
     {
         RAM : ORIGIN = 0, LENGTH = 4M
     }
              
     REGION_ALIAS("REGION_TEXT", RAM);
     REGION_ALIAS("REGION_RODATA", RAM);
     REGION_ALIAS("REGION_DATA", RAM);
     REGION_ALIAS("REGION_BSS", RAM);
    B Program code and read-only data go into the ROM.
      Read-write data goes into the RAM.
      An image of the initialized data is loaded into the ROM and will be copied during system start into the RAM.
     程序代码和只读数据进入的是ROM。可读写的数据进入的是RAM。初始化数据的一个镜像被加载到ROM并且当系统启动时会被拷贝到RAM。
    MEMORY
    {
            ROM : ORIGIN = 0, LENGTH = 3M
            RAM : ORIGIN = 0x10000000, LENGTH = 1M
    } REGION_ALIAS(
    "REGION_TEXT", ROM); REGION_ALIAS("REGION_RODATA", ROM); REGION_ALIAS("REGION_DATA", RAM); REGION_ALIAS("REGION_BSS", RAM);

    C Program code goes into the ROM. Read-only data goes into the ROM2.

      Read-write data goes into the RAM.
      An image of the initialized data is loaded into the ROM2 and will be copied during system start into the RAM.

    程序代码进入的是ROM。只读数据进入的是ROM2。可读写的数据进入的是RAM。初始化数据的一个镜像被加载到ROM2并且当系统启动时被拷贝到RAM。

    MEMORY
    {
          ROM : ORIGIN = 0, LENGTH = 2M
          ROM2 : ORIGIN = 0x10000000, LENGTH = 1M
          RAM : ORIGIN = 0x20000000, LENGTH = 1M
    }
              
    REGION_ALIAS("REGION_TEXT", ROM);
    REGION_ALIAS("REGION_RODATA", ROM2);
    REGION_ALIAS("REGION_DATA", RAM);
    REGION_ALIAS("REGION_BSS", RAM);

    It is possible to write a common system initialization routine to copy the .data section from ROM or ROM2 into the RAM if necessary:

    如果需要,请尽可能地写一个通用的系统初始化例程,实现把.data section从ROM/ROM2拷贝到RAM。

    #include <string.h>
         
    extern char data_start [];
    extern char data_size [];
    extern char data_load_start []; void copy_data(void) { if (data_start != data_load_start) { memcpy(data_start, data_load_start, (size_t) data_size); } }

     6. Other Linker Script Commands

    • ASSERT(exp, message)

    确保exp是非0的
    如果是0则退出链接,并返回错误码,打印message

    • EXTERN(symbol symbol ...)

    强制未定义的符号链接进输出文件,这样可以触发链接器从标准库文件链接。
    每个EXTERN可以列出几个symbol,也可以使用多个EXTERN,跟在命令行使用-u选项是一样的

    • FORCE_COMMON_ALLOCATION
    • INHIBIT_COMMON_ALLOCATION
    • INSERT [ AFTER | BEFORE ] output_section
    • NOCROSSREFS(section section ...)

    让ld产生一个错误

    • OUTPUT_ARCH(bfdarch)

    指定一个特别的输出机器结构,参数用的是BFD库的名字。你可以使用objdump程序的‘-f’选项查看目标文件的机器结构

    参考文献

    [1] http://blog.csdn.net/han22647/article/details/64920623

    [2] http://blog.csdn.net/huiyuyang_fish/article/details/16884593

  • 相关阅读:
    简单学习MyBatis
    探讨AOP的两种实现方式
    浅析Spring AOP术语
    依赖注入(DI)的迭代实现
    初识依赖注入(DI)
    Bean工厂ApplicationContext
    ps文章推荐
    ueditor全屏和el-dialog模态框有冲突的解决方法(其他框架请比葫芦画瓢)
    (各种转载)
    element-ui修改样式不生效的官网解决方式
  • 原文地址:https://www.cnblogs.com/smartjourneys/p/8328240.html
Copyright © 2020-2023  润新知