链接,静态库,动态库

在多个文件编译之后,每个文件生成了一个.o文件,然后是使用链接器,将.o文件链接为一个可执行文件的。链接器为了创建可执行文件,必须完成两个任务:

1.符号解析:目标文件定义和引用符号。符号解析的目的是将每个符号引用和符号定义联系起来。

2.重定位:汇编器和编译器生成从地址零开始的代码和数据段。链接器通过把每个符号定义与一个存储器位置(虚存)联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器的位置,从而重定向这些段。

这两句话我的理解是1.将不同.o文件中的变量声明和变量定义联系起来,2.因为每个编译出来的.o文件都是从地址零开始的,所以当这些.o文件链接为一个文件是,就需要将地址做相应的调整,保证程序执行的正确性。


举一个例子:

//main.c

void swap();

int buf[2] = {1,2};

int main()

{

swap();

return 0;

}

//swap.c

extern int buf[];

int *bufp0 = &buf[0];

int *bufp1;

void swap()

{

int temp;

bufp1 = &buf[1];

temp = *bufp0;

*bufp0 = *bufp1;

*bufp1 = temp;

}

上述的小程序是交换数组中的两个数字的位置。

编译的流程图为:


每一个.c文件都会经过编译生成一个.o文件,所有的.o文件经过连接,生成一个可执行文件。


静态连接:

我们使用的标准库,包含了我们经常所用的标准I/O,串操作,整数算术函数等等。下面说下静态连接的必要性:

如果没有静态库,我们将刚才的所有库函数都编译为一个.o文件,当要使用是,我们将这个.o文件连接到我们使用库函数的cpp文件中,例如gcc main.c libc.o. 这样存在的问题,是系统的每一个可执行文件都含有一份标准函数的完全拷贝,而不是我需要哪些函数就有哪些函数。所以静态库应运而生。在链接静态库时,链接器值拷贝被程序引用的目标模块,这样就减少了可执行文件在磁盘和存储器中的大小。

举个例子:

//addvec.c

void addvec(int *x,int *y, int *z, int n)
{
    int i ; 
    for(i = 0; i < n; i ++) 
        z[i] = x[i] + y[i];
}


//multvec.c

void multvec(int *x, int *y, int *z, int n)
{
    int i;
    for(i = 0; i < n; i ++ )
        z[i] = x[i] * y[i];
}

编译这两个.c文件,创建静态库

gcc -c addvec.c multvec.c

ar rcs libvector.a addvec.o multvec.o 生成静态库libvector.a其中包括两个.o文件


//main2.c

#include <stdio.h>
#include "vector.h"


int x[2] = {1,2};
int y[2] = {3,4};
int z[2];
int main()
{
    addvec(x,y,z,2);
    printf("z = [%d %d]\n", z[0],z[0]);
    return 0;
}

//vector.h

void addvec(int*, int*,int*,int);
void multvec(int*,int*,int*,int);

先编译main.o 

gcc -O2 -c main2.c

生成可执行文件

gcc -static -o p2 main2.o ./libvector.a

-static参数告诉编译器,链接器应该构建一个完全连接的可执行目标文件,它可以加载到存储器并运行,在加载时无须更进一步的连接了。当链接器运行时,他判定addvec.o定义的addvec符号是被main.o引用的,所以它拷贝addvec.o到可执行文件。因为程序不引用任何由multvec.o定义的符号,所以链接器就不会拷贝这个模块到可执行文件。链接器还会从libc.a拷贝print.o模块,以及许多C运行时系统中的模块,如图:



最后是动态共享库

我们有了静态库,但是仍然有一些问题:

1静态库的更新,如果静态库需要更新,那么所有依赖于该库的可执行程序都需要重新编译。

2一些常用的函数,例如标准I/O函数print  在运行时,这些函数会被复制到每个运行进程的代码段中去,造成了极大的浪费

所以我们引入了动态库。

程序还是我们在静态库中使用的文件

编译静态库:

gcc -shared -fPIC -o libvector.so addvec.c multvec.c

-fPIC选项只是编译器生成与位置无关的代码,-shared选项指示链接器创建一个共享的目标文件

gcc -o p2 main2.c  ./libector.so

这样就创建了一个可执行文件p2.

此时,没有任何libvector.so的代码和数据段被真正的拷贝到可执行文件p2中,取而代之的是,链接器拷贝了一些重定位和符号表的信息。


附:

查看静态库中的函数 nm  ****.a

查看动态库所依赖的其他库  ldd  ****.so

g++选项

 -L:指定链接库的路径,-L. 表示要连接的库在当前目录中
 -ltest:指定链接库的名称为test,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
例如:g++ TestDynamicLibrary.cpp -L../DynamicLibrary -ldynmath

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值