
自编译系统工程教育平台
Selfie是一个系统工程教育平台,通过12000行C代码实现了自编译编译器、自执行模拟器和自托管虚拟机监视器。该项目聚焦系统代码中的自引用挑战,为本科生和研究生提供编译器、库、操作系统和虚拟机监视器的实践构建经验,全面覆盖从编程语言到运行时系统的设计与实现。
自拍是奥地利萨尔茨堡大学计算机科学系计算系统组的一个项目。
自拍项目为本科生和研究生提供了一个教育平台,用于教授编程语言和运行时系统的设计和实现。重点是构建编译器、库、操作系统和虚拟机监控器。共同的主题是识别和解决系统代码中的自引用,这被视为教授系统工程时的关键挑战,因此得名。
自拍是一个自包含的64位、12KLOC C语言实现,包括:
自拍在一个(!)文件中实现,并保持最小化以简化。还有一个简单的内存链接器、RISC-U反汇编器、垃圾收集器、L1指令和数据缓存、分析器,以及带有重放功能的调试器,以及以RISC-V系统调用形式内置于仿真器和虚拟机监控器中的最小操作系统支持。垃圾收集器是保守的,甚至是自收集的。它可以作为库在与变异器相同的地址空间中运行,和/或作为内核地址空间中仿真器的一部分运行。
自拍生成的ELF二进制文件可以在真实的RISC-V硬件和QEMU上运行,并与官方RISC-V工具链兼容,特别是spike仿真器和pk内核。
自拍被设计为64位系统,因此需要64位系统才能运行(LP64数据模型)。然而,自拍也可以在支持编译和执行32位二进制文件的系统上编译(ILP32数据模型)。在这种情况下,自拍成为一个32位系统,可以直接生成和执行32位二进制文件。这是可能的,因为自拍的实现在整个系统中都小心避免了32位溢出。
垃圾回收:除了selfie中保守但时间复杂度为O(n^2)的垃圾回收器外,还有一个针对小内存块的O(n)时间复杂度的Boehm垃圾回收器实现,对于大内存块则回退使用selfie中的垃圾回收器。
模糊测试:有一个基于selfie的简单但自我模糊测试的模糊器,名为buzzr,用于对RISC-U代码(包括selfie的所有代码和自身)进行模糊测试。
符号执行:有一个基于selfie的自执行符号执行引擎,名为monster,它将RISC-U代码(包括selfie的所有代码和自身)转换为SMT-LIB公式。当且仅当存在使代码以非零退出代码退出或在给定的机器指令数内执行除零操作的输入时,这些公式是可满足的。
有界模型检查:有一个基于selfie的自翻译建模引擎,名为beator,它将RISC-U代码(包括selfie的所有代码和自身)转换为BTOR2公式。当且仅当存在使代码以非零退出代码退出、执行除零操作或访问已分配内存块之外的内存的输入时,这些公式是可满足的。
位精确代码分析和合成:有一个基于selfie的自翻译建模引擎,名为rotor,它将完整的RISC-V代码(包括selfie的所有代码和自身)转换为BTOR2和SMT-LIB公式。当且仅当存在使代码以非零退出代码退出、执行除零操作或访问内存段之外的内存 的输入时,这些公式是可满足的。Rotor还生成支持RISC-V代码合成的模型。
BTOR2可视化:有一个名为beatle的可视化工具,它将从RISC-U二进制文件生成的BTOR2公式显示为有向无环图。
SAT求解:有一个基于selfie的暴力SAT求解器,名为babysat,用于计算DIMACS CNF格式的SAT公式的可满足性。
二进制翻译:有一个基于selfie的自翻译二进制翻译器,它将RISC-U代码(包括selfie的所有代码和自身)翻译成x86二进制代码。
Selfie可以在Linux、macOS和Windows机器上原生运行,可能还支持其他安装了终端和C编译器的系统。即使您的机器上没有安装C编译器,或者您只能访问网络浏览器,您也可以运行selfie。安装和运行selfie至少有三种方式:
在您的机器上原生安装(推荐):下载并解压selfie。然后,打开终端运行selfie,具体见下文。为此,您需要在机器上安装C编译器。我们推荐使用clang或gcc(在Windows上使用cygwin)。
在您的机器上使用docker(高级):下载并安装docker。然后,打开终端并输入docker run -it cksystemsteaching/selfie。使用docker的优点是您可以在机器上直接运行selfie,而无需安装任何工具,如C编译器。所有必要的甚至可选的工具都预先安装在selfie docker镜像中。但是,您需要知道如何使用docker。
在云端(简单但需要互联网连接):如果您只能访问网络浏览器,只需点击这里。或者,创建一个github账户(如果您还没有),然后将selfiefork到您的github账户中。接着,创建一个cloud9学生账户,将其连接到您的github账户,验证您的电子邮件地址并设置密码(重要!),最后将您fork的selfie克隆到一个新的cloud9工作空间中。
此时,我们假设您已经有一个支持运行selfie的系统。以下我们使用make命令,假设它已安装在您的系统上,这通常是默认的。但是,我们也会展示make调用的命令,这样如果您的系统没有安装make,您也可以手动执行该命令。
下一步是生成selfie二进制文件。为此,在终端中cd到selfie文件夹,然后输入make。使用docker时,系统会回应make: 'selfie' is up to date,因为已经预先安装了selfie二进制文件。不使用docker时,make将在您的机器上或cloud9工作空间中调用C编译器:
cc -Wall -Wextra -O3 -D'uint64_t=unsigned long' selfie.c -o selfie
然后将selfie.c编译成一个名为selfie的可执行文件,如-o选项所指定。这个可执行文件包含C*编译器、mipster模拟器和hypster虚拟机监控器。-Wall和-Wextra选项启用所有编译器警告,这在selfie的进一步开发中很有用。-O3选项指示编译器生成优化代码。-D'uint64_t=unsigned long'选项用于引导代码。它定义了数据类型uint64_t,否则由于C*不包含必要的定义,该类型将是未定义的。如果您的系统支持编译和执行32位二进制文件,您也可以尝试make selfie-32,这将生成一个32位系统,然后生成和执行32位二进制文件。
一旦您成功编译了selfie.c,您可以不带任何参数调用selfie,如下所示:
$ ./selfie ./selfie { -c { source } | -o binary | [ -s | -S ] assembly | -l binary } [ ( -m | -d | -r | -y ) 0-4096 ... ]
在这种情况下,selfie会回应其使用模式。
为了充分利用自 指性,提供选项的顺序很重要。
-c选项调用C*编译器处理给定的source文件列表,将它们编译并链接成内部存储的RISC-U代码。例如,可以使用selfie来编译它自己的源代码selfie.c,如下所示:
$ ./selfie -c selfie.c
-o选项将最近一次编译器调用生成的RISC-U代码写入指定的binary文件。例如,可以指示selfie编译自身,然后将生成的RISC-U代码输出到名为selfie.m的RISC-U二进制文件:
$ ./selfie -c selfie.c -o selfie.m
-s选项将最近一次编译器调用生成的RISC-U代码的RISC-U汇编写入指定的assembly文件,而-S选项还会包括近似的行号和指令的二进制表示。类似地,可以指示selfie编译自身,然后将生成的RISC-U代码输出到名为selfie.s的RISC-U汇编文件:
$ ./selfie -c selfie.c -s selfie.s
-l选项从给定的binary文件加载RISC-U代码。-o和-s选 项也可以在-l选项之后使用。但在这种情况下,-s选项不会生成近似的源代码行号。例如,可以按如下方式加载之前生成的RISC-U二进制文件selfie.m:
$ ./selfie -l selfie.m
-m选项调用mipster模拟器执行最近加载或由编译器调用生成的RISC-U代码。模拟器创建一个具有0-4096 MB内存的机器实例。RISC-U代码的source或binary名称以及任何剩余的...参数都会传递给代码的main函数。例如,以下调用使用mipster执行selfie.m:
$ ./selfie -l selfie.m -m 1
这在语义上等同于不带任何参数执行selfie:
$ ./selfie
-d选项类似于-m选项,但mipster会输出每条执行的指令、其近似源代码行号(如果可用)以及相关的机器状态。另外,-r选项通过让mipster仅在发生运行时错误(如除以零)时重放代码执行,来限制-d选项创建 的输出量。在这种情况下,mipster只输出错误发生前刚刚执行的指令。
如果你使用docker,也可以直接在spike和pk上执行selfie.m,如下所示:
$ spike pk selfie.m
这在语义上再次等同于不带任何参数执行selfie。
-y选项调用hypster虚拟机监控器执行RISC-U代码,类似于mipster模拟器。与mipster的区别在于,hypster创建RISC-U虚拟机而不是RISC-U模拟器来执行代码。请参见下面的示例。
以下是如何执行selfie.c的自编译,然后检查通过执行./selfie二进制文件为selfie.c生成的RISC-U代码selfie1.m是否等同于通过执行刚刚生成的selfie1.m二进制文件生成的代码selfie2.m的示例:
$ ./selfie -c selfie.c -o selfie1.m -m 2 -c selfie.c -o selfie2.m $ diff -s selfie1.m selfie2.m Files selfie1.m and selfie2.m are identical
注意,这需要至少2MB的内存才能工作。
以下示例展示了如何执行mipster模拟器的自执行。在这种情况下,我们调用mipster来调用自身以执行selfie:
$ ./selfie -c selfie.c -o selfie.m -m 2 -l selfie.m -m 1
这在语义上再次等同于不带任何参数执行selfie,但这次selfie打印其使用模式的速度要慢得多,因为有一个mipster运行在另一个mipster之上。
前面的示例也可以通过在mipster上运行hypster来完成。这显著更快,并且需要更少的内存,因为hypster不会在第一个模拟器实例之上创建第二个模拟器实例。相反,hypster创建一个虚拟机来执行selfie,该虚拟机与第一个模拟器实例上的hypster并行运行:
$ ./selfie -c selfie.c -o selfie.m -m 1 -l selfie.m -y 1
我们甚至可以在mipster上运行hypster上的hypster,这仍然相当快,因为仍然只涉及一个模拟器实例,而hypster本身并不增加太多开销:
$ ./selfie -c selfie.c -o selfie.m -m 2 -l selfie.m -y 1 -l selfie.m -y 1
要编译任何C*源代码并立即执行它,而不生成RISC-U二进制文件,可以在单次调用selfie时使用:
$ ./selfie -c any-cstar-file.c -m 1 "arguments for any-cstar-file.c"
同样,你也可以使用selfie编译的selfie版本,让mipster模拟器执行selfie来编译任何C*源代码,然后立即用hypster在同一模拟器实例上执行它:
$ ./selfie -c selfie.c -m 1 -c any-cstar-file.c -y 1 "arguments for any-cstar-file.c"
你也可以用这两种方式生成RISC-U二进制文件,它们将是相同的:
$ ./selfie -c any-cstar-file.c -o any-cstar-file1.m $ ./selfie -c selfie.c -m 1 -c any-cstar-file.c -o any-cstar-file2.m $ diff -s any-cstar-file1.m any-cstar-file2.m Files any-cstar-file1.m and any-cstar-file2.m are identical
这也可以在单次调用selfie时完成:
$ ./selfie -c any-cstar-file.c -o any-cstar-file1.m -c selfie.c -m 1 -c any-cstar-file.c -o any-cstar-file2.m $ diff -s any-cstar-file1.m any-cstar-file2.m Files any-cstar-file1.m and any-cstar-file2.m are identical
然后可以按如下方式加载和执行生成的RISC-U二进制文件:
$ ./selfie -l any-cstar-file1.m -m 1 "arguments for any-cstar-file1.m"
要从多个源文件编译和链接任何C*源代码,请使用:
$ ./selfie -c any-cstar-file1.c any-cstar-file2.c ... -m 1
例如,要将 selfie.c 的源代码作为库代码在任何 C* 源代码中使用,请执行:
$ ./selfie -c any-cstar-file.c selfie.c -m 1
请注意,编译器会忽略多重符号定义,并发出警告。
Selfie 的控制台消息始终以当前运行的源文件或二进制文件的名称开头。Mipster 模拟器还会显示为其机器实例分配的内存量以及执行如何终止(退出代码)。
如前所述,selfie 和任何其他 C* 文件的 RISC-U 汇编代码可以通过以下方式生成:
$ ./selfie -c selfie.c -s selfie.s
如果汇编代码是由编译器生成的二进制文件生成的(而不是从文件加载的),汇编文件中会包含大致的源代码行号。
使用 -d 选项可以打印详细的调试信息,例如:
$ ./selfie -c selfie.c -d 1
同样,如果执行的二进制文件是由编译器生成的(而不是从文件加载的),调试信息中会包含大致的源代码行号。


免费创建高清无水印Sora视频
Vora是一个免费创建高清无水印Sora视频的AI工具


最适合小白的AI自动化工作流平台
无需编码,轻松生成可复用、可变现的AI自动化工作流

大模型驱动的Excel数据处理工具
基于大模型交互的表格处理系统,允许用户通过对话方式完成数据整理和可视化分析。系统采用机器学习算法解析用户指令,自动执行排序、公式计算和数据透视等操作,支持多种文件格式导入导出。数据处理响应速度保持在0.8秒以内,支持超过100万行数据的即时分析。


AI辅助编程,代码自动修复
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想 工具。


AI论文写作指导平台
AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的 整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。


AI一键生成PPT,就用博思AIPPT!
博思AIPPT,新一代的AI生成PPT平台,支持智能生成PPT、AI美化PPT、文本&链接生成PPT、导入Word/PDF/Markdown文档生成PPT等,内置海量精美PPT模板,涵盖商务、教育、科技等不同风格,同时针对每个页面提供多种版式,一键自适应切换,完美适配各种办公场景。


AI赋能电商视觉革命,一站式智能商拍平台
潮际好麦深耕服装行业,是国内AI试衣效果最好的软件。使用先进AIGC能力为电商卖家批量提供优质的、低成本的商拍图。合作品牌有Shein、Lazada、安踏、百丽等65个国内外头部品牌,以及国内10万+淘宝、天猫、京东等主流平台的品牌商家,为卖家节省将近85%的出图成本,提升约3倍出图效率,让品牌能够快速上架。


企业专属的AI法律顾问
iTerms是法大大集团旗下法律子品牌,基于最先进的大语言模型(LLM)、专业的法律知识库和强大的智能体架构,帮助企业扫清合规障碍,筑牢风控防线,成为您企业专属的AI法律顾问。


稳定高效的流量提升解决方案,助力品牌曝光
稳定高效的流量提升解决方案,助力品牌曝光


最新版Sora2模型免费使用,一键生成无水印视频
最新版Sora2模型免费使用,一键生成无水印视频
最新AI工具、AI资讯
独家AI资源、AI项目落地

微信扫一扫关注公众号