如何移植Chez Scheme到新的平台

By guenchi at 2018-07-24 • 0人收藏 • 269人看过

https://groups.google.com/forum/#!topic/chez-scheme/dz6nn-8KDQE


移植Chez Scheme相对简单,我们实现了几个RISC示例(ARM 32位Little Endian和PPC 32位Big Endian),这应该有助于作为移植的起点。

虽然以下不是完整的移植指南,但我尝试了一下编辑器,并至少给出了如何处理它的草图。我们一直致力于保持机器和操作系统相关的实现细节模块化,以便在移植到新的硬件平台或操作系统时可以替换它们。

#编译器,库和运行时的快速概述

大多数Chez Scheme编译器和库都在Scheme中实现,可以在's'(for Scheme)子目录中找到。运行时(包括垃圾收集器,支持与操作系统交互,以及一些更复杂的数学库支持)在C中实现,可以在“c”目录中找到。

移植到新系统需要在新平台上编译C运行时并更新Scheme编译器以生成平台的机器代码。有几个地方,编译器生成的C运行时和代码需要协调工作才能使系统运行。例如,C运行时需要知道Scheme对象的类型标签,大小和字段偏移量,以便C运行时中的垃圾收集器可以完成其工作。这是通过让Scheme编译器生成几个C头来处理的:scheme.h和equates.h,它包含有关C运行时需要完成其工作的Scheme编译器的信息。

Chez Scheme是一个启动式编译器,意味着你需要一个Chez Scheme编译器来构建一个Chez Scheme编译器。在移植到新平台的情况下,您需要在已经支持的主机上工作,以交叉编译引导文件并生成头文件。然后可以将它们移动到目标平台,并使用生成的头文件编译C运行时。一旦你完成了所有的工作,就可以在新机器上运行Chez Scheme编译器来生成本机构建的启动文件,并在'mats'目录中运行测试。

#移植到新平台

Chez Scheme为其运行的每个平台分配一个“机器类型”名称。 “机器类型”目前包含三条信息:

1.系统是否有线程? ('t'表示它是,没有任何表明它没有线程);

2.硬件平台:i3用于x86,a6用于x86_64,arm32用于32位ARM,ppc32用于32位PPC;和

3.操作系统:le for Linux,nt for Windows,osx for macOS等。

例如ta6osx,是用于运行macOS的x86_64机器的线程Chez Scheme。作为第一步,您需要为新支持选择新的机器类型名称。这些机器类型也存储在cmacros.ss文件的“define-machine-types”列表中,您需要将新机器类型添加到此列表中。

##构建对新平台的支持

Chez Scheme项目根目录中的“workarea”脚本用于生成一个子目录,其中包含为该特定计算机构建的相应内容。这是configure脚本在配置执行构建时运行的脚本,但您也可以自己运行'workarea'脚本,提供您要构建的机器类型。当您浏览此文件时,您将看到文件中的机器类型名称在哪里,它需要针对机器类型执行特定操作。

你要注意的一件事是,如果你查看's','c'和'mats'目录,它们都包含格式为'Mf- [machine-type]'的文件。这些文件是包含各种平台的特定于平台的设置的Makefile,您需要为新平台创建每个Makefile的版本。我建议从与您移植到的平台类似的一个开始。在'c'和'mats'目录中,这些主要是主机C编译器的设置差异。 's'目录'Mf- [machine-type]'文件记录正在编译的机器类型和要包含在编译器中的目标特定源文件。

您还会在's'目录中注意到每个Chez Scheme机器类型都有一个'[machine-type] .def'目录。此文件包含特定于计算机的信息,如各种整数类型的大小,计算机的字节顺序以及计算机体系结构文件的名称。您需要为新平台添加此文件的版本。

有了这个,您应该能够使用'workarea'脚本为您的机器类型提供一个新目录。您可能还想创建一个特定于体系结构的文件(如'x86.ss','x86_64.ss','ppc32.ss'或'arm32.ss'文件)。创建此方法的一种方法是复制现有的类似架构(例如'arm32.ss')作为起点,这在您开始使用时会很有用,因为它可以让您构建C头文件你需要编译C运行时并在完成后端的完整端口之前编译该部分。

###其他构建支持文件

一旦你有了工作,你可能想要更新配置脚本,以便你可以配置新平台和'bintar'脚本,它可以用来打包Chez Scheme二进制文件的tar-ball。

#使用Chez Scheme交叉编译器

在's'目录中,您将找到一个名为'Mf-cross'的文件,它是用于调用交叉编译器的Makefile。在使用它之前,您需要为构建的主机配置可执行程序。默认情况下,Mf-cross将查找要在机器的根“bin / <machine-type>”和“boot / <machine-type>”目录中签入的构建二进制文件。你可以使用'checkin'脚本从构建的主机图像中检查二进制文件(运行'./configure'和'make'的结果),或者你可以告诉'Mf-cross'在哪里寻找方案二进制。您还需要告诉它目标的机器类型。该调用如下所示:

make -f Mf-cross m = <host-machine> xm = <target-machine> Scheme =“../../ <host-make -f Mf-cross m=<host-machine> xm=<target-machine> Scheme="../../<host-machine>/bin/<host-machine>/scheme -b ../../<host-machine>/boot/<host-machine>/petite.boot -b ../../<host-machine>/boot/<host-machine>/scheme.boot"

如果您已签入主机计划二进制文件和引导文件,则不需要'Scheme'参数。例如,如果我从64位x86_64 macOS主机构建32位x86 Linux映像,我会执行以下操作:

make -f Mf-cross m=a6osx xm=i3le Scheme="../../a6osx/bin/a6osx/scheme -b ../../a6osx/boot/a6osx/petite.boot -b ../../a6osx/boot/a6osx/scheme.boot"

完成此操作后,您应该在<machine-type> / boot目录中找到目标计算机的引导和头文件(../<machine-type>/boot,您在's'目录中运行make) 。这里应该有四个文件:'petite.boot','scheme.boot','equates.h'和'scheme.h'。这些文件需要转移到目标机器(或为目标机器提供C交叉编译器),以便为目标机器构建“方案”二进制文件。

'scheme'二进制文件的启动过程检查'machine.def'文件提供的整数大小等与C编译器期望的整数大小相匹配。如果出现问题,它将报告其中一种类型的大小不匹配,这通常表明“machine.def”文件中存在错误。

当然,我们期望'scheme'在尝试加载启动文件时会失败,因为我们还没有做任何事情来替换新架构的机器特定的后端,并且它正在生成机器文件适用于不同的机器类型。

#更换机器特定的后端

如前所述,编译器的机器特定内容存储在为目标机器命名的单独文件中:'x86.ss','x86_64.ss','arm32.ss'和'ppc32.ss'。这些文件中的每一个都分为三个部分。

##第一部分:注册

第一部分提供了机器上可用寄存器的定义,以及Chez方案的任务特定寄存器的映射:%tc,%sfp,%ap,%陷阱,以及可能的其他寄存器。 %tc是线程上下文,必须获取一个寄存器,用于存储有关正在运行的会话的信息,以及线程内版本,即当前运行的线程的上下文。 %sfp是Scheme帧指针。 Chez方案不会将架构堆栈用于其调用,而是将其留在外部函数接口使用的位置。 %陷阱寄存器跟踪当前方案系统应暂停的时间,以检查自上次检查以来进入的中断,垃圾收集请求等。执行功能时,该寄存器向下计数到零。附加寄存器包括%esp,堆栈指针的结束和%eap,分配指针的结束。当这些未被指定为实际寄存器时,它们将成为%tc指向的数据结构中的“虚拟寄存器”。这里的细节不太重要,除了知道必须留出至少少数必需的寄存器。编译器的其余部分应该做一些检查,以确保它的设置是理智的。还必须指定C参数寄存器,以便在外部函数接口知道要保存和恢复外部函数调用的寄存器时。

此寄存器信息以及“machine.def”文件确定在方案调用约定中使用了多少寄存器以及将使用哪些寄存器(在可分配的列表中)。其他参数在堆栈中传递。

##第二节:说明

第二部分提供了从通用操作(如 - ,+等)到机器特定变体的映射。本节由np-select-instructions使用!传递将原始方案运算符(在np-expand-primitives传递中降低)转换为机器特定表示。本节的工作是确保用作指令输入的所有寄存器,作为指令结果设置等,都是对编译器的机器无关部分明确的。这允许寄存器分配器在不知道目标机器细节的情况下确定局部变量的寄存器位置。

在像x86这样的平台上,有许多特殊情况,只有某些寄存器可以用于某些指令,或者在使用指令期间其他寄存器被杀死,所以Chez Scheme对此有所支持,但希望你不需要那么多在Risc-V上。

本节也使用文件顶部定义的define-instruction DSL编写。这主要是为了使重复操作(比如我发现需要寄存器参数的内存参数)很简单。我们已经为每种机器类型定义了这个,但这主要是通过复制和更新来完成的

最后,本节将生成包含过程槽的表达式,该过程槽告诉汇编器如何构建特定指令。这些程序在第三节中定义。

##第三节:汇编程序和FFI

最后一节内置了汇编程序和外部函数接口支持。该模块被命名为'asm-module'并导出许多函数。值得注意的是,Chez Scheme直接生成机器代码,而不是依赖于系统提供的汇编程序。机器代码通过emit-code调用生成。这些指定了每个指令变化的位布局。在某些情况下,几个指令具有相同的位布局,仅在操作码中有所不同,因此您通常可以使用一些函数共享其中的几个来执行发射。

asm-foreign-call和asm-foreign-callable函数生成ABI指定的调用约定,以调用外部过程并允许从外部函数调用scheme程序。

您将在方案调用约定中注意到有空格允许链接器重写代码。 Chez Scheme使用自己的链接器,因为垃圾收集会导致代码移动并需要重新链接,因为在需要重新链接的会话期间可以生成或加载新代码。

#更新链接器

该链接主要嵌入在主编译器文件中:'compile.ss'你会在函数'c-faslcode'中看到一个架构上的'常量',它为不同的机器特定链接元素生成略有不同的代码例如,手臂有'arm32-abs','arm32-call'和'arm32-jump'。这些都对应于链接器可能需要在Scheme常量和调用信息中链接的位置。每个都生成一个重定位记录(或'reloc'),链接器用它来确定在加载时二进制文件中需要重写的项目。

reloc常量在cmacros.ss中定义。如果你需要添加额外的机器特定的reloc常量(你几乎可以肯定),这些都会在'define-reloc-constants'调用中添加。您还需要在此文件中的“define-machine-types”条目中添加(或者已经添加到此时已添加)新类型。


登录后方可回帖

登 录
信息栏

Scheme中文社区

推荐实现 ChezScheme / r6rs / r7rs large
theschemer.org
Q群: 724577239

精华导览

社区项目

包管理器:Raven
HTTP服务器:Igropyr (希腊火)
官方插件:vscode-chez

社区目标:

完善足以使Scheme工程化和商业化的库,特别是开发极致速度的Web服务器和ANN模块。

一直以来Scheme缺少一个活跃的中文社区,同时中文资料的稀少,导致大多数因为黑客与画家和SICP而接触Scheme的朋友,在学完SICP后无事可做,不能将Scheme转换为实际的生产力。最后渐渐的放弃。
同时Chicken等实现,却因效率问题无法与其他语言竞争。本社区只有一个目的,传播Scheme的文明之火,在最快的编译器实现上,集众人之力发展出足够与其他语言竞争的社区和库。


友情链接:

Clojure 中文论坛
函数式·China


Loading...