是否保存了$ ra注册被叫者或保存在mips中的呼叫者? [英] Whether $ra register callee saved or caller saved in mips?

查看:109
本文介绍了是否保存了$ ra注册被叫者或保存在mips中的呼叫者?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读到保留的寄存器是调用方保存的,未保留的寄存器是被调用方保存的.但是在我看来,保存了调用者的$ ra是一个保留的寄存器,因为调用者保存了它必须返回的地址.有人可以解释我所缺少的吗?

I've read that preserved registers are caller saved and non preserved registers are callee saved. But it seems to me that $ra, a preserved register, is caller saved as the caller saves the address to which it have to return. Can any one explain what I am missing?

推荐答案

我读到保留的寄存器保存为调用方,未保存的寄存器保存为被调用方.

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

这可能不是陈述事物的最佳方法,并且可能是造成混乱的根源.这是一种更好的方法:

That may not be the best way to state things and may be the source of the confusion. Here is a better way:

函数(即被调用方)必须保留 $s0-$s7全局指针 $gp堆栈指针 $sp和框架指针 $fp

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

所有其他寄存器都可以通过其认为合适的功能进行更改.

All other registers may be changed by a function as it sees fit.

例如,当fncA调用fncB时,它会执行:

For example, when fncA calls fncB, it does:

jal    fncB

返回地址放置在[hardwired]寄存器$ra

The return address is placed in the [hardwired] register $ra

通常,最后,fncB通过jr $ra返回.

At the end, normally, fncB returns via jr $ra.

但是,fncB可以在jr指令中使用 any 寄存器,因此可以:

But, fncB may use any register in the jr instruction, so it could do:

move $v0,$ra
li   $ra,0
jr   $v0

callee caller 保存$ra确实没有任何意义. $ra是被调用函数(通常)将在其中找到返回地址的地方,但是如果需要的话,它可以四处移动.

Preserving $ra by callee for caller really has no meaning. $ra is where the called function will [normally] find the return address, but it can move it around, if it wishes.

fncA中,它可以做到:

jal   fncB
jal   fncB

在两种情况下$ra值都将不同,因此谈论保留$ra为呼叫者的利益毫无意义[因为没有 ].

The $ra value will be different in both cases, so it makes no sense to talk of preserving $ra for caller's benefit [as there is none].

但是在我看来,$ ra是一个保留的寄存器

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

保留?由?呼叫者不需要该值[只要被呼叫者返回正确的位置,也不必担心它会发生什么].调用的函数不必 保留调用方的$ra.它必须保留返回地址 [但不一定要保存在$ra]中.

Preserved? By whom? Caller doesn't need the value [nor care about what happens to it as long as callee returns to the correct place]. A called function does not have to preserve $ra for caller. It has to preserve the return address [but, not necessarily in $ra] for itself.

因此,将$ra视为由调用方被调用方保留的可能是不正确的

Thus, it's probably incorrect to think of $ra as preserved by caller or callee

...已保存呼叫者,因为呼叫者保存了它必须返回的地址.

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

当调用者[通过jal] 设置$ra中的返回地址时,从保存寄存器的意义上来说,它实际上不是保存堆栈].

When caller [via jal] sets the return address in $ra, it really isn't saving it in the sense of saving registers [on the stack].

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

If fncB calls another function fncC it usually preserves $ra and it usually saves it on the stack. But, it can preserve the register contents in other ways if it desires.

此外,可以使用jalr指令代替jal [并且对于很大的地址范围,].因此,fncA可以做到:

Also, the jalr instruction could be used instead of jal [and is for very large address spans]. So, fncA could do:

la    $t0,fncB
jalr  $t0

但是,这实际上只是以下内容的简写:

But, this is really just a shorthand for:

la    $t0,fncB
jalr  $ra,$t0

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

But, if fncB is aware of how it's being called (i.e. we write the function differently), we could use a different register to hold the return address:

la    $t0,fncB
jalr  $t3,$t0

此处$t3将保存返回地址.这是非标准的调用约定(即不符合ABI).

Here $t3 will hold the return address. This is a non-standard calling convention (i.e. not ABI conforming).

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

We might have a function fncD that fully conforms to the ABI. But, it might call several internal functions that no other function will call (e.g. fncD1, fncD2, ...). fncD is at liberty to call these functions with whatever non-standard calling conventions it chooses.

例如,它可以将$t0-$t6用作函数参数而不是$a0-$a3.如果fncD在外部边缘保留$s0-s7,则可以将它们用作fncD1的函数参数.

For example, it may use $t0-$t6 for function arguments instead of $a0-$a3. If fncD preserves $s0-s7 at the outer edge, these could be used for function arguments to fncD1.

绝对硬连线的寄存器是$zero$ra.对于$ra,这仅是 ,因为它在jal指令中是硬接线/隐式的.如果仅使用jalr,则可以将$ra释放为像$t0这样的普通寄存器.

The only registers that are absolutely hardwired are $zero and $ra. For $ra this is only because it is hardwired/implicit in the jal instruction. If we only used jalr, we could free up $ra as an ordinary register like $t0.

其余寄存器不是由CPU体系结构决定的,而是由ABI约定决定的.

The rest of the registers are not dictated by the CPU architecture, but merely the ABI convention.

如果我们使用100%汇编器编写程序,并编写了所有自己的函数,则可以使用所需的 any 约定.例如,我们可以使用$t0作为我们的堆栈指针寄存器,而不是$sp.这是因为mips体系结构具有 no 推入/弹出指令,其中$sp寄存器是隐式的.它只有lw/sw,我们可以使用所需的任何寄存器.

If we wrote a program in 100% assembler, wrote all our own functions, we could use any convention we wished. For example, we could use $t0 as our stack pointer register instead of $sp. That's because the mips architecture has no push/pop instructions where the $sp register is implicit. It only has lw/sw and we can use whatever register we want.

这是一个演示您可以执行的一些标准和非标准操作的程序:

Here is a program that demonstrates some of the standard and non-standard things you can do:

    .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

这篇关于是否保存了$ ra注册被叫者或保存在mips中的呼叫者?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆