主要是链接中的可重定位目标文件和可执行目标文件
1.基本知识须知
2.相关代码文件
3.运行及解释
4.总结
1.基本知识须知
1.预处理,生成预编译文件(.i文件):
gcc –E main.c –o main.i
2.编译,生成汇编代码(.s文件):
gcc –S main.i –o main.s
3.汇编,生成目标文件(.o文件):
gcc –c main.s –o main.o
4.链接,生成可执行文件:
gcc -o prog main.o sum.o
(-o后为生成文件的命名,默认文件名为a.out)
2.相关代码文件
main.c如下
/* main.c */
/* $begin main */
int sum(int *a, int n);
int array[2] = {1, 2};
int main()
{
int val = sum(array, 2);
return val;
}
/* $end main */
sum.c如下
/* sum.c */
/* $begin sum */
int sum(int *a, int n)
{
int i, s = 0;
for (i = 0; i < n; i++) {
s += a[i];
}
return s;
}
/* $end sum */
3.运行及解释(以main.o为例,还可换为sum.o,prog)
1.在生成main.o,与sum.o链接(gcc -o prog main.o sum.o)后执行命令
objdump -dx main.o
反汇编那些特定指令机器码的section,详细信息如下
上图是main.o的节,包括.text,.data,.bss ,.rodata等,记录了各节的名称,大小,虚拟地址,装载地址,偏移,对齐。
上图是main.o的符号表。
其中有三个特殊的伪节,它们在节头部表中是没有条目的:ABS代表不该被重定位的符号;UNDEF代表未定义的符号,也就是在本目标模块中引用,但是却在其他地方定义的符号;COMMON表示还未被分配位置的未初始化的数据目标。
从上图中我们可以看出.text是从0到20 共21个字节,正是第一幅图中.text的size。
如果想指定显示某个条目的信息可以用
objdump -dx -j .data main.o(输出.data的各项信息)
显示如下
2.运用命令readelf -s main.o输出显示目标文件中所有的符号信息
符号的信息包括值,大小,类型,环境,访问等,其中Ndx=1表示.text节,Ndx=3表示.data节,以此类推。
此外,
readelf -h main.o (显示main.oELF头信息)
readelf -S main.o(显示main.o节头部表信息)
readelf -r main.o(显示main.o重定位条目信息)
readelf -l prog(显示prog程序头表信息)
注意,prog是main.o和sum.o及一些必要的系统目标文件组合而成的可执行目标文件
4.总结
可重定位目标文件格式
可执行目标文件格式及与可重定位目标文件的区别
整体比较
补充知识:符号
每个可重定位目标模块m都有一个符号表,它包含m定义和引用的符号的信息。在链接器的上下文中,有三种不同的符号:
- 由模块m定义并能被其他模块引用的全局符号。全局链接器符号对应于非静态的C 函数和全局变量 。
- 由其他模块定义并被模块m引用的全局符号。这些符号称为外部符号,对应于在其他模块中定义的非静态C函数和全局变量。
- 只被模块m定义和引用的局部符号。它们对应于带static属性的C函数和全局变量。这些符号在模块m中任何位置都可见,但是不能被其他模块引用。