新闻详情

新闻详情

首页 / 资讯中心 / 详情

从.o文件到可执行程序,搞懂ELF和静态链接

发布时间:2026/10/1 14:36:17来源:尧图网络
从.o文件到可执行程序,搞懂ELF和静态链接
前面已经能够自己制作.a和.so了。但是还有一个问题一直比较绕hello.c code.c分别编译以后得到hello.o code.o这两个.o文件到底是怎么变成最后那个可以直接执行的程序的这部分其实就是编译和链接。再往下研究还会碰到一个很重要的格式ELF一、.o文件到底是什么先写两个简单的文件。hello.c#includestdio.hvoidrun();intmain(){printf(hello world!\n);run();return0;}code.c#includestdio.hvoidrun(){printf(running...\n);}分别编译gcc-chello.c gcc-ccode.c就得到hello.o code.o.o就是目标文件。这时候如果用filehello.o可以看到它属于 ELF 格式而且是可重定位文件。二、为什么要先生成.o因为一个比较大的工程不可能所有代码都写在一个文件里。不同的源文件可以分别编译。比如hello.c - hello.o code.c - code.o如果之后只修改了code.c就只需要重新编译gcc-ccode.c不用把整个工程全部重新编译一遍。这也是目标文件比较重要的一个原因。三、为什么两个.o文件不能直接各自运行问题就在于hello.o里面用了run();但是run并没有定义在hello.c中。它实际定义在code.o同样两个文件都使用了printf但printf的实现也不在它们自己的源文件里面。所以编译的时候编译器只能先把这些还不知道的地址空出来。例如反汇编objdump-dhello.o会看到类似callq ...后面的地址还没有确定。原因很简单编译hello.c的时候并不知道run最终会在什么位置。所以这个地址只能先留着。四、链接到底在干什么链接的时候情况就不一样了。此时hello.o code.o都已经准备好了。链接器会把它们组合起来然后处理之前没有确定的符号地址。简单来说就是hello.o code.o ↓ 链接 ↓ 合并各个section ↓ 统一安排地址 ↓ 修正原来没有确定的地址 ↓ 可执行程序两个.o文件的.text最后就被合并到了最终程序的.text中并重新进行了统一编址。五、ELF是什么Linux 下很多二进制文件其实都是 ELF 格式。这里主要接触四类.o - 可重定位文件 可执行程序 - Executable File .so - Shared Object File core dump - 内核转储所以 ELF 并不是单独某一种文件而是一种二进制文件格式。六、ELF里面都有些什么从整体上看一个 ELF 文件可以看到这些部分ELF头(ELF Header) 程序头表(Program Header Table) 节头表(Section Header Table) 节(Sections)ELF Header 在文件开头。它保存 ELF 文件的一些基本信息同时还可以帮助定位文件的其他区域。比如使用readelf-hhello.o可以看到Class Data Version Type Machine Entry point Start of program headers Start of section headers ...这些信息都可以帮助我们了解一个 ELF 文件到底是什么类型、面向什么平台以及其他关键结构在哪里。七、Section到底是什么Section 可以理解成 ELF 内部按照不同用途划分出来的一块块区域。比较常见的有.text .data .rodata .bss .symtab .got .plt其中.text主要保存程序的机器指令。.text ↓ 代码.data保存已经初始化的全局变量、静态变量等数据。.data ↓ 已经初始化的数据.rodata保存只读数据比如字符串常量。.bss给没有初始化的全局变量、静态变量预留空间。可以通过readelf-Sa.out查看一个 ELF 文件有哪些 Section。八、那Segment又是什么前面看到的是 Section。程序真正加载进内存的时候又会涉及一个新的概念Segment这两个东西不能混在一起。ELF 中很多 Section 在加载到内存的时候会按照属性重新组合成 Segment。比如可读 可写 可执行具有相同属性的部分可以放到一起。比如很多代码相关section ↓ 一个可执行segment很多数据相关section ↓ 一个可读写segment这样做可以减少内存页面的浪费。比如一个 Section 有 4097 字节单独放需要占两个页面另一个很小的 Section 如果单独放又可能额外占一个页面。把属性相同的内容合并之后就可以减少这种空间浪费。九、Section Header Table和Program Header Table有什么区别这个地方刚开始很容易混。可以直接这么理解Section Header Table ↓ 更关注 ELF 文件内部是怎么组织的Program Header Table ↓ 更关注程序运行时应该怎么加载也就是Section → 链接视图 → 更适合研究链接过程 Segment → 执行视图 → 更适合研究程序加载一个主要服务于链接一个主要服务于运行加载。十、静态链接到底发生了什么回到最开始的hello.o code.o执行gcc *.o-omain.exe就可以得到最终程序。这个过程就是静态链接的一个基本例子。在这个过程中主要发生两件事情。第一件把多个模块组合起来。第二件把那些原来不知道的地址补完整。比如hello.o里面调用run编译的时候不知道run在哪里所以地址暂时不能确定。链接以后hello.o ↓ 找到 run 的定义 ↓ 确定 run 的地址 ↓ 修改原来的调用位置这就是重定位。十一、怎么查看这些东西Linux 下有几个命令特别适合拿来观察 ELFfile看文件类型filehello.oreadelf查看 ELF 内部信息readelf-hhello.o readelf-Shello.o readelf-shello.o readelf-lmain.exeobjdump查看机器指令objdump-dhello.o objdump-dmain.exe例如objdump-dhello.o可以发现call后面的地址在.o文件里还没有真正确定。而链接完成以后objdump-dmain.exe就可以看到类似callq 1149 run这样的实际跳转位置。这个变化其实就很直观地把“重定位”表现出来了。十二、符号表有什么用除了机器指令还可以看看readelf-shello.o这里能看到符号表。比如hello.o里面的main run puts会以符号的形式出现。其中如果某个符号显示UND可以理解成这个符号在当前.o中没有定义。比如hello.o里用到了run但run实际上定义在code.o所以在hello.o的符号表里run就属于未定义符号。等两个.o进行链接之后最终程序里就能够找到真正的run。十三、把编译、链接整个串起来现在整个过程可以写成hello.c ↓ hello.ocode.c ↓ code.o然后hello.o code.o 静态库 ↓ 链接 ↓ 地址重定位 ↓ ELF可执行程序所以以前我看到gcc hello.c code.c-omain感觉就是一句命令。现在再拆开看其实里面经历了源代码 ↓ 编译 ↓ .o ↓ 链接 ↓ 地址重定位 ↓ 可执行ELF真正把几个相互独立的模块拼起来的就是链接阶段。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

闲鱼转转交易猫客服台源码搭建教程:环境部署与避坑指南 2026/10/1 19:29:47

闲鱼转转交易猫客服台源码搭建教程:环境部署与避坑指南

简介:最新版闲鱼转转交易猫客服台源码,附带完整搭建教程,面向游戏交易平台运营者、个人卖家以及需要快速部署高仿真客服系统的开发者。系统深度仿照官方界面与操作习惯,支持实时收发消息、无延迟响应,并内置一键复制链…

阅读更多 →
Mac上安装Scala开发环境:从JDK到IDEA完整教程 2026/10/1 19:29:47

Mac上安装Scala开发环境:从JDK到IDEA完整教程

1. 前言:为什么单独写一篇Mac装Scala的教程写这篇东西的起因很简单——Scala的开发环境搭建,官方文档写得不算差,但Mac用户照着走一遍,十个有八个要卡在某个环节出不来了。不是JDK版本和Scala版本对不上,就是brew装到一…

阅读更多 →
ComfyUI+QwenImageEdit九宫格一致性写真:身份保持与参数调优实战 2026/10/1 19:29:47

ComfyUI+QwenImageEdit九宫格一致性写真:身份保持与参数调优实战

简介:本资源面向使用 ComfyUI 进行 AI 绘画的创作者与进阶用户,聚焦 QwenImageEdit 模型下基础人物九宫格一致性写真的生成方案。核心解决同一人物在多格画面中形象、服饰与风格难以保持统一的问题,适用于角色设定图、写真套图与分镜预览等场…

阅读更多 →
AI网关智能模型路由:多模型分流与成本优化实践 2026/10/1 19:29:46

AI网关智能模型路由:多模型分流与成本优化实践

做AI网关两年多,我越来越觉得整个网关里最核心、也最容易被低估的模块,就是智能模型路由。很多人把网关理解成“统一Key管理 请求转发”,其实这顶多算个代理。真正让网关有价值的地方,在于它能根据每一次请求的具体情况&#xff…

阅读更多 →
ComfyUI+QwenImageEdit九宫格一致性写真:身份锁定与批量生成实战 2026/10/1 19:29:46

ComfyUI+QwenImageEdit九宫格一致性写真:身份锁定与批量生成实战

简介:本资源面向使用 ComfyUI 进行 AI 绘画的创作者与进阶用户,聚焦 QwenImageEdit 模型下基础人物九宫格一致性写真的生成方案,解决同一人物在多格画面中形象统一、风格稳定的实际需求。压缩包内共 1 个文件,为 json 格式的工作流…

阅读更多 →
Windows显示器音频设备名乱码?注册表强制固化方案 2026/10/1 19:29:39

Windows显示器音频设备名乱码?注册表强制固化方案

1. 为什么显示器音频设备名会“乱码”或“重复”,而注册表是唯一解?Windows系统里,当你把一台带HDMI/DP音频输出的显示器接上电脑,它不只是显示画面——它同时会作为一个独立的音频播放设备出现在“声音设置”里。但很多人发现&am…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉