Linux 内核将部分支持 $ORIGIN,Nix 可重定位二进制文件问题或迎解决方案!
Linux 内核支持 $ORIGIN 的研究起源
2026 年 7 月 20 日相关消息显示,在 TacoSprint 2026 期间,有人决定研究能否在 Nix 中解决可重定位二进制文件的问题。此人热衷于推动 Nix 及其周边生态系统发展的宏伟目标,虽不聪明但胜在大胆。在上一篇文章结尾,其提出了一个可能的实现思路:对 Linux 内核进行打补丁,使 PT_INTERP 和 shebang 支持 $ORIGIN。
提案提交与积极反馈
此人克服了通过邮件发送补丁的复杂流程,并向 Linux 内核邮件列表提交了一份提案。首次尝试提议直接在虚拟文件系统(VFS)子系统中添加对 `$ORIGIN` 的支持。原本预想会有人不客气地让其“滚一边去”,然而结果不同。VFS 的维护者 Christian Brauner 真诚地回复,询问更改理由,并最终提出了一些将该支持引入子系统的方法。有像 John Ericson 这样的人参与并倡导非固定解释器(`PT_INTERP`)对 Nix 及其他用例(如 Buck 和 Bazel)的实用性,起到了很大帮助。
eBPF 实现可编程选择解释器
Christian Brauner 提出利用 eBPF 作为一种可编程的方式,通过 binfmt_misc 来选择解释器。原本只是想支持 `$ORIGIN`,但可编程选择的方式能实现更多功能。不久后,Christian 在休假期间就提供了该解决方案的第一版草案,经过邮件列表交流,最终形成了一个补丁系列,该系列补丁将在不久后被合并到 `-next` 分支中。
eBPF 程序支持 $ORIGIN 详解
简单来说,eBPF 可以用 C 语言的一个子集编写程序,这些程序会被编译成一种指令集,其虚拟机在内核中运行,程序会被即时编译成本地 CPU 架构的代码,且执行时间固定,加载代码前会进行“验证”以确保安全。现在可以用一个相对简单的 eBPF 程序来支持 `$ORIGIN`,程序加载并注册到内核后,可要求 binfmt_misc 子系统触发它。每个二进制文件现在都会触发 `nix_match` 函数,内核会要求 `nix_load` 动态确定要使用的解释器,特殊 BPF 程序支持 `$ORIGIN` 了。
BPF 程序的更多应用可能
现在甚至可以用一个 BPF 程序完全替代传统的 QEMU binfmt_misc 注册脚本。由于可以根据文件中的任何内容以编程方式选择解释器,能实现的功能相当多。一些小的应用场景包括,可在 shebang 中支持 `$ORIGIN`。传统 binfmt_misc 切换方式存在缺点,调用所需最终二进制文件的方式不透明,注册的解释器会“成为”进程,带来一些不便,如 `argv[0]` 和 `/proc//cmdline` 显示的是解释器的调用信息,`/proc/self/exe` 指向的是解释器。
新调度模式弥补不足
Christian 为此提交了一个大型补丁系列,其最新的补丁系列添加了两种新的调度模式,从不同角度弥补了差距,并解决了这些模式可能带来的其他一些问题。对 Nix 最期待的是加载器替换 `L` 模式,使用 `L` 标志后,内核会将匹配的二进制文件作为主镜像原生执行,仅用注册的解释器替换二进制文件 `PT_INTERP` 中指定的加载器,`binfmt_misc` 对 `PT_INTERP` 进行直接覆盖,原生动态加载器可以保持不变。
未来计划与展望
后续会持续关注 Linux 内核的发布情况。一旦这些补丁合并到 `-next` 分支并随标记版本发布,计划将一个支持 `$ORIGIN` 的 NixOS 模块上游化,使其在系统启动时进行注册。计划通过新的 `PT_INTERP_NIX` 段来启用该功能,而不是匹配每个 `ELF` 文件,这样可以保持向后兼容,Nix 生成的二进制文件在没有 BPF 处理程序的情况下仍然可以正常工作,但带有新段的文件可以提升为可重定位状态。