链接脚本文件语法规则文档格式.docx
《链接脚本文件语法规则文档格式.docx》由会员分享,可在线阅读,更多相关《链接脚本文件语法规则文档格式.docx(37页珍藏版)》请在冰豆网上搜索。
![链接脚本文件语法规则文档格式.docx](https://file1.bdocx.com/fileroot1/2022-11/17/4329e968-8006-407f-9343-f7ad427cdaaf/4329e968-8006-407f-9343-f7ad427cdaaf1.gif)
是一个功能很强大的命令.这里这们会描述一个很简单的使用.让我们假设你的程序只有代码节,初始化过的数据节,和未初始化过的数据节.这些会存在于'
.text'
'
.data'
.bss'
节,另外,让我们进一步假设在你的输入文件中只有这些节.
对于这个例子,我们说代码应当被载入到地址'
0x10000'
处,而数据应当从0x8000000处开始.下面是一个实现这个功能的脚本:
SECTIONS
{
.=0x10000;
.text:
{*(.text)}
.=0x8000000;
.data:
{*(.data)}
.bss:
{*(.bss)}
}
你使用关键字'
写了这个SECTIONS命令,后面跟有一串放在花括号中的符号赋值和输出节描述的内容.
上例中,在'
命令中的第一行是向一个特殊的符号'
.'
赋值,这是一个定位计数器.如果你没有以其它的方式指定输出节的地址(其他方式在后面会描述),那么地址值就会被设为定位计数器的现有值.定位计数器然后被加上输出节的尺寸.在'
命令的开始处,定位计数器拥有值'
0'
.
第二行定义一个输出节,'
.冒号是语法需要,现在可以被忽略.节名后面的花括号中,你列出所有应当被放入到这个输出节中的输入节的名字.'
*'
是一个通配符,匹配任何文件名.表达式'
*(.text)'
意思是所有的输入文件中的'
输入节.
因为当输出节'
定义的时候,定位计数器的值是'
连接器会把输出文件中的'
节的地址设为'
余下的内容定义了输出文件中的'
节和'
节.连接器会把'
输出节放到地址'
0x8000000'
处.连接器放好'
输出节之后,定位计数器的值是'
加上'
输出节的长度.得到的结果是连接器会把'
输出节放到紧接'
节后面的位置.
连接器会通过在必要时增加定位计数器的值来保证每一个输出节具有它所需的对齐.在这个例子中,为'
节指定的地址会满足对齐约束,但是连接器可能会需要在'
节之间创建一个小的缺口.
就这样,这是一个简单但完整的连接脚本.
简单的连接脚本命令.
=============================
在本章中,我们会描述一些简单的脚本命令.
设置入口点.
-----------------------
在运行一个程序时第一个被执行到的指令称为"
入口点"
ENTRY'
连接脚本命令来设置入口点.参数是一个符号名:
ENTRY(SYMBOL)
有多种不同的方法来设置入口点.连接器会通过按顺序尝试以下的方法来设置入口点,如果成功了,就会停止.
*`-e'
入口命令行选项;
*连接脚本中的`ENTRY(SYMBOL)'
命令;
*如果定义了start,就使用start的值;
*如果存在,就使用'
节的首地址;
*地址`0'
处理文件的命令.
---------------------------
有几个处理文件的连接脚本命令.
`INCLUDEFILENAME'
在当前点包含连接脚本文件FILENAME.在当前路径下或用'
-L'
选项指定的所有路径下搜索这个文件,你可以嵌套使用'
INCLUDE'
达10层.
`INPUT(FILE,FILE,...)'
`INPUT(FILEFILE...)'
INPUT'
命令指示连接器在连接时包含的文件,就像它们是在命令行上指定的一样.
比如,如果你在连接的时候总是要包含文件'
subr.o'
但是你对每次连接时要在命令行上输入感到厌烦,你就可以在你的连接脚本中输入'
INPUT(subr.o).
事实上,如果你喜欢,你可以把你所有的输入文件列在连接脚本中,然后在连接的时候什么也不需要,只要一个'
-T'
选项就够了.
在一个'
系统根前缀'
被配置的情况下,一个文件名如果以'
/'
字符打头,并且脚本也存放在系统根前缀的某个子目录下,文件名就会被在系统根前缀下搜索.否则连接器就会企图打开当前目录下的文件.如果没有发现,连接器会通过档案库搜索路径进行搜索.
如果你使用了'
INPUT(-lFILE)'
'
ld'
会把文件名转换为'
libFILE.a'
就像命令行参数'
-l'
一样.
当你在一个隐式连接脚本中使用'
命令的时候,文件就会在连接时连接脚本文件被包含的点上被包含进来.这会影响到档案搜索.
`GROUP(FILE,FILE,...)'
`GROUP(FILEFILE...)'
除了文件必须全是档案文件之外,'
GROUP'
命令跟'
相似,它们会被反复搜索,直至没有未定义的引用被创建.
`OUTPUT(FILENAME)'
OUTPUT'
命令命名输出文件.在连接脚本中使用'
OUTPUT(FILENAME)'
命令跟在命令行中使用'
-oFILENAME'
命令是完全等效的.如果两个都使用了,那命令行选项优先.
你可以使用'
命令为输出文件创建一个缺省的文件名,而不是常用的'
a.out'
`SEARCH_DIR(PATH)'
`SEARCH_DIR'
命令给'
用于搜索档案文件的路径中再增加新的路径.使用`SEARCH_DIR(PATH)'
跟在命令行上使用'
-LPATH'
选项是完全等效的.如果两个都使用了,那连接器会两个路径都搜索.用命令行选项指定的路径首先被搜索.
`STARTUP(FILENAME)'
除了FILENAME会成为第一个被连接的输入文件,'
STARTUP'
命令完全相似,就像这个文件是在命令行上第一个被指定的文件一样.如果在一个系统中,入口点总是存在于第一个文件中,那这个就很有用.
处理目标文件格式的命令.
-----------------------------------------
有两个处理目标文件格式的连接脚本命令.
`OUTPUT_formAT(BFDNAME)'
`OUTPUT_formAT(DEFAULT,BIG,LITTLE)'
`OUTPUT_formAT'
命令为输出文件使用的BFD格式命名.使用`OUTPUT_formAT(BFDNAME)'
-oformatBFDNAME'
是完全等效的.如果两个都使用了,命令行选项优先.
你可在使用`OUTPUT_formAT'
时带有三个参数以使用不同的基于'
-EB'
-EL'
的命令行选项的格式.
如果'
都没有使用,那输出格式会是第一个参数DEFAULT,如果使用了'
输出格式会是第二个参数BIG,如果使用了'
输出格式会是第三个参数,LITTLE.
比如,缺省的基于MIPSELF平台连接脚本使用如下命令:
OUTPUT_formAT(elf32-bigmips,elf32-bigmips,elf32-littlemips)
这表示缺省的输出文件格式是'
elf32-bigmips'
但是当用户使用'
命令行选项的时候,输出文件就会被以`elf32-littlemips'
格式创建.
`TARGET(BFDNAME)'
TARGET'
命令在读取输入文件时命名BFD格式.它会影响到后来的'
命令.这个命令跟在命令行上使用`-bBFDNAME'
相似.如果使用了'
命令但`OUTPUT_formAT'
没有指定,最后的'
命令也被用来设置输出文件的格式.
其它的连接脚本命令.
----------------------------
还有一些其它的连接脚本命令.
`ASSERT(EXP,MESSAGE)'
确保EXP不等于零,如果等于零,连接器就会返回一个错误码退出,并打印出MESSAGE.
`EXTERN(SYMBOLSYMBOL...)'
强制SYMBOL作为一个无定义的符号输入到输出文件中去.这样做了,可能会引发从标准库中连接一些节外的库.你可以为每一个EXTERN'
列出几个符号,而且你可以多次使用'
EXTERN'
.这个命令跟'
-u'
命令行选项具有相同的效果.
`FORCE_COMMON_ALLOCATION'
这个命令跟命令行选项'
-d'
具有相同的效果:
就算指定了一个可重定位的输出文件('
-r'
),也让'
为普通符号分配空间.
`INHIBIT_COMMON_ALLOCATION'
这个命令跟命令行选项`--no-define-common'
就算是一个不可重位输出文件,也让'
忽略为普通符号分配的空间.
`NOCROSSREFS(SECTIONSECTION...)'
这个命令在遇到在某些特定的节之间引用的时候会产生一条错误信息.
在某些特定的程序中,特别是在使用覆盖技术的嵌入式系统中,当一个节被载入内存时,另外一个节就不会在内存中.任何在两个节之间的直接引用都会是一个错误.比如,如果节1中的代码调用了另一个节中的一个函数,这就会产生一个错误.
`NOCROSSREFS'
命令带有一个输出节名字的列表.如果'
遇到任何在这些节之间的交叉引用,它就会报告一个错误,并返回一个非零退出码.注意,`NOCROSSREFS'
命令使用输出节名,而不是输入节名.
`OUTPUT_ARCH(BFDARCH)'
指定一个特定的输出机器架构.这个参数是BFD库中使用的一个名字.你可以通过使用带有'
-f'
选项的'
objdump'
程序来查看一个目标文件的架构.
为符号赋值.
===========================
你可以在一个连接脚本中为一个符号赋一个值.这会把一个符号定义为一个全局符号.
简单的赋值.
------------------
你可以使用所有的C赋值符号为一个符号赋值(该符号同时被定义).
`SYMBOL=EXPRESSION;
`SYMBOL+=EXPRESSION;
`SYMBOL-=EXPRESSION;
`SYMBOL*=EX