【问题标题】:Convert C into MIPS assembly language [duplicate]将C转换为MIPS汇编语言[重复]
【发布时间】:2023-11-08 19:06:02
【问题描述】:

我想将 c 代码传输到可以在 QTSimp 中运行的 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 有很多汇编语言? 任何解释或解决方案将不胜感激。提前致谢。

【问题讨论】:

  • 你还没有问任何问题
  • 可能没有明确的答案,因为您没有提出明确的问题。您是在问如何为 MIPS 进行交叉编译?或者为什么编译器生成的输出比你预期的多?
  • 您将无法获取 GCC 输出并按原样在 QtSPIM 中运行它。 QtSPIM 仅支持 GCC 支持的指令子集。它也没有 libc(所以没有printf 等),而是为您提供a bunch of system calls。您可以使用 GCC 输出作为起点,但需要进行一些手动编辑才能使其在 QtSPIM 中运行。

标签: c gcc clang llvm mips


【解决方案1】:

流行的模拟器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. 打印“hello”——使用系统调用#4(打印字符串)
  2. 打印 10 — 使用系统调用 #1(打印整数)
  3. print "\n" — 使用系统调用 #4(打印字符串)或系统调用 #11(打印字符)

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

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


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


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

【讨论】: