标题: Unix系列(17)--Cosmopolitan简介 创建: 2024-09-05 16:10 修改: 2024-09-07 14:03 链接: https://scz.617.cn/unix/202409051610.txt -------------------------------------------------------------------------- 目录: ☆ 背景介绍 ☆ APE技术原理 ☆ Cosmopolitan相关工具 ☆ Linux测试 1) 下载相关工具 2) hello.c ☆ Windows测试 1) 下载相关工具 2) 准备编译环境 3) hello.c 3.1) 在cmd中测试 3.2) 在PowerShell中测试 x) 讨论 ☆ binfmt_misc 1) 加载binfmt_misc文件系统 2) 向内核注册文件类型 3) 用xxd执行some.bin 4) 启用/禁用指定文件类型 5) 从内核反注册文件类型 6) APE与binfmt_misc ☆ cosmos中的游戏 1) 任天堂模拟器 ☆ Justine Tunney -------------------------------------------------------------------------- ☆ 背景介绍 Google有个非常牛的女程序员,名叫Justine Tunney。她搞了一套名为Cosmopolitan 的东西,四海一家。简要地说,只有一份some.c,用cosmocc编译成some.exe,后者 可在Windows、Linux、BSD、MacOS中运行,注意,只有一份some.exe,不是四份。我 只测了AMD64,也支持ARM64。 她给some.exe的文件格式起名APE,是"Actually Portable Executable"的缩写,相 比之下微软的PE一点也不Portable。APE的目标是"四处构建、四处运行",在任意受 支持的平台上构建APE,在所有受支持的平台上运行同一份APE。与Java、Python等解 释语言不同,APE无需安装庞大的解释器,some.exe自己搞掂一切,并不臃肿。 ☆ APE技术原理 -------------------------------------------------------------------------- Actually Portable Executable - Justine Tunney [2020-08-24] https://justine.lol/ape.html APE Loader - [2022-06-11] https://justine.lol/apeloader/ (Actually Portable Executable is a binary format that runs on seven operating systems) (介绍APE原理) cosmopolitan libc https://justine.lol/cosmopolitan/index.html https://justine.lol/cosmopolitan/documentation.html (API) Cosmopolitan Third Edition - [2024-08-17] https://justine.lol/cosmo3/ (Build Once Anywhere, Run Anywhere C/C++) -------------------------------------------------------------------------- APE的基本原理是,首先它是PE格式,在Windows中按PE执行;其次,充分利用PE格式 中不影响执行的区域存放shell脚本、ELF本体等等,在Linux中按ELF执行;APE整体 上有点类似"壳"。 ☆ Cosmopolitan相关工具 -------------------------------------------------------------------------- Cosmopolitan https://github.com/jart/cosmopolitan (有详细的使用说明,包括binfmt_misc) 编译工具链 https://cosmo.zip/pub/cosmocc/cosmocc.zip (最新版) https://cosmo.zip/pub/cosmocc/cosmocc-3.8.0.zip (与下面的不是一个东西) 二进制工具集合 https://cosmo.zip/pub/cosmos/zip/cosmos.zip (最新版) https://cosmo.zip/pub/cosmos/zip/cosmos-3.7.1.zip 二进制工具散装 https://cosmo.zip/pub/cosmos/bin/ https://cosmo.zip/pub/cosmos/tiny/ -------------------------------------------------------------------------- cosmocc是编译工具链,cosmos是一堆APE格式的常用工具,比如bash、curl等等。 ☆ Linux测试 1) 下载相关工具 cd /home/scz/src mkdir cosmocc wget https://cosmo.zip/pub/cosmocc/cosmocc.zip unzip -q cosmocc.zip -d cosmocc rm cosmocc.zip Linux测试时,只需下载编译工具链cosmocc.zip,无需下载cosmos.zip。 2) hello.c export PATH=/home/scz/src/cosmocc/bin:$PATH printf '#include \nint main() { printf("Hello World\\n"); }' > hello.c cosmocc -Wall -pipe -s -o hello.exe hello.c ./hello.exe cosmocc是个bash脚本,实际调用gcc。hello.exe可直接在Ubuntu 22和Win10中运行, 与cosmocc.zip、cosmos.zip毫无关系。 $ file -b hello.exe DOS/MBR boot sector; partition 1 : ID=0x7f, active, start-CHS (0x0,0,1), end-CHS (0x3ff,255,63), startsector 0, 4294967295 sectors $ xxd -g 1 -l 16 hello.exe 00000000: 4d 5a 71 46 70 44 3d 27 0a 0a 00 10 00 f8 00 00 MZqFpD='........ ☆ Windows测试 1) 下载相关工具 Windows测试时,需同时下载cosmocc.zip、cosmos.zip,将两个zip分别展开至: X:\path\cosmocc\ X:\path\cosmos\ cosmocc是个bash脚本,需在bash环境中运行,cosmos.zip提供有APE格式的bash。 2) 准备编译环境 Windows测试时还需一些额外动作 copy X:\path\cosmos\bin\bash X:\path\cosmos\bin\bash.exe 虽然这个bash已是APE格式,但cmd中执行时,需要任一扩展名;若在PowerShell中用 Start-Process执行bash,扩展名则不是必须的。 修改 X:\path\cosmocc\bin\cosmocc 该脚本第一行本来是 #!/bin/sh 修改成 #!/X/path/cosmos/bin/bash 否则cosmocc脚本执行不起来 3) hello.c 3.1) 在cmd中测试 cd /d X:\src echo %PATH% set PATH=X:\path\cosmocc\bin;X:\path\cosmos\bin;%PATH% X:\path\cosmos\bin\bash.exe -l 在bash中执行 printf '#include \nint main() { printf("Hello World\\n"); }' > hello.c cosmocc -Wall -pipe -s -o hello.exe hello.c hello.exe exit 在cmd中执行 hello.exe 该hello.exe可直接在Ubuntu 22中运行。 从cmd进bash后,快速编辑模式被关闭,Copy/Paste不方便。可通过左上角的属性-> 选项,再次打开快速编辑模式。但是,在bash中每执行一次命令,快速编辑模式就被 关闭一次,烦不胜烦,未找到永久打开的办法,只能一次次再次打开。稍好一点的办 法是,每次先Ctrl-M临时进入编辑模式,再鼠标框选复制,最后Ctrl-V粘贴。 3.2) 在PowerShell中测试 特指在Windows Terminal PowerShell中测试 cd X:\src $env:PATH $env:PATH="X:\path\cosmocc\bin;X:\path\cosmos\bin;$env:PATH" Start-Process -FilePath X:\path\cosmos\bin\bash -ArgumentList "-l" -Wait -NoNewWindow -NoNewWindow参数不可少,否则新开的bash窗口执行命令有问题,原因不明。进bash 环境后,其余操作同cmd测试。从PowerShell进bash后,快速编辑模式同样被关闭, 不幸的是,未找到再次打开的办法。临时缓解方案是,按住Shift不松的情况下,鼠 标框选复制、粘贴。 若不在Windows Terminal中,PowerShell的反应同cmd,可Ctrl-M临时进入编辑模式。 x) 讨论 实测过自己开发的一些实用工具,包括二十多年前的nsfocus_scan.c,用cosmocc成 功编译并运行,确实能做到"四处构建、四处运行"。Justine Tunney本人提供过其他 更具说服力、更复杂的示例。 但我碰上select、poll的超时机制不起作用,指定超时的情况下,不会超时结束,同 一APE,在Ubuntu、Win10上俱如此,不知是不是BUG? 从网络安全角度看,APE可能为恶意软件所用。 ☆ binfmt_misc 参看 -------------------------------------------------------------------------- Kernel Support for miscellaneous Binary Formats (binfmt_misc) https://docs.kernel.org/admin-guide/binfmt-misc.html -------------------------------------------------------------------------- binfmt_misc是Linux内核提供的功能,可指定用某程序打开某类文件,类似Windows 的ftype、assoc命令以及"按文件类型指定默认应用"。 1) 加载binfmt_misc文件系统 $ mount | grep ^binfmt_misc binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,nosuid,nodev,noexec,relatime) 若未加载,则手工加载 mount -t binfmt_misc none /proc/sys/fs/binfmt_misc 2) 向内核注册文件类型 命令模板如下 echo ':name:type:offset:magic:mask:interpreter:flags' > /proc/sys/fs/binfmt_misc/register echo指定的参数最长1920字符,参数解释如下 -------------------------------------------------------------------------- name 标识符,不能含有/ type M表示magic number,E表示extension,即根据什么来识别文件类型 offset type为M时,指定magic/mask的文件偏移,以字节为单位,省略时使用缺省值0 type为E时,忽略此字段 magic type为M时,指定magic number的字节流,可使用\xHH转义序列 you must escape any NUL bytes; parsing halts at the first one. offset+size(magic)必须小于128,magic number字节流必须全部位于目标文件 前128字节 type为E时,指定扩展名,不允许出现.、\x0a、/之类的特殊字符,大小写敏感 mask 省略时使用缺省值0xff,与magic一道工作,即"magic & mask" you must escape any NUL bytes; parsing halts at the first one. type为E时,忽略此字段 interpreter 成功识别文件类型后,用此程序执行目标文件,此字段需指定绝对路径,最长 127字符 flags 可选字段,控制interpreter的行为,可取如下值的组合 P - preserve-argv[0] binfmt_misc传统行为是,用interpreter的绝对路径覆盖原来的argv[0],指定 P时,binfmt_misc会增加一项argv[i]。比如,interpreter是/bin/foo,你执行 /usr/local/bin/blah,内核实际执行/bin/foo,其argv[]是 ["/bin/foo", "/usr/local/bin/blah", "blah"] O - open-binary Legacy behavior of binfmt_misc is to pass the full path of the binary to the interpreter as an argument. When this flag is included, binfmt_misc will open the file for reading and pass its descriptor as an argument, instead of the full path, thus allowing the interpreter to execute non-readable binaries. This feature should be used with care - the interpreter has to be trusted not to emit the contents of the non-readable binary. C - credentials Currently, the behavior of binfmt_misc is to calculate the credentials and security token of the new process according to the interpreter. When this flag is included, these attributes are calculated according to the binary. It also implies the O flag. This feature should be used with care as the interpreter will run with root permissions when a setuid binary owned by root is run with binfmt_misc. F - fix binary The usual behaviour of binfmt_misc is to spawn the binary lazily when the misc format file is invoked. However, this doesn't work very well in the face of mount namespaces and changeroots, so the F mode opens the binary as soon as the emulation is installed and uses the opened image to spawn the emulator, meaning it is always available once installed, regardless of how the environment changes. -------------------------------------------------------------------------- 3) 用xxd执行some.bin $ xxd -g 1 some.bin 00000000: 73 63 7a 5f 69 73 5f 68 65 72 65 scz_is_here 以root身份注册文件类型 echo ':scz:M::scz_::/bin/xxd:' > /proc/sys/fs/binfmt_misc/register 以普通用户测试 $ chmod +x some.bin $ ./some.bin 00000000: 7363 7a5f 6973 5f68 6572 65 scz_is_here 相当于执行"xxd some.bin" 若未注册或未启用相应文件类型,Linux执行some.bin将之视为shell script $ ./some.bin ./some.bin: line 1: scz_is_here: command not found 4) 启用/禁用指定文件类型 $ ls -l /proc/sys/fs/binfmt_misc/scz -rw-r--r-- 1 root root 0 Sep 6 13:50 /proc/sys/fs/binfmt_misc/scz $ cat /proc/sys/fs/binfmt_misc/scz enabled interpreter /bin/xxd flags: offset 0 magic 73637a5f 禁用指定文件类型 $ echo 0 > /proc/sys/fs/binfmt_misc/scz $ cat /proc/sys/fs/binfmt_misc/scz disabled ... 启用指定文件类型 $ echo 1 > /proc/sys/fs/binfmt_misc/scz $ cat /proc/sys/fs/binfmt_misc/scz enabled ... 启用/禁用所有文件类型(慎用) echo 1 > /proc/sys/fs/binfmt_misc/status echo 0 > /proc/sys/fs/binfmt_misc/status 5) 从内核反注册文件类型 反注册指定文件类型 $ echo -1 > /proc/sys/fs/binfmt_misc/scz $ ls -l /proc/sys/fs/binfmt_misc/scz ls: cannot access '/proc/sys/fs/binfmt_misc/scz': No such file or directory 反注册所有文件类型(慎用) echo -1 > /proc/sys/fs/binfmt_misc/status 6) APE与binfmt_misc APE并不绝对依赖binfmt_misc,用的话效率高一些,不用也能跑 wget -O /usr/bin/ape https://cosmo.zip/pub/cosmos/bin/ape-$(uname -m).elf chmod +x /usr/bin/ape echo ':APE:M::MZqFpD::/usr/bin/ape:' > /proc/sys/fs/binfmt_misc/register echo ':APE-jart:M::jartsr::/usr/bin/ape:' > /proc/sys/fs/binfmt_misc/register ☆ cosmos中的游戏 1) 任天堂模拟器 参看 -------------------------------------------------------------------------- Cosmopolitan NESEMU1 - [2023-08-01] https://justine.lol/nesemu1.html https://justine.lol/nesemu1-1.2.com https://cosmo.zip/pub/cosmos/bin/nesemu1 https://cosmo.zip/pub/cosmos/tiny/nesemu1 -------------------------------------------------------------------------- 在bash中执行nesemu1,或添加.exe扩展名后在cmd中执行 X:\path\cosmos\bin\nesemu1.exe 内置三款游戏 COSMOPOLITAN NESEMU1 [0] /zip/usr/share/rom/tetris.nes [1] /zip/usr/share/rom/zelda.nes [2] /zip/usr/share/rom/mario.nes Please choose a game (or CTRL-C to quit) [default 0]: tetris.nes即"俄罗斯方块",空格是调方向。 mario.nes即"超级马利奥",空格是跳。 后来小宋给我一个BattleCity.nes,这是"坦克大作战",这样加载: X:\path\cosmos\bin\nesemu1.exe X:\path\cosmos\bin\BattleCity.nes 无需进bash,不依赖cosmos其他文件。空格是发射炮弹。 说是设置FFPLAY环境变量,能找到ffplay的情况下可播放音频,但我没试成功。 ☆ Justine Tunney readyu向我推荐了Cosmopolitan项目,他评价说,这姐们对编程语言、编译器、文件 格式、操作系统的理解非常人所及,此人还是占领华尔街的社会活动家。这里有她的 照片: -------------------------------------------------------------------------- Justine Alexandra Roberts Tunney (born 1984) https://en.wikipedia.org/wiki/Justine_Tunney -------------------------------------------------------------------------- 我的感受是,Justine Tunney与Fabrice Bellard一样,TA们属于能推动技术前进的 那种天才程序员,实在是难望其项背。