【问题标题】:How to push and pop addresses on stack in MIPS如何在 MIPS 中在堆栈上推送和弹出地址
【发布时间】:2015-06-11 03:08:35
【问题描述】:

我正在为我的编译器课程做作业,我一直盯着我生成的 mips(32 位)代码好几个小时,试图找出它有什么问题,但无济于事。生成 mips 代码后,我在讲师提供的 mips VM 上使用 gcc 对其进行编译。我被告知要使用一些 C stdlib 函数,如 printf,我很确定部分代码是正确的,因为(正如我们被指示做的那样)我主要是从 gcc 的类似 C 代码的输出中窃取它。

下面是 mips 代码:

  1. 为堆栈上的 2 个整数变量创建空间
  2. 分别将它们初始化为 5 和 10(用于测试目的)
  3. 通过将它们的绝对地址压入堆栈然后将其弹出并访问它来打印它们。

目前发生的情况是第二个 printf 似乎打印了存储在堆栈上第一个变量空间中的值,而不是第二个变量的值。

(代码在使用常量整数时完全有效,所以我相信 printf 是完全正确的)

        .data
printf_string:    .asciiz  "%d\n"
scanf_string:    .asciiz  "%d"

    .text
    .globl main

main:
# make space for two ints on stack
    addiu   $sp, $sp, -8
# store return address in a saved register
# was going to push it onto the stack but until I figure out this issue I'm
# being lazy and just saving it to a saved register
    move    $s0, $ra
# make a copy of the stack pointer - likely not needed
    move    $s1, $sp

# typically here i loop and initialize the 2 ints on the stack but for now I'm
# doing it manually so I can figure out this issue with less possible things
# that could be wrong

# load some value into the register so I can store it
    li      $t7, 5
# store into first variable
    sw      $t7, 0($sp)
# different so I can tell if printing location works
    li      $t7, 10
# store into second variable
    sw      %t7, 4($sp)

instructions:

########################################
### CODE BELOW PRINTS FIRST VARIABLE ###
########################################

# appears to work...

# load standard library pointer and stuff (copied from gcc output)
# everything below works IF you did something like
# "WRITE 5" instead of "WRITE a"
    lui     $gp, %hi(__gnu_local_gp)
    addiu   $gp, %lo(__gnu_local_gp)
    lw      $t9, %call16(printf)($gp)
    .cprestore  16
    nop # needed after load word :-/

# load print_string address - works 
    la      $4, printf_string
# Here's where problems start
# make space for location of visited variable
    addiu   $sp, $sp, -4
# initialize $t0 to top of stack
    move    $t0, $s1
# add offset of variable to $t0
    addiu   $t0, $t0, 0
# store absolute memory address of variable to stack
    sw      $t0, 0($sp)

# load absolute memory address of variable from stack
    lw      $t0, 0($sp)
    nop # needed after lw
# undo stack allocation
    addiu   $sp, $sp, 4
# load MEM[$t0 + 0] into $5 (arg 2)
    lw      $5, 0($t0)
    nop
# finally call printf
    jalr    $t9
    nop

#########################################
### CODE BELOW PRINTS SECOND VARIABLE ###
#########################################

# appears to print the value stored in the first variable
# if I add "sw $s5, 4($sp)" here then it DOES work so I'm just very confused

# everything here should be basically the same as above but with a different
# offset/address pushed, popped, and accessed


    lui     $gp, %hi(__gnu_local_gp)
    addiu   $gp, %lo(__gnu_local_gp)
    lw      $t9, %call16(printf)($gp)
    .cprestore  16
    nop

    la      $4, printf_string
    addiu   $sp, $sp, -4
    move    $t0, $s1
    addiu   $t0, $t0, 4
    sw      $t0, 0($sp)

    lw      $t0, 0($sp)
    nop
    addiu   $sp, $sp, 4
    lw      $5, 0($t0)
    nop
    jalr    $t9
    nop


    addiu   $sp, $sp, 8
    move    $ra, $s0
    jr      $ra
    nop

如果有人能找到任何看起来不正常的东西,我将不胜感激!

【问题讨论】:

    标签: assembly compiler-construction mips mips32


    【解决方案1】:

    这只是一个建议,而不是一个确定的答案,您可能根本不会用地址拨打printf。我注意到在将参数的地址写入堆栈之后,您在调用printf 之前恢复堆栈指针。因此,在这两个示例中,调用 printf 时堆栈指针都指向原始的第一个参数,这可能解释了为什么它在两种情况下都打印第一个参数。

    sw      $t0, 0($sp)
    lw      $t0, 0($sp)
    nop
    addiu   $sp, $sp, 4
    ...
    # finally call printf
    jalr    $t9
    

    【讨论】:

    • 我的意图是将值加载到我从堆栈中弹出并放入 $t0 的地址中。这就是“lw $5, 0($t0)”行应该做的事情。我想我在增加堆栈指针之前将值从堆栈中加载到 $t0 中。
    猜你喜欢
    • 2016-04-04
    • 2020-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-22
    • 2018-06-12
    • 1970-01-01
    • 2014-12-19
    相关资源
    最近更新 更多