当前位置:   article > 正文

ld链接器脚本(二)_region_alias

region_alias

简单的链接器脚本命令

本部分将阐述简单的链接器脚本命令

设置入口点

第一个指令为,入口点。可以使用ENTRY链接器命令来设置入口点。他的参数为符号名。如下:

ENTRY(symbol)
  • 1

有几种方式设置入口点,链接器将按照如下顺序设置入口点,一旦某个步骤成功,则停止:

  1. -e 命令行选项
  2. 链接器脚本中的ENTRY命令
  3. 如果定义了start符号,则使用这个符号的值
  4. 如果存在.text section,则使用其第一个字节地址。
  5. 地址0

处理文件的命令

有几个链接器脚本命令可以用来处理文件

INCLUDE filename
  • 1

在此处,包含链接器脚本。filename将在当前目录,以及-L选项指定的目录中搜索。可以嵌套调用INCLUDE,十层。

也可以在MEMORY,SECTIONS命令或者输出section描述的顶层使用INCLUDE命令

INPUT(file,file,...)
INPUT(file file ...)
  • 1
  • 2

INPUT命令指示链接器在链接中包含这些文件,就好像它们是在命令行上一样。

例如,在链接时,总是想要链接’subr.o’文件。每次放在命令行上又总是让人讨厌,那么可以使用这个命令,将‘subr.o’放在链接脚本中。

事实上,如果你喜欢,你可以将所有的输入文件都放入链接脚本中,然后使用-T选项,使用这个链接脚本。

如果配置了sysroot前缀,并且文件名是以’/'字符开始,并且正在处理的脚本位于sysroot前缀内,那么文件将在sysroot前缀内进行搜索。否则在当前目录,和库搜索路径中搜索。

如果你使用了INPUT(-lfile),ld将其转换为libfile.a,就好像在命令行中使用了-l选项一样。

如果在一个隐式的链接脚本中使用了INPUT命令,则会在链接脚本出现的地方,包含指定的文件。这会影响归档文件的搜索。

GROUP(file,file,...)
GROUP(file file file)
  • 1
  • 2

GROUP命令和INPUT命令一样,不过他们的命名文件应该全部为归档文件。这些归档文件会被重复的搜索,直到没有未定义的引用被创建为止。

AS_NEEDED(file,file,...)
AS_NEEDED(file file ...)
  • 1
  • 2

这个命令只能出现在INPUT和GROUP命令的内部。列出来的文件就好像直接出现在INPUT和GROUP里面的文件一样。除ELF共享库外,只有在实际需要时才会添加它们。几乎我所有列出的文件都打开了‘–as-needed’选项。

OUTPUT(filename)
  • 1

OUTPUT命令命名输出文件。使用这个等价于在命令行中‘-o filename’如果两者都使用,则命令行选项优先。

可以使用这个命令定义一个默认的输出名,而不是a.out

SEARCH_DIR(path)
  • 1

该命令,增加归档文件的搜索路径path。使用这个命令等价于使用“-L path”命令行选项.如果两者都指定,则两个路径都搜索。不过首先搜索命令行选项中的路径。

STARTUP(filename)
  • 1

STARTUP命令类似于INPUT命令,除了filename将成为要链接的第一个输入文件,就好像它是在命令行中指定的那样。当入口点始终是第一个文件的开头时,这可能很有用。

处理obj文件格式的命令

有几个用于处理obj文件格式的命令

OUTPUT_FORMAT(bfdname)
OUTPUT_FORMAT(default,big,little)
  • 1
  • 2

使用OUTPUT_FORMAT(bfdname)就像在命令行上使用’–oformat bfdname’。如果两者都指定,则命令行选项具有更高优先级。

您可以使用带有三个参数的OUTPUT_FORMAT来使用基于’-EB’和’-EL’命令行选项的不同格式。这允许链接脚本根据所需的字节顺序设置输出格式。

如果既不使用’-EB’也不使用’-EL’,则输出格式将是第一个参数default。如果使用’-EB’,输出格式将是第二个参数big。如果使用’-EL’,输出格式将是第三个参数,little。
例如,MIPS ELF目标的默认链接脚本使用以下命令:

OUTPUT_FORMAT(elf32-bigmips, elf32-bigmips, elf32-littlemips)
  • 1

这表示输出文件的默认格式为’elf32-bigmips’,但如果用户使用’-EL’命令行选项,则输出文件将以’elf32-littlemips’格式创建。

TARGET(bfdname)
  • 1

TARGET命令命名在读取输入文件时使用的BFD格式。它会影响后续的INPUT和GROUP命令。此命令类似于在命令行上使用’-b bfdname’如果使用TARGET命令但不使用OUTPUT_FORMAT,则最后一个TARGET命令也用于设置输出文件的格式。

内存region的别名

内存region后面介绍,每个别名最多对应一个内存region

REGION_ALIAS(alias,region)
  • 1

为region创建一个alias的别名。他可以让输出section到region有更灵活的映射。举例如下:

假设我们要为嵌入式系统写一个应用,这个嵌入式系统带有各种内存存储设备。可能带有通用的易失性存储器RAM,允许代码执行或数据存储。 也可能具有只读,非易失性存储器ROM,允许代码执行和只读数据访问。还有一种可能是只读,非易失性存储器ROM2,具有只读数据访问和无代码执行能力。 我们的应用有四个输出部分:

  • .text程序代码;
  • .rodata只读数据;
  • .data读写初始化数据;
  • .bss读写零初始化数据。

目标是提供一个链接器脚本,它包含一个独立于系统的部分,用于定义输出部分,以及一个系统相关部分,用于将输出部分映射到系统上可用的内存区域。 我们的嵌入式系统有三种不同的内存设置A,B和C:

Section VariantA VariantB VariantC
.text   RAM     ROM         ROM
.rodata RAM     ROM         ROM2
.data   RAM     RAM/ROM     RAM/ROM2
.bss    RAM     RAM         RAM
  • 1
  • 2
  • 3
  • 4
  • 5

注意:RAM/ROM 或者RAM/ROM2 表示section分别加载到ROM或者ROM2

注意:在三种类型的嵌入式设备中,.data sectoin的开始地址是在.rodata section 的末尾。

主要的连接器脚本,处理输出段,如下:它包含一个系统相关的部分名为linkcmds.memory这个文件描述了内存布局。

INCLUDE linkcmds.memory
SECTONS
{
    .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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

接下来,需要为三种嵌入式设备,定义不同的linkcmds.memory文件。如下:

A
所有段都放入RAM中

MEMORY
{
    RAM:ORGIN = 0,LENGTH = 4M
}
REGION_ALIAS("REGION_TEXT",RAM);
REGION_ALIAS("REGION_RODATA",RAM);
REGION_ALIAS("REGION_DATA",RAM);
REGION_ALIAS("REGION_BSS",RAM);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

B
程序代码和只读数据放入ROM中,读写data放入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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

C
程序代码让如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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

如果有必要,可以写一个通用的代码,将rom或者rom2中的.data section复制到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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其他链接器脚本命令

如下:

ASSERT(exp,message)
  • 1

保证exp为非零,如果为0,则退出链接器,并且输出错误码,然后打印message

EXTERN(symbol symbol...)
  • 1

将上面的symbol强制放入输出文件,并且这些符号为未定义的符号。
例如:为了链接标准库模块,可以将几个符号,写入一个EXTERN中,也可以使用多个EXTERN。这个命令跟命令行选项-u具有同样的效果。

FORCE_COMMON_ALLOCATION
  • 1

这个命令跟命令行选项-d,效果相同:让ld为通用符号分配空间,即使可重定位的输出文件指定了-r选项。

INHIBIT_COMMON_ALLOCATION
  • 1

这个命令跟命令行选项–no-define-common,效果相同:使ld省略了对通用符号的地址分配,即使对于不可重定位的输出文件也是如此

INSERT[AFTER|BEFORE] output_section
  • 1

此命令通常放在脚本中用来扩充默认的section。他在output_section之后(或者之前)插入链接脚本,并且不会导致-T覆盖默认的脚本。

确切的插入点跟孤儿 section相同(见后面)。将输入section映射到输出section之后,发生插入。

在插入之前,因为’-T’脚本在默认链接脚本之前被解析,所以’-T’脚本中的语句发生在默认链接脚本之前。

下面是一个例子:

SECTIONS
{
    OVERLAY:
    {
        .ov1{ov1*(.text)}
        .ov2{ov2*(.text)}
    }
}
INSERT AFTER .text;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
NOCROSSREFS(section section...)
  • 1

这个命令可以用来告诉ld报告关于在某个section中的引用的错误

在某些类型的程序中,特别是在使用叠加层时的嵌入式系统上,当一个section加载到内存中时,另一个section不加载。这两个部分之间的任何直接引用都是错误。
例如,如果一个section中的代码在另一section中被定义为函数,则报错。

这个命令,接受一系列的输出section名。如果ld检测到任何在这些section中的跨section的调用,就报一个错误,并且返回一个非零的退出值。注意:NOCROSSREFS命令使用输出section名,而不是输入section名。

OUTPUT_ARCH(bfdarch)
  • 1

指定一个实际的输出机器架构。参数是BFD库使用的名字。可以使用objdump命令加上-f查看obj文件的架构。

后续文章,将先介绍ld里面的符号引用和赋值。然后是各个指令的详细介绍

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/219871
推荐阅读
  

闽ICP备14008679号