gpt4 book ai didi

architecture - $ra 注册被调用者保存还是调用者保存在 mips 中?

转载 作者:行者123 更新时间:2023-12-04 00:38:29 25 4
gpt4 key购买 nike

我读过保留的寄存器是调用者保存的,非保留的寄存器是被调用者保存的。但在我看来,$ra,一个保留的寄存器,是调用者保存的,因为调用者保存了它必须返回的地址。任何人都可以解释我缺少什么吗?

最佳答案

I've read that preserved registers are caller saved and non preserved registers are callee saved.



这可能不是陈述事情的最佳方式,并且可能是混淆的根源。这是一个更好的方法:

A function (i.e. callee) must preserve $s0-$s7, the global pointer $gp, the stack pointer $sp, and the frame pointer $fp



所有其他寄存器都可以由它认为合适的函数更改。

例如,当 fncA电话 fncB ,它确实:
jal    fncB

返回地址放在 [hardwired] 寄存器 $ra
最后,通常, fncB通过 jr $ra 返回.

但是, fncB可以使用 jr 中的任何寄存器指令,所以它可以做:
move $v0,$ra
li $ra,0
jr $v0

保存 $ra by callee 对于 caller 真的没有任何意义。 $ra是被调用函数将[通常]找到返回地址的地方,但如果愿意,它可以移动它。

fncA ,它可以:
jal   fncB
jal fncB
$ra两种情况下的值都会不同,因此谈论保留 $ra 毫无意义。为了来电者的利益[因为没有]。

But it seems to me that $ra, a preserved register



保存?通过谁?调用者不需要这个值[也不关心它会发生什么,只要被调用者返回到正确的地方]。被调用的函数不必保留 $ra对于来电者。它必须保留返回地址[但不一定在 $ra ] 为自己。

因此,认为 $ra 可能是不正确的。由调用者或被调用者保存

... is caller saved as the caller saves the address to which it have to return.



当来电者 [via jal ] 在 $ra 中设置返回地址,它实际上并不是在保存寄存器 [在堆栈上] 的意义上保存它。

fncB调用另一个函数 fncC它通常保留 $ra它通常将其保存在堆栈中。但是,如果需要,它可以以其他方式保存寄存器内容。

另外, jalr可以使用指令代替 jal [并且适用于非常大的地址跨度]。所以, fncA可以做:
la    $t0,fncB
jalr $t0

但是,这实际上只是以下内容的简写:
la    $t0,fncB
jalr $ra,$t0

但是,如果 fncB知道它是如何被调用的(即我们以不同的方式编写函数),我们可以使用不同的寄存器来保存返回地址:
la    $t0,fncB
jalr $t3,$t0

这里 $t3将保存返回地址。这是一个非标准的调用约定(即不符合 ABI)。

我们可能有一个函数 fncD完全符合ABI。但是,它可能会调用其他函数不会调用的几个内部函数(例如 fncD1, fncD2, ... )。 fncD可以自由地使用它选择的任何非标准调用约定来调用这些函数。

例如,它可以使用 $t0-$t6用于函数参数而不是 $a0-$a3 .如 fncD蜜饯 $s0-s7在外边缘,这些可用于 fncD1 的函数参数.

唯一绝对硬连线的寄存器是 $zero$ra .对于 $ra这只是因为它在 jal 中是硬连线/隐式的操作说明。如果我们只使用 jalr ,我们可以释放 $ra作为普通寄存器,如 $t0 .

其余的寄存器不是由 CPU 架构决定的,而只是由 ABI 约定决定的。

如果我们用 100% 汇编程序编写程序,编写我们自己的所有函数,我们可以使用我们希望的任何约定。例如,我们可以使用 $t0作为我们的堆栈指针寄存器而不是 $sp .那是因为 mips 架构没有推送/弹出指令,其中 $sp寄存器是隐式的。它只有 lw/sw我们可以使用我们想要的任何寄存器。

这是一个程序,它演示了您可以执行的一些标准和非标准操作:
    .data
msg_jal1: .asciiz "fncjal1\n"
msg_jal2: .asciiz "fncjal2\n"
msg_jalx: .asciiz "fncjalx\n"
msg_jaly: .asciiz "fncjaly\n"
msg_jalz: .asciiz "fncjalz\n"
msg_jalr1: .asciiz "fncjalr1\n"
msg_jalr2: .asciiz "fncjalr2\n"
msg_post: .asciiz "exit\n"

.text
.globl main
main:
# for the jal instruction, the return address register is hardwired to $ra
jal fncjal1

# but, once called, a function may destroy it at will
jal fncjal2

# double level call
jal fncjalx

# jalr takes two registers -- this is just a shorthand for ...
la $t0,fncjalr1
jalr $t0

# ... this
la $t0,fncjalr1
jalr $ra,$t0

# we may use any return address register we want (subject to our ABI rules)
la $t0,fncjalr2
jalr $t3,$t0

# show we got back alive
li $v0,4
la $a0,msg_post
syscall

li $v0,10 # syscall for exit program
syscall

# fncja11 -- standard function
fncjal1:
li $v0,4
la $a0,msg_jal1
syscall
jr $ra # do return

# fncja12 -- standard function that returns via different register
fncjal2:
li $v0,4
la $a0,msg_jal2
syscall

# grab the return address
# we can preserve this in just about any register we wish (e.g. $a0) as
# long as the jr instruction below matches
move $v0,$ra

# zero out the standard return register
# NOTES:
# (1) this _is_ ABI conforming
# (2) caller may _not_ assume $ra has been preserved
# (3) _we_ need to preserve the return _address_ but we may do anything
# we wish to the return _register_
li $ra,0

jr $v0 # do return

# fncja1x -- standard function that calls another function
fncjalx:
# preserve return address
addi $sp,$sp,-4
sw $ra,0($sp)

li $v0,4
la $a0,msg_jalx
syscall

jal fncjal1
jal fncjal2

# restore return address
lw $ra,0($sp)
addi $sp,$sp,4

jr $ra # do return

# fncja1y -- standard function that calls another function with funny return
fncjaly:
# preserve return address
addi $sp,$sp,-4
sw $ra,0($sp)

li $v0,4
la $a0,msg_jaly
syscall

jal fncjal1
jal fncjal2

# restore return address
lw $a0,0($sp)
addi $sp,$sp,4

jr $a0 # do return

# fncjalz -- non-standard function that calls another function
fncjalz:
move $t7,$ra # preserve return address

li $v0,4
la $a0,msg_jalz
syscall

jal fncjal1
jal fncjal2

jr $t7 # do return

# fncjalr1 -- standard function [called via jalr]
fncjalr1:
li $v0,4
la $a0,msg_jalr1
syscall
jr $ra # do return

# fncjalr2 -- non-standard function [called via jalr]
fncjalr2:
li $v0,4
la $a0,msg_jalr2
syscall
jr $t3 # do return

这个程序的输出是:
fncjal1
fncjal2
fncjalx
fncjal1
fncjal2
fncjalr1
fncjalr1
fncjalr2
exit

关于architecture - $ra 注册被调用者保存还是调用者保存在 mips 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37906276/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com