From: H.J. Lu Date: Sun, 7 Dec 2025 03:33:33 +0000 (+0800) Subject: x32: Implement prctl in assembly X-Git-Tag: glibc-2.43~114 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6afabde23ee0ad9d713fcebf9b1fd7c572a671af;p=thirdparty%2Fglibc.git 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 Reviewed-by: Florian Weimer --- 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 @@ . */ #include -#include -#include -/* 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 + . */ + +#include +#include +#include + +/* 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