【coding看计算机系统s】链接器

早期的程序,链接是手动完成的,而现代系统中,链接是由链接器完成的;

一个程序经过预处理,编译,汇编,链接而完成的;详情请看该文http://blog.csdn.net/sykpour/article/details/25550663;

本文主要侧重在链接环节;


目标文件分为三种,

(1)上述过程中汇编后的.o就是可重定位目标文件,包含二进制数据和代码;

(2)可执行目标文件就是链接完成的,其形式是可以被直接拷贝到存储器并执行;

(3)共享目标文件,是在加载或运行事被动态加载到存储器并链接;

注意:在C语言中,任何带有static修饰的,无论是函数还是变量都是私有的;


程序测试代码

add.c

#include 

int add(int x, int y)
{
	printf("%s\n", "in add");
	return x + y;
}

sub.c

#include 

int sub(int x, int y)
{
	printf("%s\n", "in sub");
	return x - y;
}

main.c

#include 

int main(void)
{
	int x = sub(1, 2);
	printf("sub:%d\n", x);
	x = add(1, 2);
	printf("sub:%d\n", x);
	
	return 1;
}

静态链接的任务是符号解析(将每一个符号刚好与一个符号定义联系起来),重定位(就是将每一个符号定义与存储器位置联系起来)



静态链接

gcc -o test1  main.c sub.c add.c #(对sub.c add.c是静态链接,而对于printf.o并不是静态链接)

【coding看计算机系统s】链接器_第1张图片



./test  #外壳调用加载器



静态库

(1)静态库可以解决大量相关函数对应用程序可用的问题,但是需要它也需要更新,也就会导致所有的应用程序,都需要重新链接;而且,如果10个应用程序都需要用到printf.o,那么在存储器中会有10份printf.o,显然是一种浪费;

(2)当使用-static选项时,就是告诉编译器程序,链接器需要构造一个完全链接的可执行目标文件(构造时,只取需要用到的可重定位文件,如printf.o),它可以直接加载到存储器并运行,在加载时是无需再次链接的,但是文件比较大;

(3)

gcc -c sub.c add.c

ar rcs lib2.a sub.o add.o

gcc -o test2  main.c lib2.a         #(对sub.c add.c是静态链接,而对于printf.o并不是静态链接)

gcc -static -o test3 main.c lib2.a      #(对sub.c add.c是静态链接,而对于printf.o也是静态链接)


【coding看计算机系统s】链接器_第2张图片


动态链接共享库

(1)动态链接共享库,可以在运行时加载到任意的存储器地址(注意是在应用程序被加载时,动态链接器加载和链接过共享库的),并和一个在存储器的程序链接起来;微软OS中是以.dll后缀表示,而类Unix系统中是.so后缀表示;

(2)共享库的共享方式针对上述的10个可执行目标文件,只有一份,并不是像静态库嵌入的;针对存储器,一个共享库的.text段也是被不同的正在运行的进程共享的;

(3)gcc -shared -fPIC -o libshared.so add.c sub.c #其中-fPIC表示编译器生成与位置无关的代码(PIC可以使的链接器不修改代码就可以在任何地址加载和执行这些代码,否则要指明地址空间片), -shared表示创建一个共享的目标文件;

 (对sub.c add.c,printf.o都是动态链接)

gcc -o test4 main.c ./libshared.so


【coding看计算机系统s】链接器_第3张图片


运行时加载和运行任意共享库(用时加载);


上述的可执行目标文件大小对比如下:显而易见,test3的大小很大;



你可能感兴趣的:(【coding看计算机系统s】链接器)