南京大学 操作系统 (JYY) 学习笔记:可执行文件、链接器与 Shebang 的彩蛋
写在前面这是本系列的第十篇。我们已经知道进程从execve后的初始状态开始可以通过mmap改变自己的地址空间通过fork创建新的进程。有了系统调用和libc我们真的可以实现“任何程序”了。但在此之前我们一直默认了编译器工具链gcc/ld可以奇迹般地帮我们实现从高级语言到可执行文件的翻译。今天是时候“打开”这个黑盒了什么是可执行文件静态链接到底做了什么以及大名鼎鼎的#!(Shebang) 究竟藏着怎样的内核魔法课前小插曲Testkit 的修复与反思关于之前的 Testkit如果工程实现里有多个.c文件执行顺序和快照机制往往让人摸不着头脑。没听懂没关系以后有机会让豆包/Kimi 详细教一下怎么用。核心回顾操作系统的对象进程状态机。管理 API:fork,execve,exit。连续的内存段可以被看作一个能在进程间共享、或映射到文件的对象。管理 API:mmap,munmap,mprotect。什么是可执行文件学习操作系统前那个鼠标“双击可以弹出窗口的东西”。学习操作系统后它是一个操作系统中的对象文件。它是一个字节序列可以用十六进制编辑器直接编辑。它是一个描述了状态机初始状态的数据结构听起来开始让人头秃了。ELF (Executable and Linkable Format)在《计算机系统基础》中我们已经接触过 ELF可执行和可链接格式。这是一种标准的文件格式用于存储可执行文件、目标文件和共享库。我们常用binutils中的工具如readelf和objdump来查看其中的信息。如果想用更现代、更友好的工具可以尝试elfcat。无论工具怎么变可执行文件在底层永远只是一段字节序列。可执行文件进程初始状态的描述根据 AMD64 架构的圣经《System V ABI》规范操作系统只规定了部分寄存器和栈的初始状态而其他的状态主要是内存布局全权由可执行文件来指定。一个合格的可执行文件需要包含什么假设没有动态链接基本信息版本、体系结构。内存布局哪些段放代码.text哪些段放数据.data,.bss。其他信息调试信息、符号表等。极简主义可执行文件其实不需要那么复杂只要满足最基本的要求我们甚至可以手捏一个最小的可执行文件一个合法的头Magic Number7f 45 4c 46也就是\x7fELF。一段蹦床代码Trampoline Code。# 最小的 ELF 实验用 Python 打印字节流即可生成 a.outhex_data 457f 464c 0102 0001 0000 0000 0000 0000 0002 003e 0001 0000 0078 0040 0000 0000 0040 0000 0000 0000 0000 0000 0000 0000 0000 0000 0040 0038 0001 0000 0000 0000 0001 0000 0007 0000 0078 0000 0000 0000 0078 0040 0000 0000 0000 0000 0000 0000 0007 0000 0000 0000 0007 0000 0000 0000 1000 0000 0000 0000 3c6a 3158 0fff 0005 用strace运行它你会发现它确实能被execve成功加载然后下一秒直接exit(0)rootLAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec10/elf-play# strace ./a.outexecve(./a.out,[./a.out], 0x7fff138033d0 /*36vars */)0exit(0)? exited with0和 ELF 搏斗的每一年ELF 是一个经典且极其稳固的设计。E ExecutableL Linkable。它统一了工具链甚至连 Core Dump核心转储用的也是 ELF 格式。但是它也是折磨历届 CS 学生的元凶同学 A期末复习看吐了。老师 A第一次打开 PPT 真的有点吐血的感觉。老师 C (JYY 自己)太好了以后再也不用教了为什么 ELF 这么难懂反思一下ELF 根本不是一个“人类友好”的数据结构描述。为什么不用 JSON因为为了极致的加载性能和空间利用率ELF 彻底违背了可读性信息局部性原则。它到处都是 offset偏移量几乎是让你直接去大脑里人肉解析一棵内存里的树当你听到“程序头表”、“节头表”看到隐晦的R_X86_64_32标记和无尽的指针时人类的大脑是抗拒的。顺带一提Core Dump 的本质Segmentation fault (core dumped)—— 为什么叫“核心转储”地狱笑话今天的 core dump 就是一个 ELF 文件。它的本质是操作系统在程序崩溃的瞬间拍下的一张“状态快照” (内存 寄存器)。Everything is a state machine如果配合ulimit -c unlimited生成 Core Dump再用 GDB 挂载你可以精确查看到程序死前的遗言。想要不仅能看还能让状态机“后退”可以使用CRIU工具。在智能 Agent 时代这类工具可以完美实现复杂应用状态的冻结与恢复。重新设计Funny Little Executable (FLE)既然 ELF 不当人那我们就自己设计一个对人类直接可读的可执行文件格式FLE。核心设计思路越“平坦”越容易理解。所有需要的信息都立即可见不要用指针跳来跳去。回归链接和加载的核心概念代码、符号、重定位。FLE 的三要素代码 (emoji1)符号 (emoji2)重定位 (emoji3)凑齐这三要素我们就可以完成链接到加载的全流程这就是 DSL (Domain Specific Language领域特定语言) 的魅力。做了减法去掉了不必要的复杂特性反而能让人更专注底层的本质。rootLAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec10/fle/demo# make# 编译阶段将 .c 编译成自定义的 .fle (目标文件)./cc-Wall-g-Osfoo.c-ofoo.o...# 链接阶段自定义的 ld 将多个 .fle 合并成最终的 hello 可执行文件./ld foo.fle libc.fle main.fle-ohello rootLAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec10/fle/demo# ./helloMessage: Hello World!... rootLAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec10/fle/demo# echo $?42从源码到加载全流程拆解1. 预编译 - 编译 (.c-.s)预处理:处理#include(其实就是无情的 Ctrl-C Ctrl-V) 和宏替换。编译:将“高级状态机” (C语言) 翻译成“低级状态机” (汇编)最终生成带标注的指令序列。2. 汇编 (.s-.o)将汇编指令打包成 sections (.text,.data,.bss等)。为每个 section 记录核心三要素代码字节序列、符号标记当前位置、重定位暂时不能确定的地址留给链接器填空。3. 静态链接 (.o-a.out)合并所有目标文件的 sections。把代码“平铺”成一整块字节序列。确定所有全局符号的绝对物理地址。解析全部重定位填空最终得到一个可以直接运行的可执行文件。4. 加载 (Loader)把生成的“字节序列”用mmap搬到内存。设置好寄存器和 PC开始运行# 极简版加载器伪代码memmmap.mmap(fileno-1,lengthlen(bs),protmmap.PROT_READ|mmap.PROT_WRITE|mmap.PROT_EXEC,flagsmmap.MAP_PRIVATE|mmap.MAP_ANONYMOUS,)mem.write(bs)mem.flush()call_pointer(mem,fle[symbols][_start])操作系统内核与 Shebang (#!) 的浪漫彩蛋加载器其实是操作系统内核实现的一部分。当你调用execve(path, argv, envp)时内核Linux 中的binfmt_elf.c会亲自解析可执行文件扫描PT_LOAD段并完成内存映射。但是等等运行程序的两种方法/bin/ls(这是一个标准的 ELF 二进制文件)./a.py(这明明是个纯文本啊操作系统怎么懂 Python)Shebang 机制的内核魔术这是 UNIX 给程序员留下的最浪漫的彩蛋对#注释的“妙用”。如果一个文本文件的第一行是#!A B C操作系统在execve尝试加载它时会发现开头的 Magic Number 不是 ELF 的\x7fELF而是#!(十六进制为0x23 0x21)。此时内核binfmt_script.c会立刻心领神会把执行命令偷偷狸猫换太子转换为execve(A, [A, B C, any_file], envp)/* Linux 内核源码片段检查是否以 #! 开头 */if((bprm-buf[0]!#)||(bprm-buf[1]!!))return-ENOEXEC;...fileopen_exec(i_name);这就是为什么你在 Python 脚本的第一行写上#!/usr/bin/env python3后这个普通的文本文件就拥有了像二进制程序一样直接运行的魔法。rootLAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec10/shebang# ./goodargv[0]A argv[1]B C argv[2]./good rootLAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec10/shebang# ./bad-bash: ./bad:..: bad interpreter: Permission denied计算机系统里没有魔法所有的神奇现象背后都是一行行清晰可查的 C 语言代码

相关新闻

Java抽象类构造函数?别做梦了,它根本不让new自己

Java抽象类构造函数?别做梦了,它根本不让new自己

1.抽象类处于自上往下的继承层次架构之中, 处在上层位置的类具备更强的通用性, 甚至有可能显得更为抽象。从特定的某种角度去看, 祖先类具有更高的通用性, 它仅仅涵盖一些最为基础的成员, 人们仅仅是把它当作派生其他类的基本类, 而并非用于创建对象。甚至, 你能够仅仅给出方法…

2026/7/29 0:37:53阅读更多 →
Alaya Lab的研究者如何让AI真正读懂游戏世界的规则

Alaya Lab的研究者如何让AI真正读懂游戏世界的规则

这项由Alaya Lab主导的研究发表于2026年7月,论文编号为arXiv:2607.14076v1,有兴趣深入了解的读者可以通过该编号查询完整论文。你有没有想过,当你在游戏里按下攻击键的那一刻,背后究竟发生了什么?屏幕上的角色不是直接…

2026/7/29 0:37:53阅读更多 →
南京大学携手上海AI实验室:AI助手学会“替盲人看路“能做到几分?

南京大学携手上海AI实验室:AI助手学会“替盲人看路“能做到几分?

这项由南京大学与上海人工智能实验室联合开展的研究,发布于2026年7月,论文编号为arXiv:2607.14660v1,发表于计算机视觉领域预印本平台arXiv,任何有兴趣深入了解的读者均可通过该编号查询完整论文。世界上有数以亿计的视障人士&…

2026/7/29 0:37:53阅读更多 →
宠物综合服务平台哪家靠谱,社交种草带货联动托运

宠物综合服务平台哪家靠谱,社交种草带货联动托运

宠物综合服务平台哪家靠谱,社交种草带货联动托运 宠物行业消费场景早已从单一用品购买、单一托运服务,升级为内容种草、好物选购、活体托运、售后养护的一体化闭环消费模式。优质的宠物综合服务平台,核心竞争力不再是单一功能完整性&#xff…

2026/7/29 3:16:29阅读更多 →
宠物商城社交系统开发,托运购物订单合并结算架构

宠物商城社交系统开发,托运购物订单合并结算架构

宠物商城社交系统开发,托运购物订单合并结算架构 宠物商城社交系统涵盖宠物用品电商交易、用户社交分享、宠物托运履约等多元业务,用户经常同时产生实物商品采购与宠物托运服务需求。在传统系统架构中,商品购物订单与托运服务订单分属两套独立…

2026/7/29 3:16:29阅读更多 →
Python硬核面试题深度解析:从语言核心到性能优化

Python硬核面试题深度解析:从语言核心到性能优化

1. 项目概述:为什么我们需要“硬核”的面试题?最近几年,Python的热度居高不下,从数据分析、机器学习到自动化运维、Web开发,几乎每个技术栈都能看到它的身影。随之而来的,是市场上Python岗位的激增和求职竞…

2026/7/29 3:16:29阅读更多 →
AI 前沿日报 | 2026年07月28日

AI 前沿日报 | 2026年07月28日

1. Kimi K3 开源:2.8T MoE 模型与技术报告 Kimi 发布其最强模型 Kimi K3,这是一个 2.8T 参数的 MoE 模型,具备原生视觉理解和 1M token 上下文窗口。新架构实现了每单位计算 2.5 倍的智能提升。除模型权重外,Kimi 还开源了高性能注…

2026/7/29 3:16:29阅读更多 →
MATLAB常用函数清单:提升工程效率的100个核心工具

MATLAB常用函数清单:提升工程效率的100个核心工具

1. 为什么你需要一份“常用函数”清单?在MATLAB的日常使用中,无论是做算法仿真、数据分析还是图像处理,我们总会遇到一些似曾相识的需求:比如,怎么快速生成一个特定规律的矩阵?如何优雅地处理缺失的数据&am…

2026/7/29 3:16:29阅读更多 →
蜂鸣器驱动电路与PWM编程实战:从原理到STM32/Arduino应用

蜂鸣器驱动电路与PWM编程实战:从原理到STM32/Arduino应用

1. 从“滴滴”声到智能交互:蜂鸣器的前世今生如果你玩过任何一块单片机开发板,比如Arduino或者STM32,那么你对蜂鸣器发出的“滴滴”声一定不会陌生。它可能是你第一个成功运行的程序,点亮LED之后,紧接着就是让这个小东…

2026/7/29 3:14:28阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/28 4:06:39阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/28 2:08:06阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/28 1:38:28阅读更多 →
28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“! 在构建复杂的 Agent 系统时,我们经常会遇到这样的场景:Agent 正在执行一个多步骤的任务,比如“下单购买商品”,但执行到一半时,我们…

2026/7/29 0:01:46阅读更多 →
自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

近日,国际专注开放式技术研发的声学品牌Nank南卡,正式官宣实力艺人曾舜晞担任品牌代言人。消息一经发出便轰动全网。为什么耳机品牌不选择流量明星、老牌歌手?而且是选择曾舜晞?让我们一起来探索一下!比起短期的流量&a…

2026/7/29 0:01:46阅读更多 →
【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:01:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/28 20:22:24阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/28 3:17:03阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/28 2:35:58阅读更多 →