有没有人能解释一下a0指针为什么不能返回到原来的值?下面的代码使用DC指令创建字符串并将其反转。Trecrev被递归调用,并使用堆栈存储值。我能理解为什么保存ra。如果我们不保存它,我们将丢失返回到main的返回地址。但为什么我们需要保存a0和a1呢?此外,如果我们把a0重新加载到a0中,为什么我们不能把字符串恢复到正常状态呢?
STR: DC "Hadoukan\0"
main:
addi a0, x0, STR
jal ra, strlen
addi a1, a0, -1
addi a0, x0, STR
jal ra, trecrev
addi x5, x0, STR
ecall x0, x5, 4
ebreak x0,x0, 0
trecrev:
bge x0, a1, trecrevbase
addi sp, sp, -24
sd ra, 0(sp)
sd a0, 8(sp)
sd a1, 16(sp)
add a1, a1, a0
jal ra, excharr
ld ra, 0(sp)
ld a0, 8(sp)
ld a1, 16(sp)
addi sp, sp, 24
addi a0, a0, 1
addi a1, a1, -2
jal x0, trecrev
trecrevbase:
jalr x0, 0(ra)
;;; EXCHARR
;;; expects two arguments (pointers to characters) and
;;; exchanges the two characters
excharr:
lb t0, 0(a0)
lb t1, 0(a1)
sb t1, 0(a0)
sb t0, 0(a1)
jalr x0, 0(ra)
;;; STRLEN
;;; expacts one argument pointer to char and returns the length of the
;;; string.
;;; t0 -> counter
;;; t1 -> temp to read the char in.
strlen:
addi t0, x0, 0
strlenloop:
lb t1, 0(a0)
beq t1, x0, strlenend
addi t0, t0, 1
addi a0, a0, 1
jal x0, strlenloop
strlenend:
addi a0, t0, 0
jalr x0, 0(ra)
我猜我对字符指针以及它们如何存储在堆栈上的理解是缺乏的。
1条答案
按热度按时间kupeojn61#
首先,让我们注意到这里没有递归:这是一种迭代算法。
堆栈正被用作变量存储,它将在对
ecxharr
的调用后继续存在。这种方法是可行的,尽管可以说是有缺陷的,因为它在每次迭代时都推送和弹出,这是不必要的,也是误导性的。误导性的是,它在每次迭代时都推送整个堆栈帧,这是不必要的。
这可以通过将堆栈帧创建移到循环之外来解决,如下面的转换所示。
(By定义函数序言出现在函数体之前,并且只运行一次;函数尾声发生在函数体之后,并且只运行一次。)
不过,对于这种情况,最好也是最合适的方法是使用
s
寄存器,而不是内存来存储那些需要在调用excharr
后仍然存在的变量。使用
s
寄存器代替堆栈存储器,从每次迭代有2次加载和2次存储变为仅一次有2次加载和2次存储。这个函数的大部分工作都在循环中进行,现在循环大大缩短了。
(使用
s
寄存器而不是内存会使函数仅在使用索引0调用时开销更大;当以索引1调用时,它是偶数,而当以索引〉1调用时,它是赢。)