库的制作与原理1.0,库打包,协作,目标文件.o、ELF格式。

@bit::Shadow
✧(≖ ◡ ≖✿

目录

库的命名规范

.o文件

协作时库的合作

协作下库打包与更新

Linux下自动配置的库(C/C++)及头文件的查询:

指定头文件下gcc/g++编译

动态库

ldd

fPIC

.o链接库成为可执行文件

1.软链接

2.export链接

[gcc/g++ -c code.c -o code.o -Ⅰ 头文件处 -L 库处 -l真实库名 【无/-static】](#gcc/g++ -c code.c -o code.o -Ⅰ [头文件处] -L [库处] -l[真实库名] 【无/-static】)

-static

ELF

四部分

Section区域合并成为Secment

ELF形成可执行

*为什么要合并为Secment?

理解向动态库链接和加载


gitee

静态库(.a) Linux .lib Windows

动态库(.so) Linux .dll Windows // 常在".so"后加以".n"(n为数字),表示版本号。这是Linux的版本管理机制,由于解决版本兼容问题。

"库"其实就是大量.o文件构成的集合加以ar指令处理。

库的命名规范

"lib"+"真实名称"+"后缀"

像:libc.a的真实库名就是'c'。

.o文件

动静态库与.o文件均是ELF格式。

内容查询指令: readelf 选项 文件名/库名

.o文件形成流程:.cpp/.c ----> .o ---> 可执行文件/库文件(.a/.so)

内容:机器码 + 符号表 + 重定位信息 + 调试信息等等。

部分内容:

UND:undefined的缩写

协作时库的合作

前言:*.o + 对应所需 *.h 链接*.o:

gcc/g++ *.o ---> a.out

执行:./a.out

当多人协作传递时: .h 作为接口文件且说明文件,供以了解接口。

.o 作为"自己开发的 .o 文件 + 协作成员的.o"。

三者构成依赖关系以形成可执行文件。

协作下库打包与更新

ar -rc 库全称 *.o(打包对象) # r--replace(存在就更新) c--creat(不存在就创建)

例如:

bash 复制代码
ar -rc libmyc.a *.o  

常用结构:

压缩: tar czf lib.tgz lib

解压: tar xzf lib.tgz lib

Linux下自动配置的库(C/C++)及头文件的查询:

Linux下头文件路径: /usr/include

Linux下库文件路径: /lib64

ls查询库文件:

指定头文件下gcc/g++编译

-Ⅰ 头文件路径:头文件可能不会与.c/cpp文件在同一目录下,此时需要指定头文件位置的选项。(当前目录且非下级目录的.h文件则无需加'-I')。

-L 库文件路径 -l 真实库名称(小写kl的l):形成可执行文件的"库"定位选项,库没有在默认寻找位置:

  • /usr/lib

  • /usr/local/lib

  • /lib

    bash 复制代码
    $ gcc -I /usr/include/ -L /lib64 -lc -c code.c

演示效果:

动态库

ldd

ldd 查询一个可执行文件/共享库依赖哪些动态链接库。

fPIC

f:编译选项前缀由于控制代码生成、优化等。

PIC:Position independent code位置无关码。

-fPIC是gcc编译选项,是形成用于链接动态库的目标**.o文件**必备选项。

bash 复制代码
gcc -c -fPIC file.c -o file.o

gcc/g++ -c code.c -o code.o -Ⅰ 头文件处 -L 库处 -l真实库名 【无/-static】

-static

1.若无-static默认动态链接,若无动态库只能链接静态库。

2.-static是强制链接静态库命令若无静态库则报错。

3.IDE集成开发环境VS2022在安装过程中就存在配置库的环节。

对比项 静态库 (.a) 动态库 (.so)
链接时机 编译时 运行时
文件后缀 .a (archive) .so (shared object)
程序体积 大(包含库代码) 小(不含库代码)
内存占用 高(每个程序独立一份) 低(多程序共享一份)
依赖关系 无依赖,可独立运行 需要库文件存在
更新库 需重新编译程序 替换库文件即可
加载速度 快(无需查找) 稍慢(需动态链接)
符号冲突 容易冲突 隔离性好
编译命令 gcc -c -fPIC *.c ar rcs lib.a *.o gcc -c -fPIC *.c gcc -shared -o lib.so *.o
使用命令 gcc main.c -L. -lfoo gcc main.c -L. -lfoo 需设置 LD_LIBRARY_PATH

ELF

动静态库、.o文件(可重定向目标文件)均是"ELF"格式(一种二进制格式)

四部分

ELF Header:文件最开头,标识文件类型、机器架构、入口点、程序头表/节头表的位置和大小等。

Program Header Table:只有可执行文件和共享对象需要,描述如何将文件映射到进程地址空间。.o文件无此区域

Section(节):真正的内容数据,如++代码、数据、符号表、重定位表++等。

Section Header Table:描述各个Section节的信息,编译器、链接器使用。

一个 hello.o 文件内部大致如下(顺序可能因编译器而异):

Section (节) 内容说明 常见标记
.text 编译后的机器指令(代码) 可读、可执行
.data 已初始化的全局/静态变量 可读写
.bss 未初始化的全局/静态变量(不占用文件空间,只记录大小) 在加载时清零
.rodata 只读数据,如字符串常量、const 变量 只读
.symtab 符号表(全局、外部符号定义/引用) 链接器使用
.strtab 符号表中符号名称的字符串表
.rel.text 对 .text 的重定位条目(修正地址)
.rela.text 同上,但使用 rela 格式(带 addend)
.comment 编译器版本信息
.note.* 各种注释/属性(如 GNU-stack)
.shstrtab 节名称字符串表

各个.o文件链接成为可执行时会进行文件合并:

Section区域合并成为Secment
  • 合并原则:相同属性。如:只读、可读写。
  • 这样即便是不同的Section,加载到内存时,也可能加载到一起。
  • 这种合并原则在形成ELF时就在形成了。被记录于(Program Header Table内)。

☝Section 是逻辑划分,给链接器 用;Segment 是物理映射,给操作系统用。

ELF形成可执行

step1-将多份C/C++代码翻译为.o文件与配置的动静态库(ELF)。

step2-将多份.o文件section进行合并。

*为什么要合并为Secment?

section连续分布每个可存储最大4096,若有4097个字节必须另开一个节。这样降低了空间利用率,使用合并方式减少了内存碎片提供内存利用率。

理解向动态库链接和加载

未链接的.o文件,并未确定call的目标具体体现为call的目标地址为00:

在进行动态库的调用(如:printf()、外部函数run())前在反汇编层面(如:main的main.o 、 main.s文件)

均是call:00 00 00 00

*.o链接库成为可执行文件

1.软链接

sudo ln -fs 链接者 链接目标库

2.export链接

LD_LIBRARY_PATH 是 Linux 下用于临时指定共享库搜索路径的环境变量。

export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:追加路径 #追加式配置搜索路径

./a.out

运行程序时,会去 LD_LIBRARY_PATH 里找库

倾囊相授,持续深耕Linux

欢迎关注

相关推荐
zzzzzz31010 小时前
9K Star 炸裂开源!这个 C 语言写的代码知识图谱,把 Linux 内核索引压缩到了 3 分钟
linux·服务器·sql
XIAOHEZIcode10 小时前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220701 天前
如何搭建本地yum源(上)
运维
A小辣椒2 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao3 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334663 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
大树884 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai