【问题标题】:mips nested procedure with jr $ramips 嵌套过程与 jr $ra
【发布时间】:2021-03-30 07:56:45
【问题描述】:

我正在尝试调用FUNC 并将其值返回给xintersect。我认为使用 jr $ra 应该返回给调用者,但它会跳转到代码的末尾。我无法修改FUNC,因为它是给定的示例测试用例。任何想法?下面是我的 MIPS 代码:

 .globl FUNC
FUNC:  
    mul   $t0, $a0, $a0
    addi  $v0, $t0, -16
    jr    $ra
# expect 4 in $v1
main:  
    la $a0, FUNC
    li $a1, 0#a
    li $a2, 100#b
    b  xintersect
xintersect:
    subu $s0, $a2, $a1
    sltiu $t3, $s0, 1
    add $s5, $0, $a0
    bne $t3, 1, whileLoop
    #return the value in $v1
    add $v1, $a1, $0
    jr $ra
whileLoop:
    addu $s2, $a1, $a2
    srl $a0, $s2, 1#m in $a0
    jr $s5
    slt $s2, $0, $v0
    beq $0, $s2, ifLoop
    addu $a2, $0, $a0
    b whileLoop
ifLoop:
    addu $a1, $0, $a0
    b whileLoop

下面应该是C代码:

int xintersect(int (*f) (int), int a, int b) {
 /* f(a) ≤ 0 ≤ f(b), a ≤ b */
 while (b-a > 1) {
     int m = (a+b)/2;
     if (f(m) <= 0) a = m; else b = m;
     }
 return a;
}

【问题讨论】:

    标签: assembly nested mips


    【解决方案1】:

    jr $ra 依赖于已放置在 $ra 中的返回地址,但您使用未设置 $rajr $s5 调用 FUNC。请改用jalr $s5

    main 中的b xintersect 应该是jal xintersect,否则xintersect 中的jr $ra 将不起作用。还要记住,xintersect 必须将$ra 保存在某个地方(例如,在堆栈上),如果它需要同时调用FUNC 然后能够返回到main

    在我看来,xintersect 中有一个无限循环。一旦你输入whileLoop,没有什么会退出循环。

    【讨论】:

    • 这个我也不能修改main,它是用FUNC给出的
    • 好吧,main 例程被破坏了。所以你需要问问你的教授或助教,如果main没有以正确的方式调用xintersect,你应该如何返回main
    • 现在我添加终止条件以停止while 循环并将$ra 存储在临时寄存器(add $t7, $ra, $0) 中,然后再使用jalr $s5。当我需要使用jr $ra 回到main(add $ra, $t7, $0) 时,我将它存储回$ra。这至少给了我正确的输出。只是想知道在 MIPS 中这样做是否合法?
    • 通常你会使用堆栈来保存$ra,但如果你知道你没有调用任何会修改$t7的代码,我想使用$t7就可以了。跨度>
    • jal xintersect 会更糟。目前 main 尾调用它,所以当它返回时,它返回到 main 的父级。如果你使用jal,它会回到jal之后,然后执行会落入xintersect:,因为main不以jr $ra结尾(或恢复$ra)。
    【解决方案2】:

    您的 while 循环没有 EXIT

    要参与jr 你需要jal 所以我也写了 您的$ra 未保存在XINTERSECT 的堆栈中:

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

    然后恢复

    lw $ra,$sp
    addi $sp,$sp,4 #restore the pointer too
    

    globl FUNC
    FUNC:  
        mul   $t0, $a0, $a0
        addi  $v0, $t0, -16
        jr    $ra
        #expect 4 in $v1
    
    main:  
        la $a0, FUNC
        li $a1, 0#a
        li $a2, 100#b
        jal xintersect
    
    xintersect:
        subu $s0, $a2, $a1
        sltiu $t3, $s0, 1
        add $s5, $0, $a0
        bne $t3, 1, whileLoop
        #return the value in $v1
        add $v1, $a1, $0
        jr $ra
    whileLoop:
        addu $s2, $a1, $a2
        srl $a0, $s2, 1#m in $a0
        jalr $s5
        slt $s2, $0, $v0
        beq $0, $s2, ifLoop
        addu $a2, $0, $a0
        b whileLoop
    ifLoop:
        addu $a1, $0, $a0
        b whileLoop
    

    【讨论】:

    • 如果xintersect 立即返回,执行将再次从main 进入xintersect。这是不对的; b xintersect 的尾调用令人惊讶,但至少是可能的。
    • @frankenapps - 很好地猜测如何格式化该文本,但我很确定“and”是英语,而不是 MIPS 助记符。并且该代码在文件顶部没有意义,看起来这是在xintersect 中执行此操作的建议,尽管大代码块没有进行了该更改。
    猜你喜欢
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    相关资源
    最近更新 更多