赞
踩
本部分将阐述简单的链接器脚本命令
第一个指令为,入口点。可以使用ENTRY链接器命令来设置入口点。他的参数为符号名。如下:
ENTRY(symbol)
有几种方式设置入口点,链接器将按照如下顺序设置入口点,一旦某个步骤成功,则停止:
有几个链接器脚本命令可以用来处理文件
INCLUDE filename
在此处,包含链接器脚本。filename将在当前目录,以及-L选项指定的目录中搜索。可以嵌套调用INCLUDE,十层。
也可以在MEMORY,SECTIONS命令或者输出section描述的顶层使用INCLUDE命令
INPUT(file,file,...)
INPUT(file file ...)
INPUT命令指示链接器在链接中包含这些文件,就好像它们是在命令行上一样。
例如,在链接时,总是想要链接’subr.o’文件。每次放在命令行上又总是让人讨厌,那么可以使用这个命令,将‘subr.o’放在链接脚本中。
事实上,如果你喜欢,你可以将所有的输入文件都放入链接脚本中,然后使用-T选项,使用这个链接脚本。
如果配置了sysroot前缀,并且文件名是以’/'字符开始,并且正在处理的脚本位于sysroot前缀内,那么文件将在sysroot前缀内进行搜索。否则在当前目录,和库搜索路径中搜索。
如果你使用了INPUT(-lfile),ld将其转换为libfile.a,就好像在命令行中使用了-l选项一样。
如果在一个隐式的链接脚本中使用了INPUT命令,则会在链接脚本出现的地方,包含指定的文件。这会影响归档文件的搜索。
GROUP(file,file,...)
GROUP(file file file)
GROUP命令和INPUT命令一样,不过他们的命名文件应该全部为归档文件。这些归档文件会被重复的搜索,直到没有未定义的引用被创建为止。
AS_NEEDED(file,file,...)
AS_NEEDED(file file ...)
这个命令只能出现在INPUT和GROUP命令的内部。列出来的文件就好像直接出现在INPUT和GROUP里面的文件一样。除ELF共享库外,只有在实际需要时才会添加它们。几乎我所有列出的文件都打开了‘–as-needed’选项。
OUTPUT(filename)
OUTPUT命令命名输出文件。使用这个等价于在命令行中‘-o filename’如果两者都使用,则命令行选项优先。
可以使用这个命令定义一个默认的输出名,而不是a.out
SEARCH_DIR(path)
该命令,增加归档文件的搜索路径path。使用这个命令等价于使用“-L path”命令行选项.如果两者都指定,则两个路径都搜索。不过首先搜索命令行选项中的路径。
STARTUP(filename)
STARTUP命令类似于INPUT命令,除了filename将成为要链接的第一个输入文件,就好像它是在命令行中指定的那样。当入口点始终是第一个文件的开头时,这可能很有用。
有几个用于处理obj文件格式的命令
OUTPUT_FORMAT(bfdname)
OUTPUT_FORMAT(default,big,little)
使用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)
这表示输出文件的默认格式为’elf32-bigmips’,但如果用户使用’-EL’命令行选项,则输出文件将以’elf32-littlemips’格式创建。
TARGET(bfdname)
TARGET命令命名在读取输入文件时使用的BFD格式。它会影响后续的INPUT和GROUP命令。此命令类似于在命令行上使用’-b bfdname’如果使用TARGET命令但不使用OUTPUT_FORMAT,则最后一个TARGET命令也用于设置输出文件的格式。
内存region后面介绍,每个别名最多对应一个内存region
REGION_ALIAS(alias,region)
为region创建一个alias的别名。他可以让输出section到region有更灵活的映射。举例如下:
假设我们要为嵌入式系统写一个应用,这个嵌入式系统带有各种内存存储设备。可能带有通用的易失性存储器RAM,允许代码执行或数据存储。 也可能具有只读,非易失性存储器ROM,允许代码执行和只读数据访问。还有一种可能是只读,非易失性存储器ROM2,具有只读数据访问和无代码执行能力。 我们的应用有四个输出部分:
目标是提供一个链接器脚本,它包含一个独立于系统的部分,用于定义输出部分,以及一个系统相关部分,用于将输出部分映射到系统上可用的内存区域。 我们的嵌入式系统有三种不同的内存设置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
注意: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 }
接下来,需要为三种嵌入式设备,定义不同的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);
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);
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);
如果有必要,可以写一个通用的代码,将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);
}
}
如下:
ASSERT(exp,message)
保证exp为非零,如果为0,则退出链接器,并且输出错误码,然后打印message
EXTERN(symbol symbol...)
将上面的symbol强制放入输出文件,并且这些符号为未定义的符号。
例如:为了链接标准库模块,可以将几个符号,写入一个EXTERN中,也可以使用多个EXTERN。这个命令跟命令行选项-u具有同样的效果。
FORCE_COMMON_ALLOCATION
这个命令跟命令行选项-d,效果相同:让ld为通用符号分配空间,即使可重定位的输出文件指定了-r选项。
INHIBIT_COMMON_ALLOCATION
这个命令跟命令行选项–no-define-common,效果相同:使ld省略了对通用符号的地址分配,即使对于不可重定位的输出文件也是如此
INSERT[AFTER|BEFORE] output_section
此命令通常放在脚本中用来扩充默认的section。他在output_section之后(或者之前)插入链接脚本,并且不会导致-T覆盖默认的脚本。
确切的插入点跟孤儿 section相同(见后面)。将输入section映射到输出section之后,发生插入。
在插入之前,因为’-T’脚本在默认链接脚本之前被解析,所以’-T’脚本中的语句发生在默认链接脚本之前。
下面是一个例子:
SECTIONS
{
OVERLAY:
{
.ov1{ov1*(.text)}
.ov2{ov2*(.text)}
}
}
INSERT AFTER .text;
NOCROSSREFS(section section...)
这个命令可以用来告诉ld报告关于在某个section中的引用的错误
在某些类型的程序中,特别是在使用叠加层时的嵌入式系统上,当一个section加载到内存中时,另一个section不加载。这两个部分之间的任何直接引用都是错误。
例如,如果一个section中的代码在另一section中被定义为函数,则报错。
这个命令,接受一系列的输出section名。如果ld检测到任何在这些section中的跨section的调用,就报一个错误,并且返回一个非零的退出值。注意:NOCROSSREFS命令使用输出section名,而不是输入section名。
OUTPUT_ARCH(bfdarch)
指定一个实际的输出机器架构。参数是BFD库使用的名字。可以使用objdump命令加上-f查看obj文件的架构。
后续文章,将先介绍ld里面的符号引用和赋值。然后是各个指令的详细介绍
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。