我正在为我的编译器课程进行一项任务,而且我一直在盯着我生成的mips(32位)代码,这些代码试图弄清楚它有什么问题但无济于事。在生成mips代码之后,我在我们的讲师提供的mips VM上使用gcc编译它。有人告诉我要使用像printf这样的一些C stdlib函数,我很确定部分代码是正确的(因为我们被指示这样做)我主要是从gcc的类似输出中偷走它C代码。
以下是mips代码:
目前发生的事情是第二个printf似乎打印存储在堆栈第一个变量空间中的值而不是第二个变量的值。
(代码在使用常量int时完全有效,所以我相信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
如果有人能找到任何看起来不合适的东西,那么我会非常感激!
答案 0 :(得分:0)
这只是一个建议,而不是一个坚定的答案,你可能根本就没有给printf
打电话。我注意到在将参数的地址写入堆栈之后,然后在调用printf
之前恢复堆栈指针。因此,在这两个示例中,堆栈指针在调用printf
时指向原始的第一个参数,这可以解释为什么它在两种情况下都会打印第一个参数。
sw $t0, 0($sp)
lw $t0, 0($sp)
nop
addiu $sp, $sp, 4
...
# finally call printf
jalr $t9