【问题标题】:How to use pointer correctly in MIPS?如何在 MIPS 中正确使用指针?
【发布时间】:2020-08-01 17:15:47
【问题描述】:

我编写了一个程序,它输入几个数字并循环遍历每个数字。如果当前数字大于我的最后一个最大值,它应该交换最大值。如果它在最后一个数字(在我的字符串的末尾),它应该退出。

我正在尝试调试,但我明白,我并不真正了解指针的工作原理以及何时必须在寄存器周围使用方括号。

代码如下:

.data
first: .word 5, 6, -128, -5, 260, 34, 3, 20, -1
last: .word 44

max: .space 4  


.text
lw $t0, first
lw $t1, last
lw $t5, max


sw $t5, $t0
loop: 

beq $t0, $t1, ex
addi $t0, $t0, 4
bgt $t0, $t5, swapmax
j loop


swapmax: 
lw $t0, ($t5)

ex: 
lw $t5, max
li $v0, 10
syscall

我在哪里需要括号?为什么?

程序确实可以编译,但出现错误:

尝试在 0x800000180 处执行非指令

这个错误是什么意思?

【问题讨论】:

    标签: assembly mips spim


    【解决方案1】:

    这个错误是什么意思?

    0x800000180 是内核异常处理程序的地址。

    因为您的代码出现异常,所以它会出现在那里。

    您的模拟器似乎没有安装异常处理程序,因此它在尝试运行异常处理程序时遇到了另一个异常。

    要查看代码中的哪条指令触发了双重异常,请单步执行代码,直到它到达 0x800000180,然后从中返回一条指令。它几乎肯定会是一个加载或存储指令,它的内存地址被赋予了一个错误的指针。

    除此之外,@Wagar 的建议应该得到重视。

    【讨论】:

      【解决方案2】:

      什么是指针?

      指针是指向内存位置的东西。我们使用指针将值放入内存位置。例如在 C 中:

      int max;
      int *ptr = &max;
      *ptr = 22; // max = 22
      

      在上面的例子中,ptr 指向一个内存位置 (max),我们通过取消引用来更改 max 到 ptr 的值。

      如何在 MIPS 中正确使用它们?

      要理解这一点,您需要了解指令语法以及每条指令采用的操作数。显然,我们无法在一个答案中完成所有说明,所以我将向您展示一些,以便您了解:

      lw register, memory_location
      sw register, memory_location
      la register, memory_location 
      
      • lw 将一个单词从内存加载到寄存器中。示例:
      lw $t0, first
      lw $t0, ($t5) # this is like, int t0 = *t5
      
      • swregister 中的值存储到 内存位置。示例:
      sw $t0, max # max = t1
      sw $t0, ($t5) # *t5 = t0
      
      • la 会将内存位置的地址加载到寄存器中。
      la $t5, max # int *t5 = &max
      

      现在让我们看看代码中的错误。这里:

      lw $t5, max   
      

      上面会将max 的值加载到$t5。好像您创建了max 来存储最大值。在这里加载它似乎毫无意义,因为它甚至不包含任何内容。您想使用la 加载它的地址:

      la $t5, max #load address of max variable into $t5
      

      继续我们看到这条指令:

      sw $t5, $t0
      

      这不会组装。这将导致错误。 sw 将第一个操作数(源)作为寄存器,第二个操作数是“内存位置”,而不是寄存器。

      sw register, memory_location
      

      所以,如果你想存储一些东西,你会这样做:

      sw $t5, ($t0)       #store value inside $t5 at the 'address' inside $t0.
      
      # Assume:
      # $t5 = 23
      # $t0 = 0x5555
      # After executing this instruction, memory location 0x5555 would have value 23 in it
      

      这只是解释。在上面的代码中,您分配了$t0 = first。它甚至没有指向内存位置!但是,如果您执行la $t5, max,$t5 将有一个内存位置。

      所以,我假设你想这样做:

      sw $t0, ($t5)
      # After executing this, 'max' == $t0 because $t5 is pointing at max.
      

      继续前进,我们看到了:

      bgt $t0, $t5, swapmax
      

      您一定已经猜到了,这是不正确的。原因:您正在将“地址”与值进行比较。 “地址”在 $t5 中,“值”在 $t0 中。如果要获取 $t5 中的值,则必须先加载它。也许使用另一个寄存器:

      lw $t3, ($t5)
      #OR
      lw $t3, max   # same thing, $t5 is pointing at 'max'
      

      这些都是明显的错误。可能存在逻辑错误,但这是您的代码和程序,所以我会留给您根据需要修改您的逻辑

      【讨论】:

      • 非常感谢您的精彩解释!我有一个普遍的问题。了解 Assembler 以及计算机如何在二进制(或接近二进制)级别上工作真的很有趣,而且了解保存的工作原理很酷。是否值得深入了解汇编程序,是否有好的工作机会,或者它(几乎)没用?
      • 值得吗?依靠。如果您使用 c/c++ 编程,那肯定会更有益。不过,学习 mips 并不能真正告诉您现代计算机的工作原理。学习汇编将教你很多关于计算机的知识,并使你成为一个更好的程序员(前提是你也用它学习计算机体系结构)。工作?我住的地方没有 asm 工作。一般来说,asm的工作并不多。但是,当您编写高性能代码时,asm 知识通常非常有用。
      猜你喜欢
      • 1970-01-01
      • 2019-11-22
      • 2012-02-20
      • 2014-03-08
      • 1970-01-01
      • 1970-01-01
      • 2019-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多