T1.c
1 #include <stdio.h>
2 int g = 1203;
3 int h;
4 static int s;
5
6 int main(int argc,char *argv[]){
7 int a = 1,b;
8 static int c = 3;
9 b = 2;
10 c = mysum(a,b);
11 printf("sum=%d\n",c);
12 }
T2.c
1 extern int g;
2 int mysum(int x,int y){
3 return x+y+g;
4 }
隐式声明和想要声明的函数一样,所以没出问题。
但我觉得这样不好。
用objdump分析第1步中的可执行文件和目标文件,提交你的分析截图以及如何和教材讲解内容对应的
比如obj文件的文件头,代码段,数据段等,可执行文件如何链接mysum的。
可重定位目标文件中包含有很多的节,格式如下图:
ELF头
包括16字节的标识信息、文件类型(.o,exec,.so)、机器类型(如Intel 80386)、节头表的偏移、节头表的表项大小及表项个数。
.text节
编译后的代码部分。
.rodata节
只读数据,如 printf用到的格式串、switch跳转表等。
.data节
已初始化的全局变量和静态变量。
.bss节
未初始化全局变量和静态变量,仅是占位符,不占据任何磁盘空间。区分初始化和非初始化是为了空间效率。
.symtab节
存放函数和全局变量(符号表)的信息,它不包括局部变量。
.rel.text节
.text节的重定位信息,用于重新修改代码段的指令中的地址信息。
.rel.data节
.data节的重定位信息,用于对被模块使用或定义的全局变量进行重定位的信息。
.debug节
调试用的符号表(gcc -g)
.strtab节
包含 .symtab节和 .debug节中的符号及节名
节头表(Section header table)
包含每个节的节名在.strtab节中的偏移、节的偏移和节的大小.
- 既然.obj文件中都没有存储.bss段的信息,那么在程序中那些初始化为0的全局变量和未初始化的局部变量它是怎么识别它们的?
- 答:由于.bss段中都是0,所以不需要记录。只需要记录其大小即可,所以通过段表即可找到。
链接过程
将.o文件的各个段分别合并
合并符号表,给符号分配正确的地址
依据符号表中的记录替换编译时保留的无效地址(占位用的)
可以看到编译过程并不给数据和函数入口分配内存地址,在.o文件中,由于无法确定具体的地址,此时编译器只是将其赋了一个特殊的地址0x0,然后在最后的链接阶段再完成正确的地址赋值。
目标文件中的符号表
目标文件的.symtab节记录着符号表信息,符号表示一个结构体数组,每个表项(16字节)的结构如下:
符号解析:所有obj文件符号表中对符号引用的地方都要找到符号定义的地方,否则就会出现链接错误。由于源文件是单独编译的,所以对外部的符号处理为UND即undefine。