From patchwork Thu Feb 23 15:14:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergey Bugaev X-Patchwork-Id: 65521 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8E272385B52A for ; Thu, 23 Feb 2023 15:15:18 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8E272385B52A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1677165318; bh=RNGuoTxOLM2ww3VMj7shhS4r9e5DdPyp7xxFrCZWN9A=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=P9cN/RZpW7yAPjqdSkPH+JFFH0pQjgrmT4QPAbQCUydPt1f8zTYezg2qp0MHexedS sUB7AFfSXAjjX0f+rP7LclP3ENYHfXcO1+ro2l8XIZHjBsOwI9SSjihljdokzjwA09 +kCxQE19EWrP5RgH40PRcVCQYuSeXF7mWQpWALSE= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-lj1-x229.google.com (mail-lj1-x229.google.com [IPv6:2a00:1450:4864:20::229]) by sourceware.org (Postfix) with ESMTPS id 263283858C5E for ; Thu, 23 Feb 2023 15:14:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 263283858C5E Received: by mail-lj1-x229.google.com with SMTP id f16so11092150ljq.10 for ; Thu, 23 Feb 2023 07:14:54 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RNGuoTxOLM2ww3VMj7shhS4r9e5DdPyp7xxFrCZWN9A=; b=dRjOeHHwXlRBpZdGcAN26a1RCKwE32H/aME7tzPMrpGjKmFR8kB3L2ln3QQNJBPgtH E7AO+/7s4KFA9HnWutZRkcm0sdAjLZAYYmy1evzj4OqnRkphqGChtVgG3PPFTJN1zVt+ nBz4VycEjIgPDBMFKeLOuGsTyZqj371JQyz7KpQVBY3ZECqPmUgUhyuZr6Rm8cYv7lXR nnroMxOMLenbYsBz9BB5+ebhWc3ZhG7n9d1cPc6S6W6MPH3CWBIc1n/DK2sERVUecf7S ei7L+eSWSfejJt9mmi0wuGAZWxNxVZPqWhIT1nSp34ZSN1peey8o5ACiCl+/gh99diCS rDoQ== X-Gm-Message-State: AO0yUKUHdZqu6QGMXluLE/qPQGwSRVbShzq4q1+VJWESrmO4BDK4AIFW HzDI54M1KeIIMYA2oQL/cCmfxofjI0MXBA== X-Google-Smtp-Source: AK7set+mWlPTcFvjWtOvrXNtgGfccciCmiBLn7cm8MS23tslhzNxLbqqUF1WfTWnxESMqFEhce1ujQ== X-Received: by 2002:a2e:a988:0:b0:295:918f:77a2 with SMTP id x8-20020a2ea988000000b00295918f77a2mr4038560ljq.30.1677165292238; Thu, 23 Feb 2023 07:14:52 -0800 (PST) Received: from surface-pro-6.. ([2a00:1370:818c:4a57:3b42:e837:4d66:1be3]) by smtp.gmail.com with ESMTPSA id e18-20020a2eb1d2000000b002934abfb109sm924009lja.45.2023.02.23.07.14.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Feb 2023 07:14:51 -0800 (PST) To: Samuel Thibault , bug-hurd@gnu.org, libc-alpha@sourceware.org Cc: Sergey Bugaev Subject: [PATCH v3 1/2] hurd: Simplify init-first.c further Date: Thu, 23 Feb 2023 18:14:35 +0300 Message-Id: <20230223151436.49180-1-bugaevc@gmail.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Sergey Bugaev via Libc-alpha From: Sergey Bugaev Reply-To: Sergey Bugaev Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" This drops all of the return address rewriting kludges. The only remaining hack is the jump out of a call stack while adjusting the stack pointer. Signed-off-by: Sergey Bugaev --- sysdeps/mach/hurd/dl-sysdep.c | 4 +- sysdeps/mach/hurd/dl-sysdep.h | 4 + sysdeps/mach/hurd/i386/dl-machine.h | 7 - sysdeps/mach/hurd/i386/init-first.c | 193 +++++++++------------------- 4 files changed, 68 insertions(+), 140 deletions(-) delete mode 100644 sysdeps/mach/hurd/i386/dl-machine.h diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c index 9e591708..a2115f6e 100644 --- a/sysdeps/mach/hurd/dl-sysdep.c +++ b/sysdeps/mach/hurd/dl-sysdep.c @@ -207,6 +207,8 @@ _dl_sysdep_start (void **start_argptr, } } + _dl_init_first (argdata); + { extern void _dl_start_user (void); /* Unwind the stack to ARGDATA and simulate a return from _dl_start @@ -793,7 +795,7 @@ _dl_show_auxv (void) void weak_function -_dl_init_first (int argc, ...) +_dl_init_first (void *p) { /* This no-op definition only gets used if libc is not linked in. */ } diff --git a/sysdeps/mach/hurd/dl-sysdep.h b/sysdeps/mach/hurd/dl-sysdep.h index 3baf56b7..fa35a71c 100644 --- a/sysdeps/mach/hurd/dl-sysdep.h +++ b/sysdeps/mach/hurd/dl-sysdep.h @@ -22,3 +22,7 @@ (open, mmap, etc). */ #define RTLD_PRIVATE_ERRNO 0 + +#ifndef __ASSEMBLER__ +void _dl_init_first (void *data); +#endif diff --git a/sysdeps/mach/hurd/i386/dl-machine.h b/sysdeps/mach/hurd/i386/dl-machine.h deleted file mode 100644 index 40f2ff29..00000000 --- a/sysdeps/mach/hurd/i386/dl-machine.h +++ /dev/null @@ -1,7 +0,0 @@ -/* Dynamic linker magic for Hurd/i386. - This file just gets us a call to _dl_first_init inserted - into the asm in sysdeps/i386/dl-machine.h that contains - the initializer code. */ - -#define RTLD_START_SPECIAL_INIT "call _dl_init_first@PLT; movl (%esp), %edx" -#include_next "dl-machine.h" diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c index a558da16..05424563 100644 --- a/sysdeps/mach/hurd/i386/init-first.c +++ b/sysdeps/mach/hurd/i386/init-first.c @@ -22,10 +22,9 @@ #include #include #include +#include #include #include "hurdstartup.h" -#include "hurdmalloc.h" /* XXX */ -#include "../locale/localeinfo.h" #include #include @@ -87,68 +86,13 @@ posixland_init (int argc, char **argv, char **envp) __init_misc (argc, argv, envp); } - static void -init1 (int argc, char *arg0, ...) +init (void **data) { - char **argv = &arg0; - char **envp = &argv[argc + 1]; - struct hurd_startup_data *d; - - while (*envp) - ++envp; - d = (void *) ++envp; - - if ((void *) d == argv[0]) - { - /* No Hurd data block to process. */ -#ifndef SHARED - __libc_enable_secure = 0; -#endif - return; - } - -#ifndef SHARED - __libc_enable_secure = d->flags & EXEC_SECURE; -#endif - - _hurd_init_dtable = d->dtable; - _hurd_init_dtablesize = d->dtablesize; - - { - /* Check if the stack we are now on is different from - the one described by _hurd_stack_{base,size}. */ - - char dummy; - const vm_address_t newsp = (vm_address_t) &dummy; - - if (d->stack_size != 0 && (newsp < d->stack_base - || newsp - d->stack_base > d->stack_size)) - /* The new stack pointer does not intersect with the - stack the exec server set up for us, so free that stack. */ - __vm_deallocate (__mach_task_self (), d->stack_base, d->stack_size); - } - - if (d->portarray || d->intarray) - /* Initialize library data structures, start signal processing, etc. */ - _hurd_init (d->flags, argv, - d->portarray, d->portarraysize, - d->intarray, d->intarraysize); -} - - -static inline void -init (int *data) -{ - /* data is the address of the argc parameter to _dl_init_first or - doinit1 in _hurd_stack_setup, so the array subscripts are - undefined. */ - DIAG_PUSH_NEEDS_COMMENT; - DIAG_IGNORE_NEEDS_COMMENT (10, "-Warray-bounds"); - - int argc = *data; + int argc = (int) *data; char **argv = (void *) (data + 1); char **envp = &argv[argc + 1]; + struct hurd_startup_data *d; /* Since the cthreads initialization code uses malloc, and the malloc initialization code needs to get at the environment, make @@ -157,18 +101,18 @@ init (int *data) stored. */ __environ = envp; -#ifndef SHARED - struct hurd_startup_data *d; - while (*envp) ++envp; d = (void *) ++envp; +#ifndef SHARED + /* If we are the bootstrap task started by the kernel, then after the environment pointers there is no Hurd data block; the argument strings start there. */ if ((void *) d == argv[0] || d->phdr == 0) { + __libc_enable_secure = 0; /* With a new enough linker (binutils-2.23 or better), the magic __ehdr_start symbol will be available and __libc_start_main will have done this that way already. */ @@ -186,51 +130,25 @@ init (int *data) } else { + __libc_enable_secure = d->flags & EXEC_SECURE; _dl_phdr = (ElfW(Phdr) *) d->phdr; _dl_phnum = d->phdrsz / sizeof (ElfW(Phdr)); assert (d->phdrsz % sizeof (ElfW(Phdr)) == 0); } #endif - /* Call `init1' (above) with the user code as the return address, and the - argument data immediately above that on the stack. */ - - void *usercode, **ret_address; - - void call_init1 (void); - - /* The argument data is just above the stack frame we will unwind by - returning. Mutate our own return address to run the code below. */ - /* The following expression would typically be written as - ``__builtin_return_address (0)''. But, for example, GCC 4.4.6 doesn't - recognize that this read operation may alias the following write - operation, and thus is free to reorder the two, clobbering the - original return address. */ - ret_address = (void **) __builtin_frame_address (0) + 1; - usercode = *ret_address; - /* GCC 4.4.6 also wants us to force loading USERCODE already here. */ - asm volatile ("# %0" : : "X" (usercode)); - *ret_address = &call_init1; - /* Force USERCODE into %eax and &init1 into %ecx, which are not - restored by function return. */ - asm volatile ("# a %0 c %1" : : "a" (usercode), "c" (&init1)); - - DIAG_POP_NEEDS_COMMENT; /* -Warray-bounds. */ -} - -/* These bits of inline assembler used to be located inside `init'. - However they were optimized away by gcc 2.95. */ + if ((void *) d == argv[0]) + return; -/* The return address of `init' above, was redirected to here, so at - this point our stack is unwound and callers' registers restored. - Only %ecx and %eax are call-clobbered and thus still have the - values we set just above. We have stashed in %eax the user code - return address. Push it on the top of the stack so it acts as - init1's return address, and then jump there. */ -asm ("call_init1:\n" - " push %eax\n" - " jmp *%ecx\n"); + _hurd_init_dtable = d->dtable; + _hurd_init_dtablesize = d->dtablesize; + if (d->portarray || d->intarray) + /* Initialize library data structures, start signal processing, etc. */ + _hurd_init (d->flags, argv, + d->portarray, d->portarraysize, + d->intarray, d->intarraysize); +} /* Do the first essential initializations that must precede all else. */ static inline void @@ -242,7 +160,7 @@ first_init (void) #ifndef SHARED /* In the static case, we need to set up TLS early so that the stack protection guard can be read at gs:0x14 by the gcc-generated snippets. */ - _hurd_tls_init(&__init1_tcbhead); + _hurd_tls_init (&__init1_tcbhead); asm ("movw %%gs,%w0" : "=m" (__init1_desc)); #endif @@ -252,21 +170,15 @@ first_init (void) #ifdef SHARED /* This function is called specially by the dynamic linker to do early initialization of the shared C library before normal initializers - expecting a Posixoid environment can run. It gets called with the - stack set up just as the user will see it, so it can switch stacks. */ + expecting a Posixoid environment can run. */ void -_dl_init_first (int argc, ...) +_dl_init_first (void *data) { first_init (); - - /* If we use ``__builtin_frame_address (0) + 2'' here, GCC gets confused. */ - init (&argc); + init (data); } -#endif - -#ifdef SHARED /* The regular posixland initialization is what goes into libc's normal initializer. */ /* NOTE! The linker notices the magical name `_init' and sets the DT_INIT @@ -280,9 +192,10 @@ __libc_init_first (int argc, char **argv, char **envp) { /* Everything was done in the shared library initializer, _init. */ } -#else -strong_alias (posixland_init, __libc_init_first); +#else /* SHARED */ + +strong_alias (posixland_init, __libc_init_first); /* XXX This is all a crock and I am not happy with it. This poorly-named function is called by static-start.S, @@ -291,32 +204,48 @@ void inhibit_stack_protector _hurd_stack_setup (void) { - intptr_t caller = (intptr_t) __builtin_return_address (0); + /* This is the very first C code that runs in a statically linked + executable -- calling this function is the first thing that _start in + static-start.S does. Once this function returns, the unusual way that it + does (see below), _start jumps to _start1, the regular start-up code. + + _start1 expects the arguments, environment, and a Hurd data block to be + located at the top of the stack. The data may already be located there, + or we may need to receive it from the exec server. */ + void *caller = __builtin_extract_return_addr (__builtin_return_address (0)); + /* If the arguments and environment are already located on the stack, this is + where they are, just above our call frame. Note that this may not be a + valid pointer in case we're supposed to receive the arguments from the exec + server, so we can not dereference it yet. */ + void **p = (void **) __builtin_frame_address (0) + 2; + + /* Init the essential things. */ + first_init (); void doinit (intptr_t *data) { - /* This function gets called with the argument data at TOS. */ - void doinit1 (int argc, ...) - { - /* If we use ``__builtin_frame_address (0) + 2'' here, GCC gets - confused. */ - init ((int *) &argc); - } - - /* Push the user return address after the argument data, and then - jump to `doinit1' (above), so it is as if __libc_init_first's - caller had called `doinit1' with the argument data already on the - stack. */ - *--data = caller; + init ((void **) data); asm volatile ("movl %0, %%esp\n" /* Switch to new outermost stack. */ - "movl $0, %%ebp\n" /* Clear outermost frame pointer. */ - "jmp *%1" : : "r" (data), "r" (&doinit1)); - /* NOTREACHED */ + "xorl %%ebp, %%ebp\n" /* Clear outermost frame pointer. */ + "jmp *%1" : : "r" (data), "r" (caller)); + __builtin_unreachable (); } - first_init (); - - _hurd_startup ((void **) __builtin_frame_address (0) + 2, &doinit); + /* _hurd_startup () will attempt to receive the data block from the exec + server; or if that is not possible, will take the data from the pointer + we pass it here. The important point here is that the data + _hurd_startup () collects may be allocated in its stack frame (with + alloca), which is why _hurd_startup () does not return the normal way. + Instead, it invokes a callback (which is not expected to return normally + either). + + Our callback not only passes the data pointer to init (), but also jumps + out of the call stack back to our caller (i.e. to _start1), while setting + the stack pointer to the data (which is somewhere on the current stack + anyway). This way, _start1 find the data on the top of the stack, just as + it expects to. */ + _hurd_startup (p, &doinit); + __builtin_unreachable (); } #endif