自由软件在Elbrus架构上的移植

2020-06-02 22:53:15

与大多数其他CPU不同,Elbrus系列(E2K)使用VLIW指令集(非常大的指令字),每个周期有25条通用指令。这种依赖性对系统编译器的优化提出了更高的要求。此外,为了最大限度地减少硅胶的使用,每个可能的高级函数都从硬件转移到编译器,因此粗略地说,没有微码和微码级操作是在编译时进行的,而不是像x86系列CPU上那样在运行时进行。

虽然这种方法可以产生更好的功耗和每使用晶体管数量的性能,但它的副作用是,唯一的系统编译器-LCC-是封闭源代码的,并且很可能会一直保持这种状态。LCC试图通过用户界面(支持的选项和GCC特有的功能)模仿GCC,但相似之处到此为止。LCC基于EDG 1前端和MCST制造的多层后端。

但是,编译器工具链中也使用了自由软件:libstdc++、libatonomy、libgcc_s、C运行时等等。将所有自由组件从编译器捆绑包中分离出来,从源代码中构建它们,并将它们与剩下的二进制blob分开打包,以形成符合分发标准的全功能工具链(在我们的例子中是ALT),这是一项具有挑战性的任务。

虽然Elbrus机器支持使用用于x86/AMD64汇编的运行时JIT编译器运行x86和AMD64指令,但出于性能和安全原因,我们不使用此模式。此JIT编译器仅用于特殊目的,如运行没有本地E2K支持的专有封闭源代码软件。

大多数软件移植问题都是由于各种原因与GCC没有完全兼容而产生的。主要的问题是,负责程序语法解析的EDG前端在支持的语言特性上落后于GCC,例如目前的生产版本Lcc-1.23与GCC-5.5.。为了在E2K上构建,许多代码需要向后移植到较旧的C++标准或类似的调整。

有时LCC会注意到GCC跳过的问题,比如未初始化变量的使用。这会导致问题,特别是与-Werror结合使用时。有时我们修复这样的问题,有时我们只是禁用-Werror。

Lcc-1.23并没有实现GCC-5.5中的所有扩展数据类型,例如__(U)int128t和_decimal64。这样的问题通常很容易通过宏观定义来解决。

LCC的预处理器假定输入是C/C++代码,并用空格替换缩进制表符。这打破了那些使用编译器的预处理器来解析Makefile和类似的制表敏感数据的应用程序。

一些软件依赖于棘手的GCC功能,例如,依赖于未归档的VLAI(结构中的可变长度数组),或者依赖于编写C++代码“足够小心”而不使用C++运行时,并将这些代码链接为普通的C代码。虽然这些技巧适用于GCC,但它们给其他编译器带来了很多问题,示例案例是libraphite2。这些问题是在个案的基础上解决的,容易成为令人痛苦的问题。

目前,LCC仅支持C、C++和Fortran。因此,不可能在E2K上构建和使用原生模式软件,这些软件是用Go、Rust和Haskell等语言编写的代码生成器编写的。这个问题应该通过为LCC创建LLVM后端的持续努力来解决,但ETA未知。

除了编译器引起的问题之外,E2K除了使用VLIW之外,还有显着不同的硬件架构。它有三个独立的堆栈:数据堆栈、函数指针堆栈和函数参数堆栈。这样,系统就可以受到硬件保护,免受各种缓冲区溢出和指针劫持攻击。但这是要付出代价的:应该重写垃圾收集器或上下文切换等低级内存操作,以考虑到这种堆栈布局。

当然,系统调用和ioctls也有部分不同,在直接使用这些调用移植软件时应该考虑到这种差异。但这是所有新架构的通用规则。

E2K也支持标记内存,但我们不使用这种模式来构建通用应用程序,因为需要在严格的安全环境下工作,例如,C++中的所有虚拟调用都将被设计为无效。有关E2K硬件体系结构和安全功能的更多详细信息,请参阅MCST官方教科书2。

Elbrus的上行软件有其局限性,但也是可能的。目前的主要障碍是,硬件和软件都是由MCST在保密协议下分发的,因此我们不能在未经事先批准的情况下发布从他们那里收到的补丁。但是,我们可以自由地上游所有自己代码,包括低级内容和汇编。Alt团队已经将特定于E2K的更改引入了许多自由软件项目,如ruby、lxc、gimagereader、iMake。更完整的列表可以在我们的维基3上找到。

每个人都不一样,上游也不一样。一些人乐于接受补丁,一些人不感兴趣并忽略更改,一些人要求在接受任何更改之前打开工具链。如果运气好的话,NDA的限制可能会在未来大部分时间被取消,这个美丽的建筑将看到它发展的第二股风。