public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Willy Tarreau <w@1wt.eu>
To: "Paul E. McKenney" <paulmck@kernel.org>
Cc: linux-kernel@vger.kernel.org, Willy Tarreau <w@1wt.eu>
Subject: [PATCH v2 03/22] tools/nolibc: support thumb mode with frame pointers on ARM
Date: Tue, 10 Jan 2023 08:24:15 +0100	[thread overview]
Message-ID: <20230110072434.3863-4-w@1wt.eu> (raw)
In-Reply-To: <20230110072434.3863-1-w@1wt.eu>

In Thumb mode, register r7 is normally used to store the frame pointer.
By default when optimizing at -Os there's no frame pointer so this works
fine. But if no optimization is set, then build errors occur, indicating
that r7 cannot not be used. It's difficult to cheat because it's the
compiler that is complaining, not the assembler, so it's not even possible
to report that the register was clobbered. The solution consists in saving
and restoring r7 around the syscall, but this slightly inflates the code.
The syscall number is passed via r6 which is never used by syscalls.

The current patch adds a few macroes which do that only in Thumb mode,
and which continue to directly assign the syscall number to register r7
in ARM mode. Now this always builds and works for all modes (tested on
Arm, Thumbv1, Thumbv2 modes, at -Os, -O0, -O0 -fomit-frame-pointer).
The code is very slightly inflated in thumb-mode without frame-pointers
compared to previously (e.g. 7928 vs 7864 bytes for nolibc-test) but at
least it's always operational. And it's possible to disable this mechanism
by setting NOLIBC_OMIT_FRAME_POINTER.

Signed-off-by: Willy Tarreau <w@1wt.eu>
---
 tools/include/nolibc/arch-arm.h | 60 ++++++++++++++++++++++++++-------
 1 file changed, 47 insertions(+), 13 deletions(-)

diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h
index e4ba77b0310f..ef94df2d93d5 100644
--- a/tools/include/nolibc/arch-arm.h
+++ b/tools/include/nolibc/arch-arm.h
@@ -70,20 +70,44 @@ struct sys_stat_struct {
  *     don't have to experience issues with register constraints.
  *   - the syscall number is always specified last in order to allow to force
  *     some registers before (gcc refuses a %-register at the last position).
+ *   - in thumb mode without -fomit-frame-pointer, r7 is also used to store the
+ *     frame pointer, and we cannot directly assign it as a register variable,
+ *     nor can we clobber it. Instead we assign the r6 register and swap it
+ *     with r7 before calling svc, and r6 is marked as clobbered.
+ *     We're just using any regular register which we assign to r7 after saving
+ *     it.
  *
  * Also, ARM supports the old_select syscall if newselect is not available
  */
 #define __ARCH_WANT_SYS_OLD_SELECT
 
+#if (defined(__THUMBEB__) || defined(__THUMBEL__)) && \
+    !defined(NOLIBC_OMIT_FRAME_POINTER)
+/* swap r6,r7 needed in Thumb mode since we can't use nor clobber r7 */
+#define _NOLIBC_SYSCALL_REG         "r6"
+#define _NOLIBC_THUMB_SET_R7        "eor r7, r6\neor r6, r7\neor r7, r6\n"
+#define _NOLIBC_THUMB_RESTORE_R7    "mov r7, r6\n"
+
+#else  /* we're in ARM mode */
+/* in Arm mode we can directly use r7 */
+#define _NOLIBC_SYSCALL_REG         "r7"
+#define _NOLIBC_THUMB_SET_R7        ""
+#define _NOLIBC_THUMB_RESTORE_R7    ""
+
+#endif /* end THUMB */
+
 #define my_syscall0(num)                                                      \
 ({                                                                            \
-	register long _num __asm__ ("r7") = (num);                            \
+	register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
 	register long _arg1 __asm__ ("r0");                                   \
 	                                                                      \
 	__asm__  volatile (                                                   \
+		_NOLIBC_THUMB_SET_R7                                          \
 		"svc #0\n"                                                    \
-		: "=r"(_arg1)                                                 \
-		: "r"(_num)                                                   \
+		_NOLIBC_THUMB_RESTORE_R7                                      \
+		: "=r"(_arg1), "=r"(_num)                                     \
+		: "r"(_arg1),                                                 \
+		  "r"(_num)                                                   \
 		: "memory", "cc", "lr"                                        \
 	);                                                                    \
 	_arg1;                                                                \
@@ -91,12 +115,14 @@ struct sys_stat_struct {
 
 #define my_syscall1(num, arg1)                                                \
 ({                                                                            \
-	register long _num __asm__ ("r7") = (num);                            \
+	register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
 	register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
 	                                                                      \
 	__asm__  volatile (                                                   \
+		_NOLIBC_THUMB_SET_R7                                          \
 		"svc #0\n"                                                    \
-		: "=r"(_arg1)                                                 \
+		_NOLIBC_THUMB_RESTORE_R7                                      \
+		: "=r"(_arg1), "=r" (_num)                                    \
 		: "r"(_arg1),                                                 \
 		  "r"(_num)                                                   \
 		: "memory", "cc", "lr"                                        \
@@ -106,13 +132,15 @@ struct sys_stat_struct {
 
 #define my_syscall2(num, arg1, arg2)                                          \
 ({                                                                            \
-	register long _num __asm__ ("r7") = (num);                            \
+	register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
 	register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
 	register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
 	                                                                      \
 	__asm__  volatile (                                                   \
+		_NOLIBC_THUMB_SET_R7                                          \
 		"svc #0\n"                                                    \
-		: "=r"(_arg1)                                                 \
+		_NOLIBC_THUMB_RESTORE_R7                                      \
+		: "=r"(_arg1), "=r" (_num)                                    \
 		: "r"(_arg1), "r"(_arg2),                                     \
 		  "r"(_num)                                                   \
 		: "memory", "cc", "lr"                                        \
@@ -122,14 +150,16 @@ struct sys_stat_struct {
 
 #define my_syscall3(num, arg1, arg2, arg3)                                    \
 ({                                                                            \
-	register long _num __asm__ ("r7") = (num);                            \
+	register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
 	register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
 	register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
 	register long _arg3 __asm__ ("r2") = (long)(arg3);                    \
 	                                                                      \
 	__asm__  volatile (                                                   \
+		_NOLIBC_THUMB_SET_R7                                          \
 		"svc #0\n"                                                    \
-		: "=r"(_arg1)                                                 \
+		_NOLIBC_THUMB_RESTORE_R7                                      \
+		: "=r"(_arg1), "=r" (_num)                                    \
 		: "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
 		  "r"(_num)                                                   \
 		: "memory", "cc", "lr"                                        \
@@ -139,15 +169,17 @@ struct sys_stat_struct {
 
 #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
 ({                                                                            \
-	register long _num __asm__ ("r7") = (num);                            \
+	register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
 	register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
 	register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
 	register long _arg3 __asm__ ("r2") = (long)(arg3);                    \
 	register long _arg4 __asm__ ("r3") = (long)(arg4);                    \
 	                                                                      \
 	__asm__  volatile (                                                   \
+		_NOLIBC_THUMB_SET_R7                                          \
 		"svc #0\n"                                                    \
-		: "=r"(_arg1)                                                 \
+		_NOLIBC_THUMB_RESTORE_R7                                      \
+		: "=r"(_arg1), "=r" (_num)                                    \
 		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
 		  "r"(_num)                                                   \
 		: "memory", "cc", "lr"                                        \
@@ -157,7 +189,7 @@ struct sys_stat_struct {
 
 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
 ({                                                                            \
-	register long _num __asm__ ("r7") = (num);                            \
+	register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
 	register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
 	register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
 	register long _arg3 __asm__ ("r2") = (long)(arg3);                    \
@@ -165,8 +197,10 @@ struct sys_stat_struct {
 	register long _arg5 __asm__ ("r4") = (long)(arg5);                    \
 	                                                                      \
 	__asm__  volatile (                                                   \
+		_NOLIBC_THUMB_SET_R7                                          \
 		"svc #0\n"                                                    \
-		: "=r" (_arg1)                                                \
+		_NOLIBC_THUMB_RESTORE_R7                                      \
+		: "=r"(_arg1), "=r" (_num)                                    \
 		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
 		  "r"(_num)                                                   \
 		: "memory", "cc", "lr"                                        \
-- 
2.17.5


  parent reply	other threads:[~2023-01-10  7:26 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-10  7:24 [PATCH v2 00/22] nolibc: usability improvements (errno, environ, auxv) Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 01/22] tools/nolibc: make compiler and assembler agree on the section around _start Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 02/22] tools/nolibc: enable support for thumb1 mode for ARM Willy Tarreau
2023-01-10  7:24 ` Willy Tarreau [this message]
2023-01-10  7:24 ` [PATCH v2 04/22] tools/nolibc: remove local definitions of O_* flags for open/fcntl Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 05/22] tools/nolibc: make errno a weak symbol instead of a static one Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 06/22] tools/nolibc: export environ as a weak symbol on x86_64 Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 07/22] tools/nolibc: export environ as a weak symbol on i386 Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 08/22] tools/nolibc: export environ as a weak symbol on arm64 Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 09/22] tools/nolibc: export environ as a weak symbol on arm Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 10/22] tools/nolibc: export environ as a weak symbol on mips Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 11/22] tools/nolibc: export environ as a weak symbol on riscv Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 12/22] tools/nolibc: export environ as a weak symbol on s390 Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 13/22] tools/nolibc: add auxiliary vector retrieval for i386 Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 14/22] tools/nolibc: add auxiliary vector retrieval for x86_64 Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 15/22] tools/nolibc: add auxiliary vector retrieval for arm64 Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 16/22] tools/nolibc: add auxiliary vector retrieval for arm Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 17/22] tools/nolibc: add auxiliary vector retrieval for riscv Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 18/22] tools/nolibc: add auxiliary vector retrieval for mips Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 19/22] tools/nolibc: add auxiliary vector retrieval for s390 Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 20/22] nolibc/stdlib: Implement `getauxval(3)` function Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 21/22] nolibc/sys: Implement `getpagesize(2)` function Willy Tarreau
2023-01-10  7:24 ` [PATCH v2 22/22] selftests/nolibc: Add `getpagesize(2)` selftest Willy Tarreau
2023-01-10 22:21 ` [PATCH v2 00/22] nolibc: usability improvements (errno, environ, auxv) Paul E. McKenney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230110072434.3863-4-w@1wt.eu \
    --to=w@1wt.eu \
    --cc=linux-kernel@vger.kernel.org \
    --cc=paulmck@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox