如何让一个二进制可执行程序同时在Windows与Linux下原生启动?
有同学说过 APE 了。
actual portable executable 依旧是个 windows PE 格式文件,只是利用了 Unix 在不清楚一个可执行文件该如何打开的时候会当作 POSIX shell 执行的特性。
比如 安装 mono 后:
sudo less /proc/sys/fs/binfmt_misc/CLR
enabled
interpreter /usr/bin/mono
flags:
offset 0
magic 4d5a
那么遇到 MZ (0x4d 0x5a) 开头的 windows PE 文件就会使用 mono 执行。
wine 也是同理。 你也可以配置遇到 windows PE 文件用 wine 打开。例如下图的 python.exe 在 Linux 上运行:
而对于没有配置用 wine 或 mono 打开 windows PE 文件的 Linux 系统, APE 会被当成 POSIX shell 执行。妙就妙在他还真是一个合法的 POSIX shell 。。。
当然你如果配置了 windows PE 打开方式,你就要再额外配置 APE 打开方式了。 magic 就不是 MZ 而是 MZqFpD 。
不过我想补充的一点是:
APE 格式文件利用的 Unix 会把一个文件当 POSIX shell 脚本执行的技巧也有别的使用场景。例如我就经常写这样的 C 示例代码:
#if 0
bin="$(basename "$0")" && bin="${bin%%.*}" && cc -g -Wall -o"$bin" "$0" && exec ./"$bin" "$@" || exit
#endif
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
printf("hello\n");
return EXIT_SUCCESS;
}
chmod +x main.c
./main.c
这里的 main.c 也会作为一个可执行文件,执行会会编译自己得到一个 main 文件,再执行 main 输出结果。第一行会被当场 POSIX shell 的注释直接忽视。这样把编译命令和代码写在一起有时怪省事的。唯一美中不足的是没有 shell 的语法高亮。。。(实现不了,因为就算在 tree-sitter 里写 query 匹配这个 AST 节点再 injection bash 的高亮,也会因为 #if 0 被 LSP 当成注释,除非改 clangd 的代码)
就酱紫。