间接控制流指令和禁止进行数据值推测的制作方法

文档序号:23068009发布日期:2020-11-25 17:55阅读:109来源:国知局
相关申请的交叉引用本申请引用了由richardearnshaw、kristofbeyls、jamesgreenhalgh和scottdouglass发明并转让给armlimited的、于2018年7月6日提交的、gb1811154的“利用间接控制流指令进行推测(speculationwithindirectcontrolflowinstructions)”,其内容通过引用合并于此。本技术涉及数据处理。具体地,本技术与推测执行(speculativeexecution)领域相关。
背景技术
::推测执行是一种在知道是否应当执行一系列指令之前执行这些指令的技术。在稍后的某个时间点,确定是否应当执行推测执行的指令。如果是,则过程继续。如果否,则执行“倒退”。这种推测形式称为控制流推测。在某些情况下,已经发现这种推测执行会导致安全漏洞。例如,可以使处理器推测性地执行特权代码以将受保护的数据不必要地加载到缓存中。由于在倒退之后,可能无法清除缓存,因此可以使用边信道攻击来探查请求的数据。推测的另一种形式是数据值推测,其中在已知指令的所有输入之前推测指令产生的结果值。本技术认识到期望在发生控制流推测的地方保持数据安全。技术实现要素:从第一示例配置的角度来看,提供了一种装置,包括:输入电路,用于接收输入数据;输出电路,用于输出要由数据处理电路执行的指令序列;以及生成电路,用于执行生成过程以使用输入数据生成指令序列,其中,指令序列包括间接控制流指令,该间接控制流指令包括指示间接控制流指令的目标存储在哪里的字段;生成过程使得指令序列中的至少一条指令在执行间接控制流指令之后存储控制流推测的状态;并且数据处理电路禁止指令序列中存储控制流推测的状态的至少一条指令经受数据值推测。从第二示例配置的角度来看,提供了一种设备,包括:用于接收输入数据的装置;用于输出要由数据处理电路执行的指令序列的装置;以及用于执行生成过程以使用输入数据生成指令序列的装置,其中,指令序列包括间接控制流指令,该间接控制流指令包括指示间接控制流指令的目标存储在哪里的字段;生成过程使得指令序列中的至少一条指令在执行间接控制流指令之后存储控制流推测的状态;并且数据处理电路禁止指令序列中存储控制流推测的状态的至少一条指令经受数据值推测。从第三示例配置的角度来看,提供了一种方法,包括:接收输入数据;输出要由数据处理电路执行的指令序列;以及执行生成过程以使用输入数据生成指令序列,其中,指令序列包括间接控制流指令,该间接控制流指令包括指示间接控制流指令的目标存储在哪里的字段;生成过程使得指令序列中的至少一条指令在执行间接控制流指令之后存储控制流推测的状态;数据处理电路禁止指令序列中存储控制流推测的状态的至少一条指令经受数据值推测。从第四示例配置的角度来看,提供了一种可读存储介质,包括根据上述方法产生的计算机程序。附图说明将仅通过示例的方式,参考如附图所示的本技术的实施例来进一步描述本技术,其中:图1示出了根据一些实施例的装置;图2示出了分支指令的行为,并用于演示一种形式的推测执行;图3示出了条件选择指令的示例;图4a和图4b示出了根据一些实施例的将输入数据转换为包含数据值推测限制指令的输出指令序列,使得能够进行控制流未命中推测跟踪(miss-speculationtracking);图5a、图5b和图5c示出了根据一些实施例的将输入数据转换为包含跨功能调用边界的符合abi的控制流未命中推测跟踪的输出指令序列;图6示出了如何将几种涉及转换的技术结合起来;图7示出了根据一些实施例的装置;图8以流程图形式示出了根据一些实施例的数据处理方法;图9以流程图形式示出了根据一些实施例的数据处理方法;图10a示出了根据一些实施例的输入数据到输出指令序列的转换;图10b示出了根据一些实施例的输入数据到输出指令序列的转换;图11示意性地示出了根据一些实施例的代码块之间的关系;图12以流程图形式示出了根据一些实施例的数据处理方法;图13a示意性地示出了示例类层次(classhierarchy);图13b示意性地示出了基于参考图13a所示的示例类层次的vtable的生成;图14a示出了根据一些实施例的输入数据到输出指令序列的转换;图14b示出了根据一些实施例的输入数据到输出指令序列的转换;图14c示出了根据一些实施例的输入数据到输出指令序列的转换;图15a示意性地示出了根据一些实施例的具有虚拟功能包装器(wrapper)的代码块与用于生成针对虚拟功能调用的控制流推测成功的指示符的thunk之间的关系;图15b示意性地示出了根据一些实施例的具有虚拟功能包装器的代码块与用于生成针对虚拟功能调用的控制流推测成功的指示符的thunk之间的关系;以及图16以流程图形式示出了根据一些实施例的数据处理方法。在参考附图讨论实施例之前,提供以下实施例的描述和相关联的优点。具体实施方式根据一个方面,提供了一种装置,包括:输入电路,用于接收输入数据;输出电路,用于输出要由数据处理电路执行的指令序列;以及生成电路,用于执行生成过程以使用输入数据生成指令序列,其中,指令序列包括间接控制流指令,该间接控制流指令包括指示间接控制流指令的目标存储在哪里的字段;生成过程使得指令序列中的至少一条指令在执行间接控制流指令之后存储控制流推测的状态;并且数据处理电路禁止指令序列中存储控制流推测的状态的至少一条指令经受数据值推测。间接控制流指令可以被认为是以下指令:该指令不直接指示控制流应该到达的位置,而是通过指定能够找到控制流参数的位置(例如,地址)来间接指示这一点。这样的装置可以采取将输入指令转换为输出指令的编译器的形式。输入电路接收输入数据,而输出电路输出将由数据处理电路执行的指令序列。生成电路对输入数据执行生成过程,以便生成指令序列。生成过程使得输出的至少一条指令在执行指令时存储控制流推测的状态。这些一条或多条指令在执行了间接控制流指令之后发生,因此控制流推测的状态指示是否针对间接控制流指令发生了控制流推测。输入数据可以通过生成过程从第一语言翻译为第二语言,该第二语言可由数据处理电路(其可以是处理电路本身)执行。在其他实施例中,输入数据可以是与输出的指令序列相同的语言,并且生成过程可以使得添加附加指令以便建立控制流推测的状态。禁止可以通过例如提供“推测屏障(speculationbarrier)”来实现,该“推测屏障”禁止在另外的指令中使用推测的数据值,直到已经确定那些推测的数据值是正确的为止。如前所述,数据推测是一种用于估计数据值的技术。因此,通过在确定控制流推测的状态时禁止发生数据值推测,可以确定实际上是否应该遵循分支。在一些实施例中,控制流推测的状态指示控制流推测是否正确发生。在条件分支指令的情况下,可能会发生控制流推测,在这种情况下进行分支预测,以便确定在获取、解码和开始执行另外的指令方面,是否应该遵循分支以及将分支遵循到何处,直到该分支的结果是已知的为止。在这些实施例中,提供了指示推测是否正确发生的指令。在一些实施例中,指令序列中存储控制流推测的状态的至少一条指令适于使得数据处理电路执行比较并根据比较的结果来存储控制流推测的状态。执行比较以便确定控制流推测是否应该引起分支。然后对控制流推测的状态进行存储,以便可以在其他地方的其他计算中参考或使用它。在一些实施例中,输入数据包括多目标分支指令和变量;多目标分支指令的目标是基于该变量而确定的;并且指令序列在目标处包括指令序列中存储控制流推测的状态的至少一条指令。多目标分支指令是以下指令:它具有多个可能的“目标”,该多个可能的“目标”可以被表示为根据变量值执行的多个不同的指令块。在相应的指令序列中的每个“目标”处,对控制流推测的状态进行存储。存储控制流推测的状态的指令发生在可能进行了控制流推测的分支指令之后。因此,在发生了控制流推测的情况下,可以确定分支的决定(以及分支的目的地)是否正确。在一些实施例中,多目标分支指令的目标是通过基于变量来执行计算而确定的;以及比较在逻辑上与计算相对应。应当理解,如果由确定控制流推测的状态的指令执行的比较与对变量执行的计算相匹配,则控制流推测的状态匹配是否应该采用条件分支。在此,术语“在逻辑上与…相对应”是指对于计算和比较两者而言,存在从输入到输出的等效映射。在一些实施例中,对于变量的多个定义的可能值中的每一个,存在相关联的目标值;并且在每个目标处,比较确定变量的值是否对应于与该目标相关联的目标值。例如,当变量具有第一值时,目标是第一目标,当变量是第二值时,目标是第二目标,在第一目标处,比较确定值是否具有第一值,并且在第二目标处,比较确定值是否具有第二值。以这种方式,在每个目标处,控制流推测的状态可以用于指示该目标是否是应该已经发生了推测分支的正确目标。在一些实施例中,变量的定义的可能值的第一子集具有同一关联目标;并且在同一关联目标处,比较确定变量的值是否对应于与同一关联目标相关联的任何目标值。以这种方式,分支的每个可能的目标都不必唯一。实际上,在某些情况下,可能存在变量的多个值,而目标仍保持不变。在这些情况下,比较是这样进行的:比较检查变量是否持有能够将程序流带到当前目标的任何可能的变量值。这可以采取范围测试的形式(例如,变量x是否在两个极限之间,或者x是否小于一个值,或者大于另一值),或与一系列可能性进行比较(例如,使用布尔比较)等。在一些实施例中,变量的定义的可能值的第二子集具有不同关联目标;并且在不同关联目标中的每一个处,如果比较指示对应关系,则出现到公共功能的分支。在这些情况下,可以为每个可能的目标提供唯一的“包装器”,其中包装器对控制流推测的状态执行必要的确定。然后可以分支到不同的公共代码段。这使得可以具有多个公共代码段。在一些实施例中,响应于与计算相对应的比较的结果,控制流推测的状态指示控制流推测正确地发生。在一些实施例中,指令序列的至少一个子集遵循应用二进制接口;并且通过根据应用二进制接口在存储电路中存储非法值,在指令序列的功能之间保持所存储的控制流推测的状态。应用二进制接口(abi)指示软件应该如何使用硬件的某些元件。例如,abi可以规定调用约定(例如,如何将不同的值存储在寄存器和/或堆栈中以便执行功能调用或从功能调用返回)。因此,abi可以指示特定的寄存器应该/不应该存储特定的值。无论如何,在这样的实施例中,尽管abi被多个指令的至少一个子集所遵循,但是“非法”(例如,不允许的)值(根据abi是非法的)被存储在存储电路中,以便在功能之间保持控制流推测的状态。以这种方式,由于存储电路中“非法”值的存在应当没有影响,因此可以保持与现有系统的兼容性。在一些实施例中,响应于指示发生未命中推测的控制流推测的状态,将非法值存储在存储电路中。由于作为未命中推测的结果,预期将发生“倒退”,因此可以认为在倒退发生之前将非法值存储在存储电路中是可接受的。应注意,在一些其他实施例中,相反的情况可能是正确的,即,响应于指示未发生未命中推测的控制流推测的状态而存储非法值。在一些实施例中,存储电路包括堆栈指针寄存器;以及非法值为0。在一些abi中,堆栈指针寄存器(其可能用于指向存储器中存储前一堆栈帧末尾的地址)在功能调用中不允许为0。因此,通过将值0存储在堆栈指针寄存器中,可以指示已经发生未命中推测。另外,由于禁止在堆栈指针寄存器中存储该值,因此在此处存储该值不会产生整体效果。在一些实施例中,指令序列包括访问指令,该访问指令包括访问地址;以及访问指令的正确执行取决于控制流推测的状态。以这种方式,可以根据是否应该进行控制流推测来控制对数据的访问。在某些情况下,可以认为访问指令的正确执行是安全的,因为以这种方式可以禁止访问指令在不安全的情况下执行,例如在已经发生控制流未命中推测以及其中数据值被不当访问的情况下。这可以帮助防止特权数据泄漏,因为在发生未命中推测的情况下,实际上可能不会检索到该数据。在一些实施例中,指令序列包括在访问指令之前对访问地址执行操作、或对由访问指令从访问地址检索到的数据执行操作的指令;以及操作取决于控制流推测的状态。通过对取决于控制流推测的状态的地址或数据执行操作,可以根据控制流推测是否正确来影响该地址或数据。如果不适合进行访问,则可以“破坏”地址或数据。以这种方式,或者由于地址无效而没有发生访问,或者发生了访问但数据被无效,从而使其无法被其他指令使用。通过使得地址无效,数据本身不会被检索,这使得数据被不当访问变得更加困难。存在多种方法可以执行该操作。在一些实施例中,该操作是包括操作数的逻辑“与”操作;以及在控制流推测的状态指示发生未命中推测的情况下,操作数为0。因此,当发生了未命中推测时,执行“与”操作的结果是有效地使访问地址“无效”(为零),从而禁止了访问的发生。在根据控制流推测的状态未发生未命中推测的情况下,操作数可以全为1值(例如,存储在适当寄存器中的每个位均为1),使得与访问地址的“与”产生了访问地址本身。在一些实施例中,间接控制流指令是通过输入数据中的切换指令而生成的。切换指令用于根据变量值来指示许多不同的结果。例如,如果变量具有一个值,则执行一段代码,如果变量具有第二值,则执行另一段代码,依此类推。switch语句使得如果不满足任何一种情况,则可以指定要执行的默认代码。此外,可以将一些结果分组在一起,使得如果变量具有多个值之一,则执行一段代码。在一些实施例中,可以使用提供变量值和分支位置之间的映射的查找表来编译switch语句,以使执行分支的指令是间接的(以表查找的形式进行计算以便确定分支的目标)。现在将参考附图来描述特定实施例。图1示出了根据一些实施例的装置100。该装置可以例如采用用于执行指令的流水线形式。在图1的示例中,提供了指令获取器110。该指令获取器例如从存储器或从指令缓存中获取要执行的指令。然后,指令获取器将(一个或多个)获取的指令传递给指令解码器120,该指令解码器120对获取的指令进行解码并且为每个指令生成一个或多个控制信号。控制信号被传递到一个或多个预留站(reservationstation)130a-130d。每个预留站存储与由执行单元140a-140d执行的指令相对应的数据。每个预留站130对于解码指令而言充当队列,并且给定预留站130a中的解码指令可以由相应执行单元140a以任何顺序来处理。在此,执行单元140包括两个算术逻辑单元(alu)140a、140b,浮点单元140c以及加载/存储单元140d。解码指令被发送到适当的执行单元140。例如,浮点指令经由相应预留站130c被发送到浮点单元140c。图2示出了分支指令的行为,并用于演示一种形式的推测执行。具体地,第一组指令200包括分支指令a。这导致流程跳转到第二组指令210。在条件分支指令(具有与之相关联的条件的分支指令)的情况下,分支只有在满足该条件的情况下才会发生。如果分支发生,则执行将在分支指令b的目标处继续。在该示例中,这涉及到指令d、e、f、g和h的执行。指令h充当返回指令,其使得分支返回。流程然后返回到指令200的第一块中的指令c,在该指令c处执行恢复。在典型的执行中,指令获取器110需要一个处理器周期来获取指令,并且指令解码器需要另外的处理器周期来解码指令。该指令然后可以在预留站130中等待,直到已经获得了必要的数据为止。例如,如果指令对存储器中的数据进行操作,则可能要花费几个处理器周期才能从存储器中检索数据。一旦指令已经传递,则可能要花费另外的处理器周期在执行单元140处实际执行指令。为了有效地维护,典型的数据处理系统将继续同时操作(例如,获取、解码和执行)其他指令。在此,条件分支指令在理论上可能会引起问题,因为在实际评估条件之前,不知道接下来应当获取/解码/执行哪些指令。为了帮助解决该问题,进行了分支预测,并且假定该分支将朝一个特定方向前进。然后,获取/解码/执行在该方向上的指令。如果预测正确,则可以保持效率。如果不正确,则发生“倒退”,并且从正确的位置执行恢复。在这种情况下,与其中仅停止执行直到分支被执行的情况相比,不会浪费大量时间。这是推测执行的示例。因此,在图2的示例中,当到达a处的分支指令时,某些或全部的指令b-h(并且如果执行了h处的返回指令,甚至c指令)都可以在知道是否应该遵循a处的分支之前被执行。图3示出了条件选择指令300的示例。该指令包括目的地310(例如,寄存器x20)、第一源320(例如,特殊寄存器xzr,其总是包含值“0”)、第二源330(例如,寄存器x20)和条件340(例如,“ge”指示“设置了大于或等于标志”)。大于或等于标志可以被设置为前一指令将两个值进行比较的结果。替换地,在一些实施例中,组成条件选择指令的条件340可以包括直接比较两个值。如果未设置大于或等于标志,则执行该指令会使得值0(在xzr寄存器中)存储在寄存器x20中。否则(如果设置了大于或等于标志),则寄存器x20中的值将存储在寄存器x20中(即,寄存器x20的值保持不变)。应注意,如果条件选择指令中的条件340与条件分支指令的条件相对应,则可以使存储在寄存器x20中的值根据控制流推测执行是否正确发生而改变,如下所述。图4a示出了可以如何使用条件选择指令,以便通过将输入指令集400编译(例如,转换)为输出指令集410来确定是否已经发生未命中推测。应注意,输入指令400可以是一种语言,而输出指令410可以是旨在在诸如图1所示的数据处理电路100上执行的第二种语言。输入指令包含典型的条件分支场景。在该示例中,分支指令的条件420是设置了“大于或等于标志”。如果满足条件,则分支发生,跳转到目标标签bb2(其包括指令instr2)。否则,执行在标签bb1(其包括指令instr1)处继续。在输出指令中,寄存器x20最初加载了值“-1”。然后按照输入指令发生分支。如先前参考图3所述,在目标标签bb2处,发生了条件选择指令。然而,条件选择指令430的条件是分支指令中的条件420的逆——取决于“lt”(“小于”)标志被设置。因此,条件选择指令的条件与分支指令的条件相对应,因为它们各自依赖于相同的测试,并且仅根据可能的结果而采取不同的动作。然后执行分支bb2的其余指令(包括instr2)。类似地,在分支bb1处,发生条件选择指令440。如果不遵循分支指令420,则执行该代码。在这种情况下,条件选择指令440中的条件与分支指令420的条件相同。以这种方式,在分支bb1处,寄存器x20中的值将保持不变(“-1”)或将其更改为(“0”)。由于每个条件选择指令430、440中的条件420与到达包含该条件选择指令的目标所需的分支指令420中的条件相反,因此仅在发生了未命中推测时才改变寄存器x20的值。否则,寄存器x20将保持不变。例如,假设推测发生在bb2处。如果设置了“ge”标志,这将被证明是正确的。在此,条件选择指令420确定是否设置了“lt”标志。假设“ge”和“lt”标志是互斥的,如果满足分支指令420中的条件(即,如果正确地发生了推测),则条件选择指令420将使得寄存器x20中的值保持不变(例如,通过将寄存器x20中的值移动到寄存器x20)并且在bb1处对于条件选择指令440而言是类似的。在每种情况下,如果正确地推测了分支,则寄存器x20将保持值“-1”。在该示例中,csdb指令禁止在csdb指令之后执行的任何指令观察到可能发生在csel指令上的数据值推测。这使得寄存器x20中的值准确地表示了在执行了csdb之后执行的指令的控制流预测的正确性。csdb指令是一种特殊的指令,用于禁止在csdb指令之后执行的指令看到在csdb指令之前发生的数据值未命中推测。因此,建立了csel指令的实际结果,而不是通过数据值推测来对其进行估计。当然,如果发生了未命中推测,则在将来的某个时间点处,将发生“倒退”。然而,直到那时,了解发生了控制流未命中推测以便防止特权数据泄漏是有用的。应当理解,在相关示例中,如果推测正确发生,则可以进行改变以发生,并且如果分支被未命中推测,则可以保持不变。类似地,应当理解,可以为每个结果任意选择特定值(例如,“0”和“-1”)。图4b示出了可以如何使用条件选择指令产生的输出来保护对特定数据的访问。这里假设寄存器x20包含推测是正确发生(全为1)还是不正确发生(全为0)的指示。在输入数据450中,进行加载以获得存储在以下存储器中的数据:该存储器的存储器地址被存储在寄存器x1中。数据被加载到寄存器x0中。在此,存储在寄存器x1中的存储器地址被认为包含特权信息,因为它与安全数据有关。因此,希望在发生控制流未命中推测时(即,当程序员不打算加载该数据时)不使数据被记载到寄存器x0中。输出数据460对寄存器x1中的存储器地址与存储在寄存器x20中的值执行逻辑“与”操作。在控制流未命中推测的情况下,这导致x1的值为0,因此从地址0而不是特权数据的地址加载负载。最后,加载发生在现在存储在寄存器x1中的存储器地址上。如果发生了未命中推测,则将寄存器x20中的所有0值进行逻辑“与”操作将导致寄存器x1中的存储器地址被擦除,从而防止加载指令对其进行访问。如果推测正确发生,则逻辑“与”操作将值单独保留在寄存器x20中,从而允许加载指令对其进行访问。因此,可以保护加载,以便仅在正确执行推测的情况下才会发生加载。应注意,csdb指令可以放置在寄存器x20上的最后csel操作和“与”指令中首次使用寄存器x20之间的任何位置,以便保护加载特权数据的加载指令。对于指示是否发生未命中推测在整个功能调用中持续存在的指示是理想的。图5a、图5b和图5c示出了如何执行进一步的转换,以便使得未命中推测指示符能够在功能调用中持续存在。在这些示例中,假设输出指令510、530、550遵循应用二进制接口(abi)。这决定了底层软件应当如何利用硬件。例如,它可能会规定指定应当如何实现功能调用的调用约定——例如,应当用于将参数传递给被调用功能的寄存器,应当如何将结果传递回,应当如何以及何时更改程序计数器和堆栈指针等。在本示例中,假设(通常是这种情况)abi禁止跨功能将值“0”存储在堆栈指针中(例如,在调用或返回期间)。因此,通过将值“0”存储在堆栈指针中,可以提供向后兼容的系统,该向后兼容的系统可以跨功能传送以下事实:控制流推测已经正确发生或未命中推测已经发生。由于这使用了abi禁止的寄存器中的值,因此它不会对任何现有系统造成问题。换句话说,在堆栈指针寄存器中存在“0”应该不起作用。本示例使用值“0”来表示已经发生未命中推测的事实。此外,与先前使用的寄存器x20相反,本示例使用寄存器ip1在功能之内存储指示是否发生了未命中推测的值。图5a示出了如何将输入指令500中的功能调用转换为执行功能调用的输出指令510。输出指令将当前堆栈指针移到临时寄存器ip0中。然后在ip0中的堆栈指针值与包含控制流未命中推测值的寄存器ip1的值之间执行逻辑“与”操作(如果正确地推测了控制流,则全为1,而如果不正确地推测了控制流,则为0),并且结果被存储在临时寄存器ip0中。该“与”操作导致ip0包含堆栈指针的值(在正确的控制流推测的情况下)或0(在不正确的控制流推测的情况下)。然后将结果存储回堆栈指针。某些架构禁止直接在堆栈指针上进行算术/逻辑操作。在该示例中,mov指令将堆栈指针的值移动到临时寄存器以允许对其进行更改。在允许直接在堆栈指针上进行操作的其他架构上,当直接发生控制流未命中推测而无需mov指令时,可以将堆栈指针的值设置为0。然后执行分支链接(branch-and-link)指令,这将导致对标签“被调用者”的无条件功能调用的发生。应注意,分支链接指令不是条件分支指令,因此不会由于该分支链接指令本身而发生未命中推测。然而,由于发生了未命中推测,因此可能已经输入了包含该分支链接指令的功能。本技术使得可以跨功能维持控制流推测的状态,因此在从该分支链接指令输入的功能中,可以知道是否已经发生了未命中推测(来自先前的条件分支指令,未示出)。图5b示出了被调用者标签处的行为。在输入指令520中,这将仅包括标签“被调用者(callee):”。在由此生成的输出指令530中(例如,通过编译或转换),在堆栈指针和值“0”之间进行比较,随后是条件选择指令。当堆栈指针为零时,即当发生了控制流未命中推测时,该代码序列将使得寄存器ip1包含全零。如果在此之前未发生控制流未命中推测,则堆栈指针将具有非零值,并且该代码序列将使得ip1包含全为“1”值。这样,通过使用堆栈指针中的abi非法值“0”,ip1的值已经从对“被调用者”的功能调用之前转移到了功能“被调用者”。图5c示出了使得从功能调用返回的返回指令处的行为。在输入指令540中,这将仅包括指令“ret”。在由此生成的输出指令550中(例如,通过编译或转换),堆栈指针被移入临时寄存器ip0。然后对ip0和ip1的内容执行逻辑“与”操作。最后,将结果移回堆栈指针,并且发生返回到调用者。如上所述,使用临时寄存器ip0以便对存储在堆栈指针中的值执行操作。再次参考图5a,输出指令510的最后两行指示返回后在调用者处发生了什么。具体地,将堆栈指针再次与值“0”进行比较。如果堆栈指针等于“0”,则将“0”存储在ip1中(即,指示发生了控制流未命中推测),否则csetm指令将全为1的值存储在寄存器ip1中。组合的图5a、图5b和图5c示出了如何通过使用堆栈指针的abi非法值来跨功能调用边界传送寄存器ip1中的控制流未命中推测值。图6示出了几种技术可以如何组合。在此,输入数据580导致分支到标签“function”。在标签“function”处,保存在存储器中的值随后被加载到寄存器x0中,该存储器的地址在寄存器x1中列出。然后在返回之前执行指令“instr1”。在输出数据590中,寄存器ip1在功能内再次用于表示控制流未命中推测是否已经发生。通过将值放入堆栈指针而在功能之间传递该值。在发生未命中推测的情况下,ip1中的值为“0”,否则全为1值。对于堆栈指针,当发生未命中推测时,值为“0”,否则为未更改的堆栈指针值(abi规则禁止其为“0”)。如上所述,堆栈指针被移入寄存器ip0,以便可以对其进行调整。然后将其与ip1的当前值进行“与”操作,并且移回到堆栈指针。在此阶段,堆栈指针现在将反映控制流推测的状态。然后发生功能调用(bl指令)。在功能“function”处,控制流推测的状态被转移回ip1。如上所述,如果控制流推测已经正确发生,则寄存器“x1”中的访问地址将保持不变,否则该值将“损坏”,从而阻止访问。在“与”指令之前的csdb指令意味着ip1的值将不是此时推测的数据值(未命中),因此当控制流未命中推测发生时,x1中的地址将被破坏。然后执行指令“instr1”。最后,控制流推测的状态在返回之前被存储回堆栈指针。在返回调用功能时,堆栈指针中的控制流未命中推测指示(“0”表示未命中推测,任何非零值用于正确推测)被转换回寄存器ip1(“0”表示未命中推测,全为1表示正确推测),并且其余指令继续执行(在图6中示出为“…”)。图7示出了根据一些实施例的用于从输入数据产生输出指令的装置600。该装置包括接收输入数据(其可以是指令的形式,也许是与输出指令不同的语言)的输入电路610。输入电路将这些指令传递到生成电路620,该生成电路620生成输出指令序列。该输出指令序列是基于输入指令的。在该示例中,输出指令将实现与输入指令相同的效果,但是将添加另外的指令(具有对数据值推测添加的至少一些限制),从而导致在寄存器中跟踪控制流未命中推测,例如针对图4a、图4b、图5a、图5b和图5c中的一些或全部进行示范的。输出指令然后由输出电路630输出。由输出电路630输出的指令序列被设计为在处理电路100上执行。指令序列使得,除了一个特定的例外之外,它们实现了abi。一个例外是,对于诸如堆栈指针寄存器之类的存储电路640,实际上是将被禁止跨功能调用存储在存储电路中的值跨功能调用存储在该存储电路中,以便表示发生(或未发生)未命中推测的事实。图8示出了根据一些实施例的数据处理方法。该方法以流程图700的形式示出,并且例如可以由如图1所示的数据处理装置100执行。在步骤710,对指令进行解码并生成控制信号。在步骤720,控制信号用于执行一个或多个数据处理操作。在步骤730,确定是否以某种方式标记了与数据处理操作相对应的控制信号(并因此对相应指令进行了标记),以禁止对那些指令执行数据值推测。如果否,则在步骤740允许对于那些数据处理操作的推测。否则,在步骤750,禁止对于那些指令的推测。图9示出了根据一些实施例的数据处理方法。该方法以流程图800的形式示出,并且例如可以使用如图7所示的装置600来执行。在步骤810,接收输入数据。在步骤820,执行生成过程。这可以与关于图4a、图4b、图5a、图5b和图5c示出的一些或全部过程相对应。一个或多个输出指令使得控制流推测的状态在执行期间被存储。最后,在步骤830输出生成过程的输出(输出指令序列)。图10a示出了如何相对于间接控制流指令来使用本技术。间接控制流指令是其中必须计算(例如,查找或数学确定)控制流指令的目标而不是形成指令本身的部分的指令。采用这种机制的部分原因是要避免直接分支指令的复杂结构。例如,如果必须将变量与多个不同的值进行比较,并根据每次比较来执行不同的代码,则可能需要花费一些时间来执行以下一系列指令:该指令将变量与第一值、接着第二值、接着第三值等进行比较以确定可以在哪里找到要执行的代码。作为其替代方案,可以执行查找表或计算以便直接确定可以在哪里找到要执行的代码。图10a示出了包括switch语句的输入代码900的示例。在这种情况下,switch语句具有变量“i”,并且根据“i”的值来执行不同的代码。例如,如果i=0,则代码“x=2;…;break”被执行。如果i=1,则代码“x=3;…;break”被执行等。尽管很可能使用直接分支指令来实现该简短的代码片段,但是可以使用输出指令920中的间接控制流指令910来实现(并且我们将假设出于该示例的目的来实现)。此处,间接控制流指令910采用“switch<expr>”指令的形式,该指令在程序中向前跳由表达式<expr>确定的行数。此处,表达式使用基于值i的映射,并且该映射使得如果i=0则程序向前跳2行,如果i=1则程序向前跳4行,如果i=2则程序向前跳6行,以及如果i=3则程序向前跳8行。例如,如果i=3则程序向前跳8行,并因此执行“sstate&=-(i==3);x=7;…;break”。break语句使得该块退出。与参考图4a所示的示例不同,switch语句等效于对变量i和不同目标执行多次不同的比较,以用于不同结果。因此,基于针对每个目标的不同比较来确定输出指令920中的控制流推测的状态(由变量sstate表示)。每个目标处的比较“模仿”了switch语句中将通往该目标的比较。例如,当i=1时,控制流在第6行结束(使得它从第2行向前跳4行)。因此,通过比较变量i以确定其是否为1来确定第6行的控制流推测的状态。如果是,则sstate变为-1(全为1)。如果不是,则sstate变为0。与前面的示例一样,可以在过程的后面使用csdb指令,以便保护可能容易受到例如边信道攻击的变量。此外,根据前面的示例,以sstate存储的值可以用于控制对访问地址或从该访问地址检索的数据的访问(例如,通过对这些项之一和sstate的值执行逻辑“与”),以便如果sstate指示不应发生控制流推测,则访问地址或数据值将变为零。指示控制值推测是否应该发生的值也可以使用例如前面示出的堆栈指针来在功能之间传送。图10b示出了一种其中i的可能值的子集指向同一目标的变体。例如,输入指令930使得如果i为0或1,则执行代码“x=3;break;”,如果i为2或3,则执行代码“x=7;break;”。在输出指令950中,间接控制流指令940提供了新的修订映射。然而,执行比较以确定控制流推测的状态已进行调整,以检查变量是否为导致特定目标的任何值。例如,如果i为0或1,则可以到达第5行的代码。因此,如果i等于0或1,则在第5行的代码中执行的比较将控制流推测的状态设置为-1(全为1),否则将其设置为0。显然,其他比较也是可能的。例如,如果值0-3中的任何一个导致要分支的目标,则该目标处的比较可以检查i是否在>=0和<=3的范围内。应理解,在这些示例中,间接控制流指令已经用伪代码表示。然而,很明显,如本领域技术人员所知,可以通过间接分支指令和查找表的方式来复制由usemap(<indexvariable>,<mapping>)执行的查找功能。变量和目标之间的关系可能更复杂。图11示出了实际上允许实现目标和变量的任何组合的数据流的示例。在块1010中,基于变量i来执行间接控制流指令。根据i的值,执行不同的块1020、1030、1040、1050以便设置sstate。然后,每个块分支到公共代码块1060。以这种方式,可以对每个可能的目标执行适当的比较,而不管变量值和目标之间的关系的复杂性如何。图12以流程图1100的形式示出了根据一些实施例的方法,并且可以使用例如图7中示出的装置600来示出。在步骤1110,接收输入数据。在步骤1120,执行生成过程。参考图10a、图10b和图11示出的过程可以对应于参考图4a、图4b、图5a、图5b和图5c描述的一些技术。一个或多个输出指令会在执行间接控制流指令之后的执行期间存储控制流推测的状态。最后,在步骤1130输出生成过程的输出(输出指令序列)。本技术还可以用于例如具有虚拟功能调用的关于覆写的继承功能。图13a示出了可以例如以面向对象的编程语言来实现的示例类结构1200。提供了基类person,其实现了两个可覆写的功能——getname和getincome。类person具有两个子类——employee和pensioner。这两个类都覆写了基本方法getincome,从而提供了自己的该方法的实现方式。类结构使得对于employee类型的对象,当调用方法getincome时,将调用作为employee定义的部分提供的getincome的实现方式。当在pensioner类型的对象上调用getincome方法时,将调用作为pensioner定义的部分提供的getincome的实现方式。相反,由于这两个类都不提供getname方法的实现方式,因此当任一类的对象调用功能getname时,这将导致调用person类的部分的getname实现方式。图13b示出了基于关于图13a所示的类结构生成的vtable结构1240。为person对象生成的vtable1250包括分别指向getname和getincome的基本实现方式的指针。employeevtable1260包括指向getname的person实现方式的指针和指向getincome的employee实现方式的指针。同时,pensionervtable1270包括指向person的getname实现方式和pensioner自己的getincome实现方式的指针。给定的程序可以在person类型的许多不同对象上调用getincome功能。由于类结构的原因,因此每个对象可以是person类型的,也可以是employee类型或pensioner类型的(由于这些类因为是person的子类而也是person类型)。因此,在提供了许多完全相同类的对象之后,分支预测电路可以被训练为分支到其中提供了getincome的一种实现方式的特定地址。当提供了属于其他类别之一的对象时,这可能导致控制流未命中推测。例如,如果前几个对象都是employee类型的,则可以训练分支预测器以分支到getincome的employee实现方式。然而,如果下一对象是pensioner类型的,则受过训练的分支预测器将未命中推测并分支到getincome的employee实现方式而不是getincome的pensioner实现方式。图14a示出了其中代码被转换以实现这种虚拟功能调用的典型方式。可以提供包含功能调用“person.getincome()”的输入数据,该输入数据使得在名称为“person”的对象(大概是person类型)上调用方法getincome()。隐式地,这等效于调用getincome(person)以用于针对person类提供的getincome的实现方式。在实践中,输出指令获取指针thispointer,该指针指向对象本身的当前实例。这将添加到对象内部的vtable指针的预定义偏移量。然后将指针取消引用并存储在寄存器x1中。因此,寄存器x1有效地存储了变量“person”的vtable的地址。然后,下一行确定指向getincome功能的指针的偏移量,并将其与存储在x1中的值相加,并将结果存储回x1。然后,寄存器x1存储getincome方法的位置,其存储在变量“person”的vtable中。最后,使用x1调用分支链接指令,以便分支到变量“person”的getincome方法的实现方式的位置。图14b示出了可以如何更改该转换,以便帮助提供指示有关此类功能调用的控制流推测的状态的变量。这次,不是确定指向功能getincome的指针,而是确定指向功能“vfunc_validate_pensioner_getincome”的指针。功能“vfunc_validate_pensioner_getincome”是以下特殊功能:其由生成过程生成,以便在传递给getincome方法的实际实现方式之前确定控制流推测的状态。图14c示出了如何针对生成过程更改getincome方法的实现方式。如上所述,提供了查找操作。这确定了vtable的地址,以便确定由指向当前变量的vfunc_validate_pensioner_getincome方法的指针所指向的地址(由指针thisptr引用)。adr指令直接获取与功能vfunc_validate_pensioner_getincome相关联的地址。然后通过cmp指令来比较这些位置。然后,可以将该比较的结果作为条件选择指令csel的对象,以便反映控制流推测是否正确发生(如前所述)。此外,如前所述,其结果存储在堆栈指针中,以便可以在功能之间传递。最后,分支到pensioner_getincome的实际实现方式。因此,通过将旨在调用的功能(其可以由于在进行功能调用时隐式传递“this”对象来确定)与实际调用的功能(其可以从adr指令确定)进行比较,可以比较应该调用的功能实际上是否被调用,从而可以反映控制流推测是由于虚拟功能调用而正确发生还是不正确发生。图15a示出了在其中使用thunk来处理多种继承的情况下可以如何扩展过程,这种情况在几种面向对象的语言(例如,c++)中使用。在这些情况下,在第一代码块1300中进行初始查找和功能调用。这导致包装器1320被调用,该包装器检查控制值推测是否正确发生。该包装器存储了指示在跳转到thunk1340之前推测是否正确发生的状态。thunk1340随后进行任何必要的校正,以便处理多重继承。最后,thunk跳转到该功能的实际实现方式1360。当实现方式1360返回时,它返回到主代码块1300。应当理解,存在许多不同的入口点。第一入口点1310在包装器块1320的起点处。第二入口点1330在thunk块1340的起点处,而第三入口点1350在实现方式块1360的起点处。根据要执行的初始化量,可以使用入口点1310、1330、1350中的每一个。例如,如果不执行未命中推测检查,则可以使用第二入口点1330。本领域技术人员应当理解,在某些情况下(例如,在不使用多重继承的情况下)可以省略thunk。在这种情况下,包装器块1320将直接跳转到实现方式块1360的入口点1350。图15b示出了另一实现方式。在这种情况下,不是提供完整的链,而是主代码块1370调用包装器块1380。该包装器块1380执行检查并存储指示控制流推测是否正确发生的状态。然后,该相同的功能执行thunk1340的功能。然后,在返回主代码块1370之前,该相同的功能执行实现方式1360。在该示例中,包装器块再次包含多个入口点。在存储控制流推测的状态的代码的起点处提供了第一入口点1385。在处理多个继承的代码的起点处提供了第二入口点1390。在执行该实现方式的代码的起点处提供了第三入口点1395。图16示出了根据一些实施例的数据处理方法。该方法以流程图1500的形式示出,并且可以例如使用如图7所示的装置600来执行。在步骤1510,接收输入数据。在步骤1520,执行生成过程。例如,这可以对应于针对图14a、图14b或图14c中的任何一个示出的过程,并且可以与针对图4a、图4b、图5a、图5b和图5c示出的一些或全部技术相结合。在执行了其目标是功能(例如,虚拟功能)的间接控制流指令之后,一个或多个输出指令使得在执行期间存储控制流推测的状态。最后,在步骤1530输出生成过程的输出。该装置还可以以多种其他方式配置。在一些实施例中,提供了一种装置,包括:输入电路,用于接收输入数据;输出电路,用于输出要由数据处理电路执行的指令序列,至少一些指令被分组为功能;以及生成电路,用于执行生成过程以使用输入数据生成指令序列,其中,生成过程使得指令序列中的至少一条指令存储在执行指令序列期间执行的控制流推测的状态;以及在功能之间保持控制流推测的存储状态。这样的装置可以采取将输入指令转换为输出指令的编译器的形式。输入电路接收输入数据,而输出电路输出将由数据处理电路执行的指令序列。生成电路对输入数据执行生成过程,以便生成指令序列。生成过程使得输出的至少一条指令在执行指令时存储控制流推测的状态。在功能之间保持这种状态,例如在功能调用期间以及从功能调用返回时。在这种情况下,可能会在另一功能中访问在一个功能中建立的推测状态。输入数据可以通过生成过程从第一语言翻译为第二语言,该第二语言可由数据处理电路(其可以是处理电路本身)执行。在其他实施例中,输入数据可以是与输出的指令序列相同的语言,并且生成过程可以使得添加附加指令以便建立控制流推测的状态。在一些实施例中,控制流推测的状态指示控制流推测是否正确发生。在条件分支指令的情况下,可能会发生控制流推测,在这种情况下进行分支预测,以便确定在获取、解码和开始执行另外的指令方面,是否应该遵循分支,直到该分支的结果是已知的为止。在这些实施例中,提供了指示推测是否正确发生的指令。在一些实施例中,数据处理电路禁止指令序列中存储控制流推测的状态的至少一条指令经受数据值推测。该禁止可以通过例如提供“推测屏障”来实现,该“推测屏障”禁止在另外的指令中使用推测的数据值,直到已经确定那些推测的数据值是正确的为止。如前所述,数据推测是一种用于估计数据值的技术。因此,通过在确定控制流推测的状态时禁止发生数据值推测,可以确定实际上是否应该遵循分支。在一些实施例中,指令序列中存储控制流推测的状态的至少一条指令适于使得数据处理电路执行比较并根据比较的结果来存储控制流推测的状态。执行比较以便确定控制流推测是否应该引起分支。然后对控制流推测的状态进行存储,以便可以在其他地方的其他计算中参考或使用它。在一些实施例中,输入数据包括条件分支指令,该条件分支指令包括条件和在满足该条件时分支到的目标;以及指令序列,该指令序列在目标处包括指令序列中存储控制流推测的状态的至少一条指令。存储控制流推测的状态的指令发生在可能进行了控制流推测的分支指令之后。因此,在发生了控制流推测的情况下,可以确定分支的决定是否正确。在一些实施例中,比较在逻辑上与条件相对应。应当理解,如果由指令执行的比较确定控制流推测的状态与条件分支指令中的条件相匹配,则控制流推测的状态与是否应当采取条件分支相匹配。在此,术语“在逻辑上与…相对应”是指条件和比较具有逻辑上的等价关系。如本领域技术人员将知道的,这可以使用布尔真值表来建立。在一些实施例中,响应于与条件未满足相对应的比较结果,控制流推测的状态指示控制流推测不正确地发生。在一些实施例中,指令序列的至少一个子集遵循应用二进制接口;并且通过根据应用二进制接口在存储电路中存储非法值,在功能之间保持所存储得控制流推测的状态。应用二进制接口(abi)指示软件应该如何使用硬件的某些元件。例如,abi可以规定调用约定(例如,如何将不同的值存储在寄存器和/或堆栈中以便执行功能调用或从功能调用返回)。因此,abi可以指示特定的寄存器应该/不应该存储特定的值。无论如何,在这样的实施例中,尽管abi被多个指令的至少一个子集所遵循,但是“非法”(例如,不允许的)值(根据abi是非法的)被存储在存储电路中,以便在功能之间保持控制流推测的状态。以这种方式,由于存储电路中“非法”值的存在应当没有影响,因此可以保持与现有系统的兼容性。在一些实施例中,通过根据应用二进制接口来存储合法值,在至少一些功能值内维持控制流推测的存储状态。在一些实施例中,合法值被存储在与非法值被存储的相同的存储电路中、功能之间。然而,在一些实施例中,合法值被存储在不同的存储电路中、功能之内。在一些实施例中,响应于指示发生未命中推测的控制流推测的状态,而将非法值存储在存储电路中。由于作为未命中推测的结果,预期将发生“倒退”,因此可以认为在倒退发生之前将非法值存储在存储电路中是可接受的。应注意,在一些其他实施例中,相反的情况可能是正确的,即,响应于指示未发生未命中推测的控制流推测的状态而存储非法值。在一些实施例中,存储电路包括寄存器。例如,在一些实施例中,存储电路包括堆栈指针寄存器;以及非法值为0。在一些abi中,堆栈指针寄存器(其可能用于指向存储器中存储前一堆栈帧末尾的地址)在功能调用中不允许为0。因此,通过将值0存储在堆栈指针寄存器中,可以指示已经发生未命中推测。另外,由于禁止在堆栈指针寄存器中存储该值,因此在此处存储该值不会产生整体效果。在一些实施例中,指令序列包括访问指令,该访问指令包括访问地址;以及访问指令的正确执行取决于控制流推测的状态。以这种方式,可以根据是否应该进行控制流推测来控制对数据的访问。在某些情况下,可以认为访问指令的正确执行是安全的,因为以这种方式可以禁止访问指令在不安全的情况下执行,例如在已经发生控制流未命中推测以及其中数据值被不当访问的情况下。这可以帮助防止特权数据泄漏,因为在发生未命中推测的情况下,实际上可能不会检索到该数据。在一些实施例中,指令序列包括在访问指令之前对访问地址执行操作的指令;以及操作取决于控制流推测的状态。通过对取决于控制流推测的状态的地址执行操作,可以根据控制流推测是否正确来影响该地址。如果不适合进行访问,则可以“破坏”地址,使得不会发生访问,从而阻止了数据的检索。存在多种方法可以执行该操作。在一些实施例中,该操作是逻辑“与”操作,包括操作数;以及在控制流推测的状态指示发生未命中推测的情况下,操作数为0。因此,当发生了未命中推测时,执行“与”操作的结果是有效地“无效化”(零)访问地址,从而禁止了访问的发生。在根据控制流推测的状态未发生未命中推测的情况下,操作数可以全为1值(例如,存储在适当寄存器中的每个位均为1),使得与访问地址的“与”产生了访问地址本身。保护数据的另一种方法是在检索到数据之后对数据本身执行操作。因此,在一些实施例中,指令序列包括对由访问指令从访问地址检索的数据执行操作的指令;以及操作取决于控制流推测的状态。再次,例如,在一些实施例中,操作是包括操作数的逻辑“与”操作;以及在其中控制流推测的状态指示发生了未命中推测的情况下,操作数为0。因此,在检索到数据之后,如果指示发生了未命中推测,则其将立即被使数据无效(为零)的“与”操作所影响。在本申请中,词语“被配置为…”用来表示装置的元件具有能够执行所定义的操作的配置。在本文中,“配置”是指硬件或软件的互连的布置或方式。例如,装置可以具有提供所定义的操作的专用硬件,或者可以被编程以执行功能的处理器或其他处理设备。“被配置为”并不意味着需要以任何方式改变装置元件以便提供所定义的操作。尽管本文已经参考附图详细描述了本发明的说明性实施例,但是应当理解,本发明不限于那些精确的实施例,并且在不脱离由所附权利要求限定的本发明的范围和精神的情况下,本领域技术人员可以在其中进行各种改变、增加和修改。例如,在不脱离本发明的范围的情况下,可以将从属权利要求的特征与独立权利要求的特征进行各种组合。当前第1页12当前第1页12
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1