有没有办法使用gcc将C转换为MIPS?

Mik*_*ike 14 c compiler-construction gcc mips

我为一个类完成了C到MIPS的转换,我想针对程序集进行检查.我听说有一种配置gcc的方法,它可以将C代码转换为MIPS架构而不是x86架构(我的计算机用户使用Intel i5处理器)并打印输出.

在Ubuntu(gcc附带)中运行终端,我用什么命令配置gcc转换为MIPS?我还需要安装什么吗?

编辑:让我澄清一下.请阅读这个.我不是在寻找使用哪种编译器,或者人们说"你可以交叉编译,但你应该使用其他没有指示如何设置的东西."

如果您要发布,至少请参阅说明.GCC附带Ubuntu.我没有关于如何安装编译器的经验,除了GCC之外,找不到其他任何内容的在线教程并不容易.然后是我需要知道的交叉编译的情况.谢谢.

Tho*_*nin 26

GCC 可以为大量架构生成汇编代码,包括MIPS.但是,当GCC本身被编译时,决定了给定GCC实例所针对的架构.您将在Ubuntu系统中找到的预编译二进制文件知道x86(可能是32位和64位模式),但不知道MIPS.

使用与GCC本身将运行的体系结构不同的目标体系结构编译GCC称为准备交叉编译工具链.这是可行的,但需要相当多的文档阅读和耐心; 您通常需要首先构建交叉汇编器和交叉链接器(GNU binutils),然后构建交叉GCC本身.

我建议使用buildroot.这是一组脚本和makefile,旨在帮助生成完整的交叉编译工具链和实用程序.在一天结束时,您将获得目标系统的完整操作系统和开发工具.这包括您所追求的交叉编译器.

另一个完全不同的解决方案是使用QEMU.这是用于各种处理器和系统的仿真器,包括MIPS系统.您可以使用它来运行带有MIPS处理器的虚拟机,并在该计算机内安装MIPS操作系统,例如Debian,一个Linux发行版.这样,您就可以获得本机 GCC(在MIPS系统上运行的GCC并为MIPS生成代码).

QEMU方式可能更简单; 使用交叉编译需要对一些毛茸茸的细节有所了解.无论哪种方式,您将需要大约1 GB的可用磁盘空间.


Fab*_*sen 6

这不是配置,你需要一个可以交叉编译为MIPS的GCC版本.这需要一个特殊的GCC构建,并且设置非常多毛(构建GCC不适合胆小的人).

我建议使用LCC.使用LCC进行交叉编译比使用GCC更容易,并且在当前机器上构建LCC只需几秒钟.

  • 我假设您的主要兴趣是编译C到MIPS汇编,而不是GCC.如果你坚持使用GCC,请继续,但考虑自己警告 - 编译一个程序是不值得的(特别是如果你很难获得LCC构建).关于构建交叉GCC的一些(相对过时,但我没有找到任何更新的)指令在这里:http://gcc.gnu.org/wiki/Building_Cross_Toolchains_with_gcc (5认同)

Pet*_*des 6

对于一次性使用一个小程序或几个功能,您不需要在本地安装任何东西。

使用 Matt Godbolt 的编译器浏览器站点https://godbolt.org/,其中包含适用于各种 ISA(包括 MIPS 和 x86-64)以及其他一些编译器的 GCC 和 clang。

请注意,编译器资源管理器默认会过滤指令,因此您只能看到指令,而忽略对齐、节.globl等内容。(对于没有全局/静态数据的函数,这实际上很好,特别是当您只想使用编译器为您制作示例时。.text如果您不使用任何指令,则默认部分无论如何都是。)


大多数需要 MIPS asm 来做作业的人都在使用 SPIM 或 MARS,通常没有分支延迟槽。(与真正的 MIPS 不同,因此您需要调整编译器,使其在无条件运行分支后不利用下一条指令,即使它已被采用。)对于 GCC,选项是--fno-delayed-branch它将用 NOP 填充每个延迟槽,因此该代码仍将在真正的 MIPS 上运行。您可以手动删除所有 NOP。

可能还需要其他调整,例如 MARS 可能要求您使用jr $31,j $31调整 mips-gcc 输出以在不使用脚本的情况下与 MARS 一起使用。当然,I/O 代码必须使用MARS 的玩具系统调用来实现,而不是jal调用标准库函数,例如printfstd::ostream::operator<<。不过,您可以有效地编译(和手动调整)asm 来操作数据,例如整数相乘或求和或反转数组。

不幸的是,GCC 没有选项来使用寄存器名称,例如$a0代替$r。对于 PowerPC,可以-mregnames使用r1代替1,但 MIPS 没有类似的选项来使用“更具符号性”的寄存器名称。

int maybe_square(int num) {
    if (num>0)
        return num;
    return num * num;
}
Run Code Online (Sandbox Code Playgroud)

关于 Godbolt和 GCC 5.4-xc -O3 -march=mips32r2 -Wall -fverbose-asm -fno-delayed-branch

-xc编译为 C,而不是 C++,因为我发现这比在下拉列表中在 C 和 C++ 语言之间切换并让网站删除我的源代码更方便。

-fverbose-asm使用目标和源的 C 变量名称注释 asm。(在优化的代码中,这通常是临时发明的,但并非总是如此。)

-O3启用全面优化,因为默认的-O0调试模式对于人类来说是一团糟。-Og如果您想手动查看代码并了解它如何实现源代码, 请务必使用至少。如何从 GCC/clang 汇编输出中消除“噪音”?。您还可以使用-fno-unroll-loops, 和-fno-tree-vectorizeif 为带有 SIMD 指令的 ISA 进行编译。

它使用mul而不是经典的 MIPS mult+ mflo,这要归功于-march=告诉 GCC 我们正在为更高版本的 MIPS ISA 进行编译的选项,而不是默认基线是什么。(也许 MIPS I 又名 R2000,-march=mips1

另请参阅 GCC 手册中有关MIPS 目标选项的部分。

int maybe_square(int num) {
    if (num>0)
        return num;
    return num * num;
}
Run Code Online (Sandbox Code Playgroud)

或者使用 clang,-target mips告诉它为 MIPS 进行编译。 您可以在桌面上执行此操作;与 GCC 不同,clang 通常是在启用多个后端的情况下构建的

来自同一个 Godbolt 链接, clang 10.1 -xc -O3 -target mips -Wall -fverbose-asm -fomit-frame-pointer。默认目标显然是 MIPS32 或类似 clang 的目标。此外,clang 默认启用 MIPS 的帧指针,从而使 asm 变得嘈杂。

请注意,它选择制作无分支汇编,将 if 转换为条件移动以在原始输入和 mul 结果之间进行选择。不幸的是 clang 不支持-fno-delayed-branch; 也许同一个选项有另一个名字,或者也许没有希望。

# gcc 5.4 -O3
square:
        blez    $4,$L5
        nop
        move    $2,$4    # D.1492, num         # retval = num
        j       $31                            # jr $ra  = return
        nop

$L5:
        mul     $2,$4,$4   # D.1492, num, num   # retval = num * num
        j       $31                             # jr $ra  = return
        nop
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们可以简单地将 放在mul之前jr,但在其他情况下,转换为无分支延迟汇编并不是完全微不足道的。例如,在递减之前在循环计数器上进行分支,不能通过先递减来撤消;这会改变含义。


寄存器名称:

编译器使用寄存器编号,而不关心名称。对于人类使用,您经常需要翻译回来。网上很多地方都有 MIPS 寄存器表,显示 $4..$7 是 $a0..$a3,$8 .. $15 是 $t0 .. $t7 等。例如这个


Ben*_*son 2

您需要将源代码下载到 binutils 和 gcc-core 并使用诸如../configure --target=mips .... 您可能需要选择特定的 MIPS 目标。那么你就可以使用mips-gcc -S.