[PATCH v3] x32: Implement prctl in assembly
"H.J. Lu" <[email protected]> Tue, 9 Dec 2025 06:41:28 +0800
| Newsgroups | org.kernel.vger.util-linux |
|---|---|
| Message-ID | <CAMe9rOpkDi3Pq+vexnU8aP0f1xpcHRAAiwAR9CN7Ovh=3B3m9g@mail.gmail.com> |
On Mon, Dec 8, 2025 at 10:25 PM Florian Weimer <[email protected]> wrote: > > * Adhemerval Zanella Netto: > > > On 08/12/25 06:09, Florian Weimer wrote: > >> * H. J. Lu: > >> > >>> On Mon, Dec 8, 2025 at 4:11 PM Florian Weimer <[email protected]> wrote: > >>>> > >>>> * H. J. Lu: > >>>>> 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. > >>>> > >>>> What's the advantage of the assembler implementation over the C > >>>> implementation? I'm missing the context for this change. > >>>> > >>> > >>> It is inspired by > >>> > >>> commit 6a04404521ac4119ae36827eeb288ea84eee7cf6 > >>> Author: Florian Weimer <[email protected]> > >>> Date: Sat Feb 17 09:17:04 2024 +0100 > >>> > >>> Linux: Switch back to assembly syscall wrapper for prctl (bug 29770) > >> > >> The justification for that does not apply to x32, though, because prctl > >> doesn't take floating point arguments. I don't have a strong opinion, > >> the C and assembler versions are of similar complexity. > > > > The main justification is UB to va_args *all* the arguments without taking > > in the consideration which option is passed. If x32 requires additional > > argument handling to clear the upper 32-bits, there is no advantage of > > using the assembly wrapper. > > I'm okay with making this change to avoid UB. > > Patch looks okay to me. > > Reviewed-by: Florian Weimer <[email protected]> > > Minor nit: > > +weak_alias (__prctl, __prctl_time64) > +hidden_weak (__prctl_time64) > > This isn't necessary because there is no __prctl_time64 on x32. Fixed in the v3 patch I am checking in. Thanks. -- H.J.
v3-0001-x32-Implement-prctl-in-assembly.patch
(application/x-patch, 5.6 KB)
From 24cf75e8d7ab735f9a06286e228466c0f33c7982 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" <[email protected]> Date: Sun, 7 Dec 2025 11:33:33 +0800 Subject: [PATCH v3] 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]> Reviewed-by: Florian Weimer <[email protected]> --- sysdeps/unix/sysv/linux/x86_64/x32/Makefile | 6 ++ .../linux/x86_64/x32/{prctl.c => prctl.S} | 35 +++++------ .../sysv/linux/x86_64/x32/tst-prctl-x32.c | 63 +++++++++++++++++++ 3 files changed, 84 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..827101e8aa 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,21 @@ <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 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