Browse Source

py/nlrx64: Mark nlr_push() as naked function when possible.

Supported from GCC 8 and up, and Compiler Explorer suggests it works as
expected with Clang since 3.6 (2014).

- Fixes situation where building embedded MicroPython with -O0 and
  MICROPY_NLR_X64 crashes at runtime (due to nlr_push pushing the
  frame pointer register EBP). Closes #12421.

- Allows removing the macOS tweak to undo pushing EBP onto the stack
  in the generated function prelude.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
pull/12434/head
Angus Gratton 1 year ago
parent
commit
fa68523968
  1. 24
      py/nlrx64.c

24
py/nlrx64.c

@ -35,8 +35,27 @@
__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
#if !MICROPY_NLR_OS_WINDOWS
#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 8)
#define USE_NAKED 1
#else
// On older gcc the equivalent here is to force omit-frame-pointer
__attribute__((optimize("omit-frame-pointer")))
#endif
#endif
#if !defined(USE_NAKED)
#define USE_NAKED 0
#endif
#if USE_NAKED
// nlr_push prelude should never push frame pointer register ebp onto the stack
__attribute__((naked))
#endif
unsigned int nlr_push(nlr_buf_t *nlr) {
#if !USE_NAKED
(void)nlr;
#endif
#if MICROPY_NLR_OS_WINDOWS
@ -58,9 +77,6 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
#else
__asm volatile (
#if defined(__APPLE__) && defined(__MACH__)
"pop %rbp \n" // undo function's prelude
#endif
"movq (%rsp), %rax \n" // load return %rip
"movq %rax, 16(%rdi) \n" // store %rip into nlr_buf
"movq %rbp, 24(%rdi) \n" // store %rbp into nlr_buf
@ -79,7 +95,9 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
#endif
#if !USE_NAKED
return 0; // needed to silence compiler warning
#endif
}
NORETURN void nlr_jump(void *val) {

Loading…
Cancel
Save