summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngus Gratton <angus@redyak.com.au>2023-09-13 10:07:21 +1000
committerAngus Gratton <angus@redyak.com.au>2023-09-20 11:48:36 +1000
commitfa685239687b0ee3d34788b2edd0711e9fc6bc3c (patch)
treef0ccfe7f62649b1b6cdb947e9baadc8c6263536d
parent00930b213e55f4396c1e255092f09bdb8dd8c16f (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.c24
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) {