Linux:库制作与原理(三)

关键词:目标文件、ELF、section、segment、readelf、objdump

适合:想真正搞懂"编译/链接在干啥"的你,话不多说,我们正式开始啦

1.为什么你一改代码不用全量重编?

在 Linux 下,我们常用 gcc 把源码编译成目标文件(.o),再把多个 .o 链接成可执行程序。一个很实际的好处是:改了哪个源文件,只需要重编它对应的 .o,不必把整个工程重来一遍

最典型的演示是两个源文件:

  • hello.c 里调用 run()

  • code.c 里定义 run()

hello.c代码

cpp 复制代码
#include <stdio.h>

int main()
{
    printf("hello linux\n");
    func();
}

code.c代码

复制代码
#include <stdio.h>

void func()
{
    printf("hello func\n");
}

分别编译:

gcc -c hello.c gcc -c code.c ls # code.o hello.o

此时 .o 就是"目标文件"。你可以用 file 看它是什么类型:

file hello.o # ELF 64-bit LSB relocatable...

目标文件本质是 ELF 的一种形式:可重定位文件(Relocatabl e)

2.ELF 到底是啥?别怕,它就是"二进制的收纳盒"

ELF(Executable and Linkable Format)不止可执行文件才用,常见四类都属于 ELF:

  • .o:可重定位文件

  • 可执行文件:Executable

  • .so:共享目标文件(动态库)

  • core dump:内核转储文件

理解 ELF 的关键不是背字段,而是抓住它的两个"视角":

视角 A:链接视图(Linking view)------按"节 section"看

链接器更关心 section:.text/.data/.rodata/.bss/.symtab 等等。比如:

  • .text:机器指令(代码)

  • .data:已初始化的全局/静态变量

  • .rodata:只读常量,比如字符串

  • .bss:未初始化的全局/静态变量占位

  • .symtab:符号表(函数名/变量名等的记录)

查看 section:

readelf -S a.out

视角 B:执行视图(Execution view)------按"段 segment"看

操作系统加载程序时,更关心 segment(段)。段是加载单位:哪些要映射进内存、权限是什么(R/W/X),这些信息记录在 Program Header Table 里。

查看 segment:

readelf -l a.out

你会看到典型的 LOAD 段:

  • 一段通常是 R E (可读可执行):装 .text 等

  • 一段通常是 RW (可读可写):装 .data/.bss/.got 等

3.为什么要把 section 合并成 segment?

一句话:为了省内存、方便权限管理。

如果 .text、.init 等小节各占一页(比如 4KB),碎片会非常多;合并成 segment 后能减少浪费。同时把"可执行"和"可写"等权限隔离开,更安全。

4.链接到底修了什么?------"call 0" 是怎么变成正确地址的

你用 objdump -d hello.o 反汇编时,可能会看到 call 的跳转地址像"空的"(例如全 0)。原因是:编译阶段并不知道外部符号(比如 printf、另一个文件里的 run)最终会放到哪里。

那怎么解决?

靠链接阶段:链接器会根据重定位信息 与符号表把这些地址修正好。

你可以用 readelf -s 看符号表,会看到 UND(未定义):

readelf -s hello.o # ... puts UND # ... run UND

链接完成后(比如 gcc *.o -o main.exe),再看符号表会发现 run 已经有了地址,说明链接把它"对上了"。

5.把这条线串起来

  • .o 是 ELF(可重定位),内部有 section 和符号等信息

  • 链接阶段会:合并 section、做地址重定位、生成最终 ELF

  • 运行阶段 OS 按 segment 映射到进程虚拟地址空间

  • 你能用 readelf/objdump/ldd 把这一切"看见"

到这里,你就不是"只会 gcc 一把梭"的选手了,下篇博客见啦~~

相关推荐
feng_you_ying_li几秒前
linux之网络层
linux·运维·网络
未来之窗软件服务8 分钟前
Linux 运维日志删除的多种方式—东方仙盟
linux·运维·服务器·仙盟创梦ide·东方仙盟
卓豪终端管理10 分钟前
IT 运维视角下的终端数据安全:能力框架与落地清单
运维
小雉系统20 分钟前
BcoreOS实战:用一个升级包,让Rocky Linux跑进Debian服务器
linux·运维·服务器·debian
thethefighter21 分钟前
快速预览Word、WPS秒开,支持空格弹窗
linux·word·wps·快速预览·空格弹窗·nhdeepview
甜到心里的蛋糕28 分钟前
从 QQ 机器人到 B 站 AI 运营:一套可复现的视频流水线踩坑实录
运维·人工智能·python·自动化·视频制作
QYR-分析40 分钟前
26.2% 高增!场内及园区无人物流车,厂内短驳自动化的 L4 货运载体
运维·自动化
熊猫钓鱼>_>41 分钟前
鸿蒙 PC 三方库适配复盘:libfvad 1.0 —— 把 WebRTC VAD 做成能装进采集链路的静态库
服务器·开发语言·华为·harmonyos·openharmony·适配·鸿蒙pc
用户8351414049491 小时前
把日志和寄存器值喂给AI做故障定位,我的实际问法
linux·ubuntu
java_logo1 小时前
Docker 部署 DPanel:轻松搭建轻量容器管理平台
运维·docker·容器·podman·容器管理·dpanel·轩辕镜像