From fa685239687b0ee3d34788b2edd0711e9fc6bc3c Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 13 Sep 2023 10:07:21 +1000 Subject: [PATCH] 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 --- py/nlrx64.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/py/nlrx64.c b/py/nlrx64.c index 6f006e755..6b7d0262f 100644 --- a/py/nlrx64.c +++ b/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) {