在我的 MIPS 程序中,地址并不总是增加 4

发布于 2025-01-14 00:58:50 字数 1609 浏览 2 评论 0原文

下面的 MIPS 代码应该编写一个函数 swapbigsmall,它使用嵌套函数 findloc 来查找该数组中最大和最小数字的位置,并交换它们。但是当我运行该程序时,findloc 错误地增加了地址,导致 v0 可能等于不是 4 的倍数的数字,从而产生错误地址异常。如何确保地址始终增加 4?

A: .word 90, 2, 93, 66, 8, 120, 121, 11, 33, 9

   .text
   .globl main

main: la $a0, A
      li $a1, 10

      jal swapbigsmall

done: li $v0, 10
      syscall

swapbigsmall:

      #Creates 3 spaces in stack,
      #then stores registers
      addi $sp, $sp, -12
      sw $ra, 8($sp)
      sw $ra, 4($sp)
      sw $ra, 0($sp)

      jal findloc  #Find smallest
      #Stores first result in s1
      #This is where exception occurs

      lw $s1, 0($v0)

      #Finds and stores largest
      li $a2, 1
      jal findloc
      lw $s2, 0($v0)
      
      #Swap code
      lw $t3, 0($s1)
      lw $t4, 0($s2)
      sw $t3, 0($s2)
      sw $t4, 0($s1)

      #Function conclusion
      lw $ra, 8($sp)
      lw $s2, 4($sp)
      lw $s1, 0($sp)
      add $sp, $sp, 12
      jr $ra

findloc:
      li $t0, 0

      #t9 = A[0]
      lw $t9, 0($a0)

      blt $a2, 1, LOOPSM

      #t1 = A[i]
      LOOPL: sll $t1, $t0, 2
      add $t1, $t1, $a0
      lw $t1, 0($t1)
      sgt $t2, $t9, $t1
      bne $t2, $0, LOOP_NEXTL

      addi $t9, $t1, 0
      sll $v0, $t0, 2
      LOOP_NEXTL: addi $t0, $t0, 1
      bne $t0, $a1, LOOPL

      j Exit

      LOOPSM: sll $t1, $t0, 2
      add $t1, $t1, $a0
      lw $t1, 0($t1)
      slt $t2, $t9, $t1
      bne $t2, $0, LOOP_NEXTSM

      addi $t9, $t1, 0
      sll $v0, $t0, 2
      LOOP_NEXTSM: addi $t0, $t0, 1
      bne $t0, $a1, LOOPL

      EXIT:

      jr $ra

The MIPS code below is supposed to write a function swapbigsmall that uses nested function findloc to find the location of the biggest and smallest numbers in this array, and swap them. But when I run the program, findloc increments the address incorrectly, causing v0 to potentially equal a number that isn't a multiple of 4, creating a bad address exception. How can I make sure that the address goes up by 4 at all times?

A: .word 90, 2, 93, 66, 8, 120, 121, 11, 33, 9

   .text
   .globl main

main: la $a0, A
      li $a1, 10

      jal swapbigsmall

done: li $v0, 10
      syscall

swapbigsmall:

      #Creates 3 spaces in stack,
      #then stores registers
      addi $sp, $sp, -12
      sw $ra, 8($sp)
      sw $ra, 4($sp)
      sw $ra, 0($sp)

      jal findloc  #Find smallest
      #Stores first result in s1
      #This is where exception occurs

      lw $s1, 0($v0)

      #Finds and stores largest
      li $a2, 1
      jal findloc
      lw $s2, 0($v0)
      
      #Swap code
      lw $t3, 0($s1)
      lw $t4, 0($s2)
      sw $t3, 0($s2)
      sw $t4, 0($s1)

      #Function conclusion
      lw $ra, 8($sp)
      lw $s2, 4($sp)
      lw $s1, 0($sp)
      add $sp, $sp, 12
      jr $ra

findloc:
      li $t0, 0

      #t9 = A[0]
      lw $t9, 0($a0)

      blt $a2, 1, LOOPSM

      #t1 = A[i]
      LOOPL: sll $t1, $t0, 2
      add $t1, $t1, $a0
      lw $t1, 0($t1)
      sgt $t2, $t9, $t1
      bne $t2, $0, LOOP_NEXTL

      addi $t9, $t1, 0
      sll $v0, $t0, 2
      LOOP_NEXTL: addi $t0, $t0, 1
      bne $t0, $a1, LOOPL

      j Exit

      LOOPSM: sll $t1, $t0, 2
      add $t1, $t1, $a0
      lw $t1, 0($t1)
      slt $t2, $t9, $t1
      bne $t2, $0, LOOP_NEXTSM

      addi $t9, $t1, 0
      sll $v0, $t0, 2
      LOOP_NEXTSM: addi $t0, $t0, 1
      bne $t0, $a1, LOOPL

      EXIT:

      jr $ra

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

久随 2025-01-21 00:58:50

当您在汇编语言中遇到错误时,您不应该假设您知道重点在哪里或出了什么问题,因为任何小打字错误都可能对执行产生戏剧性或意外的影响。

所以,这是您学习调试的机会。

模拟器具有单步功能,您应该使用它来验证每条指令是否执行其应执行的操作:您期望它执行的操作。

如果任何一条指令错误,程序将无法运行,也不会挂起。

  • 大多数指令都会影响寄存器,因此请验证您期望的正确效果。
  • 其他指令会影响控制流(指令流的排序),因此请验证这些指令。
  • 而且,其他指令仍然存储到内存中,因此请验证每个存储是否在正确的位置存储了正确的内容。

您需要特别小心系统调用和 jal 调用。如果被调用函数(被调用者)扰乱了调用者的期望,那么当被调用者返回到调用者时,调用者将无法工作。

当您拨打电话时,请验证每个参数。 当调用返回时,验证堆栈指针是否已返回到其原始位置,并且所有寄存器都具有预期值。寄存器在调用者和被调用者之间共享,因此从抽象意义上讲,在单步执行函数调用时需要验证更多内容。 (不过,要明确的是,被调用者中破坏调用者期望的错误可以在被调用者中找到;但有时,只需跳过调用就可以让您快速了解正在破坏的内容。)

就像 C 或其他语言一样调试时,我们可以单步调试“向前”,也可以使用“除法”“向后”调试。征服以找到代码中出现问题的点。

我更喜欢转发新代码,因为错误的影响不会复合。所有新代码都应该至少向前运行一次。

然而,使用divide & 逆向工作征服有时可以很好地快速找到故障原因 - 其想法是从故障/异常返回代码并确定错误时的原因。通常这是一个迭代过程,因为逆向工作发现的问题不一定是错误,并且您必须继续逆向工作才能找到真正的错误。

When you have bugs in assembly language, you should not assume you know where to focus or what's going wrong, as any little typo can have a dramatic or unexpected effect on the execution.

So, this is your opportunity to learn debugging.

The simulators have a single step feature, and you are supposed to use it to verify that each and every instruction does what it is supposed to do: what you expect it to do.

If any one instruction is wrong, the program won't work, it won't hang together.

  • Most instructions have an affect on the registers, so verify the proper effect you're expecting.
  • Other instructions affect the flow of control (sequencing of the instruction stream) so verify those for that.
  • And still, other instructions store to memory, so verify every store is storing the right thing at the right place.

You need to be especially careful of syscalls and jal calls.  If the called function, the callee, messes up the expectations of the caller, then the caller just won't work when the callee returns to the caller.

When you're making a call, verify every parameter.  When the call comes back, verify that the stack pointer has returned to its original position, and that all the registers have the expected values.  The registers are shared between caller and callee, so in the abstract sense, there's more to verify when stepping over a function call.  (Bugs in the callee that stomp on the caller's expectations can be found in the callee, though, to be clear; but sometimes just stepping over the call may give you quick insight as to what's being clobbered.)

Just like with C or other language debugging, we can debug "forwards" with single step or debug "backwards" using divide & conquer to find the point in the code where something went wrong.

I prefer forwards for new code, since the effect of mistakes won't compound.  All new code should be run forwards at least once.

However, working backwards with divide & conquer can sometimes work well to quickly find the cause of a fault — the idea being to go back in the code from a fault/exception and determine what when wrong.  Usually that is an iterative processes because working backwards the issues you find are not necessarily the bugs, and you have to keep working backwards to find the real bugs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文