diff mbox

Reduce the statically linked startup code [BZ #23323]

Message ID edc80e57-356a-dc28-6195-f4508410c8ab@redhat.com
State New, archived
Headers show

Commit Message

Florian Weimer Aug. 8, 2018, 2:48 p.m. UTC
This is the patch rebased for glibc 2.29.

Should we make more far-reaching changes and remove the arguments which 
are now zero?

Thanks,
Florian

Comments

H.J. Lu Aug. 8, 2018, 3:10 p.m. UTC | #1
On Wed, Aug 8, 2018 at 7:48 AM, Florian Weimer <fweimer@redhat.com> wrote:
> This is the patch rebased for glibc 2.29.
>
> Should we make more far-reaching changes and remove the arguments which are
> now zero?
>

i386 and x86-64 parts look good, except for

+ /* These used to be the addresses of .fini and .init.  */
+ xor %R8_LP, %R8_LP
+ xor %RCX_LP, %RCX_LP

Please use

xorl %r8d, %r8d
xorl %ecx, %ecx

They will zero-extend to 64 bits.

Thanks.
Florian Weimer Aug. 8, 2018, 3:17 p.m. UTC | #2
On 08/08/2018 05:10 PM, H.J. Lu wrote:
> On Wed, Aug 8, 2018 at 7:48 AM, Florian Weimer <fweimer@redhat.com> wrote:
>> This is the patch rebased for glibc 2.29.
>>
>> Should we make more far-reaching changes and remove the arguments which are
>> now zero?
>>
> 
> i386 and x86-64 parts look good, except for
> 
> + /* These used to be the addresses of .fini and .init.  */
> + xor %R8_LP, %R8_LP
> + xor %RCX_LP, %RCX_LP
> 
> Please use
> 
> xorl %r8d, %r8d
> xorl %ecx, %ecx
> 
> They will zero-extend to 64 bits.

Thanks, I've made the change locally.  xorl %ecx, %ecx is indeed one 
byte shorter.

Florian
Szabolcs Nagy Aug. 8, 2018, 3:56 p.m. UTC | #3
On 08/08/18 15:48, Florian Weimer wrote:
> This is the patch rebased for glibc 2.29.
> 
> Should we make more far-reaching changes and remove the arguments which are now zero?
> 

there might be code that calls __libc_start_main directly
(e.g. the cgo runtime ?), if removing args breaks something
then i'd keep them (i don't know if it does).

the aarch64 changes look good.

> Subject: [PATCH] Reduce the statically linked startup code [BZ #23323]
> To:libc-alpha@sourceware.org
> 
> It turns out the startup code in csu/elf-unit.c has a perfect pair of

i think you mean csu/elf-init.c

> ROP gadgets (see Marco-Gisbert and Ripoll-Ripoll, “return-to-csu: A
> New Method to Bypass 64-bit Linux ASLR”).  These functions are not
> needed in dynamically-linked binaries because DT_INIT/DT_INIT_ARRAY
> are already processed by the dynamic linker.  However, the dynamic
> linker skipped the main program for some reason.  For maximum
> backwards compatibility, this is not changed, and instead, the main
> map is consulted from __libc_start_main if the init function argument
> is a NULL pointer.
> 
> For statically linked binaries, the old approach based on linker
> symbols is still used because there is nothing else available.
> 
> A new symbol version __libc_start_main@@GLIBC_2.29 is introduced because
> new binaries running on an old libc would not run their ELF
> constructors, leading to difficult-to-debug issues.  This approach
> (multiple symbol versions for the same function symbol) requires a
> recent binutils version (later than 2.25 on some architectures) because
> earlier versions cannot use a symbol alias to define multiple symbol
> versions for the same symbol.
> 
> Tested on aarch64, armhfp, i686, mips64, ppc, ppc64, ppc64el, s390,
> s390x, x86_64, and built with build-many-glibcs.py.  This patch
> depends on the earlier patch which introduces ELF_INITFINI.
> 
> 2018-06-23  Florian Weimer<fweimer@redhat.com>
> 
> 	[BZ #23323]
> 	Reduce statically-linked startup code.
> 	* csu/Makefile (routines): Remove elf-init.
> 	* csu/elf-init.c: Remove file.
> 	* csu/Versions (GLIBC_2.29): Export __libc_start_main from libc.
> 	* csu/libc-start.c: Add note that this is not part of the startup
> 	code for dynamically linked applications.
> 	[SHARED] (call_init): New function, based on call_init from
> 	elf/dl-init.c.
> 	[!SHARED] (call_init, call_fini): New functions, based on
> 	csu/elf-init.c
> 	(LIBC_START_MAIN): Update function comment.  Register call_fini
> 	directly for statically linked applications.  Call call_init
> 	instead of init (in statically linked applications, and if it is
> 	not NULL).
> 	(DO_DEFINE_LIBC_START_MAIN_VERSION)
> 	(DEFINE_LIBC_START_MAIN_VERSION_1)
> 	(DEFINE_LIBC_START_MAIN_VERSION): Define.
> 	* elf/dl-init.c (init_t): Move to <ldsodefs.h>.
> 	(call_init, _dl_init) Adjust.
> 	* sysdeps/generic/ldsodefs.h (dl_init_t): Moved from
> 	elf/dl-init.c.
> 	(DL_CALL_DT_INIT): Adjust.
> 	* sysdeps/hppa/dl-lookupcfg.h (DL_CALL_DT_INIT): Likewise.
> 	* sysdeps/ia64/dl-lookupcfg.h (DL_CALL_DT_INIT): Likewise.
> 	* sysdeps/aarch64/start.S (_start): Pass zero for init and fini.
> 	* sysdeps/alpha/start.S (_start): Likewise.
> 	* sysdeps/arm/start.S (_start): Likewise.  Adjust offset of
> 	pointer to main.
> 	(.L_GOT): Adjust.
> 	* sysdeps/hppa/start.S (.Lp__libc_csu_fini, .Lp__libc_csu_init):
> 	Remove.
> 	(_start): Pass zero for init and fini.
> 	* sysdeps/ia64/start.S (_start): Pass zero for init and fini.
> 	* sysdeps/i386/start.S (_start): Likewise.
> 	* sysdeps/m68k/start.S (_start): Likewise.
> 	* sysdeps/microblaze/start.S (_start): Likewise.
> 	* sysdeps/mips/start.S (ENTRY_POINT): Likewise.
> 	* sysdeps/nios2/start.S (_start): Likewise.
> 	* sydeps/powerpc/powerpc32/start.S (start_addresses): Use zero for
> 	init and fini.
> 	* sysdeps/powerpc/powerpc64/start.S (start_addresses): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/libc-start: Use
> 	DEFINE_LIBC_START_MAIN_VERSION.
> 	* sysdeps/riscv/start.S (ENTRY_POINT): Pass zero for init and fini.
> 	* sysdeps/s390/s390-32/start.S (_start): Pass zero for init and
> 	fini.
> 	(.L1, .L2): Remove.
> 	* sysdeps/s390/s390-64/start.S (_start): Pass zero for init and
> 	fini.
> 	* sysdeps/s390/s390-64/start.S (_start): Pass zero for init and
> 	fini.
> 	* sysdeps/sh/start.S (_start): Likewise.
> 	(L_init, L_fini): Remove.
> 	* sysdeps/sparc/sparc32/start.S (_start): Pass zero for init and
> 	fini.
> 	* sysdeps/sparc/sparc64/start.S (_start): Likewise.
> 	* sysdeps/x86_64/start.S (start): Likewise.
> 	* sysdeps/mach/hurd/i386/libc.abilist: Add
> 	__libc_start_main@GLIBC_2.29.
> 	* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
Florian Weimer Aug. 8, 2018, 4:11 p.m. UTC | #4
On 08/08/2018 05:56 PM, Szabolcs Nagy wrote:
> On 08/08/18 15:48, Florian Weimer wrote:
>> This is the patch rebased for glibc 2.29.
>>
>> Should we make more far-reaching changes and remove the arguments 
>> which are now zero?
>>
> 
> there might be code that calls __libc_start_main directly
> (e.g. the cgo runtime ?), if removing args breaks something
> then i'd keep them (i don't know if it does).

If that's a concern, we should rename the symbol as well.

I think cgo mentions it only in the documentation, quoting Go code which 
has been auto-generated from the underlying executable link.

Thanks,
Florian
diff mbox

Patch

Subject: [PATCH] Reduce the statically linked startup code [BZ #23323]
To: libc-alpha@sourceware.org

It turns out the startup code in csu/elf-unit.c has a perfect pair of
ROP gadgets (see Marco-Gisbert and Ripoll-Ripoll, “return-to-csu: A
New Method to Bypass 64-bit Linux ASLR”).  These functions are not
needed in dynamically-linked binaries because DT_INIT/DT_INIT_ARRAY
are already processed by the dynamic linker.  However, the dynamic
linker skipped the main program for some reason.  For maximum
backwards compatibility, this is not changed, and instead, the main
map is consulted from __libc_start_main if the init function argument
is a NULL pointer.

For statically linked binaries, the old approach based on linker
symbols is still used because there is nothing else available.

A new symbol version __libc_start_main@@GLIBC_2.29 is introduced because
new binaries running on an old libc would not run their ELF
constructors, leading to difficult-to-debug issues.  This approach
(multiple symbol versions for the same function symbol) requires a
recent binutils version (later than 2.25 on some architectures) because
earlier versions cannot use a symbol alias to define multiple symbol
versions for the same symbol.

Tested on aarch64, armhfp, i686, mips64, ppc, ppc64, ppc64el, s390,
s390x, x86_64, and built with build-many-glibcs.py.  This patch
depends on the earlier patch which introduces ELF_INITFINI.

2018-06-23  Florian Weimer  <fweimer@redhat.com>

	[BZ #23323]
	Reduce statically-linked startup code.
	* csu/Makefile (routines): Remove elf-init.
	* csu/elf-init.c: Remove file.
	* csu/Versions (GLIBC_2.29): Export __libc_start_main from libc.
	* csu/libc-start.c: Add note that this is not part of the startup
	code for dynamically linked applications.
	[SHARED] (call_init): New function, based on call_init from
	elf/dl-init.c.
	[!SHARED] (call_init, call_fini): New functions, based on
	csu/elf-init.c
	(LIBC_START_MAIN): Update function comment.  Register call_fini
	directly for statically linked applications.  Call call_init
	instead of init (in statically linked applications, and if it is
	not NULL).
	(DO_DEFINE_LIBC_START_MAIN_VERSION)
	(DEFINE_LIBC_START_MAIN_VERSION_1)
	(DEFINE_LIBC_START_MAIN_VERSION): Define.
	* elf/dl-init.c (init_t): Move to <ldsodefs.h>.
	(call_init, _dl_init) Adjust.
	* sysdeps/generic/ldsodefs.h (dl_init_t): Moved from
	elf/dl-init.c.
	(DL_CALL_DT_INIT): Adjust.
	* sysdeps/hppa/dl-lookupcfg.h (DL_CALL_DT_INIT): Likewise.
	* sysdeps/ia64/dl-lookupcfg.h (DL_CALL_DT_INIT): Likewise.
	* sysdeps/aarch64/start.S (_start): Pass zero for init and fini.
	* sysdeps/alpha/start.S (_start): Likewise.
	* sysdeps/arm/start.S (_start): Likewise.  Adjust offset of
	pointer to main.
	(.L_GOT): Adjust.
	* sysdeps/hppa/start.S (.Lp__libc_csu_fini, .Lp__libc_csu_init):
	Remove.
	(_start): Pass zero for init and fini.
	* sysdeps/ia64/start.S (_start): Pass zero for init and fini.
	* sysdeps/i386/start.S (_start): Likewise.
	* sysdeps/m68k/start.S (_start): Likewise.
	* sysdeps/microblaze/start.S (_start): Likewise.
	* sysdeps/mips/start.S (ENTRY_POINT): Likewise.
	* sysdeps/nios2/start.S (_start): Likewise.
	* sydeps/powerpc/powerpc32/start.S (start_addresses): Use zero for
	init and fini.
	* sysdeps/powerpc/powerpc64/start.S (start_addresses): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/libc-start: Use
	DEFINE_LIBC_START_MAIN_VERSION.
	* sysdeps/riscv/start.S (ENTRY_POINT): Pass zero for init and fini.
	* sysdeps/s390/s390-32/start.S (_start): Pass zero for init and
	fini.
	(.L1, .L2): Remove.
	* sysdeps/s390/s390-64/start.S (_start): Pass zero for init and
	fini.
	* sysdeps/s390/s390-64/start.S (_start): Pass zero for init and
	fini.
	* sysdeps/sh/start.S (_start): Likewise.
	(L_init, L_fini): Remove.
	* sysdeps/sparc/sparc32/start.S (_start): Pass zero for init and
	fini.
	* sysdeps/sparc/sparc64/start.S (_start): Likewise.
	* sysdeps/x86_64/start.S (start): Likewise.
	* sysdeps/mach/hurd/i386/libc.abilist: Add
	__libc_start_main@GLIBC_2.29.
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.

diff --git a/csu/Makefile b/csu/Makefile
index 88fc77662e..50d291ce72 100644
--- a/csu/Makefile
+++ b/csu/Makefile
@@ -27,10 +27,9 @@  subdir := csu
 include ../Makeconfig
 
 routines = init-first libc-start $(libc-init) sysdep version check_fds \
-	   libc-tls elf-init dso_handle
+	   libc-tls dso_handle
 aux	 = errno
 elide-routines.os = libc-tls
-static-only-routines = elf-init
 csu-dummies = $(filter-out $(start-installed-name),crt1.o Mcrt1.o)
 extra-objs = start.o \
 	     $(start-installed-name) g$(start-installed-name) $(csu-dummies) \
diff --git a/csu/Versions b/csu/Versions
index 43010c3443..136e8155d5 100644
--- a/csu/Versions
+++ b/csu/Versions
@@ -7,6 +7,9 @@  libc {
     # New special glibc functions.
     gnu_get_libc_release; gnu_get_libc_version;
   }
+  GLIBC_2.29 {
+    __libc_start_main;
+  }
   GLIBC_PRIVATE {
     errno;
   }
diff --git a/csu/elf-init.c b/csu/elf-init.c
deleted file mode 100644
index 8bde25a340..0000000000
--- a/csu/elf-init.c
+++ /dev/null
@@ -1,107 +0,0 @@ 
-/* Startup support for ELF initializers/finalizers in the main executable.
-   Copyright (C) 2002-2018 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.
-
-   In addition to the permissions in the GNU Lesser General Public
-   License, the Free Software Foundation gives you unlimited
-   permission to link the compiled version of this file with other
-   programs, and to distribute those programs without any restriction
-   coming from the use of this file. (The GNU Lesser General Public
-   License restrictions do apply in other respects; for example, they
-   cover modification of the file, and distribution when not linked
-   into another program.)
-
-   Note that people who make modified versions of this file are not
-   obligated to grant this special exception for their modified
-   versions; it is their choice whether to do so. The GNU Lesser
-   General Public License gives permission to release a modified
-   version without this exception; this exception also makes it
-   possible to release a modified version which carries forward this
-   exception.
-
-   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
-   <http://www.gnu.org/licenses/>.  */
-
-#include <stddef.h>
-#include <platform-params.h>
-
-
-/* These magic symbols are provided by the linker.  */
-extern void (*__preinit_array_start []) (int, char **, char **)
-  attribute_hidden;
-extern void (*__preinit_array_end []) (int, char **, char **)
-  attribute_hidden;
-extern void (*__init_array_start []) (int, char **, char **)
-  attribute_hidden;
-extern void (*__init_array_end []) (int, char **, char **)
-  attribute_hidden;
-extern void (*__fini_array_start []) (void) attribute_hidden;
-extern void (*__fini_array_end []) (void) attribute_hidden;
-
-
-#if ELF_INITFINI
-/* These function symbols are provided for the .init/.fini section entry
-   points automagically by the linker.  */
-extern void _init (void);
-extern void _fini (void);
-#endif
-
-
-/* These functions are passed to __libc_start_main by the startup code.
-   These get statically linked into each program.  For dynamically linked
-   programs, this module will come from libc_nonshared.a and differs from
-   the libc.a module in that it doesn't call the preinit array.  */
-
-
-void
-__libc_csu_init (int argc, char **argv, char **envp)
-{
-  /* For dynamically linked executables the preinit array is executed by
-     the dynamic linker (before initializing any shared object).  */
-
-#ifndef LIBC_NONSHARED
-  /* For static executables, preinit happens right before init.  */
-  {
-    const size_t size = __preinit_array_end - __preinit_array_start;
-    size_t i;
-    for (i = 0; i < size; i++)
-      (*__preinit_array_start [i]) (argc, argv, envp);
-  }
-#endif
-
-#if ELF_INITFINI
-  _init ();
-#endif
-
-  const size_t size = __init_array_end - __init_array_start;
-  for (size_t i = 0; i < size; i++)
-      (*__init_array_start [i]) (argc, argv, envp);
-}
-
-/* This function should not be used anymore.  We run the executable's
-   destructor now just like any other.  We cannot remove the function,
-   though.  */
-void
-__libc_csu_fini (void)
-{
-#ifndef LIBC_NONSHARED
-  size_t i = __fini_array_end - __fini_array_start;
-  while (i-- > 0)
-    (*__fini_array_start [i]) ();
-
-# if ELF_INITFINI
-  _fini ();
-# endif
-#endif
-}
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 494132368f..eccc42a70c 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -1,4 +1,5 @@ 
-/* Copyright (C) 1998-2018 Free Software Foundation, Inc.
+/* Perform initialization and invoke main.
+   Copyright (C) 1998-2018 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
@@ -15,6 +16,10 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+/* Note: This code is only part of the startup code proper for
+   statically linked binaries.  For dynamically linked binaries, it
+   resides in libc.so.  */
+
 #include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -22,6 +27,8 @@ 
 #include <ldsodefs.h>
 #include <exit-thread.h>
 #include <libc-internal.h>
+#include <platform-params.h>
+#include <shlib-compat.h>
 
 #include <elf/dl-tunables.h>
 
@@ -88,9 +95,11 @@  apply_irel (void)
 # else
 #  define STATIC static inline __attribute__ ((always_inline))
 # endif
+# define DO_DEFINE_LIBC_START_MAIN_VERSION 0
 #else
 # define STATIC
 # define LIBC_START_MAIN __libc_start_main
+# define DO_DEFINE_LIBC_START_MAIN_VERSION 1
 #endif
 
 #ifdef MAIN_AUXVEC_ARG
@@ -106,6 +115,92 @@  apply_irel (void)
 # define ARCH_INIT_CPU_FEATURES()
 #endif
 
+#ifdef SHARED
+/* Initialization for dynamic executables.  Find the main executable
+   link map and run its init functions.  */
+static void
+call_init (int argc, char **argv, char **env)
+{
+  /* Obtain the main map of the executable.  */
+  struct link_map *l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
+  /* DT_PREINIT_ARRAY is not processed here.  It is already handled in
+     _dl_init in elf/dl-init.c.  Also see the call_init function in
+     the same file.  */
+
+  if (ELF_INITFINI && l->l_info[DT_INIT] != NULL)
+    DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr,
+		    argc, argv, env);
+
+  ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY];
+  if (init_array != NULL)
+    {
+      unsigned int jm
+	= l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
+      ElfW(Addr) *addrs = (void *) (init_array->d_un.d_ptr + l->l_addr);
+      for (unsigned int j = 0; j < jm; ++j)
+	((dl_init_t) addrs[j]) (argc, argv, env);
+    }
+}
+
+#else /* !SHARED */
+
+/* These magic symbols are provided by the linker.  */
+extern void (*__preinit_array_start []) (int, char **, char **)
+  attribute_hidden;
+extern void (*__preinit_array_end []) (int, char **, char **)
+  attribute_hidden;
+extern void (*__init_array_start []) (int, char **, char **)
+  attribute_hidden;
+extern void (*__init_array_end []) (int, char **, char **)
+  attribute_hidden;
+extern void (*__fini_array_start []) (void) attribute_hidden;
+extern void (*__fini_array_end []) (void) attribute_hidden;
+
+# if ELF_INITFINI
+/* These function symbols are provided for the .init/.fini section entry
+   points automagically by the linker.  */
+extern void _init (void);
+extern void _fini (void);
+# endif
+
+/* Initialization for static executables.  There is no dynamic
+   segment, so we access the symbols directly.  */
+static void
+call_init (int argc, char **argv, char **envp)
+{
+  /* For static executables, preinit happens right before init.  */
+  {
+    const size_t size = __preinit_array_end - __preinit_array_start;
+    size_t i;
+    for (i = 0; i < size; i++)
+      (*__preinit_array_start [i]) (argc, argv, envp);
+  }
+
+# if ELF_INITFINI
+  _init ();
+# endif
+
+  const size_t size = __init_array_end - __init_array_start;
+  for (size_t i = 0; i < size; i++)
+      (*__init_array_start [i]) (argc, argv, envp);
+}
+
+/* Likewise for the destructor.  */
+static void
+call_fini (void *unused)
+{
+  size_t i = __fini_array_end - __fini_array_start;
+  while (i-- > 0)
+    (*__fini_array_start [i]) ();
+
+# if ELF_INITFINI
+  _fini ();
+# endif
+}
+
+#endif /* !SHARED */
+
 #include <libc-start.h>
 
 STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
@@ -122,9 +217,16 @@  STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
      __attribute__ ((noreturn));
 
 
-/* Note: the fini parameter is ignored here for shared library.  It
-   is registered with __cxa_atexit.  This had the disadvantage that
-   finalizers were called in more than one place.  */
+/* Note: The init and fini parameters are no longer used.  fini is
+   completely unused, init is still called if not NULL, but the
+   current startup code always passes NULL.  (In the future, it would
+   be possible to use fini to pass a version code if init is NULL, to
+   indicate the link-time glibc without introducing a hard
+   incompatibility for new programs with older glibc versions.)
+
+   For dynamically linked executables, the dynamic segment is used to
+   locate constructors and destructors.  For statically linked
+   executables, the relevant symbols are access directly.  */
 STATIC int
 LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
 		 int argc, char **argv,
@@ -243,9 +345,8 @@  LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
      run the constructors in `_dl_start_user'.  */
   __libc_init_first (argc, argv, __environ);
 
-  /* Register the destructor of the program, if any.  */
-  if (fini)
-    __cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
+  /* Register the destructor of the statically-linked program.  */
+  __cxa_atexit (call_fini, NULL, NULL);
 
   /* Some security at this point.  Prevent starting a SUID binary where
      the standard file descriptors are not opened.  We have to do this
@@ -253,15 +354,24 @@  LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
      loader did the work already.  */
   if (__builtin_expect (__libc_enable_secure, 0))
     __libc_check_standard_fds ();
-#endif
+#endif /* !SHARED */
 
   /* Call the initializer of the program, if any.  */
 #ifdef SHARED
   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
     GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
-#endif
-  if (init)
+
+  if (init != NULL)
+    /* This is a legacy program which supplied its own init
+       routine.  */
     (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
+  else
+    /* This is a current program.  Use the dynamic segment to find
+       constructors.  */
+    call_init (argc, argv, __environ);
+#else /* !SHARED */
+  call_init (argc, argv, __environ);
+#endif /* SHARED */
 
 #ifdef SHARED
   /* Auditing checkpoint: we have a new object.  */
@@ -341,3 +451,28 @@  LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
 
   exit (result);
 }
+
+#ifdef SHARED
+/* Starting with glibc 2.29, the init parameter is always NULL.  Older
+   libcs are not prepared to handle that.  */
+# define DEFINE_LIBC_START_MAIN_VERSION \
+  DEFINE_LIBC_START_MAIN_VERSION_1 \
+  versioned_symbol (libc, __libc_start_main, __libc_start_main, GLIBC_2_29);
+
+# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_29)
+#  define DEFINE_LIBC_START_MAIN_VERSION_1 \
+  strong_alias (__libc_start_main, __libc_start_main_alias)		\
+  compat_symbol (libc, __libc_start_main_alias, __libc_start_main, GLIBC_2_0);
+#  else
+#  define DEFINE_LIBC_START_MAIN_VERSION_1
+# endif
+#else
+# define DEFINE_LIBC_START_MAIN_VERSION
+#endif
+
+/* Only define the version information if LIBC_START_MAIN was not set.
+   If there is a wrapper file, it must expand
+   DEFINE_LIBC_START_MAIN_VERSION on its own.  */
+#if DO_DEFINE_LIBC_START_MAIN_VERSION
+DEFINE_LIBC_START_MAIN_VERSION
+#endif
diff --git a/elf/dl-init.c b/elf/dl-init.c
index 31eb12b974..dad3902254 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -21,10 +21,6 @@ 
 #include <platform-params.h>
 
 
-/* Type of the initializer.  */
-typedef void (*init_t) (int, char **, char **);
-
-
 static void
 call_init (struct link_map *l, int argc, char **argv, char **env)
 {
@@ -71,7 +67,7 @@  call_init (struct link_map *l, int argc, char **argv, char **env)
 
       addrs = (ElfW(Addr) *) (init_array->d_un.d_ptr + l->l_addr);
       for (j = 0; j < jm; ++j)
-	((init_t) addrs[j]) (argc, argv, env);
+	((dl_init_t) addrs[j]) (argc, argv, env);
     }
 }
 
@@ -103,7 +99,7 @@  _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
 
       addrs = (ElfW(Addr) *) (preinit_array->d_un.d_ptr + main_map->l_addr);
       for (cnt = 0; cnt < i; ++cnt)
-	((init_t) addrs[cnt]) (argc, argv, env);
+	((dl_init_t) addrs[cnt]) (argc, argv, env);
     }
 
   /* Stupid users forced the ELF specification to be changed.  It now
diff --git a/sysdeps/aarch64/start.S b/sysdeps/aarch64/start.S
index bad000f555..2c22b6ff27 100644
--- a/sysdeps/aarch64/start.S
+++ b/sysdeps/aarch64/start.S
@@ -64,26 +64,16 @@  _start:
 # ifdef SHARED
         adrp    x0, :got:main
 	ldr     PTR_REG (0), [x0, #:got_lo12:main]
-
-        adrp    x3, :got:__libc_csu_init
-	ldr     PTR_REG (3), [x3, #:got_lo12:__libc_csu_init]
-
-        adrp    x4, :got:__libc_csu_fini
-	ldr     PTR_REG (4), [x4, #:got_lo12:__libc_csu_fini]
 # else
 	adrp	x0, __wrap_main
 	add	x0, x0, :lo12:__wrap_main
-	adrp	x3, __libc_csu_init
-	add	x3, x3, :lo12:__libc_csu_init
-	adrp	x4, __libc_csu_fini
-	add	x4, x4, :lo12:__libc_csu_fini
 # endif
 #else
 	/* Set up the other arguments in registers */
 	MOVL (0, main)
-	MOVL (3, __libc_csu_init)
-	MOVL (4, __libc_csu_fini)
 #endif
+	mov	x3, #0		/* Used to be init.  */
+	mov	x4, #0		/* Used to be fini.  */
 
 	/* __libc_start_main (main, argc, argv, init, fini, rtld_fini,
 			      stack_end) */
diff --git a/sysdeps/alpha/start.S b/sysdeps/alpha/start.S
index 5de8ceeca7..57ea0d67f7 100644
--- a/sysdeps/alpha/start.S
+++ b/sysdeps/alpha/start.S
@@ -55,9 +55,8 @@  _start:
 	ldl	a1, 16(sp)	/* get argc */
 	lda	a2, 24(sp)	/* get argv */
 
-  /* Load address of our own entry points to .fini and .init.  */
-	lda	a3, __libc_csu_init
-	lda	a4, __libc_csu_fini
+	mov	$r31, a3 	/* Used to be init.  */
+	mov	$r31, a4 	/* Used to be init.  */
 
   /* Store address of the shared library termination function.  */
 	mov	v0, a5
diff --git a/sysdeps/arm/start.S b/sysdeps/arm/start.S
index adef090717..ad2b25c2e1 100644
--- a/sysdeps/arm/start.S
+++ b/sysdeps/arm/start.S
@@ -94,30 +94,20 @@  _start:
 	adr a4, .L_GOT
 	add sl, sl, a4
 
-	ldr ip, .L_GOT+4	/* __libc_csu_fini */
-	ldr ip, [sl, ip]
+	mov a4, #0		/* Used to be init.  */
+	push { a4 }		/* Used to be fini.  */
 
-	push { ip }		/* Push __libc_csu_fini */
-
-	ldr a4, .L_GOT+8	/* __libc_csu_init */
-	ldr a4, [sl, a4]
-
-	ldr a1, .L_GOT+12	/* main */
+	ldr a1, .L_GOT+4	/* main */
 	ldr a1, [sl, a1]
 
 	/* __libc_start_main (main, argc, argv, init, fini, rtld_fini, stack_end) */
 	/* Let the libc call main and exit with its return code.  */
 	bl __libc_start_main(PLT)
 #else
-	/* Fetch address of __libc_csu_fini */
-	ldr ip, =__libc_csu_fini
 
-	/* Push __libc_csu_fini */
-	push { ip }
-
-	/* Set up the other arguments in registers */
+	mov a4, #0		/* Used to init.  */
+	push { a4 }		/* Used to fini.  */
 	ldr a1, =main
-	ldr a4, =__libc_csu_init
 
 	/* __libc_start_main (main, argc, argv, init, fini, rtld_fini, stack_end) */
 	/* Let the libc call main and exit with its return code.  */
@@ -131,8 +121,6 @@  _start:
 	.align 2
 .L_GOT:
 	.word _GLOBAL_OFFSET_TABLE_ - .L_GOT
-	.word __libc_csu_fini(GOT)
-	.word __libc_csu_init(GOT)
 	.word main(GOT)
 #endif
 
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 95dc87519b..76a1f0dd56 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -75,6 +75,10 @@  typedef struct link_map *lookup_t;
    : (__glibc_unlikely ((ref)->st_shndx == SHN_ABS) ? 0			\
       : LOOKUP_VALUE_ADDRESS (map, map_set)) + (ref)->st_value)
 
+/* Type of a constructor function, in DT_INIT, DT_INIT_ARRAY,
+   DT_PREINIT_ARRAY.  */
+typedef void (*dl_init_t) (int, char **, char **);
+
 /* On some architectures a pointer to a function is not just a pointer
    to the actual code of the function but rather an architecture
    specific descriptor. */
@@ -83,7 +87,7 @@  typedef struct link_map *lookup_t;
  (void *) SYMBOL_ADDRESS (map, ref, false)
 # define DL_LOOKUP_ADDRESS(addr) ((ElfW(Addr)) (addr))
 # define DL_CALL_DT_INIT(map, start, argc, argv, env) \
- ((init_t) (start)) (argc, argv, env)
+ ((dl_init_t) (start)) (argc, argv, env)
 # define DL_CALL_DT_FINI(map, start) ((fini_t) (start)) ()
 #endif
 
diff --git a/sysdeps/hppa/dl-lookupcfg.h b/sysdeps/hppa/dl-lookupcfg.h
index 38db345936..f9ef78d856 100644
--- a/sysdeps/hppa/dl-lookupcfg.h
+++ b/sysdeps/hppa/dl-lookupcfg.h
@@ -56,7 +56,7 @@  void attribute_hidden _dl_unmap (struct link_map *map);
 {							\
   ElfW(Addr) addr;					\
   DL_DT_FUNCTION_ADDRESS(map, start, , addr)		\
-  init_t init = (init_t) addr; 				\
+  dl_init_t init = (dl_init_t) addr; 			\
   init (argc, argv, env);				\
 }
 
diff --git a/sysdeps/hppa/start.S b/sysdeps/hppa/start.S
index c1d2bd4bb7..8ffc247827 100644
--- a/sysdeps/hppa/start.S
+++ b/sysdeps/hppa/start.S
@@ -36,8 +36,6 @@ 
 	.import main, code
 	.import $global$, data
 	.import __libc_start_main, code
-	.import __libc_csu_fini, code
-	.import __libc_csu_init, code
 
 	/* Have the linker create plabel words so we get PLABEL32
 	   relocs and not 21/14.  The use of 21/14 relocs is only
@@ -52,10 +50,6 @@ 
 	.word P%main
 .Lp__libc_start_main:
 	.word P%__libc_start_main
-.Lp__libc_csu_fini:
-	.word P%__libc_csu_fini
-.Lp__libc_csu_init:
-	.word P%__libc_csu_init
 
 	.text
 	.align 4
@@ -77,8 +71,8 @@  _start:
 		1. r26 - Application main
 		2. r25 - argc
 		3. r24 - argv
-		4. r23 - __libc_csu_init
-		5. sp-52 - __libc_csu_fini
+		4. r23 - init (unused)
+		5. sp-52 - fini (unused)
 		6. sp-56 - rtld_fini
 		7. sp-60 - stackend  */
 
@@ -108,14 +102,6 @@  _start:
 	addil	LT'.Lpmain, %r19
 	ldw	RT'.Lpmain(%r1), %r26
 	ldw	0(%r26),%r26
-	/* void (*init) (void) (4th argument) */
-	addil	LT'.Lp__libc_csu_init, %r19
-	ldw	RT'.Lp__libc_csu_init(%r1), %r23
-	ldw	0(%r23), %r23
-	/* void (*fini) (void) (5th argument) */
-	addil	LT'.Lp__libc_csu_fini, %r19
-	ldw	RT'.Lp__libc_csu_fini(%r1), %r22
-	ldw	0(%r22), %r22
 #else
 	/* Load $global$ address into %dp */
 	ldil	L%$global$, %dp
@@ -124,13 +110,9 @@  _start:
 	/* load main (1st argument) */
 	ldil	LR'.Lpmain, %r26
 	ldw	RR'.Lpmain(%r26), %r26
-	/* void (*init) (void) (4th argument) */
-	ldil	LR'.Lp__libc_csu_init, %r23
-	ldw	RR'.Lp__libc_csu_init(%r23), %r23
-	/* void (*fini) (void) (5th argument) */
-	ldil	LR'.Lp__libc_csu_fini, %r22
-	ldw	RR'.Lp__libc_csu_fini(%r22), %r22
 #endif
+	ldi	0,%r23		/* Used to be init.  */
+	ldi	0,%r22		/* Used to be fini.  */
 	/* Store 5th argument */
 	stw	%r22, -52(%sp)
 	/* void *stack_end (7th argument) */
diff --git a/sysdeps/i386/start.S b/sysdeps/i386/start.S
index 91035fa83f..92781dc121 100644
--- a/sysdeps/i386/start.S
+++ b/sysdeps/i386/start.S
@@ -86,11 +86,9 @@  _start:
 	call 1f
 	addl $_GLOBAL_OFFSET_TABLE_, %ebx
 
-	/* Push address of our own entry points to .fini and .init.  */
-	leal __libc_csu_fini@GOTOFF(%ebx), %eax
-	pushl %eax
-	leal __libc_csu_init@GOTOFF(%ebx), %eax
-	pushl %eax
+	/* This used to be the addresses of .fini and .init.  */
+	pushl $0
+	pushl $0
 
 	pushl %ecx		/* Push second argument: argv.  */
 	pushl %esi		/* Push first argument: argc.  */
@@ -111,9 +109,9 @@  _start:
 	   But let the libc call main.    */
 	call __libc_start_main@PLT
 #else
-	/* Push address of our own entry points to .fini and .init.  */
-	pushl $__libc_csu_fini
-	pushl $__libc_csu_init
+	/* This used to be the addresses of .fini and .init.  */
+	pushl $0
+	pushl $0
 
 	pushl %ecx		/* Push second argument: argv.  */
 	pushl %esi		/* Push first argument: argc.  */
diff --git a/sysdeps/ia64/dl-lookupcfg.h b/sysdeps/ia64/dl-lookupcfg.h
index 48f91202c4..83734a9562 100644
--- a/sysdeps/ia64/dl-lookupcfg.h
+++ b/sysdeps/ia64/dl-lookupcfg.h
@@ -50,7 +50,7 @@  extern void attribute_hidden _dl_unmap (struct link_map *map);
 {							\
   ElfW(Addr) addr;					\
   DL_DT_FUNCTION_ADDRESS(map, start, , addr)		\
-  init_t init = (init_t) addr; 				\
+  dl_init_t init = (dl_init_t) addr; 			\
   init (argc, argv, env);				\
 }
 
diff --git a/sysdeps/ia64/start.S b/sysdeps/ia64/start.S
index 04205aa94f..6c3e468bcb 100644
--- a/sysdeps/ia64/start.S
+++ b/sysdeps/ia64/start.S
@@ -83,20 +83,15 @@  _start:
 	{
 	  addl r11 = @ltoff(__libc_ia64_register_backing_store_base), gp
 	  addl out0 = @ltoff(@fptr(main)), gp
-	  addl out3 = @ltoff(@fptr(__libc_csu_init)), gp
+	  mov out3 = r0		/* Used to be init.  */
 	  ;;
 	}
 	{ .mmi
 	  ld8 r3 = [r11]	/* pointer to __libc_ia64_register_backing_store_base */
 	  ld8 out0 = [out0]	/* pointer to `main' function descriptor */
-	  addl out4 = @ltoff(@fptr(__libc_csu_fini)), gp
+	  mov out4 = r0		/* Used to be fini.  */
 	  ;;
 	}
-	{ .mmi
-	  ld8 out3 = [out3]	/* pointer to `init' function descriptor */
-	  ld8 out4 = [out4]	/* pointer to `fini' function descriptor */
-	  nop 0
-	}
 	.body
 	{ .mib
 	  st8 [r3] = r10
diff --git a/sysdeps/m68k/start.S b/sysdeps/m68k/start.S
index 7bab3e1cde..7d151a3205 100644
--- a/sysdeps/m68k/start.S
+++ b/sysdeps/m68k/start.S
@@ -76,15 +76,14 @@  _start:
 	pea (%a1)		/* Push address of the shared library
 				   termination function.  */
 
+	/* These used to be addresses of the .fini and .init entry points.  */
+	clr.l -(%sp)
+	clr.l -(%sp)
+
 #ifdef PIC
 	/* Load PIC register.  */
 	LOAD_GOT (%a5)
 
-	/* Push the address of our own entry points to `.fini' and
-	   `.init'.  */
-	move.l __libc_csu_fini@GOT(%a5), -(%sp)
-	move.l __libc_csu_init@GOT(%a5), -(%sp)
-
 	pea (%a0)		/* Push second argument: argv.  */
 	move.l %d0, -(%sp)	/* Push first argument: argc.  */
 
@@ -94,10 +93,6 @@  _start:
 	   let the libc call main.  */
 	jbsr __libc_start_main@PLTPC
 #else
-	/* Push the address of our own entry points to `.fini' and
-	   `.init'.  */
-	pea __libc_csu_fini
-	pea __libc_csu_init
 
 	pea (%a0)		/* Push second argument: argv.  */
 	move.l %d0, -(%sp)	/* Push first argument: argc.  */
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index e3fc05137b..0705f9e129 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2038,6 +2038,7 @@  GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
 GLIBC_2.28 statx F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/microblaze/start.S b/sysdeps/microblaze/start.S
index cc8dd13fe4..39f858ab71 100644
--- a/sysdeps/microblaze/start.S
+++ b/sysdeps/microblaze/start.S
@@ -63,14 +63,14 @@  _start:
     mfs     r20,rpc
     addik   r20,r20,_GLOBAL_OFFSET_TABLE_+8
     lwi     r5,r20,main@GOT
-    lwi     r8,r20,__libc_csu_init@GOT
-    lwi     r9,r20,__libc_csu_fini@GOT
+    addk    r8,r0,r0		/* Used to be init.  */
+    addk    r8,r0,r0		/* Used to be fini.  */
     brid    __libc_start_main@PLT
     addk    r10,r0,r0
 #else
     addik   r5,r0,main
-    addik   r8,r0,__libc_csu_init
-    addik   r9,r0,__libc_csu_fini
+    addk    r8,r0,r0		/* Used to be init.  */
+    addk    r8,r0,r0		/* Used to be fini.  */
     brid    __libc_start_main
     addk    r10,r0,r0
 #endif
diff --git a/sysdeps/mips/start.S b/sysdeps/mips/start.S
index a4c4ef0fae..f1ba04bc97 100644
--- a/sysdeps/mips/start.S
+++ b/sysdeps/mips/start.S
@@ -96,10 +96,9 @@  ENTRY_POINT:
 # if _MIPS_SIM == _ABIO32
 	PTR_SUBIU $29, 32
 # endif
-	PTR_LA $7, __libc_csu_init		/* init */
-	PTR_LA $8, __libc_csu_fini
+	move  $7, $0			/* init */
 # if _MIPS_SIM == _ABIO32
-	PTR_S $8, 16($29)		/* fini */
+	PTR_S $0, 16($29)		/* fini */
 	PTR_S $2, 20($29)		/* rtld_fini */
 	PTR_S $29, 24($29)		/* stack_end */
 # else
@@ -143,19 +142,17 @@  ENTRY_POINT:
 	/* Lay out last arguments, and call __libc_start_main().  */
 # ifdef __PIC__
 	sw	$7, 24($sp)			/* stack_end */
-	lw	$4, %got(__libc_csu_fini)($3)
-	lw	$7, %got(__libc_csu_init)($3)	/* init */
-	sw	$4, 16($sp)			/* fini */
+	move	$4, $0				/* Used to be ini.  */
+	sw	$0, 16($sp)			/* Used to be fini.  */
 	lw	$4, %got(main)($3)		/* main */
 	lw	$3, %call16(__libc_start_main)($3)
 	sw	$2, 20($sp)			/* rtld_fini */
 	move	$25, $3
 	jalr	$3
 # else
-	lw	$4, 1f
 	sw	$7, 24($sp)			/* stack_end */
-	lw	$7, 2f				/* init */
-	sw	$4, 16($sp)			/* fini */
+	move	$7, $0				/* Used to be init.  */
+	sw	$0, 16($sp)			/* Used to be fini.  */
 	lw	$4, 3f				/* main */
 	sw	$2, 20($sp)			/* rtld_fini */
 	/* Load and call __libc_start_main().  */
@@ -165,8 +162,6 @@  ENTRY_POINT:
 hlt:	b	hlt		/* Crash if somehow it does return.  */
 # ifndef __PIC__
 	.align	2
-1:	.word	__libc_csu_fini
-2:	.word	__libc_csu_init
 3:	.word	main
 4:	.word	__libc_start_main
 # endif
diff --git a/sysdeps/nios2/start.S b/sysdeps/nios2/start.S
index fa224ef75c..51a0757d78 100644
--- a/sysdeps/nios2/start.S
+++ b/sysdeps/nios2/start.S
@@ -92,18 +92,11 @@  _start:
 	addi	r2, r2, %lo(_gp_got - 1b)
 	add	r22, r22, r2
 
-	/* Push fini */
-	movhi	r8, %call_hiadj(__libc_csu_fini)
-	addi	r8, r8, %call_lo(__libc_csu_fini)
-	add	r8, r8, r22
-	ldw	r8, 0(r8)
-	stw	r8, 0(sp)
+	/* Used to be fini.  */
+	stw	zero, 0(sp)
 
-	/* r7 == init */
-	movhi	r7, %call_hiadj(__libc_csu_init)
-	addi	r7, r7, %call_lo(__libc_csu_init)
-	add	r7, r7, r22
-	ldw	r7, 0(r7)
+	/* Used to be init.  */
+	mov	r7, zero
 
 	/* r6 == argv */
 	addi	r6, sp, 16
diff --git a/sysdeps/powerpc/powerpc32/start.S b/sysdeps/powerpc/powerpc32/start.S
index 5c10a22f8a..0be6aed543 100644
--- a/sysdeps/powerpc/powerpc32/start.S
+++ b/sysdeps/powerpc/powerpc32/start.S
@@ -52,8 +52,8 @@ 
 L(start_addresses):
 	.long	_SDA_BASE_
 	.long	main
-	.long 	__libc_csu_init
-	.long 	__libc_csu_fini
+	.long 	0 /* Used to be init.  */
+	.long 	0 /* Used to be fini.  */
 	ASM_SIZE_DIRECTIVE(L(start_addresses))
 
 	.section ".text"
diff --git a/sysdeps/powerpc/powerpc64/start.S b/sysdeps/powerpc/powerpc64/start.S
index bd7189310c..149afbeab1 100644
--- a/sysdeps/powerpc/powerpc64/start.S
+++ b/sysdeps/powerpc/powerpc64/start.S
@@ -53,8 +53,8 @@  L(start_addresses):
 	.quad	0 /* was _SDA_BASE_  but not in 64-bit ABI*/
 /*     function descriptors so don't need JUMPTARGET */
 	.quad	main
-	.quad 	__libc_csu_init
-	.quad 	__libc_csu_fini
+	.quad 	0 /* Used to be init.  */
+	.quad 	0 /* Used to be fini.  */
 
 	ASM_SIZE_DIRECTIVE(L(start_addresses))
 
diff --git a/sysdeps/riscv/start.S b/sysdeps/riscv/start.S
index 4635ddb5eb..9dd4714910 100644
--- a/sysdeps/riscv/start.S
+++ b/sysdeps/riscv/start.S
@@ -50,8 +50,8 @@  ENTRY (ENTRY_POINT)
 	REG_L a1, 0(sp)      /* argc.  */
 	addi  a2, sp, SZREG  /* argv.  */
 	andi  sp, sp, ALMASK /* Align stack. */
-	lla   a3, __libc_csu_init
-	lla   a4, __libc_csu_fini
+	li    a3, 0	     /* Used to be init.  */
+	li    a4, 0	     /* Used to be fini.  */
 	mv    a6, sp  /* stack_end.  */
 
 	tail  __libc_start_main@plt
diff --git a/sysdeps/s390/s390-32/start.S b/sysdeps/s390/s390-32/start.S
index 1483642985..4587b2de5e 100644
--- a/sysdeps/s390/s390-32/start.S
+++ b/sysdeps/s390/s390-32/start.S
@@ -175,18 +175,16 @@  _start:
 	 */
 	stm     %r14,%r15,96(%r15)      # store rtld_fini/stack_end to parameter area
 	la      %r7,96(%r15)
-	l       %r6,.L2-.Llit(%r13)     # load pointer to __libc_csu_fini
-	l       %r5,.L1-.Llit(%r13)     # load pointer to __libc_csu_init
 	l       %r2,.L3-.Llit(%r13)     # load pointer to main
 	l       %r1,.L4-.Llit(%r13)	# load pointer to __libc_start_main
 #ifdef PIC
 	l       %r12,.L5-.Llit(%r13)    # load .got pointer
-	la	%r6,0(%r13,%r6)
-	la	%r5,0(%r13,%r5)
 	la	%r12,0(%r13,%r12)
 	l	%r2,0(%r12,%r2)
 	la	%r1,0(%r13,%r1)
 #endif
+	lhi	%r6, 0			# Used to fini.
+	lhi	%r5, 0			# Used to init.
 
 	/* ok, now branch to the libc main routine */
 	basr    %r14,%r1
@@ -197,13 +195,9 @@  _start:
 	cfi_endproc
 .Llit:
 #ifndef PIC
-.L1:    .long  __libc_csu_init
-.L2:    .long  __libc_csu_fini
 .L3:    .long  main
 .L4:    .long  __libc_start_main
 #else
-.L1:    .long  __libc_csu_init-.Llit
-.L2:    .long  __libc_csu_fini-.Llit
 .L3:    .long  main@GOT
 .L4:    .long  __libc_start_main@plt-.Llit
 .L5:    .long  _GLOBAL_OFFSET_TABLE_-.Llit
diff --git a/sysdeps/s390/s390-64/start.S b/sysdeps/s390/s390-64/start.S
index 79e7b69f1d..518dfd989e 100644
--- a/sysdeps/s390/s390-64/start.S
+++ b/sysdeps/s390/s390-64/start.S
@@ -80,8 +80,8 @@  _start:
 	 */
 	stmg	%r14,%r15,160(%r15)	# store rtld_fini/stack_end to parameter area
 	la	%r7,160(%r15)
-	larl	%r6,__libc_csu_fini	# load pointer to __libc_csu_fini
-	larl	%r5,__libc_csu_init	# load pointer to __libc_csu_init
+	lghi	%r6,0			# Used to be fini.
+	lghi	%r5,0			# Used to be init.
 
 	/* Ok, now branch to the libc main routine.  */
 #ifdef PIC
diff --git a/sysdeps/sh/start.S b/sysdeps/sh/start.S
index f52077abca..4b0aad511b 100644
--- a/sysdeps/sh/start.S
+++ b/sysdeps/sh/start.S
@@ -70,12 +70,11 @@  _start:
 
 	/* Push the last arguments to main() onto the stack */
 	mov.l r4,@-r15
-	mov.l L_fini,r0
-	mov.l r0,@-r15
+	mov.l r14,@-r15		/* Used to be fini.  */
 
 	/* Set up the other arguments for main() that go in registers */
 	mov.l L_main,r4
-	mov.l L_init,r7
+	mov #0,r7		/* Used to be init.  */
 
 	/* __libc_start_main (main, argc, argv, init, fini, rtld_fini) */
 
@@ -90,10 +89,6 @@  _start:
 	.align	2
 L_main:
 	.long	main
-L_init:
-	.long	__libc_csu_init
-L_fini:
-	.long	__libc_csu_fini
 L_libc_start_main:
 	.long	__libc_start_main
 L_abort:
diff --git a/sysdeps/sparc/sparc32/start.S b/sysdeps/sparc/sparc32/start.S
index 46ba8b6afa..48b30a3fb5 100644
--- a/sysdeps/sparc/sparc32/start.S
+++ b/sysdeps/sparc/sparc32/start.S
@@ -59,22 +59,14 @@  _start:
   /* Load the addresses of the user entry points.  */
 #ifndef PIC
 	sethi	%hi(main), %o0
-	sethi	%hi(__libc_csu_init), %o3
-	sethi	%hi(__libc_csu_fini), %o4
 	or	%o0, %lo(main), %o0
-	or	%o3, %lo(__libc_csu_init), %o3
-	or	%o4, %lo(__libc_csu_fini), %o4
 #else
 	sethi	%gdop_hix22(main), %o0
-	sethi	%gdop_hix22(__libc_csu_init), %o3
-	sethi	%gdop_hix22(__libc_csu_fini), %o4
 	xor	%o0, %gdop_lox10(main), %o0
-	xor	%o3, %gdop_lox10(__libc_csu_init), %o3
-	xor	%o4, %gdop_lox10(__libc_csu_fini), %o4
 	ld	[%l7 + %o0], %o0, %gdop(main)
-	ld	[%l7 + %o3], %o3, %gdop(__libc_csu_init)
-	ld	[%l7 + %o4], %o4, %gdop(__libc_csu_fini)
 #endif
+	mov	0, %o3		/* Used to be init.  */
+	mov	0, %o4		/* Used to be fini.  */
 
   /* When starting a binary via the dynamic linker, %g1 contains the
      address of the shared library termination function, which will be
diff --git a/sysdeps/sparc/sparc64/start.S b/sysdeps/sparc/sparc64/start.S
index 75ff5093dc..73395df40a 100644
--- a/sysdeps/sparc/sparc64/start.S
+++ b/sysdeps/sparc/sparc64/start.S
@@ -60,22 +60,14 @@  _start:
   /* Load the addresses of the user entry points.  */
 #ifndef PIC
 	sethi	%hi(main), %o0
-	sethi	%hi(__libc_csu_init), %o3
-	sethi	%hi(__libc_csu_fini), %o4
 	or	%o0, %lo(main), %o0
-	or	%o3, %lo(__libc_csu_init), %o3
-	or	%o4, %lo(__libc_csu_fini), %o4
 #else
 	sethi	%gdop_hix22(main), %o0
-	sethi	%gdop_hix22(__libc_csu_init), %o3
-	sethi	%gdop_hix22(__libc_csu_fini), %o4
 	xor	%o0, %gdop_lox10(main), %o0
-	xor	%o3, %gdop_lox10(__libc_csu_init), %o3
-	xor	%o4, %gdop_lox10(__libc_csu_fini), %o4
 	ldx	[%l7 + %o0], %o0, %gdop(main)
-	ldx	[%l7 + %o3], %o3, %gdop(__libc_csu_init)
-	ldx	[%l7 + %o4], %o4, %gdop(__libc_csu_fini)
 #endif
+	mov	0, %o3		/* Used to be init.  */
+	mov	0, %o4		/* Used to be fini.  */
 
   /* When starting a binary via the dynamic linker, %g1 contains the
      address of the shared library termination function, which will be
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 15f966f841..1bee009bd5 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2138,3 +2138,4 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index e22b91655d..4985abf3ff 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2033,6 +2033,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index a231812eea..828d53d583 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -123,6 +123,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 24b11b15c0..d3d3c7d821 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1880,6 +1880,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 9762c81365..a4be302340 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2045,6 +2045,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 50c94adff9..a35aac00e6 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1914,6 +1914,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index f57be98e49..09837b79bf 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -124,6 +124,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index ddc7ebca67..ff86eada39 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1989,6 +1989,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index daed511f00..63008d937e 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2130,3 +2130,4 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index dda9797e0e..6ed8e7fe97 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1967,6 +1967,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 42e930d565..792876692a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1965,6 +1965,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index f89b44f3a1..f39bfd392f 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1973,6 +1973,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 1486af11d7..c71f720538 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1968,6 +1968,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index aab1c44e46..6d1a92ca9f 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2171,3 +2171,4 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
diff --git a/sysdeps/unix/sysv/linux/powerpc/libc-start.c b/sysdeps/unix/sysv/linux/powerpc/libc-start.c
index f2ad0c355d..522926604b 100644
--- a/sysdeps/unix/sysv/linux/powerpc/libc-start.c
+++ b/sysdeps/unix/sysv/linux/powerpc/libc-start.c
@@ -103,3 +103,4 @@  __libc_start_main (int argc, char **argv,
 			     stinfo->init, stinfo->fini, rtld_fini,
 			     stack_on_entry);
 }
+DEFINE_LIBC_START_MAIN_VERSION
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 45839ed25b..7d06166905 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1993,6 +1993,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 344e5ae87c..5b079783cc 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1997,6 +1997,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index e26930e728..d0ee5d21ed 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2228,3 +2228,4 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 8c1781adf4..01a394146e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -123,6 +123,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 _Exit F
 GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
 GLIBC_2.3 _IO_2_1_stdin_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index daacceebd6..a1f19becf9 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2100,3 +2100,4 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 3a5ec2a1e4..3d4adb5018 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2002,6 +2002,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 3b5465558b..9d6d587a2b 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1907,6 +1907,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 1f4e648baa..1d2a8f5759 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1884,6 +1884,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index d308ac8b05..f041d824e6 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1996,6 +1996,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 6731ebfc28..d709b89be4 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1937,6 +1937,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 816e4a7426..73fcf0e0d0 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1895,6 +1895,7 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 6fee16a850..4be56f140d 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2146,3 +2146,4 @@  GLIBC_2.28 thrd_current F
 GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
+GLIBC_2.29 __libc_start_main F
diff --git a/sysdeps/x86_64/start.S b/sysdeps/x86_64/start.S
index 354d2e6ec7..8060586b5c 100644
--- a/sysdeps/x86_64/start.S
+++ b/sysdeps/x86_64/start.S
@@ -96,17 +96,13 @@  ENTRY (_start)
 	   which grow downwards).  */
 	pushq %rsp
 
+	/* These used to be the addresses of .fini and .init.  */
+	xor %R8_LP, %R8_LP
+	xor %RCX_LP, %RCX_LP
+
 #ifdef PIC
-	/* Pass address of our own entry points to .fini and .init.  */
-	mov __libc_csu_fini@GOTPCREL(%rip), %R8_LP
-	mov __libc_csu_init@GOTPCREL(%rip), %RCX_LP
-
 	mov main@GOTPCREL(%rip), %RDI_LP
 #else
-	/* Pass address of our own entry points to .fini and .init.  */
-	mov $__libc_csu_fini, %R8_LP
-	mov $__libc_csu_init, %RCX_LP
-
 	mov $main, %RDI_LP
 #endif