⚠️阅读前请注意
- 本博客适用于Cosmopolitan Libc 3.X版本,不适用于Cosmopolitan Libc 2.X版本。
- Cosmopolitan Libc 是一个非常年轻的项目,可能存在各种问题。
- Cosmopolitan Libc 仍处于快速迭代开发之中,本文内容在一定时期内会持续更新。
Cosmopolitan Libc 工作原理 与 多平台使用
Cosmopolitan Libc 简介
Cosmopolitan Libc makes C a build-anywhere run-anywhere language, like Java, except it doesn’t need an interpreter or virtual machine. Instead, it reconfigures stock GCC and Clang to output a POSIX-approved polyglot format that runs natively on Linux + Mac + Windows + FreeBSD + OpenBSD + NetBSD + BIOS on AMD64 and ARM64 with the best possible performance.
带有补充信息的翻译:
Cosmopolitan Libc 让 C 语言成为了“到处构建,到处运行”的语言。就像 Java 语言那样,但无需使用解释器或虚拟机。Cosmopolitan Libc 配套的编译工具链重新配置了现有的 GCC 和 Clang,以构建得到符合 POSIX 标准的多语言格式的二进制文件——该格式的二进制文件可以在 AMD64 和 ARM64 架构上的 Linux + Mac + Windows + FreeBSD + OpenBSD + NetBSD + BIOS 多种平台上原生运行,并具有尽可能高的性能。
- Cosmopolitan Libc 项目主页:https://justine.lol/cosmopolitan/index.html
- Cosmopolitan Libc 代码仓库:https://github.com/jart/cosmopolitan
Cosmopolitan Libc 是由Justine Tunney主导开发的一款跨架构跨平台的C标准库。配合Cosmopolitan 编译工具链,编译出的二进制文件可以在不同架构的不同系统平台上原生运行。
Cosmopolitan Libc 3.3.3 的平台支持表
Platform | Min Version | Circa |
---|---|---|
AMD | K8 Venus | 2005 |
Intel | Core | 2006 |
Linux | 2.6.18 | 2007 |
Windows | 8 | 2012 |
Darwin (macOS) | 23.1.0+ | 2023 |
OpenBSD | 7 | 2021 |
FreeBSD | 13 | 2020 |
NetBSD | 9.2 | 2021 |
跨平台运行原理
一般而言,Windows平台原生支持的可执行文件与库文件(统称为二进制文件)为
PE
格式(Portable Executable 可移植的可执行文件)。
Unix平台原生支持的二进制文件为ELF
格式(Executable and Linkable Format 可执行并可链接的文件格式)。
为了顾及上述两个平台的兼容性,Cosmopolitan工具链
编译出的二进制文件为APE
格式(Actually Portable Executable 确实可移植的可执行文件)。Justine Tunney之所以取这个名字,可能是为了调侃Windows二进制文件的PE
格式(Portable Executable 可移植的可执行文件)不够“可移植”。
APE
格式的绝妙之处在于
APE
是一种完全合法的Windows PE
格式。只不过APE
利用了PE
格式文件开头的DOS Header
段、DOS Stub
段与空白空间来存放Shell脚本,并利用PE
结尾的空白空间来存放ELF
文件内容。
因此在Windows平台下,APE
格式的文件会被当作正常的PE
格式文件执行。读者可以通过PE-bear(Windows)或readpe
(Linux)工具查看它的具体结构。APE
是一段可以执行的Unix Shell
脚本。根据Unix Shell的特性,若在Unix平台直接执行APE
格式的文件,文件会被默认当做Shell脚本执行。此时位于APE
开头的Shell脚本,将会发挥它的作用。
该脚本会自动将APE Loader解压到本地,接着APE Loader
会读取APE
中存储的ELF
文件头与段信息。最终通过mmap()
操作,把藏在APE
文件里的ELF
信息加载到内存之中。
这一步“加载到内存”的操作,与普通的ELF
文件被加载到内存的过程一致。随后程序被Unix系统内核调度运行,就像那些从普通ELF
文件被加载到内存的程序一样。
Unix平台下,可以通过Shell的调试手段来观察APE
文件的执行原理sh -x APE格式的可执行文件
。
在 x64 Linux / WSL2 平台使用 Cosmopolitan Libc
参考测试环境
- Ubuntu 22.04.3 LTS
获取Cosmopolitan工具链
若想直接体验Cosmopolitan Libc的功能,可以按照其官网主页的指示,直接获取编译好的Cosmopolitan编译工具链
。按如下命令执行,工具链将被放置在./cosmocc/
目录,下列命令执行后,当前工作路径即为该目录。
mkdir cosmocc
cd cosmocc
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
unzip cosmocc.zip
和GCC编译工具链类似,Cosmopolitan编译工具链
主要包含
- C编译器
bin/cosmocc
工具链的C编译器。为提供跨架构跨平台支持,该文件实际上是一个Shell脚本。在构建目标时,其会调用bin/
目录下具体针对不同架构、不同平台的C编译工具。编译工具均为APE
格式。 - C标准库
x86_64-linux-cosmo/lib/libcosmo.a
与aarch64-linux-cosmo/lib/libcosmo.a
工具链中,针对不同架构的静态C标准库。Cosmopolitan Libc本体。静态库中被归档的二进制对象文件均为ELF
格式。 - C++编译器
bin/cosmoc++
工具链的C++编译器。为提供跨架构跨平台支持,该文件实际上是一个Shell脚本。在构建目标时,其会调用bin/
目录下具体针对不同架构、不同平台的C++编译工具。编译工具均为APE
格式。 - C++标准库
x86_64-linux-cosmo/lib/libcxx.a
与aarch64-linux-cosmo/lib/libcxx.a
工具链中,针对不同架构的,基于Cosmopolitan Libc与LLVM项目的静态C++标准库。静态库中被归档的二进制对象文件均为ELF
格式。 - C/C++头文件目录
include/
工具链的C/C++头文件存放与搜寻目录。 - 其它构建工具
工具链所需要的构建工具,如bin/make
、bin/ctags
等。构建工具均为APE
格式。
测试运行APE文件
执行以下命令,测试您的系统能否运行APE
格式的可执行文件。以工具链中的bin/make
工具为例
bin/make --version
参考输出
GNU Make 4.4.1
Built for x86_64-linux-cosmo
Copyright (C) 1988-2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Zsh 与 Fish 使用者
如果出现zsh: exec format error
,则需要升级到 zsh 5.9 以上版本。Fish 也是如此。
若要临时解决该问题,根据APE
文件的运行原理,我们可以显式地把APE
文件当作Shell脚本运行sh bin/make
WSL2 使用者
如果出现error: APE is running on WIN32 inside WSL. You need to run: sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop'
,代表WSL2启用了WSLInterop支持。
若WSL2启用了该支持,当WSL2检测到可执行文件属于Windows原生程序(如PE
文件)时,会以WIN32方式执行该文件,因此会报错。请参见安装 APE Loader 并配置 binfmt_misc一节。
若要临时解决该问题,根据APE
文件的运行原理,我们可以显式地把APE
文件当作Shell脚本运行sh bin/make
【可选】安装 APE Loader 并配置 binfmt_misc
WSL2 使用者
若WSL2启用了WSLInterop支持(应当默认启用),当WSL2检测到可执行文件属于Windows原生程序(如PE
文件)时,会以WIN32方式执行该文件。
为了在不影响WSLInterop功能的情况下运行APE
文件,请WSL2使用者务必执行该步骤。
Wine 使用者
如果Linux中安装了Wine,且Linux会自动通过Wine运行PE
可执行文件,则必须要执行该步骤。
执行该步骤后,APE
文件会被绑定到APE Loader。以后运行APE
文件时,系统会直接将该文件交给APE Loader运行。
根据跨平台运行原理所述,在Unix平台上运行APE
文件时,该文件会被当作Shell脚本执行,并且自动运行APE Loader。在此过程中,APE
文件会作为入参被传递给APE Loader,由其提取并加载文件中的ELF信息到内存。
若Unix平台未安装APE Loader(即ape
命令不存在),则Shell脚本会自动将APE Loader解压到本地。解压位置规则如文档所描述,典型位置是$HOME/.ape*
或$TMPDIR/.ape*
或./.ape*
。
如果Unix平台已经安装APE Loader,ape
命令已存在,则APE
文件会直接调用ape
命令。我们可以执行下列命令,把APE Loader安装到Linux系统的/usr/bin/ape
位置
sudo wget -O /usr/bin/ape https://cosmo.zip/pub/cosmos/bin/ape-$(uname -m).elf
sudo chmod +x /usr/bin/ape
binfmt_misc是Linux内核提供的一个功能特性——用户可以指定使用某个程序去运行某类文件。效果上有点类似于Unix的Shebang或者Windows的“文件默认打开方式”。
执行以下命令,可以临时指定使用/usr/bin/ape
程序来运行APE
格式文件(靠文件头的magic number识别),重启后失效
sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
sudo sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
当我们再次从Shell中运行bin/make
文件时,系统将自动运行/usr/bin/ape bin/make
命令。不再需要依靠APE
文件头部的Shell脚本去运行APE Loader。
对于使用了
systemd-binfmt.service
服务的Linux发行版,可以在/etc/binfmt.d/
目录下创建相应的注册项,然后重启systemd-binfmt.service
服务,即可永久生效。sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/etc/binfmt.d/ape.conf" sudo sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/etc/binfmt.d/ape-jart.conf"
重启
systemd-binfmt.service
服务# 对于WSL2,systemd-binfmt.service服务可能默认被mask掉,请先将其unmask,然后再restart # sudo systemctl unmask systemd-binfmt.service sudo systemctl restart systemd-binfmt.service
编译运行 Hello World
确认APE
文件可以正常运行后,创建一个简单的测试用的C文件hello.c
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("hello world\n");
}
和GCC编译工具链的使用方式一致,使用bin/cosmocc
C语言编译器来编译hello.c
,得到APE
格式的./hello
可执行文件
bin/cosmocc -o hello hello.c
跨平台运行
得到APE
格式的./hello
可执行文件后,首先尝试在本平台运行
./hello
将其复制到Windows系统下。更改其文件名为hello.exe
,增加Windows可执行文件的后缀.exe
。尝试在PowerShell或者CMD中运行
.\hello.exe
在Windows平台运行APE
文件时,可能会触发Windows Defender的报警。请仔细阅读如下Issue。若信任Cosmopolitan项目,请将APE
文件列入Windows Defender白名单,再尝试运行。
https://github.com/search?q=repo%3Ajart%2Fcosmopolitan+windows+defender&type=issues
参考文档
Shell脚本的执行机制
https://stackoverflow.com/questions/12296308/shell-script-working-fine-without-shebang-line-why
Executable and Linkable Format
https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
Portable Executable
https://en.wikipedia.org/wiki/Portable_Executable
https://0xrick.github.io/win-internals/pe2/
Actually Portable Executable
https://justine.lol/ape.html
https://justine.lol/apeloader/