]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
x32: Implement prctl in assembly
authorH.J. Lu <hjl.tools@gmail.com>
Sun, 7 Dec 2025 03:33:33 +0000 (11:33 +0800)
committerH.J. Lu <hjl.tools@gmail.com>
Mon, 8 Dec 2025 22:41:55 +0000 (06:41 +0800)
Since the variadic prctl function takes at most 5 integer arguments which
are passed in the same integer registers on x32 as the function with 5
integer arguments, we can use assembly for prctl.  Since upper 32-bits in
the last 4 arguments of pcrtl must be cleared to match the x32 prctl
syscall interface where the last 4 arguments are unsigned 64 bit longs,
implement prctl in assembly to clear upper 32-bits in the last 4 arguments
and add a test to verify it.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
sysdeps/unix/sysv/linux/x86_64/x32/Makefile
sysdeps/unix/sysv/linux/x86_64/x32/prctl.S [moved from sysdeps/unix/sysv/linux/x86_64/x32/prctl.c with 50% similarity]
sysdeps/unix/sysv/linux/x86_64/x32/tst-prctl-x32.c [new file with mode: 0644]

index 16b768d8ba52283ff4ee7d578a1084d8300ee422..004f44988315c9ce20e0faa69cf66d89e3ab537f 100644 (file)
@@ -3,6 +3,12 @@ default-abi := x32
 
 ifeq ($(subdir),misc)
 sysdep_routines += arch_prctl
+
+tests += \
+  tst-prctl-x32 \
+# tests
+
+CFLAGS-tst-prctl-x32.c += $(no-stack-protector)
 endif
 
 ifeq ($(subdir),conform)
similarity index 50%
rename from sysdeps/unix/sysv/linux/x86_64/x32/prctl.c
rename to sysdeps/unix/sysv/linux/x86_64/x32/prctl.S
index 714fd2883763592f151d92f1ee696113f63ac210..827101e8aa3eb3b6c475e1476e1271d4018ab11a 100644 (file)
@@ -1,5 +1,5 @@
-/* prctl - Linux specific syscall.  x86-64 x32 version.
-   Copyright (C) 2020-2025 Free Software Foundation, Inc.
+/* The prctl system call.  Linux/x32 version.
+   Copyright (C) 2025 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
    <https://www.gnu.org/licenses/>.  */
 
 #include <sysdep.h>
-#include <stdarg.h>
-#include <sys/prctl.h>
 
-/* Unconditionally read all potential arguments.  This may pass
-   garbage values to the kernel, but avoids the need for teaching
-   glibc the argument counts of individual options (including ones
-   that are added to the kernel in the future).  */
+/* Clear upper 32-bits in the last 4 arguments.  Since the first argument
+   of prctl is int, leave it alone.  */
+#undef DO_CALL
+#define DO_CALL(syscall_name, args, ulong_arg_1, ulong_arg_2) \
+  movl %esi, %esi;                     \
+  movl %edx, %edx;                     \
+  movl %ecx, %r10d;                    \
+  movl %r8d, %r8d;                     \
+  movl $SYS_ify (syscall_name), %eax;  \
+  syscall;
 
-int
-__prctl (int option, ...)
-{
-  va_list arg;
-  va_start (arg, option);
-  unsigned long int arg2 = va_arg (arg, unsigned long int);
-  unsigned long int arg3 = va_arg (arg, unsigned long int);
-  unsigned long int arg4 = va_arg (arg, unsigned long int);
-  unsigned long int arg5 = va_arg (arg, unsigned long int);
-  va_end (arg);
-  return INLINE_SYSCALL_CALL (prctl, option, arg2, arg3, arg4, arg5);
-}
+PSEUDO (__prctl, prctl, 5)
+       ret
+PSEUDO_END (__prctl)
 
 libc_hidden_def (__prctl)
 weak_alias (__prctl, prctl)
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/tst-prctl-x32.c b/sysdeps/unix/sysv/linux/x86_64/x32/tst-prctl-x32.c
new file mode 100644 (file)
index 0000000..295b09e
--- /dev/null
@@ -0,0 +1,63 @@
+/* Smoke test for prctl.
+   Copyright (C) 2021-2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+#include <sys/prctl.h>
+#include <support/check.h>
+
+/* On x32, when parameters are passed in 64-bit registers, only the lower
+   32 bits are used and the upper 32 bits must be cleared.  */
+typedef union
+{
+  struct
+    {
+      union
+       {
+         const char *ptr;
+         int i1;
+       };
+      int i2;
+    } s;
+  long long ll;
+} parameter_t;
+
+static int
+__attribute__ ((noipa))
+do_prctl (int op, long long arg1, long long arg2, long long arg3,
+         long long arg4)
+{
+  return prctl (op, arg1, arg2, arg3, arg4);
+}
+
+static int
+do_test (void)
+{
+  parameter_t name = { { { "thread name" }, -1 } };
+  parameter_t zero = { { { 0 }, -2 } };
+  TEST_COMPARE (do_prctl (PR_SET_NAME, name.ll, zero.ll, zero.ll,
+                         zero.ll), 0);
+  char buffer[16] = { 0, };
+  name.s.ptr = buffer;
+  TEST_COMPARE (do_prctl (PR_GET_NAME, name.ll, zero.ll, zero.ll,
+                         zero.ll), 0);
+  char expected[16] = "thread name";
+  TEST_COMPARE_BLOB (buffer, sizeof (buffer), expected, sizeof (expected));
+  return 0;
+}
+
+#include <support/test-driver.c>