В попытке уменьшить вероятность переполнения стека я хотел бы сбросить указатель стека после ввода функции, которая никогда не вернется. В моем коде есть два случая, когда это происходит: main () и ISR shutdown_immediate (), который сохраняет данные на флэш-память и входит в глубокий сон. Я использую LTO для подгонки кода, поэтому main () оказывается довольно большой функцией, которая требует выделения части стека для локальных переменных.
Моей первой попыткой было использование __attribute__ ((noreturn))
в сочетании с вызовом __builtin_unreachable()
, но это никак не изменило сгенерированную сборку. Затем я создал встроенную функцию сборки для сброса указателя стека на последний адрес SRAM, который вызывается первым в main () и обработчике shutdown_immediate ().
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
Проверенные цепочки инструментов:
- НКУ-рука-ни-EABI-6-2017-q2-обновление
- НКА-рычажный ни-EABI-8-2018-q4-мажорный