linux可执行程序和库区别,Linux 平台基于 C /C++ 的静态库和动态库的区别

本文详细比较了Linux下静态库(.a)与动态库(.so)的区别,涉及目标文件类型、链接过程、静态库的特性以及如何在gcc编译中使用它们。通过实例演示,阐述了静态链接和动态链接的不同以及链接libm库的方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们在编写代码的时候经常用到已有的接口,他们是以库的形式提供给我们使用的,而常见形式有两种,一种常以。a 为后缀,为静态库;另一种以。so 为后缀,为动态库。那么这两种库有什么区别呢?

说明:本文主要说明 Linux 下的情况,Windows 不涉及。

1. 目标文件

在解释静态库和动态库之前,需要简单了解一下什么是目标文件。目标文件常常按照特定格式来组织,在 Linux 下,它是 ELF 格式(Executable Linkable Format,可执行可链接格式),而在 Windows 下是 PE(Portable Executable,可移植可执行)。

而通常目标文件有三种形式:

可执行目标文件。即我们通常所认识的,可直接运行的二进制文件。

可重定位目标文件。包含了二进制的代码和数据,可以与其他可重定位目标文件合并,并创建一个可执行目标文件。

共享目标文件。它是一种在加载或者运行时进行链接的特殊可重定位目标文件。

我们来看一个简单实例:

//main.c

#include

#include

int main(int argc,char *argv[])

{

printf("hello 编程珠玑

");

int b = 2;

double a = exp(b);

printf("%lf

",a);

return 0;

}

代码计算 e 的 2 次方并打印结果。由于代码中用到了 exp 函数,它位于数学库 libm.so 或者 libm.a 中,因此编译时需要加上 -lm。

生成可重定位目标文件 main.o:

$ gcc -c main.c   #生成可重定位目标文件

$ readelf -h main.o  #查看 elf 文件头部信息

ELF Header:

Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00

Class:                             ELF64

Data:                              2's complement, little endian

Version:                           1 (current)

OS/ABI:                            UNIX - System V

ABI Version:                       0

Type:                              REL (Relocatable file)

(省略其他内容)

通过上面的命令将 main.c 生成为可重定位目标文件。通过 readelf 命令也可以看出来:Type 为 REL (Relocatable file)。

观察共享目标文件 libm.so:

$ readelf -h /lib/x86_64-Linux-gnu/libm.so.6

ELF Header:

Magic:   7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00

Class:                             ELF64

Data:                              2's complement, little endian

Version:                           1 (current)

OS/ABI:                            UNIX - GNU

ABI Version:                       0

Type:                              DYN (Shared object file)

(省略其他内容)

不同系统中 libm.so 的位置可能不一样,你可以通过 locate 命令来查找。locate 命令的用法可参考《Linux 中的文件查找技巧》。从结果可以看到,libm.so 是共享目标文件(Shared object file)。

查看可执行目标文件 main:

$ gcc -o main main.o -lm  #编译成最终的可执行文件

$ readelf -h main         #查看 ELF 文件头

ELF Header:

Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00

Class:                             ELF64

Data:                              2's complement, little endian

Version:                           1 (current)

OS/ABI:                            UNIX - System V

ABI Version:                       0

Type:                              EXEC (Executable file)

(省略其他内容)

这里必须要强调一点,如果使用到的函数没有在 libc 库中,那么你就需要指定要链接的库,本文中需要链接 libm.so 或 libm.a。可以看到,最终生成的 main 类型是 Executable file,即可执行目标文件。

2. 什么是静态库

前面所提到可重定位目标文件以一种特定的方式打包成一个单独的文件,并且在链接生成可执行文件时,从这个单独的文件中“拷贝”它自己需要的内容到最终的可执行文件中。这个单独的文件,称为静态库。Linux 中通常以。a(archive) 为后缀

还是拿前面的例子来说,我们使用静态链接构建我们的可执行文件:

$ gcc -c main.c

$ gcc -static -o main main.o -lm

在这个过程中,就会用到系统中的静态库 libm.a。这个过程做了什么呢?首先第一条命令会将 main.c 编译成可重定位目标文件 main.o,第二条命令的 static 参数,告诉链接器应该使用静态链接,-lm 参数表明链接 libm.a 这个库(类似的,如果要链接 libxxx.a, 使用 -lxxx 即可)。由于 main.c 中使用了 libm.a 中的 exp 函数,因此链接时,会将 libm.a 中需要的代码“拷贝”到最终的可执行文件 main 中。

特别注意,必须把 -lm 放在后面。放在最后时它是这样的一个解析过程:

链接器从左往右扫描可重定位目标文件和静态库

扫描 main.o 时,发现一个未解析的符号 exp,记住这个未解析的符号

扫描 libm.a,找到了前面未解析的符号,因此提取相关代码

最终没有任何未解析的符号,编译链接完成

那如果将 -lm 放在前面,又是怎样的情况呢?

请您登录后阅读全文, 登录 或者 注册

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值