深入 C 语言和程序运行原理
于航
PayPal 技术专家
21121 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
深入 C 语言和程序运行原理
15
15
1.0x
00:00/00:00
登录|注册

25|可执行二进制文件里有什么?

包含类型、偏移地址、大小、权限等信息
指定进程 VAS 内数据组织
描述文件的动态视图
静态视图,支持链接过程
包含名称、长度、偏移位置、权限等信息
按功能分类的数据
文件类型、入口地址、目标硬件和操作系统类型
Magic 字段识别
包含文件的基本信息
编写 C 程序读取并打印 ELF 文件 Section 信息
ELF 文件类型的应用场景和组成差异
ELF 分析和处理工具的编写
静态视图与动态视图
ELF 文件的组成:ELF 头、Section、Segment
核心转储文件(ET_CORE)
可执行文件(ET_EXEC)
共享目标文件(ET_DYN)
可重定位文件(ET_REL)
示例代码展示 ELF 头部读取
预定义结构类型与宏
使用 Linux 内核提供的 elf.h 头文件
ELF Program 头
ELF Section 头
ELF 头
早期 Unix: a.out(Assembler Output)
MacOS & IOS: Mach-O
类 Unix: ELF(Executable and Linkable Format)
Windows: PE(Portable Executable)
适用于系统级编程语言(Rust、C++、Go 等)
从 C 代码到操作系统交互的运行过程
思考题
总结
ELF 文件类型
ELF 编程
ELF 文件格式
可执行文件的格式
C 程序运行原理篇
可执行二进制文件里有什么?

该思维导图由 AI 生成,仅供参考

你好,我是于航。从这一讲开始,我们就进入到了“C 程序运行原理篇”的学习。
和之前的内容相比,在这一模块中,我们将会从“台前”走向“幕后”:从由 C 代码直观表示的程序逻辑,走向程序在运行过程中,背后与操作系统交互时的具体原理。相信学习完这个模块后,你会对一个 C 程序从代码编写,到通过编译,再到最终被操作系统运行的完整过程有更深入的理解。其中,程序的运行细节仅与所在操作系统紧密相关,因此,这一模块中介绍的原理性知识也同样适用于由 Rust、C++,以及 Go 等其他系统级编程语言编写的程序。
而今天我们先来看下,经常被提及的“二进制可执行文件”究竟是什么。

可执行文件的格式

我们都知道,一份 C 代码在经过编译器处理后,便可得到能够直接运行的二进制可执行程序。而在不同操作系统上,这些编译生成的可执行文件都有着不同的特征,其中最明显的差别便是文件后缀名。比如,在 Microsoft Windows 操作系统上,通常会以 “.exe” 为后缀名来标注可执行文件;而在类 Unix 操作系统上,可执行文件通常没有任何后缀名。
除此之外,更重要的不同点体现在各类可执行文件在内部数据的组织和结构上。通常来说,最常见的几种可执行文件格式有针对微软 Windows 平台的 PE(Portable Executable)格式、针对类 Unix 平台的 ELF(Executable and Linkable Format)格式,以及针对 MacOS 和 IOS 平台的 Mach-O 格式。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了可执行二进制文件的内部结构和原理,以 ELF 格式为例,详细解释了可执行文件的基本组织方式,包括 ELF 头部和 ELF Section 头。通过实例展示了如何通过命令来查看可执行文件的内部组成结构,以及如何理解 ELF 文件的基本结构。此外,还介绍了 ELF 文件类型和各个 Section 的作用,以及静态视图在应用程序生命周期中的链接过程。文章还探讨了在 Linux 系统中使用内核提供的头文件 elf.h 进行针对 ELF 格式的应用编程的方法。最后,总结了几种不同 ELF 文件类型之间的区别。整体来看,本文对于想要深入了解程序运行原理的读者来说,是一篇很有价值的文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入 C 语言和程序运行原理》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(9)

  • 最新
  • 精选
  • LDxy
    Elf64_Ehdr* elf_header;为指针类型,应该先让其指向内存空间再使用fread

    作者回复: 感谢指正!

    2022-02-18
    3
    2
  • 勿更改任何信息
    https://www.ics.uci.edu/~aburtsev/238P/hw/hw3-elf/hw3-elf.html 这里有一个ELF的作业,可以作为实践

    作者回复: 看了一眼,这个实践不错的

    2023-04-12归属地:福建
  • 石天兰爱学习
    文章内容很硬核,赞👍🏻

    作者回复: 感谢支持!

    2022-04-12
  • 龍蝦
    ``` #include <stdio.h> #include <stdlib.h> #include <elf.h> void print_section(const char *strtable, int index, Elf64_Shdr *shdr) { printf("[%02d] sh_name: %21s, sh_size: %4x, sh_offset: %4x, \n", index, &strtable[shdr->sh_name], shdr->sh_size, shdr->sh_offset); } int main(int argc, char **argv) { Elf64_Ehdr elf_header; FILE *fp = fopen(argv[1], "r"); fread(&elf_header, sizeof(Elf64_Ehdr), 1, fp); Elf64_Shdr shdr; fseek(fp, elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx, SEEK_SET); fread(&shdr, sizeof(Elf64_Shdr), 1, fp); // Section 名字并不是保存在 Section 头结构中,而是保存在字符串表中 // Section 头结构的 sh_name 字段表示 Section 名称在字符串表中的偏移(以 \0 结尾) // 而字符串表其实是作为一个 Section 存在 ELF 中的,所以这里先把字符串表对应的 Section 读出来 char *strtable = (char *)calloc(shdr.sh_size, sizeof(char)); fseek(fp, shdr.sh_offset, SEEK_SET); fread(strtable, sizeof(char), shdr.sh_size, fp); fseek(fp, elf_header.e_shoff, SEEK_SET); for (int i = 0; i < elf_header.e_shnum; i++) { fread(&shdr, sizeof(Elf64_Shdr), 1, fp); print_section(strtable, i, &shdr); } free(strtable); fclose(fp); return 0; } ```
    2022-03-09
    3
  • 白花风信子
    最期待的就是原理篇了!!!
    2022-02-19
    3
  • 西坠客
    现在的gcc需要加上-no-pie选项才能编译出exec类型的文件
    2023-10-20归属地:安徽
  • 前端1期-高雪荣
    readelf zsh: command not found: readelf
    2023-04-21归属地:河南
  • TableBear
    今天这门课解决了不少我读程序员自我修养这本书时产生的疑惑。👍👍
    2022-08-11归属地:广东
  • zxk
    最近刚看完 JVM 的字节码文件格式,配合这篇作对比两者的异同,十分有趣。
    2022-04-24
    1
收起评论
显示
设置
留言
9
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部