Linux: Consolidate auxiliary vector parsing

And optimize it slightly.

The large switch statement in _dl_sysdep_start can be replaced with
a large array.  This reduces source code and binary size.  On
i686-linux-gnu:

Before:

   text	   data	    bss	    dec	    hex	filename
   7791	     12	      0	   7803	   1e7b	elf/dl-sysdep.os

After:

   text	   data	    bss	    dec	    hex	filename
   7135	     12	      0	   7147	   1beb	elf/dl-sysdep.os

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 8c8510ab27)
This commit is contained in:
Florian Weimer 2022-02-03 10:58:59 +01:00
parent 08728256fa
commit 4b9cd5465d
6 changed files with 107 additions and 181 deletions

View File

@ -239,93 +239,21 @@ __rtld_lock_define_initialized_recursive (, _dl_load_tls_lock)
#ifdef HAVE_AUX_VECTOR #ifdef HAVE_AUX_VECTOR
#include <dl-parse_auxv.h>
int _dl_clktck; int _dl_clktck;
void void
_dl_aux_init (ElfW(auxv_t) *av) _dl_aux_init (ElfW(auxv_t) *av)
{ {
int seen = 0;
uid_t uid = 0;
gid_t gid = 0;
#ifdef NEED_DL_SYSINFO #ifdef NEED_DL_SYSINFO
/* NB: Avoid RELATIVE relocation in static PIE. */ /* NB: Avoid RELATIVE relocation in static PIE. */
GL(dl_sysinfo) = DL_SYSINFO_DEFAULT; GL(dl_sysinfo) = DL_SYSINFO_DEFAULT;
#endif #endif
_dl_auxv = av; _dl_auxv = av;
for (; av->a_type != AT_NULL; ++av) dl_parse_auxv_t auxv_values = { 0, };
switch (av->a_type) _dl_parse_auxv (av, auxv_values);
{
case AT_PAGESZ:
if (av->a_un.a_val != 0)
GLRO(dl_pagesize) = av->a_un.a_val;
break;
case AT_CLKTCK:
GLRO(dl_clktck) = av->a_un.a_val;
break;
case AT_PHDR:
GL(dl_phdr) = (const void *) av->a_un.a_val;
break;
case AT_PHNUM:
GL(dl_phnum) = av->a_un.a_val;
break;
case AT_PLATFORM:
GLRO(dl_platform) = (void *) av->a_un.a_val;
break;
case AT_HWCAP:
GLRO(dl_hwcap) = (unsigned long int) av->a_un.a_val;
break;
case AT_HWCAP2:
GLRO(dl_hwcap2) = (unsigned long int) av->a_un.a_val;
break;
case AT_FPUCW:
GLRO(dl_fpu_control) = av->a_un.a_val;
break;
#ifdef NEED_DL_SYSINFO
case AT_SYSINFO:
GL(dl_sysinfo) = av->a_un.a_val;
break;
#endif
#ifdef NEED_DL_SYSINFO_DSO
case AT_SYSINFO_EHDR:
GL(dl_sysinfo_dso) = (void *) av->a_un.a_val;
break;
#endif
case AT_UID:
uid ^= av->a_un.a_val;
seen |= 1;
break;
case AT_EUID:
uid ^= av->a_un.a_val;
seen |= 2;
break;
case AT_GID:
gid ^= av->a_un.a_val;
seen |= 4;
break;
case AT_EGID:
gid ^= av->a_un.a_val;
seen |= 8;
break;
case AT_SECURE:
seen = -1;
__libc_enable_secure = av->a_un.a_val;
__libc_enable_secure_decided = 1;
break;
case AT_RANDOM:
_dl_random = (void *) av->a_un.a_val;
break;
case AT_MINSIGSTKSZ:
_dl_minsigstacksize = av->a_un.a_val;
break;
DL_PLATFORM_AUXV
}
if (seen == 0xf)
{
__libc_enable_secure = uid != 0 || gid != 0;
__libc_enable_secure_decided = 1;
}
} }
#endif #endif

View File

@ -20,16 +20,8 @@
extern long __libc_alpha_cache_shape[4]; extern long __libc_alpha_cache_shape[4];
#define DL_PLATFORM_AUXV \ #define DL_PLATFORM_AUXV \
case AT_L1I_CACHESHAPE: \ __libc_alpha_cache_shape[0] = auxv_values[AT_L1I_CACHESHAPE]; \
__libc_alpha_cache_shape[0] = av->a_un.a_val; \ __libc_alpha_cache_shape[1] = auxv_values[AT_L1D_CACHESHAPE]; \
break; \ __libc_alpha_cache_shape[2] = auxv_values[AT_L2_CACHESHAPE]; \
case AT_L1D_CACHESHAPE: \ __libc_alpha_cache_shape[3] = auxv_values[AT_L3_CACHESHAPE];
__libc_alpha_cache_shape[1] = av->a_un.a_val; \
break; \
case AT_L2_CACHESHAPE: \
__libc_alpha_cache_shape[2] = av->a_un.a_val; \
break; \
case AT_L3_CACHESHAPE: \
__libc_alpha_cache_shape[3] = av->a_un.a_val; \
break;

View File

@ -0,0 +1,61 @@
/* Parse the Linux auxiliary vector.
Copyright (C) 1995-2022 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 <elf.h>
#include <entry.h>
#include <fpu_control.h>
#include <ldsodefs.h>
#include <link.h>
typedef ElfW(Addr) dl_parse_auxv_t[AT_MINSIGSTKSZ + 1];
/* Copy the auxiliary vector into AUX_VALUES and set up GLRO
variables. */
static inline
void _dl_parse_auxv (ElfW(auxv_t) *av, dl_parse_auxv_t auxv_values)
{
auxv_values[AT_ENTRY] = (ElfW(Addr)) ENTRY_POINT;
auxv_values[AT_PAGESZ] = EXEC_PAGESIZE;
auxv_values[AT_FPUCW] = _FPU_DEFAULT;
/* NB: Default to a constant CONSTANT_MINSIGSTKSZ. */
_Static_assert (__builtin_constant_p (CONSTANT_MINSIGSTKSZ),
"CONSTANT_MINSIGSTKSZ is constant");
auxv_values[AT_MINSIGSTKSZ] = CONSTANT_MINSIGSTKSZ;
for (; av->a_type != AT_NULL; av++)
if (av->a_type <= AT_MINSIGSTKSZ)
auxv_values[av->a_type] = av->a_un.a_val;
GLRO(dl_pagesize) = auxv_values[AT_PAGESZ];
__libc_enable_secure = auxv_values[AT_SECURE];
GLRO(dl_platform) = (void *) auxv_values[AT_PLATFORM];
GLRO(dl_hwcap) = auxv_values[AT_HWCAP];
GLRO(dl_hwcap2) = auxv_values[AT_HWCAP2];
GLRO(dl_clktck) = auxv_values[AT_CLKTCK];
GLRO(dl_fpu_control) = auxv_values[AT_FPUCW];
_dl_random = (void *) auxv_values[AT_RANDOM];
GLRO(dl_minsigstacksize) = auxv_values[AT_MINSIGSTKSZ];
GLRO(dl_sysinfo_dso) = (void *) auxv_values[AT_SYSINFO_EHDR];
#ifdef NEED_DL_SYSINFO
if (GLRO(dl_sysinfo_dso) != NULL)
GLRO(dl_sysinfo) = auxv_values[AT_SYSINFO];
#endif
DL_PLATFORM_AUXV
}

View File

@ -21,13 +21,12 @@
#include <dl-auxv.h> #include <dl-auxv.h>
#include <dl-hwcap-check.h> #include <dl-hwcap-check.h>
#include <dl-osinfo.h> #include <dl-osinfo.h>
#include <dl-parse_auxv.h>
#include <dl-procinfo.h> #include <dl-procinfo.h>
#include <dl-tunables.h> #include <dl-tunables.h>
#include <elf.h> #include <elf.h>
#include <entry.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <fpu_control.h>
#include <ldsodefs.h> #include <ldsodefs.h>
#include <libc-internal.h> #include <libc-internal.h>
#include <libintl.h> #include <libintl.h>
@ -63,24 +62,24 @@ void *_dl_random attribute_relro = NULL;
# define DL_STACK_END(cookie) ((void *) (cookie)) # define DL_STACK_END(cookie) ((void *) (cookie))
#endif #endif
ElfW(Addr) /* Arguments passed to dl_main. */
_dl_sysdep_start (void **start_argptr, struct dl_main_arguments
void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv))
{ {
const ElfW(Phdr) *phdr = NULL; const ElfW(Phdr) *phdr;
ElfW(Word) phnum = 0; ElfW(Word) phnum;
ElfW(Addr) user_entry; ElfW(Addr) user_entry;
ElfW(auxv_t) *av; };
#ifdef NEED_DL_SYSINFO
uintptr_t new_sysinfo = 0;
#endif
__libc_stack_end = DL_STACK_END (start_argptr); /* Separate function, so that dl_main can be called without the large
array on the stack. */
static void
_dl_sysdep_parse_arguments (void **start_argptr,
struct dl_main_arguments *args)
{
_dl_argc = (intptr_t) *start_argptr; _dl_argc = (intptr_t) *start_argptr;
_dl_argv = (char **) (start_argptr + 1); /* Necessary aliasing violation. */ _dl_argv = (char **) (start_argptr + 1); /* Necessary aliasing violation. */
_environ = _dl_argv + _dl_argc + 1; _environ = _dl_argv + _dl_argc + 1;
for (char **tmp = _environ + 1; ; ++tmp) for (char **tmp = _environ; ; ++tmp)
if (*tmp == NULL) if (*tmp == NULL)
{ {
/* Another necessary aliasing violation. */ /* Another necessary aliasing violation. */
@ -88,75 +87,26 @@ _dl_sysdep_start (void **start_argptr,
break; break;
} }
user_entry = (ElfW(Addr)) ENTRY_POINT; dl_parse_auxv_t auxv_values = { 0, };
GLRO(dl_platform) = NULL; /* Default to nothing known about the platform. */ _dl_parse_auxv (GLRO(dl_auxv), auxv_values);
/* NB: Default to a constant CONSTANT_MINSIGSTKSZ. */ args->phdr = (const ElfW(Phdr) *) auxv_values[AT_PHDR];
_Static_assert (__builtin_constant_p (CONSTANT_MINSIGSTKSZ), args->phnum = auxv_values[AT_PHNUM];
"CONSTANT_MINSIGSTKSZ is constant"); args->user_entry = auxv_values[AT_ENTRY];
GLRO(dl_minsigstacksize) = CONSTANT_MINSIGSTKSZ; }
for (av = GLRO(dl_auxv); av->a_type != AT_NULL; av++) ElfW(Addr)
switch (av->a_type) _dl_sysdep_start (void **start_argptr,
{ void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
case AT_PHDR: ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv))
phdr = (void *) av->a_un.a_val; {
break; __libc_stack_end = DL_STACK_END (start_argptr);
case AT_PHNUM:
phnum = av->a_un.a_val; struct dl_main_arguments dl_main_args;
break; _dl_sysdep_parse_arguments (start_argptr, &dl_main_args);
case AT_PAGESZ:
GLRO(dl_pagesize) = av->a_un.a_val;
break;
case AT_ENTRY:
user_entry = av->a_un.a_val;
break;
case AT_SECURE:
__libc_enable_secure = av->a_un.a_val;
break;
case AT_PLATFORM:
GLRO(dl_platform) = (void *) av->a_un.a_val;
break;
case AT_HWCAP:
GLRO(dl_hwcap) = (unsigned long int) av->a_un.a_val;
break;
case AT_HWCAP2:
GLRO(dl_hwcap2) = (unsigned long int) av->a_un.a_val;
break;
case AT_CLKTCK:
GLRO(dl_clktck) = av->a_un.a_val;
break;
case AT_FPUCW:
GLRO(dl_fpu_control) = av->a_un.a_val;
break;
#ifdef NEED_DL_SYSINFO
case AT_SYSINFO:
new_sysinfo = av->a_un.a_val;
break;
#endif
case AT_SYSINFO_EHDR:
GLRO(dl_sysinfo_dso) = (void *) av->a_un.a_val;
break;
case AT_RANDOM:
_dl_random = (void *) av->a_un.a_val;
break;
case AT_MINSIGSTKSZ:
GLRO(dl_minsigstacksize) = av->a_un.a_val;
break;
DL_PLATFORM_AUXV
}
dl_hwcap_check (); dl_hwcap_check ();
#ifdef NEED_DL_SYSINFO
if (new_sysinfo != 0)
{
/* Only set the sysinfo value if we also have the vsyscall DSO. */
if (GLRO(dl_sysinfo_dso) != 0)
GLRO(dl_sysinfo) = new_sysinfo;
}
#endif
__tunables_init (_environ); __tunables_init (_environ);
__brk (0); /* Initialize the break. */ __brk (0); /* Initialize the break. */
@ -184,8 +134,9 @@ _dl_sysdep_start (void **start_argptr,
if (__builtin_expect (__libc_enable_secure, 0)) if (__builtin_expect (__libc_enable_secure, 0))
__libc_check_standard_fds (); __libc_check_standard_fds ();
(*dl_main) (phdr, phnum, &user_entry, GLRO(dl_auxv)); (*dl_main) (dl_main_args.phdr, dl_main_args.phnum,
return user_entry; &dl_main_args.user_entry, GLRO(dl_auxv));
return dl_main_args.user_entry;
} }
void void

View File

@ -16,15 +16,5 @@
License along with the GNU C Library; if not, see License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#include <ldsodefs.h> #define DL_PLATFORM_AUXV \
GLRO(dl_cache_line_size) = auxv_values[AT_DCACHEBSIZE];
#if IS_IN (libc) && !defined SHARED
int GLRO(dl_cache_line_size);
#endif
/* Scan the Aux Vector for the "Data Cache Block Size" entry and assign it
to dl_cache_line_size. */
#define DL_PLATFORM_AUXV \
case AT_DCACHEBSIZE: \
GLRO(dl_cache_line_size) = av->a_un.a_val; \
break;

View File

@ -0,0 +1,4 @@
#include <elf/dl-support.c>
/* Populated from the auxiliary vector. */
int _dl_cache_line_size;