use*_*550 5 c arm volatile armcc
考虑以下代码:
volatile int status;
status = process_package_header(&pack_header, PACK_INFO_CONST);
if ((((status) == (SUCCESS_CONST)) ? ((random_delay() && ((SUCCESS_CONST) == (status))) ? 0 : side_channel_sttack_detected()) : 1))
{
...
}
Run Code Online (Sandbox Code Playgroud)
它生成此机器代码(使用工具链的objdump生成):
60: f7ff fffe bl 0 <process_package_header>
64: 9000 str r0, [sp, #0] /* <- storing to memory as status is volatile */
66: 42a0 cmp r0, r4 /* <- where is the load before compare? status is volatile, it could have change between the last store instruction (above line) and now */
68: d164 bne.n 134 <func+0x134>
6a: f7ff fffe bl 0 <random_delay>
Run Code Online (Sandbox Code Playgroud)
现在,由于它是易失性的,因此当到达语句status时应该已经从内存中读取它。if我希望在将它 ( cmp) 与进行比较之前看到一些加载命令SUCCESS_CONST,无论它被分配了函数的返回值process_package_header()并存储在内存中,因为它是易失性的并且可以在指令与指令status之间更改。strcmp
请尝试忽略该if条件的动机,其目的是尝试检测对 CPU 的物理攻击,其中条件标志和寄存器可以通过物理设备从外部更改。
工具链ARM DS-5_v5.27.0arm编译器:ARMCompiler5.06u5(armcc)
目标是 ARM CortexM0+ CPU
管理对象的主要规则volatile是这样的,来自C11 6.7.3/7:
任何引用此类对象的表达式都应严格根据抽象机的规则进行计算,如 5.1.2.3 中所述。此外,在每个序列点,最后存储在对象中的值应与抽象机规定的值一致,除非被前面提到的未知因素修改。
它接着说
对具有 volatile 限定类型的对象的访问是由实现定义的。
,这适用于如何解释其他规则(例如 5.1.2.3 中的规则)。您的编译器的用户指南讨论了易失性访问的详细信息,但那里似乎没有什么令人惊讶的。5.1.2.3节本身主要讲的是排序规则;评估表达式的规则在其他地方(但仍然必须遵循有关访问 易失性对象的给定规则)。
以下是抽象机行为的相关细节:
赋值操作有一个副作用,即在由 标识的对象中存储值status。该语句末尾有一个序列点,因此
status是 易失性的,所以该行表示的赋值是程序在序列点之前执行的最后一次写入。statusif接下来评估语句中的条件表达式,其中
(status) == (SUCCESS_CONST),然后再计算任何其他子表达式。status发生在操作评估之前==,并且status值执行任何操作,必须首先读取该值。 该标准不要求易失性对象驻留在可寻址存储中,因此原则上,您的易失性自动变量可以专门分配给寄存器。在这种情况下,只要使用该对象的机器指令直接从其寄存器读取其值或直接对其寄存器进行更新,就不需要单独的加载或存储来实现正确的易失性语义。但是,您的特定对象似乎不属于此类别,因为生成的程序集中的存储指令似乎表明它确实与内存中的某个位置相关联。
此外,如果程序正确地为分配给寄存器的对象实现了易失性语义,则该寄存器必须是 r0。我不熟悉这种汇编语言的细节以及运行代码的处理器,但看起来 r0 显然不是此类存储的可行位置。
在这种情况下,我同意status应该从内存中读回,如果需要评估它在条件表达式中的第二次出现,则应该再次从内存中读回。这是抽象机的行为,对于所有易失性访问,一致的实现都会表现出这种行为。那么,我的分析是,您的实现在这方面不符合要求,我倾向于将其报告为错误。
至于解决方法,我认为最好的选择是在汇编中编写重要的部分 - 如果您的实现支持内联汇编,或者如果需要,作为在汇编中实现的完整函数。
| 归档时间: |
|
| 查看次数: |
591 次 |
| 最近记录: |