- 论坛徽章:
- 0
|
1.
目标文件格式与类型
GNU
C
compiler根据源文件的后缀名来对文件进行预处理、汇编或编译操作。在编译链接时,生成的目标文件都是ELF格式的(可执行链接格式,Executable
and Linking Format)。Object文件格式有三种类型:
(1)可重定位(relocatable)文件:用来和其他的object文件一起链接为一个可执行文件(executable)或一个共享文件(.so文件,shared
object)。
(2)可执行(executable)文件;
(3)共享目标文件(shared
object file):用于被下面的两个链接器链接。一是链接编辑器(ld),可以和其他的relocatable或shared
object
file来创建其他的目标文件,例如.so共享库(可用file命令查看其属性);二是动态链接器,联合一个可执行文件和其他的shared
object file来创建一个进程映像。
2.
链接与链接脚本
链接器ld把object文件中的每个section都作为一个整体,为其分配运行的地址(memory
layout),这个过程就是重定位(relocation);最后把所有目标文件合并为一个目标文件。
链接通过一个linker
script来控制,这个脚本描述了输入文件的sections到输出文件的映射,以及输出文件的memory
layout。
因此,linker总会使用一个linker
script,如果不特别指定,则使用默认的script;可以使用‘-T’命令行选项来指定一个linker
script。
*映像文件的输入段与输出段
linker把多个输入文件合并为一个输出文件。输出文件和输入文件都是目标文件(object
file),输出文件通常被称为可执行文件(executable)。
每个目标文件都有一系列section,输入文件的section称为input
section,输出文件的section则称为output
section。
一个section可以是loadable的,即输出文件运行时需要将这样的section加载到memory(类似于RO&RW段);也可以是allocatable的,这样的section没有任何内容,某些时候用0对相应的memory区域进行初始化(类似于ZI段);如果一个section既非loadable也非allocatable,则它通常包含的是调试信息。
每个loadable或allocatable的output
section都有两个地址,一是VMA(virtual
memory address),是该section的运行时域地址;二是LMA(load
memory address),是该section的加载时域地址。
可以通过objdump工具附加'-h'选项来查看目标文件中的sections。
*简单的Linker
script
(1)
SECTIONS命令:
The
SECTIONS command tells the linker how to map input sections into
output sections, and how to place the output sections in memory.
命令格式如下:
SECTIONS
{
sections-command
sections-command
......
}
其中sections-command可以是ENTRY命令,符号赋值,输出段描述,也可以是overlay描述。
(2)
地址计数器‘.’(location
counter):
该符号只能用于SECTIONS命令内部,初始值为‘0’,可以对该符号进行赋值,也可以使用该符号进行计算或赋值给其他符号。它会自动根据SECTIONS命令内部所描述的输出段的大小来计算当前的地址。
(3)
输出段描述(output
section description):
前面提到在SECTIONS命令中可以作输出段描述,描述的格式如下:
section
[address] [(type)] : [AT(lma)]
{
output-section-command
output-section-command
...
}
[>region] [AT>lma_region] [:phdr :phdr ...] [=fillexp]
很多附加选项是用不到的。其中的output-section-command又可以是符号赋值,输入段描述,要直接包含的数据值,或者某一特定的输出段关键字。
*linker
script 实例
==============================
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
.
= 0xa3f00000;
__boot_start
= .;
.start ALIGN(4)
: {
*(.text.start)
}
.setup ALIGN(4)
: {
setup_block
= .;
*(.setup)
setup_block_end
= .;
}
.text ALIGN(4)
: {
*(.text)
}
.rodata ALIGN(4)
: {
*(.rodata)
}
.data ALIGN(4)
: {
*(.data)
}
.got ALIGN(4)
: {
*(.got)
}
__boot_end
= .;
.bss ALIGN(16)
: {
bss_start
= .;
*(.bss)
*(COMMON)
bss_end
= .;
}
.comment ALIGN(16)
: {
*(.comment)
}
stack_point
= __boot_start + 0x00100000;
loader_size
= __boot_end - __boot_start;
setup_size
= setup_block_end - setup_block;
}
=============================
在SECTIONS命令中的类似于下面的描述结构就是输出段描述:
.start ALIGN(4)
: {
*(.text.start)
}
.start为output
section name,ALIGN(4)返回一个基于location
counter(.)的4字节对齐的地址值。*(.text.start)是输入段描述,*为通配符,意思是把所有被链接的object文件中的.text.start段都链接进这个名为.start的输出段。
源文件中所标识的section及其属性实际上就是对输入段的描述,例如.text.start输入段在源文件start.S中的代码如下:
.section
.text.start
.global
_start
_start
:
b start
[推荐阅读]
1.ARM学习报告002--GNU tool开发ARM程序及生成映象文件机理
2.Using ld, the GNU Linker
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/26710/showart_343210.html |
|