1From 7b050b366b7dacfb43779c51702a892d8f1873d0 Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?J=2E=20Neusch=C3=A4fer?= <j.ne@posteo.net>
3Date: Sun, 2 Apr 2023 19:58:42 +0200
4Subject: [PATCH] py/nlrthumb: Make non-Thumb2 long-jump workaround opt-in.
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9Although the original motivation given for the workaround[1] is correct,
10nlr.o and nlrthumb.o are linked with a small enough distance that the
11problem does not occur, and the workaround isn't necessary. The distance
12between the b instruction and its target (nlr_push_tail) is just 64
13bytes[2], well within the ±2046 byte range addressable by an
14unconditional branch instruction in Thumb mode.
15
16The workaround induces a relocation in the text section (textrel), which
17isn't supported everywhere, notably not on musl-libc[3], where it causes
18a crash on start-up. With the workaround removed, micropython works on an
19ARMv5T Linux system built with musl-libc.
20
21This commit changes nlrthumb.c to use a direct jump by default, but
22leaves the long jump workaround as an option for those cases where it's
23actually needed.
24
25[1]: commit dd376a239dc4f47b0ee7866810fcda151f3cf6dd
26
27Author: Damien George <damien.p.george@gmail.com>
28Date:   Fri Sep 1 15:25:29 2017 +1000
29
30    py/nlrthumb: Get working again on standard Thumb arch (ie not Thumb2).
31
32    "b" on Thumb might not be long enough for the jump to nlr_push_tail so
33    it must be done indirectly.
34
35[2]: Excerpt from objdump -d micropython:
36
37000095c4 <nlr_push_tail>:
38    95c4:       b510            push    {r4, lr}
39    95c6:       0004            movs    r4, r0
40    95c8:       f02d fd42       bl      37050 <mp_thread_get_state>
41    95cc:       6943            ldr     r3, [r0, #20]
42    95ce:       6023            str     r3, [r4, #0]
43    95d0:       6144            str     r4, [r0, #20]
44    95d2:       2000            movs    r0, #0
45    95d4:       bd10            pop     {r4, pc}
46
47000095d6 <nlr_pop>:
48    95d6:       b510            push    {r4, lr}
49    95d8:       f02d fd3a       bl      37050 <mp_thread_get_state>
50    95dc:       6943            ldr     r3, [r0, #20]
51    95de:       681b            ldr     r3, [r3, #0]
52    95e0:       6143            str     r3, [r0, #20]
53    95e2:       bd10            pop     {r4, pc}
54
55000095e4 <nlr_push>:
56    95e4:       60c4            str     r4, [r0, #12]
57    95e6:       6105            str     r5, [r0, #16]
58    95e8:       6146            str     r6, [r0, #20]
59    95ea:       6187            str     r7, [r0, #24]
60    95ec:       4641            mov     r1, r8
61    95ee:       61c1            str     r1, [r0, #28]
62    95f0:       4649            mov     r1, r9
63    95f2:       6201            str     r1, [r0, #32]
64    95f4:       4651            mov     r1, sl
65    95f6:       6241            str     r1, [r0, #36]   @ 0x24
66    95f8:       4659            mov     r1, fp
67    95fa:       6281            str     r1, [r0, #40]   @ 0x28
68    95fc:       4669            mov     r1, sp
69    95fe:       62c1            str     r1, [r0, #44]   @ 0x2c
70    9600:       4671            mov     r1, lr
71    9602:       6081            str     r1, [r0, #8]
72    9604:       e7de            b.n     95c4 <nlr_push_tail>
73
74[3]: https://www.openwall.com/lists/musl/2020/09/25/4
75
76Signed-off-by: J. Neuschäfer <j.ne@posteo.net>
77Upstream: https://github.com/micropython/micropython/commit/7b050b366b7dacfb43779c51702a892d8f1873d0
78---
79 py/mpconfig.h |  6 ++++++
80 py/nlrthumb.c | 10 +++++++++-
81 2 files changed, 15 insertions(+), 1 deletion(-)
82
83diff --git a/py/mpconfig.h b/py/mpconfig.h
84index af2480266..1aa3e0699 100644
85--- a/py/mpconfig.h
86+++ b/py/mpconfig.h
87@@ -587,6 +587,12 @@
88 /*****************************************************************************/
89 /* Python internal features                                                  */
90
91+// Use a special long jump in nlrthumb.c, which may be necessary if nlr.o and
92+// nlrthumb.o are linked far apart from each other.
93+#ifndef MICROPY_NLR_THUMB_USE_LONG_JUMP
94+#define MICROPY_NLR_THUMB_USE_LONG_JUMP (0)
95+#endif
96+
97 // Whether to enable import of external modules
98 // When disabled, only importing of built-in modules is supported
99 // When enabled, a port must implement mp_import_stat (among other things)
100diff --git a/py/nlrthumb.c b/py/nlrthumb.c
101index a22c5df5b..e7b24f242 100644
102--- a/py/nlrthumb.c
103+++ b/py/nlrthumb.c
104@@ -38,6 +38,14 @@
105
106 __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
107
108+    // If you get a linker error here, indicating that a relocation doesn't
109+    // fit, try the following (in that order):
110+    //
111+    // 1. Ensure that nlr.o nlrthumb.o are linked closely together, i.e.
112+    //    there aren't too many other files between them in the linker list
113+    //    (PY_CORE_O_BASENAME in py/py.mk)
114+    // 2. Set -DMICROPY_NLR_THUMB_USE_LONG_JUMP=1 during the build
115+    //
116     __asm volatile (
117         "str    r4, [r0, #12]       \n" // store r4 into nlr_buf
118         "str    r5, [r0, #16]       \n" // store r5 into nlr_buf
119@@ -71,7 +79,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
120         "str    lr, [r0, #8]        \n" // store lr into nlr_buf
121         #endif
122
123-        #if !defined(__thumb2__)
124+        #if MICROPY_NLR_THUMB_USE_LONG_JUMP
125         "ldr    r1, nlr_push_tail_var \n"
126         "bx     r1                  \n" // do the rest in C
127         ".align 2                   \n"
128--
1292.43.0
130
131