计算机体系结构基础知识介绍之控制流指令

控制流指令是指能够改变程序执行顺序的指令,如分支、跳转、返回等。控制流指令必须指定目标地址,即要跳转到哪里继续执行。

一、地址指定方式

目标地址有两种指定方式:

- 显式指定:在指令中直接给出目标地址或者与当前指令地址(即程序计数器PC)的偏移量。这种方式称为PC相对寻址,是最常见的方式。PC相对寻址的优点是可以节省指令位数,因为目标地址通常离当前指令很近,偏移量比绝对地址需要的位数少。PC相对寻址还可以使代码与加载位置无关,即不管代码被加载到哪里,都可以正确运行。这种特性称为位置无关性,可以减少程序链接时的工作量,也可以方便动态链接库的使用。
- 隐式指定:在指令中不给出目标地址,而是通过某种方式动态地确定目标地址。这种方式通常用于返回和间接跳转等情况,因为这些情况下目标地址在编译时无法确定,只能在运行时才能知道。这种动态确定目标地址的方式有很多种,最简单的一种是使用一个寄存器来存放目标地址,然后通过寄存器间接寻址来跳转。这种寄存器间接跳转还可以用于以下四种重要的功能:
  - Case或Switch语句,用于在多个选项中选择一个执行。
  - 虚函数或方法,用于面向对象语言中根据参数的类型来调用不同的函数或方法。
  - 高阶函数或函数指针,用于将函数作为参数传递,实现一些面向对象编程的特性。
  - 动态共享库,用于在程序运行时按需加载和链接库文件,而不是在程序运行前就加载和链接。

在所有这四种情况下,目标地址都是在编译时无法确定的,因此通常需要从内存中加载到寄存器中再进行寄存器间接跳转。

由于分支指令通常使用PC相对寻址来指定目标地址,所以一个重要的问题是分支目标地址离分支指令有多远。知道这个距离的分布情况可以帮助我们选择支持哪些偏移量范围,从而影响指令长度和编码方式。

二、过程调用和返回寄存器的保存问题

过程调用和返回时,除了要进行控制转移,还可能需要保存一些状态,至少要保存返回地址,有时候是保存在一个特殊的链接寄存器或者一个通用寄存器中。

一些旧的体系结构提供了一种机制来保存多个寄存器,而一些新的体系结构则要求编译器为每个要保存和恢复的寄存器生成存储和加载指令。

保存寄存器有两种基本的约定:要么在调用点保存,要么在被调用的过程内部保存。调用者保存(caller saving)意味着调用过程必须保存它想在调用后继续访问的寄存器,因此被调用的过程不需要担心寄存器。被调用者保存(callee saving)则相反:被调用的过程必须保存它想使用的寄存器,不影响调用者。有些时候必须使用调用者保存,因为两个不同的过程可能访问全局可见的变量。

例如,假设我们有一个过程P1,它调用了另一个过程P2,而这两个过程都操作全局变量x。如果P1将x分配到一个寄存器中,它必须在调用P2之前将x保存到一个P2能够知道的位置。假设P2不会触碰x,但是可以调用另一个过程P3,而P3可能访问x,但是P2和P3是分别编译的。由于这些复杂性,大多数编译器会保守地在每次调用时保存任何可能被访问的变量。在可以使用任何一种约定的情况下,有些程序使用被调用者保存会更优化,有些程序使用调用者保存会更优化。因此,现在大多数真实的系统使用两种机制的组合。

你可能感兴趣的:(计算机体系结构学习笔记,risc-v,嵌入式硬件)