为了减轻堆栈溢出的可能性,我想在输入永不返回的函数后重设堆栈指针。在我的代码中有两种情况发生,即main()和shutdown_immediate()ISR,ISR将数据保存到闪存并进入深度睡眠。我使用LTO来使代码适合,因此main()最终是一个很大的函数,需要为局部变量分配部分堆栈。
我的第一个尝试是结合使用__attribute__ ((noreturn))
和对__builtin_unreachable()
的调用,但这并不会以任何方式更改生成的程序集。然后,我创建了一个内联汇编函数,以将堆栈指针重置为最后一个SRAM地址,该地址在main()和shutdown_immediate()处理程序中称为first。
inline __attribute__((always_inline)) void NO_RETURN (void)
{
extern const uint32_t __stack_top__; // Defined in .ld file
asm volatile ("ldr r3, %[stack_top]\n"
"mov sp, r3\n"
: /* no outputs */
: [stack_top] "m" (__stack_top__)
: /* no clobbers */
);
}
int main (void)
{
NO_RETURN();
/* rest of the code here... */
}
void shutdown_immediate (void)
{
NO_RETURN();
}
这会为ISR生成看似正确的代码。对于main()
,mov sp, r3
发生在之后堆栈被分配给局部变量等。一旦主分支开始分支,这将失败。
生成的汇编代码:
00007f60 <shutdown_immediate>:
7f60: b570 push {r4, r5, r6, lr}
7f62: 4b21 ldr r3, [pc, #132] ; (7fe8 <shutdown_immediate+0x88>)
7f64: 681b ldr r3, [r3, #0]
7f66: 469d mov sp, r3
; ...
7fe8: 00202000 eoreq r2, r0, r0 ; last SRAM address
00001180 <main>:
1180: b5f0 push {r4, r5, r6, r7, lr}
1182: 4be7 ldr r3, [pc, #924] ; (1520 <main+0x3a0>)
1184: b097 sub sp, #92 ; 0x5c ; This SUB must be _after_ 0x1188!
1186: 681b ldr r3, [r3, #0]
1188: 469d mov sp, r3
; ...
1520: 00202000 eoreq r2, r0, r0 ; Last SRAM address
有人能正确完成此操作吗?我总是可以创建NO_RETURN()
函数的第二个变量,该变量将堆栈分配值作为参数,进行编译,反汇编,再次编译,并在sub sp, #nn
之后插入所需的mov sp, r3
,但是是一个混乱的解决方案。
架构:Cortex-M0
已测试的工具链:
答案 0 :(得分:0)
最可靠的解决方案是在汇编中实现$stmt->bind_param("ssssss",$fullName,$contact,$email,$username,$passwordHash,$salt);
并在重置堆栈后从那里跳转到用户的main
(适当重命名)。从长远来看,围绕编译器逻辑进行黑客攻击将过于脆弱。