CSAPP第七章链接笔记(上)
本文为基于哈工大史先俊老师上课的课堂笔记。
虚拟机不要在运行程序的时候关机,否则第二次就打不开了,解决方法
链接有什么用:程序模块化,从时间空间上提高效率
静态链接
运行链接文件
反汇编链接文件
链接器的作用:
链接器的两大作用是符号解析和重定位
局部变量放在寄存器也可以放在堆栈区,参数只能放在寄存器并存入堆栈,全局变量存放在数据区,从0开始的一个相对的偏移
EFL
三种目标文件:
-
可重定位目标文件 可执行文件 共享文件
这三种目标文件在Linux下都采用.ELF格式,可以使用readelf对这些符号进行解析
EFL的几种文件格式:
链接器符号符号解析(很重要)
三种符号
全局符号
-
由模块m来定义,可以被其他模块引用的符号。 如果不想被引用,在变量的前面加上static. c++方法加private 例如非静态none-static C函数和非静态全局变量。
外部符号
-
由模块m引用,但是在其他模块定义,对m来说是外部符号。 举例:在m模块上: extern int c; void main(){..... x = c+1就可以调用了}; 外部变量c不在m模块占用任何的数据和空间,数据区没有c变量空间。
本地/局部符号
-
只在模块m定义并且只在m模块上使用,别的地方不能调用。 举例:变量前面加static: static c;只能在模块用 举例:在子程序声明的局部变量: int f(){ static int c = 1};只能在函数用 只要是声明static的局部变量也是全局变量:有人可能疑问既然是局部变量,那他是不是就变成寄存器变成堆栈了不是这样的,只要是声明static,即使是局部变量,形式只能在函数里用但是实际上他的物理实现和全局变量是一摸一样的。程序退出来了,程序的值还存在,下次进去还是会把值取到,他一定不在堆栈里,一定不在寄存器里,他一定是在全局变量里,只不过只能在子程序使用。 本地链接符号不是程序的局部变量。不加staic的局部变量不是局部符号
举例
非链接符号&本地符号 emmmm原谅我记的时候字写的有点着急。
本地符号
链接器处理重复符号
强符号弱符号
-
强符号:函数和初始化的全局变量。 弱符号:未初始化的全局变量。
处理规则
小练习
注:
-
第三个:取哪个定义一般是由链接顺序来决定,如果先链接第一个模块,那么就会出现右边的情况,如果先链接第二个double模块,那么就不会报错,因为第二个double是八个字节,int只使用四个字节不会被覆盖掉。 第四个同上 第五个指向同一块内存空间。
课堂小测
局部变量不是链接符号,因此就不是ABC
强符号弱符号都是指全局变量和函数,函数都是强符号,弱符号一定是全局变量,没有赋初值的全局变量是弱符号。
重定位
过程
将这些内存和数据放入到内存中很大的地址,Linux好像是400000,原来在他们的代码块是0,合并完之后不是0,重定位是指.o文件合并过程中发生的。
举例
array需要重定位,sum需要重定位,别人要调用main所以main的位置也要重新确定
开一下汇编代码,保留空间-参数传递
生成执行程序
程序进行跳转的时候取指已经完成,IP已经指向下条指令,所以应该减去下条指令的地址。
书上讲了一些更加复杂的链接比如gut、gir