Sparc架构中的栈与寄存器

寄存器的基本结构

  • 通用整数寄存器

    在sparc架构中,同一时刻可以使用的整数寄存器为32个,如下图所示,其中8个为一组,除了一组全局寄存器(%g1-g7)外,其余的3组寄存器组成了一个寄存器窗口,在不同的sparc处理器里,寄存器窗口可以有2到32个,寄存器总数从40到520不等,大多数sparc处理器有7到8个窗口,这也是为什么sparc架构被称为是“可扩充的(scalable)”的原因。寄存器
  • 寄存器窗口

    下图展示了一个拥有8个寄存器窗口(w0-w7)的sparc处理器。
    寄存器窗口
    • 当前寄存器窗口指针(CWP)

      CWP是PSR(程序状态寄存器)的一部分,如上面所说的,同一时刻只有32个整数寄存器处于可用状态,即8个全局寄存器和CWP所指向寄存器窗口中的24个寄存器,CWP通常会因SAVE指令(SAVE指令一般在过程调用时使用,用来开辟新的栈帧并切换寄存器窗口)而减一,因RESTORE指令(在从过程中返回前切换回调用者的寄存器窗口)而加一,陷阱事件(中断,异常或TRAP指令)和RETT指令(从陷阱中返回)也会改变CWP,不过函数调用比陷阱更为常见。
    • 窗口无效掩码(WIM)

      WIM指示了哪个窗口是无效的,无效的意思是该窗口保存了调用者的信息所以不可再使用,上图中,WIM指向w7,而CWP指向w0,所以现在如果执行一条SAVE指令,则会触发窗口溢出陷阱,反之,如果CWP指向w0且又执行了一条RESTORE指令,则会触发窗口下溢陷阱
    • 窗口的重叠

      或许你已经注意到了,上图中的out寄存器组和in寄存器组是重叠的,也就是说,相邻窗口的out和in寄存器内容相同,这是为了方便过程(或者说函数)的调用,在调用者(caller)中,先把要传递的函数参数依次放入out寄存器,之后执行CALL指令(CALL callee)跳转到被调用者(callee)处,然后执行SAVE指令切换寄存器窗口,被调用者便可以使用in寄存器来访问这些参数。同样的,被调用者也可以成为调用者。

寄存器使用规则

使用规则 上面说到,out和in寄存器组用来传递和接受参数,但实际上只有%o0-o5以及%i0-i5用来存放参数,六个以上的参数存放在栈中。那么%o6,%i6和%o7,%i7用来做什么呢,先来说o7和i7,调用者在执行CALL callee时,会把当前指令的地址存放在o7中,在被调用者执行完SAVE指令后,o7就变成了i7,此时执行RET指令便会跳转到刚才调用者执行调用的条指令的地址,这样就完成了函数的返回。
而o6和i6寄存器有些特殊o6又被称为sp(stack pointer),即栈指针,i6又被称为fp(frame pointer),即帧指针,sp指向栈顶,而fp指向栈帧的起始位置,当执行SAVE指令时,o6变为i6,sp的值传给了fp,而SAVE指令又同时会执行一次加法操作,将旧sp的值加上栈帧的长度赋给新sp,这样就完成了函数调用中栈帧的开辟。

栈帧的结构

下图便是栈帧的结构
栈帧 注意图中被一片空白分成了上下两部分,上面的部分用sp+偏移量来访问,下面的部分用fp-偏移量来访问。为什么是sp+偏移量,fp-偏移量?因为栈是向着低地址增长的,所以在上图中,下面是高地址,上面是低地址。
注意最接近fp的一个部分,即addressable scalar automatics,这个的意思其实就是局部变量,函数中声明的变量存放于此处
栈 上图为一个栈的内容的例子,注意local和in寄存器的值和栈中暂存的值并不相同,这是因为许多事件都会导致寄存器的值被冲进栈中,比如许多的系统调用

窗口上溢与下溢陷阱 上 下


原版地址(需翻墙):
https://cseweb.ucsd.edu/~gbournou/CSE131/sparcstack.html

猜你喜欢

转载自blog.csdn.net/sopora/article/details/83316713