JingS-5


运行时支持


1. 基本的数据类型在运行时是如何表示的

    编程语言有多个类型,这些类型在运行时表示和运算,由具体的机器指令来实现。


    int:signed 32-bit。load/store

    char:一个字节、两个字节。

    浮点:单精度、双精度、扩展精度。

    枚举值:

    数组:

    记录:unpacked(各个field对齐)、packed(field连续存放,未对齐)。

    指针:

    string:x86提供string操作指令。

    集合:


2. 寄存器的使用

    对于CISC的x86 CPU,RISC风格的指令(operand和result都在reg中),速度比CISC风格的指令更快。

    RISC的CPU,所有的计算都必须在寄存器上进行。


3. Local Stack Frame

    函数需要有一个内存,用作某些变量的home。这些变量要么被取地址,要么需要index索引。

    函数的实参,如果在reg中放不下,也就放在这块内存中。


    sp总是有的。是否使用fp,原因仍然不理解(据说为了支持alloca(),要使用fp)。

        dynamic link:如果有fp,则dynamic link指向上一个fp;否则,指向上一个sp。


4. Runtime Stack

    运行时栈,有dynamic link(指向上一个活动栈),还"可能"有static link(指向词法上的外围,pascal这样的语言需要static link,而C语言不需要)。


5. 参数传递规则

    call by value:将实参的值传给形参。所谓的in参数。

    call by result:将形参的值传给实参。所谓的out参数。

    call by value-result:所谓的in-out参数。    

    call by reference:实参与形参别名。Fortran提供这种传参方式。如果参数值可以放入reg中,就call by value-result,如果不能(例如数组),就call by reference。

    call by name:仅具历史意义。


6. 函数的prologue、epilogue、call、和return

    函数调用的步骤:

        1. 传参和控制转移:

             将参数放入寄存器、或者stack mem。

             caller-saved register如果已经在使用,则写入mem。

             (如果需要,计算static link)。

             保存返回地址到reg,PC跳转到callee代码。一般使用call指令完成该动作。

        2. prologue:进入callee之后首先执行的一段代码。

             将old fp写入当前stack mem。fp = old sp。sp = old sp - stacksize。

             callee-saved regiser如果要使用,则写入mem。

             (如果需要,计算display,即static link的映射。)

        3. 函数执行body。

        4. epilogue:

             从mem中恢复callee-saved register。

             返回值放入合适位置(reg或mem)。

             恢复old fp和old sp。

             将PC改为返回地址。此动作由ret指令完成。

       5. caller将caller-saved register从mem中恢复。使用返回值。

    

    6.1 用寄存器传参

    6.2 用stack来传参(x86)

       

代码共享和PIC             

    动态链接需要确定:一个external symbol,是否有定义,是否存在多个定义。

    每个共享库有一个table:

        1. entry point+external symbol。本库定义的符号和入口。

        2. 本库使用的符号和入口。

        3. 本库使用的符号所在的其他共享库。

    在链接一个共享库的时候,就可以检查table,从而报告那些符号找不到。


    对单个程序而言,动态链接对性能的影响:

        1. 运行时进行动态链接有一定的开销。

        2. 共享库的代码是PIC的。


    共享库访问自己定义的符号时,采取PC-relative的方式。

        1. global offset table,GOT。保存所有符号相对于本共享库的偏移地址。

        2. 动态链接时,GOT中每个符号的地址被修改为绝对地址。同时获得GOT_off

        3. 通过下列指令,将GOT的绝对地址放入gp寄存器。


                  gp <-  GOT_off - 4                    ; GOT_off是GOT相对于当前指令的offset ——动态链接时获得

                  call   next, r31                           ; 跳转到next执行,r31保存了返回地址(就是next)

        next:  gp <- gp + r31                           ; gp保存了GOT的绝对地址

 

        4. 符号表保存了符号和符号在GOT中的偏移量a_off

                 r2 <-   [gp + a_off]                      ; 获得a的绝对地址

                 r3 <-   [r2]                                   ; 获得a的值

    

             问题:a_off如果超出了load [reg + offset]指令中offset的上界,则需要如下指令取得a的值。

                r3 <- high_part(a_off)

                r3 <- gp + r3

                r2 <- [r2 + low_part(a_offt)]

                r3 <- [r2]

        

             每个共享库都有自己的GOT。


    共享库1访问共享库2中的函数func

        被共享库1调用的函数func,有一个stub,它是一段代码,但保存在共享库1的数据段中(而不是只读的代码段),因此是可以被修改的。在func首次被调用时,它被加载并链接;以后就可以直接调用了。

        stub的工作方式有多种实现方式。例如,stub含有:函数名,对动态链接器的调用指令,当连接器被调用时,将stub替换为调用func的实际代码。下面介绍一种procedure linkage table, PLT的结构。

.PLT0       保存dynamic linker的调用代码

        .PLT1 保存共享库2的id

        .PLT2       分别保存共享库2中各个函数的stub

        .PLT3

        ...

        

符号和多态语言支持

       论文【Lee91】有详细论述。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值