将 C 语言转换为 MIPS 汇编语言

时间:2021-06-04 14:42:25

标签: c gcc clang llvm mips

我想把c代码转成可以在QTSpim中运行的MIPS。例如:转换

#include<stdio.h>

int main() {
   printf("Hello, World!");
   return 0;
}

进入

.data
msg:   .asciiz "Hello World"
    .extern foobar 4

        .text
        .globl main
main:   li $v0, 4       # syscall 4 (print_str)
        la $a0, msg     # argument: string
        syscall         # print the string
        lw $t1, foobar
        
        jr $ra          # retrun to caller

我在我的 mac 中尝试了 gcc -S helloWorld.c,然后我得到了下面的 helloWorld.s:

.section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 11, 0 sdk_version 11, 3
    .globl  _main                           ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movl    $0, -4(%rbp)
    leaq    L_.str(%rip), %rdi
    movb    $0, %al
    callq   _printf
    xorl    %ecx, %ecx
    movl    %eax, -8(%rbp)                  ## 4-byte Spill
    movl    %ecx, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "Hello, World!"

.subsections_via_symbols

我已经搜索了一些,但没有明确的答案。我对 MIPS 很陌生,因为我发现 MIPS 有很多汇编语言? 任何解释或解决方案将不胜感激。提前致谢。

1 个答案:

答案 0 :(得分:0)

流行的模拟器 MARS 和 QTSpim 都有自己的环境,也就是说,它们没有 printfgetChar

相反,他们使用系统调用进行 I/O。系统调用不是一个完整的编程环境,因此虽然它们可以做一些 printf 可以做的事情,但它们没有很多功能(例如,完全缺少 sprintf 的功能)。

这是 MARS 中可用的系统调用的文档(QTSPim 支持第一组,但不支持编号较高的。)

http://courses.missouristate.edu/kenvollmar/mars/help/syscallhelp.html

要将 printf 语句转换为系统调用形式,我们需要进行一些分解:

printf ( "hello %d\n", 10 ); 

会变成三个不同的系统调用:

  1. print "hello " — 使用系统调用 #4(打印字符串)
  2. print 10 — 使用系统调用 #1(打印整数)
  3. print "\n" — 使用系统调用 #4(打印字符串)或系统调用 #11(打印字符)

接下来你需要了解的是,系统调用本身有点像函数调用,所以我们需要了解参数传递。系统调用接受 $v0 一个函数代码,说明要执行什么操作。每个函数根据上面链接中的规范解释 $a0、$a1 等的值。

需要将值放入寄存器以进行参数传递,但是将值放入寄存器的顺序是任意的——只要 $v0 有 4 并且 $a0 有一个指向内存中字符串的指针,那么 { {1}} 指令将打印该字符串。


我不知道有任何编译器会自动将 syscall 语句转换为 MARS/QTSpim 所需的形式。然而,可用的编译器(例如,godbolt.org 有几个可用的 MIPS 编译器)通常适用于显示非 I/O C 语句和表达式的汇编翻译(尽管它们的输出对于模拟器想要的东西来说是嘈杂的)。


模拟器的编程通常被简化。局部变量,尤其是数组,通常作为全局变量来完成,因为在堆栈上创建数组需要额外的工作和对堆栈处理和堆栈偏移量的理解,而全局变量很容易用名称声明。