当前位置:网站首页>简述C语言中的符号和链接库

简述C语言中的符号和链接库

2022-07-06 03:25:00 是阿翔啊

简述C语言中的符号和链接库

强弱符号以及他们的规则

链接器在解析符号引用中, 将他输入的可重定位目标文件的符号表中一个确定的符号定义关联起来.
局部变量和静态局部变量只有唯一一个定义.
但是对全局符号得出引用解析就会复杂很多, 当编译器遇到不在本模块中定义的符号时候, 会假设在其他的某个模块中定义, 此时会生成一个链接器符号交给链接器处理, 如果链接器还找不到会报错退出

但是会出现多个目标文件中定义相同的全局符号, 此时会想汇编器输出每个全局符号, 或是强符号 或是弱符号.
根据强弱符号的定义, linux链接器使用了以下规则来处理多重定义的符号名

  • 规则1: 不允许出现有多个同名的强符号
  • 规则2: 如果有一个强符号和多个弱符号 选择强符号
  • 规则3: 如果有多个弱符号同名, 会从这些弱符号中任意选择一个

注释: 弱符号出现通常都是全局声明变量 局部进行赋值操作

规则2会导致别的模块定义的全局变量被本模块局部符号引用修改
规则3也是如此
更可怕的是当重复的符号定义还是不同类型的时候, 会导致别的数据被覆盖

比如别的模块定义的强符号是int x 此模块声明的是double x

由于double占用字节是int的2倍 在赋值过程中会把别的x附近的内存地址的值修改, 导致程序出现未知错误.

当我们怀疑会出现这种错误的时候 可以用GCC-fno-common选项调用链接器 这个选项会告诉链接器遇到多重定义的全局符号的时候会触发错误…也可以使用-Werror将所有的警告都变成错误

COMMON在节头部表中没有条目,是一个特殊的伪节(oseudosection),表示还未被分配位置的未初始化的的数据目标。
COMMON 为初始化的全局变量
.bss 未初始化的静态变量,以及初始化为0的全局或静态变量

规则: 当编译器在翻译某个模块的时候, 遇到了一个弱全局符号, 由于他不知道有没有在别的模块中进行定义, 所以编译器会把它放到COMMON段, 决定权留给链接器. 另一方面 如果给他初始化为0 那么他是一个强符号, 所以编译器可以很自信的把它分配到.bss段,
类似的 由于静态符号的构造是唯一的 所以编译器可以很自信的把它们分成.data或者.bss

与静态库链接

我们可以将常用的所有目标模块打包成一个单独的文件, 称之为静态库, 比如我们常见的libc.a还有支持数学函数的labm.a静态库等等

静态库的优缺点:

如果我们不用静态库 每次都一大堆文件进行编译, 尽管我们会比较方便可用 因为标准函数总是可用的(都有源码了)
但是不好的地方就是会极大的增加编译器的负担, 导致编译时间变得非常长

我们使用静态库的话, 可以将编译器的实现和标准函数的实现分离开, 并且仍然对程序员保持适度的便利. 然而缺点就是系统中每个可执行文件都要包含着一份标准函数集合的完全副本, 这磁盘是一个很大的浪费.更糟糕的是, 每个正在运行的程序会将他们的这些函数副本放到内存中, 这是对内存的极大的浪费. 另一个缺点就是, 对任何的标准库函数的改变, 无论多么小的改变都要重新编译整个源文件, 是一个非常耗时的操作

当然也可以为每个标准函数创建一个独立的可重定位文件, 但是这个方法要求程序员显式的链接合适的模块到可执行文件中, 这个过程是一个非常容易出错和耗时的过程 就是后面接着一堆.o

为了解决上面这些缺点, 我们可以将相关的函数编译成独立的目标文件. 然后把这些目标文件打包成.a文件

这样链接时候只会复制被程序引用的模块, 这样减少了磁盘和内存中的消耗.另一方面我们后面只要包含较少的.a文件即可

-lpthread就是 路径/pthread.a的缩写

链接顺序很重要, 不正确的先后顺序会报错
所以一般把库文件放到最后面

原网站

版权声明
本文为[是阿翔啊]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_42716357/article/details/125545369