diff options
| author | Angus Gratton <angus@redyak.com.au> | 2023-09-13 10:07:21 +1000 |
|---|---|---|
| committer | Angus Gratton <angus@redyak.com.au> | 2023-09-20 11:48:36 +1000 |
| commit | fa685239687b0ee3d34788b2edd0711e9fc6bc3c (patch) | |
| tree | f0ccfe7f62649b1b6cdb947e9baadc8c6263536d | |
| parent | 00930b213e55f4396c1e255092f09bdb8dd8c16f (diff) | |
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>
| -rw-r--r-- | py/nlrx64.c | 24 |
1 files 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) { |
