[PATCH v2] x32: Implement prctl in assembly
"H.J. Lu" <[email protected]> Mon, 8 Dec 2025 09:48:55 +0800
| Newsgroups | org.kernel.vger.util-linux |
|---|---|
| Message-ID | <CAMe9rOqMGabug88Qm7p22Qk+oMOk9YdbAQeyb77rL3ot4HS1UA@mail.gmail.com> |
On Sun, Dec 7, 2025 at 5:41 PM Florian Weimer <[email protected]> wrote: > > * H. J. Lu: > > > On Thu, Dec 4, 2025 at 10:06 PM Adhemerval Zanella Netto > > <[email protected]> wrote: > >> > >> The x32 and or1k (which also uses similar implementation) does seems broken > >> without checking the 'option' argument to see which arg we can va_arg. > >> > >> The problem is adding this logic on libc will add some forward-compatibility > >> that we try to avoid (newer kernel prctl additions might now work correctly). > >> > >> I am not sure why we haven't switch x32 back to the assembly wrappers > >> with 6a04404521ac4119ae36827eeb288ea84eee7cf6 fix (BZ#29770). H.J, can > >> use remove the x32 C version (and also or1k as well)? > > > > 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 safely use assembly syscall wrapper for prctl > > for x32. > > The C implementation clears the upper 32 bits of registers. Does the > assembler wrapper do the same? > Here is the v2 patch to implement prctl in assembly for x32. 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 prctl 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. -- H.J.
v2-0001-x32-Implement-prctl-in-assembly.patch
(text/x-patch, 5.6 KB)
From 20f922113e65f4806db724935f7a747db639db42 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" <[email protected]> Date: Sun, 7 Dec 2025 11:33:33 +0800 Subject: [PATCH v2] x32: Implement prctl in assembly 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 <[email protected]> --- sysdeps/unix/sysv/linux/x86_64/x32/Makefile | 6 ++ .../linux/x86_64/x32/{prctl.c => prctl.S} | 38 ++++++----- .../sysv/linux/x86_64/x32/tst-prctl-x32.c | 63 +++++++++++++++++++ 3 files changed, 87 insertions(+), 20 deletions(-) rename sysdeps/unix/sysv/linux/x86_64/x32/{prctl.c => prctl.S} (50%) create mode 100644 sysdeps/unix/sysv/linux/x86_64/x32/tst-prctl-x32.c diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/Makefile b/sysdeps/unix/sysv/linux/x86_64/x32/Makefile index 16b768d8ba..004f449883 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/Makefile +++ b/sysdeps/unix/sysv/linux/x86_64/x32/Makefile @@ -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) diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c b/sysdeps/unix/sysv/linux/x86_64/x32/prctl.S 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 714fd28837..41f643ea80 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c +++ b/sysdeps/unix/sysv/linux/x86_64/x32/prctl.S @@ -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 @@ -17,26 +17,24 @@ <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) +hidden_weak (prctl) +weak_alias (__prctl, __prctl_time64) +hidden_weak (__prctl_time64) 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 index 0000000000..295b09e364 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/x32/tst-prctl-x32.c @@ -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> -- 2.52.0