2015-04-06 77 views
3

我正在为我的编译器课程进行分配,并且我一直在盯着我生成几个小时的mips(32位)代码,试图找出它的错误无济于事。在生成mips代码之后,我使用由我们的教师提供的mips VM上的gcc进行编译。我被告知要使用一些C的stdlib函数,比如printf,并且我非常确定部分代码是正确的,因为(正如我们被指示的那样),我大部分都是从类似C代码的gcc输出中偷取它的。如何在MIPS中推送和弹出堆栈中的地址

下面是MIPS代码应:

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

目前会发生什么情况是第二个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 

如果任何人都可以找到任何东西,甚至看似已关闭,然后我将不胜感激它(代码中使用常量整数的时候,所以我相信的printf的是完全正确的完全有效)!

回答

0

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

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

我的意图是加载地址上的值,我弹出堆栈并进入$ t0。这就是“lw $ 5,0($ t0)”应该做的。我想我在堆栈指针前增加堆栈中的值到$ t0。 –