首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MIPS32叠架坏了吗?

MIPS32叠架坏了吗?
EN

Stack Overflow用户
提问于 2016-05-17 08:33:23
回答 1查看 124关注 0票数 2

因此,这里的代码如下所愿:

程序1

代码语言:javascript
复制
.text
  .globl main
  main: 
    li     $t0, 10
    mtc1    $t0, $f12
    cvt.s.w $f12, $f12               # 10.0 as single in $f12
    jal     printFloat      

    li      $v0, 4001               #sys_exit
    syscall

printFloat:
        addi    $sp, $sp, -4            #opens the stack frame            
        sw      $ra, 0($sp)             #saves the return adress

        cvt.d.s $f12, $f12              #converts the single to double
        la      $a0, strDouble          #arguments needed for printf ("%f" in $a0, upper 32 bit of the float in $a2, lower ones in $a1)
        mfc1    $a1, $f12               
        mfc1    $a2, $f13               
        jal     printf                  
        jal     fflush                  

        la      $a1, strBreakLine       #arguments needed for printf (Adress of String in $a1, "%s" in $a0)    
        la      $a0, strStringOut       
        jal     printf                  
        jal     fflush                  

        lw      $ra, 0($sp)             #restores the return adress
        addi    $sp, $sp, 4             #pops the stack frame
        jr      $ra

.data
strDouble:      .asciiz "%f"
strStringOut:   .asciiz "%s"
strBreakLine:   .asciiz "\n"


phm15fix@ci20:~$ gcc -o test -g test1.s
phm15fix@ci20:~$ ./test
10.000000

程序2

代码语言:javascript
复制
.text
.globl main
main: 
        li     $t0, 10
        mtc1    $t0, $f12
        cvt.s.w $f12, $f12               # 10.0 as single in $f12
        jal     printFloat      

        li      $v0, 4001               #sys_exit
        syscall

printFloat:
        addi    $sp, $sp, -4            #opens the stack frame            
        sw      $ra, 0($sp)             #saves the return adress

        cvt.d.s $f12, $f12              #converts the single to double
        la      $a0, strDouble          #arguments needed for printf ("%f" in $a0, upper 32 bit of the float in $a2, lower ones in $a1)
        mfc1    $a1, $f12               
        mfc1    $a2, $f13               
        jal     printf                  
        jal     fflush
        jal     printNewLine                  

        lw      $ra, 0($sp)             #restores the return adress
        addi    $sp, $sp, 4             #pops the stack frame
        jr      $ra

printNewLine:
        addi    $sp, $sp, -4            #opens the stack frame            
        sw      $ra, 0($sp)             #saves the return adress

        la      $a1, strBreakLine       #arguments needed for printf (Adress of String in $a1, "%s" in $a0)    
        la      $a0, strStringOut       
        jal     printf                  
        jal     fflush 

        lw      $ra, 0($sp)             #restores the return adress
        addi    $sp, $sp, 4             #pops the stack frame
        jr      $ra

.data
strDouble:      .asciiz "%f"
strStringOut:   .asciiz "%s"
strBreakLine:   .asciiz "\n"


phm15fix@ci20:~$ gcc -o test -g test1.s
phm15fix@ci20:~$ ./test
10.000000
Bus error

程序3

代码语言:javascript
复制
.text
.globl main
main:
        li     $t0, 10
        mtc1    $t0, $f12
        cvt.s.w $f12, $f12               # 10.0 as single in $f12
        jal     function

        li      $v0, 4001               #sys_exit
        syscall

function:
        addi    $sp, $sp, -4            #opens the stack frame
        sw      $ra, 0($sp)             #saves the return adress

        jal     printFloat

        lw      $ra, 0($sp)             #restores the return adress
        addi    $sp, $sp, 4             #pops the stack frame
        jr      $ra

printFloat:
        addi    $sp, $sp, -4            #opens the stack frame
        sw      $ra, 0($sp)             #saves the return adress

        cvt.d.s $f12, $f12              #converts the single to double
        la      $a0, strDouble          #arguments needed for printf ("%f" in $a0, upper 32 bit of the float in $a2, lower ones in $a1)
        mfc1    $a1, $f12
        mfc1    $a2, $f13
        jal     printf
        jal     fflush
        jal     printNewLine

        lw      $ra, 0($sp)             #restores the return adress
        addi    $sp, $sp, 4             #pops the stack frame
        jr      $ra

printNewLine:
        addi    $sp, $sp, -4            #opens the stack frame
        sw      $ra, 0($sp)             #saves the return adress

        la      $a1, strBreakLine       #arguments needed for printf (Adress of String in $a1, "%s" in $a0)
        la      $a0, strStringOut
        jal     printf
        jal     fflush

        lw      $ra, 0($sp)             #restores the return adress
        addi    $sp, $sp, 4             #pops the stack frame
        jr      $ra

.data
strDouble:      .asciiz "%f"
strStringOut:   .asciiz "%s"
strBreakLine:   .asciiz "\n"

在每个程序的末尾都是特定的输出。

第一个程序运行得很好。在第二个程序中,我增加了一个打印新行的功能。如果我运行这个,我会得到一个“公共汽车错误”。

在第三个程序中,我制作了一个虚拟函数来模拟另一个堆栈级别。也有一个“总线错误”,我想打印的数字不是打印。

我想我们的堆叠有问题。

我使用调试器,如果我从堆栈加载返回地址,我的$ra中有错误的地址,我不知道为什么。如果它跳到这个地址,我会得到“总线错误”。

以下是功能:

代码语言:javascript
复制
PRINT_DOUBLE:
        addi    $sp, $sp, -4            
        sw      $ra, 0($sp)             

        la      $a0, strDouble          
        mfc1    $a1, $f12               
        mfc1    $a2, $f13               
        jal     printf                  
        nop
#       lw      $a0, stdout
#        jal     fflush                  
        jal     BREAK_LINE

        lw      $ra, 0($sp)             
        addi    $sp, $sp, 4             
        jr      $ra


BREAK_LINE:
        addi    $sp, $sp, -4            
        sw      $ra, 0($sp)             

        la      $a0, strBreakLine
        jal     PRINT_STRING

        lw      $ra, 0($sp)             
        addi    $sp, $sp, 4             
        nop

        jr      $ra

PRINT_STRING:
        addi    $sp, $sp, -4            
        sw      $ra, 0($sp)             

        add     $a1, $a0, $zero         
        la      $a0, strStringOut       
        jal     printf                  
        la      $a0, stdout
        lw      $a0, 0($a0)
        jal     fflush                  

        lw      $ra, 0($sp)             
        addi    $sp, $sp, 4             
        nop
        jr      $ra
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-17 17:46:10

我看过你的节目了,大部分都没问题。我认为您的堆栈保存/还原是好的。但是,我至少看到了另外一个问题。

在每个jal printf之后,您将立即执行jal fflush,因此fflush将获得printf的第一个参数,即字符串指针,而不是文件描述符指针(例如stdout)。

根据mips,$a0-$a3寄存器可以被被调用者修改/销毁。所以,在printf返回之后,$a0可以是任何东西。

这三个程序似乎都有这个问题。国际海事组织,如果程序1起作用,那只是抽签的运气(即)在$a0中结束的一切都是无害的。也就是说,不管里面有什么,都指向一个不是文件描述符的内存位置,但是fflush试图将其解释为文件描述符,并从中获益。

另外,对于fflush$a0应该指向一个地址,即单词4字节对齐。如果不是,那可能是总线错误的根源。

要解决这个问题,请将所有fflush调用更改为:

代码语言:javascript
复制
lw     $a0,stdout
jal    fflush

这可能会起作用,但是,根据gcc汇编程序所做的工作,您可能必须这样做:

代码语言:javascript
复制
la     $a0,stdout
lw     $a0,0($a0)
jal    fflush

我已经看到,如果我尝试从一个函数跳回(例如,我跳到PRINT_DOUBLE,在那里跳到BREAK_LINE,然后跳到PRINT_STRING,如果我跳回BREAK_LINE,一切都很好),那么就会出现总线错误,但是从BREAK_LINE跳到PRINT_DOUBLE,我得到了buserror

我已经查过你的密码了,又一次看上去很好。调试这一点的一种方法是使用gdb,在函数中单步使用stepi,并在jal printfjal fflush之后放置断点。

在每个jal之前和之后,注意$sp值。一定是一样的。为了你所有的功能。另外,当从函数返回时,请注意$sp值,然后是从lw返回到$ra的值。他们都应该符合“预期”

此外,$sp必须在任何时候都对齐4字节。实际上,根据我看过的一份mips文档,它说堆栈帧必须对齐8字节。在这一点上这可能有点过分,但我要提一提。

如果您从未对齐处执行lw,则这是一个对齐异常,它可能会显示为SIGBUS。此外,在执行$ra之前检查jr $ra值。它还必须是“预期”值,并对齐4字节。

换句话说,到底哪条指令会产生异常?

您可以做的另一件事是注释掉一些函数调用。从jal fflush开始。然后,在您的子函数中注释掉jal printf。我注意到,您在一开始就做了一个“裸”printf调用,这似乎很好。继续这样做,直到程序停止故障。这应该有助于使这个地区[呼叫]本地化。

您没有说明您是在像spimmars这样的模拟器中运行,还是在真正的H/W (可能是在运行linux )中运行。我怀疑真实的H/W.但是,您可以通过在我更喜欢的mars模拟器下运行来验证您的逻辑,并为只执行jr $raprintffflush提供虚拟函数。请注意,spimmars都不能链接到.o文件。它们完全来源于工作,所以您只能使用.s

如果您在实际的H/W上运行,gdb应该能够提供有关异常源的详细信息。如果没有,请创建一个C函数,该函数使用SIGBUSsigaction设置信号处理程序(参见手册)。然后,在信号处理程序上放置一个断点。

信号处理程序的一个参数是指向具有其他信息的siginfo_t结构的指针。注意,对于SIGBUSsi_code字段将有一个可能有更多information.The第三参数的BUS_*值,尽管void *是指向在异常发生时可以为您提供寄存器值的指针。

在我给出的另一个答案中:mips recursion how to correctly store return address for a function,另一个OP,也有类似的问题。我的答案添加了一些特殊的堆栈对齐和检查代码,这可能给你一些想法。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37271004

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档