请选择 进入手机版 | 继续访问电脑版

前馈科技

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 642|回复: 0

SPARC函数返回时jmp %i7+8的原因

[复制链接]

66

主题

66

帖子

354

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
354
发表于 2020-3-14 11:33:06 | 显示全部楼层 |阅读模式
   SPARC采用call指令调用函数,但“call”只是一个符号,真是执行的jmpl指令(imp link):
      call <function>    ; jmpl <address>, %o7
      mov 0, %o0
   由于SPARC的流水线结构,call指令有个延迟槽,即:call指令之后的一条指令执行完毕后才会真正跳转,详细过程如下:
SPARC用两个程序指针PC和nPC,来保持指令执行的轨迹。PC持有当前执行指令的地址;第二个程序指针,nPC持有下一条要执行的指令的地址。
通常,SPARC在每一条指令执行结束时更新当前程序指针,更新时,用nPC的值代替PC的值,nPC的值则是“其原值+4”。当它执行一个转移指令时,SPARC分配nPC的值给PC,然后更新nPC的值。如果跳转发生,nPC被分配一个用指令声明的目标(地址)值(否则,nPC的值是自增4的)。
也就是说,跳转指令发生时,一时并没改变PC的值到目标地址,它只能执行原nPC给的下一条指令(这就产生了跳转间隙)。
  mov 0, %o0是编译器为了不浪费机流水线,放置的一条指令,奢侈点的话也可以是这样:

             call <function>    ; jmpl <address>, %o7
             nop                ;   Branch delay slot)
  综上所属,call一个函数,实际二进制代码里call指令后面被插入了一条指令,返回后需要执行的地址是call指令地址+8,在被调函数中,正常情况下是如下结构:
  function:
              save  %sp, -C, %sp
                               ; perform function, leave return value,
                               ; if any, in register %i0 upon exit
             ret            ; jmpl %i7+8, %g0
             restore    ; restore %g0,%g0,%g0
       执行了save指令后寄存器窗口指针发生了顺时针旋转,因此call指令的地址保存在了%i7中,返回时的过程和调用时的过程类似:
       待返回的目的地址给了nPC,nPC的值(ret指令的下一条指令的地址)给了PC,因此执行为ret指令后将先执行ret指令的下一条指令,为了不浪费机时,是restore %g0,%g0,%g0,实现寄存器窗口指针逆时针旋转。这就是ret指令是jmpl %i7+8, %g0的原因。
一种优化的方式是舍弃save和restore指令,这样的话寄存器窗口指针不会发生旋转,因此被调函数只能是%o0~%o7寄存器,且call指令的地址在%o7中,因此返回时应该跳转至%o7+8

  function:
                              ; no save instruction needed upon entry

                              ; perform function, leave return value,
                              ; if any, in register %o0 upon exit

                 retl       ; jmpl %o7+8, %g0
                 nop      ; the delay slot can be used for something else
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|计算机控制

GMT+8, 2022-7-1 09:42 , Processed in 0.049519 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表