C通过交叉编译器汇编MIPS(需要解释$ sp,$ fp)

时间:2014-01-04 07:21:16

标签: c assembly mips

编译此C代码后:

int main(void)
{
   unsigned int i = 5;
   switch(i)
   {
      case 1: i = i + 3; break;
      case 5: i = i<<3; break;
      case 10: i = i>>2;
   }
}

我有本大会MIPS:

.file   1 "SwitchCase.c"
    .text
    .align  2
    .globl  main
    .ent    main
main:
    .frame  $fp,16,$31      # vars= 8, regs= 1/0, args= 0, gp= 0
    .mask   0x40000000,-8
    .fmask  0x00000000,0
    addiu   $sp,$sp,-16
    sw  $fp,8($sp)
    move    $fp,$sp
    li  $2,5            # 0x5
    sw  $2,0($fp)
    lw  $2,0($fp)
    sw  $2,4($fp)
    li  $2,5            # 0x5
    lw  $3,4($fp)
    beq $3,$2,$L4
    lw  $3,4($fp)
    sltu    $2,$3,6
    beq $2,$0,$L6
    li  $2,1            # 0x1
    lw  $3,4($fp)
    beq $3,$2,$L3
    j   $L2
$L6:
    li  $2,10           # 0xa
    lw  $3,4($fp)
    beq $3,$2,$L5
    j   $L2
$L3:
    lw  $2,0($fp)
    addiu   $2,$2,3
    sw  $2,0($fp)
    j   $L2
$L4:
    lw  $2,0($fp)
    sll $2,$2,3
    sw  $2,0($fp)
    j   $L2
$L5:
    lw  $2,0($fp)
    srl $2,$2,2
    sw  $2,0($fp)
$L2:
    move    $sp,$fp
    lw  $fp,8($sp)
    addiu   $sp,$sp,16
    j   $31
    .end    main

我真的不明白这个汇编MIPS,特别是带有 $ sp,$ fp 寄存器的指令(这个代码的寄存器的目的),有人可以帮我解释一下这个吗? / p>

2 个答案:

答案 0 :(得分:2)

可以在Wikipedia中找到相关信息。 $sp代表堆栈指针$fp代表帧指针

您的main()在堆栈上为其变量创建了一个框架。帧长16个字节。

addiu   $sp,$sp,-16   # reserve 16 B on stack
sw  $fp,8($sp)        # store previous frame pointer onto stack
move    $fp,$sp       # set frame pointer for main()
# ...
lw  $2,0($fp)         # load a value from $fp+0 to register 2
sw  $2,4($fp)         # save a value to $fp+4 from register 2
# ...
move    $sp,$fp       # reverting the first 3 instructions now
lw  $fp,8($sp)
addiu   $sp,$sp,16

@ Dolda2000已经解释为什么这样做了。

答案 1 :(得分:2)

从评论中判断实际问题:'“我认为只是通过子程序我们必须使用$ sp,$ fp,但我不在这里使用任何子程序(程序),为什么这个代码有$ sp,$ fp寄存器吗?“

首先,main仍需要一个自己的堆栈框来保存局部变量(以及临时的非命名值),这就是为什么它需要一个有效的帧指针($fp

如果你想知道它为什么会保存前一个帧指针,那是因为甚至main被其他函数调用(在某些CRT库中通常称为_start),这需要有它的框架保留。

main是否依次调用其他子例程是无关紧要的,因为这并不能解除它对堆栈帧的需求,如上所述。

此外,它通常被指定为平台的ABI的一部分,所有功能都应该设置适当的帧,无论它们是否真正需要它们。这是因为堆栈上的正确框架链通常对调试器和其他分析工具很有用,之后经常会发现在需要时缺少它们​​会很麻烦(例如对崩溃的程序进行事后调试) 。但是,如果您真的想要,可以通过使用某些特定于编译器的标志-fomit-frame-pointer来告诉大多数编译器违反ABI而忽略它们。