[PATCH] i386: Add the clone3 wrapper

Noah Goldstein goldstein.w.n@gmail.com
Wed Jul 14 18:19:30 GMT 2021


On Wed, Jul 14, 2021 at 9:33 AM H.J. Lu via Libc-alpha <
libc-alpha@sourceware.org> wrote:

> extern int clone3 (struct clone_args *__cl_args, size_t __size,
>                    int (*__func) (void *__arg), void *__arg);
> ---
>  sysdeps/unix/sysv/linux/i386/clone3.S | 123 ++++++++++++++++++++++++++
>  sysdeps/unix/sysv/linux/i386/sysdep.h |   2 +
>  2 files changed, 125 insertions(+)
>  create mode 100644 sysdeps/unix/sysv/linux/i386/clone3.S
>
> diff --git a/sysdeps/unix/sysv/linux/i386/clone3.S
> b/sysdeps/unix/sysv/linux/i386/clone3.S
> new file mode 100644
> index 0000000000..bef3ce0455
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/i386/clone3.S
> @@ -0,0 +1,123 @@
> +/* The clone3 syscall wrapper.  Linux/i386 version.
> +   Copyright (C) 2021 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/>.  */
> +
> +/* clone3() is even more special than fork() as it mucks with stacks
> +   and invokes a function in the right context after its all over.  */
> +
> +#include <sysdep.h>
> +
> +/* The userland implementation is:
> +   int clone3 (struct clone_args *cl_args, size_t size,
> +              int (*func)(void *arg), void *arg);
> +   the kernel entry is:
> +   int clone3 (struct clone_args *cl_args, size_t size);
> +
> +   The parameters are passed on stack from userland:
> +   16(%esp)    arg
> +   12(%esp)    func
> +    8(%esp)    size
> +    4(%esp)    cl_args
> +     (%esp)    Return address
> +
> +   The kernel expects:
> +   eax:                system call number
> +   ebx:                cl_args
> +   ecx:                size
> + */
> +
> +#define CL_ARGS        4
> +#define SIZE   8
> +#define FUNC   12
> +#define ARG    16
> +
> +        .text
> +ENTRY (__clone3)
> +       /* Sanity check arguments.  */
> +       movl    $-EINVAL, %eax
> +       movl    CL_ARGS(%esp), %ecx     /* No NULL cl_args pointer.  */
> +       testl   %ecx, %ecx
> +       jz      SYSCALL_ERROR_LABEL
> +       /* Save the function pointer in EDX which is preserved by the
> +          system call.  */
> +       movl    FUNC(%esp), %edx        /* No NULL function pointer.  */
> +       testl   %edx, %edx
> +       jz      SYSCALL_ERROR_LABEL
> +
> +       /* Save EBX and ESI.  */
> +       pushl   %ebx
> +       cfi_adjust_cfa_offset (4)
> +       pushl   %esi
> +       cfi_adjust_cfa_offset (4)
> +
> +       /* Save the function argument in ESI which is preserved by the
> +          system call.  */
> +       movl    (ARG + 8)(%esp), %esi
> +
> +       /* Put cl_args in EBX.  */
> +       movl    %ecx, %ebx
> +
> +       /* Put size in ECX.  */
> +       movl    (SIZE + 8)(%esp), %ecx
> +
> +       /* Do the system call.  */
> +       movl    $SYS_ify(clone3), %eax
> +
> +       /* End FDE now, because in the child the unwind info will be
> +          wrong.  */
> +       cfi_endproc
> +
> +       int     $0x80
> +       test    %eax, %eax
> +       /* No need to restore EBX and ESI in child.  */
>
does esp need to be adjusted?

+       jz      L(thread_start)
> +
> +       /* Restore EBX and ESI in parent.  */
> +       pop     %esi
> +       pop     %ebx
> +       jl      SYSCALL_ERROR_LABEL
> +
> +       ret
> +
> +L(thread_start):
> +       cfi_startproc
> +       /* Clearing frame pointer is insufficient, use CFI.  */
> +       cfi_undefined (eip)
> +       xorl    %ebp, %ebp      /* Terminate the stack frame.  */
> +
> +       /* Align stack to 16 bytes per the i386 psABI.  */
> +       andl    $-16, %esp

+
> +       /* The PUSH below will decrement stack pointer by 4 bytes.  */
> +       subl    $12, %esp
> +
> +       /* Set up the argument for the function call.  */
> +       pushl   %esi            /* Argument.  */
>
Can you pushl then align and drop the subl? Or does esp need to be aligned
before
the pushl?

> +       cfi_adjust_cfa_offset (4)
> +       call    *%edx           /* Call function.  */
> +
> +       /* Call exit with return value from function call. */
> +       movl    %eax, %ebx
> +       movl    $SYS_ify(exit), %eax
> +       ENTER_KERNEL
> +       cfi_endproc
> +
> +       cfi_startproc
> +PSEUDO_END (__clone3)
> +
> +libc_hidden_def (__clone3)
> +weak_alias (__clone3, clone3)
> diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h
> b/sysdeps/unix/sysv/linux/i386/sysdep.h
> index 8680b49bf7..3927a1a6e0 100644
> --- a/sysdeps/unix/sysv/linux/i386/sysdep.h
> +++ b/sysdeps/unix/sysv/linux/i386/sysdep.h
> @@ -291,6 +291,8 @@ struct libc_do_syscall_args
>  # define HAVE_TIME_VSYSCALL             "__vdso_time"
>  # define HAVE_CLOCK_GETRES_VSYSCALL     "__vdso_clock_getres"
>
> +# define HAVE_CLONE3_WAPPER            1
> +
>  # undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
>  # define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
>
> --
> 2.31.1
>
>


More information about the Libc-alpha mailing list