* sysdeps/unix/sysv/linux/dl-osinfo.h (_dl_discover_osversion)

[(NEED_DL_SYSINFO || NEED_DL_SYSINFO_DSO) && SHARED]: Scan
	GLRO(dl_sysinfo_map) for PT_NOTE giving Linux kernel version,
	we can skip the uname call if it's there.
	* sysdeps/generic/dl-sysdep.c (_dl_sysdep_start): Don't use
	DL_SYSDEP_OSCHECK here.
	* elf/rtld.c (dl_main) [DL_SYSDEP_OSCHECK]: Do it here instead.

	* sysdeps/generic/ldsodefs.h (struct rtld_global_ro):
	Add _dl_sysinfo_map.
	* elf/rtld.c (dl_main): Don't call _dl_init_paths early in the
	rtld_is_main case.  Call it unconditionally later.
	Move GLRO(dl_sysinfo_dso) handling earlier, before _dl_init_paths call.
	Initialize GLRO(dl_sysinfo_map).
	* elf/dl-load.c (open_path): Bail out if _dl_init_paths wasn't called.
	* sysdeps/generic/dl-sysdep.c (_DL_FIRST_EXTRA): New macro.
	(_dl_important_hwcaps)
	[(NEED_DL_SYSINFO || NEED_DL_SYSINFO_DSO) && SHARED]: Scan
	GLRO(dl_sysinfo_map) for PT_NOTE giving synthetic hwcap names
	and bit values.
	* elf/ldconfig.c (_DL_FIRST_EXTRA): New macro.
	(hwcap_extra): New static variable.
	(is_hwcap_platform): Check hwcap_extra for a matching name.
	Remove tls special case.
	(path_hwcap): Likewise.
	(parse_conf): Parse "hwcap" directive to define synthetic hwcap bits
	and their names, stored in hwcap_extra.
	(main) [USE_TLS]: Initialize final synthetic hwcap bit as "tls".

	* sysdeps/generic/ldsodefs.h (struct rtld_global_ro): Use uint64_t for
	_dl_hwcap and _dl_hwcap_mask.
	* sysdeps/generic/dl-sysdep.c (_dl_sysdep_start): Cast a_val for
	AT_HWCAP to unsigned long int.
	* elf/dl-support.c (_dl_aux_init): Likewise.
	(_dl_hwcap): Update defn.

	* elf/cache.c (print_entry): Pad hwcap value with 0s in diagnostic.
	* elf/ldconfig.c (search_dir): Likewise.
This commit is contained in:
Roland McGrath 2005-04-07 20:57:41 +00:00
parent da232bf925
commit ab1d521db3
9 changed files with 337 additions and 124 deletions

View File

@ -1,3 +1,44 @@
2005-04-07 Roland McGrath <roland@redhat.com>
* sysdeps/unix/sysv/linux/dl-osinfo.h (_dl_discover_osversion)
[(NEED_DL_SYSINFO || NEED_DL_SYSINFO_DSO) && SHARED]: Scan
GLRO(dl_sysinfo_map) for PT_NOTE giving Linux kernel version,
we can skip the uname call if it's there.
* sysdeps/generic/dl-sysdep.c (_dl_sysdep_start): Don't use
DL_SYSDEP_OSCHECK here.
* elf/rtld.c (dl_main) [DL_SYSDEP_OSCHECK]: Do it here instead.
* sysdeps/generic/ldsodefs.h (struct rtld_global_ro):
Add _dl_sysinfo_map.
* elf/rtld.c (dl_main): Don't call _dl_init_paths early in the
rtld_is_main case. Call it unconditionally later.
Move GLRO(dl_sysinfo_dso) handling earlier, before _dl_init_paths call.
Initialize GLRO(dl_sysinfo_map).
* elf/dl-load.c (open_path): Bail out if _dl_init_paths wasn't called.
* sysdeps/generic/dl-sysdep.c (_DL_FIRST_EXTRA): New macro.
(_dl_important_hwcaps)
[(NEED_DL_SYSINFO || NEED_DL_SYSINFO_DSO) && SHARED]: Scan
GLRO(dl_sysinfo_map) for PT_NOTE giving synthetic hwcap names
and bit values.
* elf/ldconfig.c (_DL_FIRST_EXTRA): New macro.
(hwcap_extra): New static variable.
(is_hwcap_platform): Check hwcap_extra for a matching name.
Remove tls special case.
(path_hwcap): Likewise.
(parse_conf): Parse "hwcap" directive to define synthetic hwcap bits
and their names, stored in hwcap_extra.
(main) [USE_TLS]: Initialize final synthetic hwcap bit as "tls".
* sysdeps/generic/ldsodefs.h (struct rtld_global_ro): Use uint64_t for
_dl_hwcap and _dl_hwcap_mask.
* sysdeps/generic/dl-sysdep.c (_dl_sysdep_start): Cast a_val for
AT_HWCAP to unsigned long int.
* elf/dl-support.c (_dl_aux_init): Likewise.
(_dl_hwcap): Update defn.
* elf/cache.c (print_entry): Pad hwcap value with 0s in diagnostic.
* elf/ldconfig.c (search_dir): Likewise.
2005-04-05 Roland McGrath <roland@redhat.com> 2005-04-05 Roland McGrath <roland@redhat.com>
* NEWS: Copy 2.3.5 section from 2.3 branch. * NEWS: Copy 2.3.5 section from 2.3 branch.

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1999, 2000, 2001, 2002, 2003 /* Copyright (C) 1999,2000,2001,2002,2003,2005
Free Software Foundation, Inc. Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Andreas Jaeger <aj@suse.de>, 1999. Contributed by Andreas Jaeger <aj@suse.de>, 1999.
@ -99,7 +99,7 @@ print_entry (const char *lib, int flag, unsigned int osversion,
break; break;
} }
if (hwcap != 0) if (hwcap != 0)
printf (", hwcap: 0x%" PRIx64, hwcap); printf (", hwcap: %#.16" PRIx64, hwcap);
if (osversion != 0) if (osversion != 0)
{ {
static const char *const abi_tag_os[] = static const char *const abi_tag_os[] =

View File

@ -1760,6 +1760,11 @@ open_path (const char *name, size_t namelen, int preloaded,
const char *current_what = NULL; const char *current_what = NULL;
int any = 0; int any = 0;
if (__builtin_expect (dirs == NULL, 0))
/* We're called before _dl_init_paths when loading the main executable
given on the command line when rtld is run directly. */
return -1;
buf = alloca (max_dirnamelen + max_capstrlen + namelen); buf = alloca (max_dirnamelen + max_capstrlen + namelen);
do do
{ {

View File

@ -1,5 +1,5 @@
/* Support for dynamic linking code in static libc. /* Support for dynamic linking code in static libc.
Copyright (C) 1996-2002, 2003, 2004 Free Software Foundation, Inc. Copyright (C) 1996-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -121,7 +121,7 @@ int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID;
ElfW(Phdr) *_dl_phdr; ElfW(Phdr) *_dl_phdr;
size_t _dl_phnum; size_t _dl_phnum;
unsigned long int _dl_hwcap __attribute__ ((nocommon)); uint64_t _dl_hwcap __attribute__ ((nocommon));
/* Prevailing state of the stack, PF_X indicating it's executable. */ /* Prevailing state of the stack, PF_X indicating it's executable. */
ElfW(Word) _dl_stack_flags = PF_R|PF_W|PF_X; ElfW(Word) _dl_stack_flags = PF_R|PF_W|PF_X;
@ -179,7 +179,7 @@ _dl_aux_init (ElfW(auxv_t) *av)
GL(dl_phnum) = av->a_un.a_val; GL(dl_phnum) = av->a_un.a_val;
break; break;
case AT_HWCAP: case AT_HWCAP:
GLRO(dl_hwcap) = av->a_un.a_val; GLRO(dl_hwcap) = (unsigned long int) av->a_un.a_val;
break; break;
#ifdef NEED_DL_SYSINFO #ifdef NEED_DL_SYSINFO
case AT_SYSINFO: case AT_SYSINFO:

View File

@ -44,6 +44,12 @@
#include "dl-procinfo.h" #include "dl-procinfo.h"
#ifdef _DL_FIRST_PLATFORM
# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
#else
# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
#endif
#ifndef LD_SO_CONF #ifndef LD_SO_CONF
# define LD_SO_CONF SYSCONFDIR "/ld.so.conf" # define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
#endif #endif
@ -115,6 +121,9 @@ static const char *config_file;
/* Mask to use for important hardware capabilities. */ /* Mask to use for important hardware capabilities. */
static unsigned long int hwcap_mask = HWCAP_IMPORTANT; static unsigned long int hwcap_mask = HWCAP_IMPORTANT;
/* Configuration-defined capabilities defined in kernel vDSOs. */
static const char *hwcap_extra[64 - _DL_FIRST_EXTRA];
/* Name and version of program. */ /* Name and version of program. */
static void print_version (FILE *stream, struct argp_state *state); static void print_version (FILE *stream, struct argp_state *state);
void (*argp_program_version_hook) (FILE *, struct argp_state *) void (*argp_program_version_hook) (FILE *, struct argp_state *)
@ -165,10 +174,10 @@ is_hwcap_platform (const char *name)
if (hwcap_idx != -1) if (hwcap_idx != -1)
return 1; return 1;
#ifdef USE_TLS for (hwcap_idx = _DL_FIRST_EXTRA; hwcap_idx < 64; ++hwcap_idx)
if (strcmp (name, "tls") == 0) if (hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA] != NULL
return 1; && !strcmp (name, hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA]))
#endif return 1;
return 0; return 0;
} }
@ -203,11 +212,11 @@ path_hwcap (const char *path)
h = _dl_string_platform (ptr + 1); h = _dl_string_platform (ptr + 1);
if (h == (uint64_t) -1) if (h == (uint64_t) -1)
{ {
#ifdef USE_TLS for (h = _DL_FIRST_EXTRA; h < 64; ++h)
if (strcmp (ptr + 1, "tls") == 0) if (hwcap_extra[h - _DL_FIRST_EXTRA] != NULL
h = 63; && !strcmp (ptr + 1, hwcap_extra[h - _DL_FIRST_EXTRA]))
else break;
#endif if (h == 64)
break; break;
} }
} }
@ -636,7 +645,7 @@ search_dir (const struct dir_entry *entry)
if (opt_verbose) if (opt_verbose)
{ {
if (hwcap != 0) if (hwcap != 0)
printf ("%s: (hwcap: 0x%" PRIx64 ")\n", entry->path, hwcap); printf ("%s: (hwcap: %#.16" PRIx64 ")\n", entry->path, hwcap);
else else
printf ("%s:\n", entry->path); printf ("%s:\n", entry->path);
} }
@ -1017,6 +1026,53 @@ parse_conf (const char *filename, bool do_chroot)
if (dir[0] != '\0') if (dir[0] != '\0')
parse_conf_include (filename, lineno, do_chroot, dir); parse_conf_include (filename, lineno, do_chroot, dir);
} }
else if (!strncasecmp (cp, "hwcap", 5) && isblank (cp[5]))
{
cp += 6;
char *p, *name = NULL;
unsigned long int n = strtoul (cp, &cp, 0);
if (cp != NULL && isblank (*cp))
while ((p = strsep (&cp, " \t")) != NULL)
if (p[0] != '\0')
{
if (name == NULL)
name = p;
else
{
name = NULL;
break;
}
}
if (name == NULL)
{
error (EXIT_FAILURE, 0, _("%s:%u: bad syntax in hwcap line"),
filename, lineno);
break;
}
if (n >= (64 - _DL_FIRST_EXTRA))
error (EXIT_FAILURE, 0,
_("%s:%u: hwcap index %lu above maximum %u"),
filename, lineno, n, 64 - _DL_FIRST_EXTRA - 1);
if (hwcap_extra[n] == NULL)
{
for (unsigned long int h = 0; h < (64 - _DL_FIRST_EXTRA); ++h)
if (hwcap_extra[h] != NULL && !strcmp (name, hwcap_extra[h]))
error (EXIT_FAILURE, 0,
_("%s:%u: hwcap index %lu already defined as %s"),
filename, lineno, h, name);
hwcap_extra[n] = xstrdup (name);
}
else
{
if (strcmp (name, hwcap_extra[n]))
error (EXIT_FAILURE, 0,
_("%s:%u: hwcap index %lu already defined as %s"),
filename, lineno, n, hwcap_extra[n]);
if (opt_verbose)
error (0, 0, _("%s:%u: duplicate hwcap %lu %s"),
filename, lineno, n, name);
}
}
else else
add_dir (cp); add_dir (cp);
} }
@ -1118,6 +1174,10 @@ main (int argc, char **argv)
add_dir (argv[i]); add_dir (argv[i]);
} }
#ifdef USE_TLS
hwcap_extra[63 - _DL_FIRST_EXTRA] = "tls";
#endif
set_hwcap (); set_hwcap ();
if (opt_chroot) if (opt_chroot)

View File

@ -958,11 +958,6 @@ of this helper program; chances are you did not intend to run this program.\n\
--_dl_argc; --_dl_argc;
++INTUSE(_dl_argv); ++INTUSE(_dl_argv);
/* Initialize the data structures for the search paths for shared
objects. */
_dl_init_paths (library_path);
/* The initialization of _dl_stack_flags done below assumes the /* The initialization of _dl_stack_flags done below assumes the
executable's PT_GNU_STACK may have been honored by the kernel, and executable's PT_GNU_STACK may have been honored by the kernel, and
so a PT_GNU_STACK with PF_X set means the stack started out with so a PT_GNU_STACK with PF_X set means the stack started out with
@ -1229,10 +1224,98 @@ ld.so does not support TLS, but program uses it!\n");
_exit (has_interp ? 0 : 2); _exit (has_interp ? 0 : 2);
} }
if (! rtld_is_main) struct link_map **first_preload = &GL(dl_rtld_map).l_next;
/* Initialize the data structures for the search paths for shared #if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
objects. */ /* Set up the data structures for the system-supplied DSO early,
_dl_init_paths (library_path); so they can influence _dl_init_paths. */
if (GLRO(dl_sysinfo_dso) != NULL)
{
/* Do an abridged version of the work _dl_map_object_from_fd would do
to map in the object. It's already mapped and prelinked (and
better be, since it's read-only and so we couldn't relocate it).
We just want our data structures to describe it as if we had just
mapped and relocated it normally. */
struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
0, LM_ID_BASE);
if (__builtin_expect (l != NULL, 1))
{
static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso)
+ GLRO(dl_sysinfo_dso)->e_phoff);
l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum;
for (uint_fast16_t i = 0; i < l->l_phnum; ++i)
{
const ElfW(Phdr) *const ph = &l->l_phdr[i];
if (ph->p_type == PT_DYNAMIC)
{
l->l_ld = (void *) ph->p_vaddr;
l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
}
else if (ph->p_type == PT_LOAD)
{
if (! l->l_addr)
l->l_addr = ph->p_vaddr;
if (ph->p_vaddr + ph->p_memsz >= l->l_map_end)
l->l_map_end = ph->p_vaddr + ph->p_memsz;
if ((ph->p_flags & PF_X)
&& ph->p_vaddr + ph->p_memsz >= l->l_text_end)
l->l_text_end = ph->p_vaddr + ph->p_memsz;
}
else
/* There must be no TLS segment. */
assert (ph->p_type != PT_TLS);
}
l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso);
l->l_addr = l->l_map_start - l->l_addr;
l->l_map_end += l->l_addr;
l->l_text_end += l->l_addr;
l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
elf_get_dynamic_info (l, dyn_temp);
_dl_setup_hash (l);
l->l_relocated = 1;
/* Now that we have the info handy, use the DSO image's soname
so this object can be looked up by name. Note that we do not
set l_name here. That field gives the file name of the DSO,
and this DSO is not associated with any file. */
if (l->l_info[DT_SONAME] != NULL)
{
/* Work around a kernel problem. The kernel cannot handle
addresses in the vsyscall DSO pages in writev() calls. */
const char *dsoname = ((char *) D_PTR (l, l_info[DT_STRTAB])
+ l->l_info[DT_SONAME]->d_un.d_val);
size_t len = strlen (dsoname);
char *copy = malloc (len);
if (copy == NULL)
_dl_fatal_printf ("out of memory\n");
l->l_libname->name = memcpy (copy, dsoname, len);
}
/* Rearrange the list so this DSO appears after rtld_map. */
assert (l->l_next == NULL);
assert (l->l_prev == main_map);
GL(dl_rtld_map).l_next = l;
l->l_prev = &GL(dl_rtld_map);
first_preload = &l->l_next;
/* We have a prelinked DSO preloaded by the system. */
GLRO(dl_sysinfo_map) = l;
# ifdef NEED_DL_SYSINFO
if (GLRO(dl_sysinfo) == DL_SYSINFO_DEFAULT)
GLRO(dl_sysinfo) = GLRO(dl_sysinfo_dso)->e_entry + l->l_addr;
# endif
}
}
#endif
#ifdef DL_SYSDEP_OSCHECK
DL_SYSDEP_OSCHECK (dl_fatal);
#endif
/* Initialize the data structures for the search paths for shared
objects. */
_dl_init_paths (library_path);
/* Initialize _r_debug. */ /* Initialize _r_debug. */
struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr, struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr,
@ -1477,7 +1560,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
/* We have two ways to specify objects to preload: via environment /* We have two ways to specify objects to preload: via environment
variable and via the file /etc/ld.so.preload. The latter can also variable and via the file /etc/ld.so.preload. The latter can also
be used when security is enabled. */ be used when security is enabled. */
assert (GL(dl_rtld_map).l_next == NULL); assert (*first_preload == NULL);
struct link_map **preloads = NULL; struct link_map **preloads = NULL;
unsigned int npreloads = 0; unsigned int npreloads = 0;
@ -1589,12 +1672,11 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
} }
} }
if (__builtin_expect (GL(dl_rtld_map).l_next != NULL, 0)) if (__builtin_expect (*first_preload != NULL, 0))
{ {
/* Set up PRELOADS with a vector of the preloaded libraries. */ /* Set up PRELOADS with a vector of the preloaded libraries. */
struct link_map *l; struct link_map *l = *first_preload;
preloads = __alloca (npreloads * sizeof preloads[0]); preloads = __alloca (npreloads * sizeof preloads[0]);
l = GL(dl_rtld_map).l_next; /* End of the chain before preloads. */
i = 0; i = 0;
do do
{ {
@ -1604,82 +1686,6 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
assert (i == npreloads); assert (i == npreloads);
} }
#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
struct link_map *sysinfo_map = NULL;
if (GLRO(dl_sysinfo_dso) != NULL)
{
/* Do an abridged version of the work _dl_map_object_from_fd would do
to map in the object. It's already mapped and prelinked (and
better be, since it's read-only and so we couldn't relocate it).
We just want our data structures to describe it as if we had just
mapped and relocated it normally. */
struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
0, LM_ID_BASE);
if (__builtin_expect (l != NULL, 1))
{
static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso)
+ GLRO(dl_sysinfo_dso)->e_phoff);
l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum;
for (uint_fast16_t i = 0; i < l->l_phnum; ++i)
{
const ElfW(Phdr) *const ph = &l->l_phdr[i];
if (ph->p_type == PT_DYNAMIC)
{
l->l_ld = (void *) ph->p_vaddr;
l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
}
else if (ph->p_type == PT_LOAD)
{
if (! l->l_addr)
l->l_addr = ph->p_vaddr;
if (ph->p_vaddr + ph->p_memsz >= l->l_map_end)
l->l_map_end = ph->p_vaddr + ph->p_memsz;
if ((ph->p_flags & PF_X)
&& ph->p_vaddr + ph->p_memsz >= l->l_text_end)
l->l_text_end = ph->p_vaddr + ph->p_memsz;
}
else
/* There must be no TLS segment. */
assert (ph->p_type != PT_TLS);
}
l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso);
l->l_addr = l->l_map_start - l->l_addr;
l->l_map_end += l->l_addr;
l->l_text_end += l->l_addr;
l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
elf_get_dynamic_info (l, dyn_temp);
_dl_setup_hash (l);
l->l_relocated = 1;
/* Now that we have the info handy, use the DSO image's soname
so this object can be looked up by name. Note that we do not
set l_name here. That field gives the file name of the DSO,
and this DSO is not associated with any file. */
if (l->l_info[DT_SONAME] != NULL)
{
/* Work around a kernel problem. The kernel cannot handle
addresses in the vsyscall DSO pages in writev() calls. */
const char *dsoname = ((char *) D_PTR (l, l_info[DT_STRTAB])
+ l->l_info[DT_SONAME]->d_un.d_val);
size_t len = strlen (dsoname);
char *copy = malloc (len);
if (copy == NULL)
_dl_fatal_printf ("out of memory\n");
l->l_libname->name = memcpy (copy, dsoname, len);
}
/* We have a prelinked DSO preloaded by the system. */
sysinfo_map = l;
# ifdef NEED_DL_SYSINFO
if (GLRO(dl_sysinfo) == DL_SYSINFO_DEFAULT)
GLRO(dl_sysinfo) = GLRO(dl_sysinfo_dso)->e_entry + l->l_addr;
# endif
}
}
#endif
/* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD /* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD
specified some libraries to load, these are inserted before the actual specified some libraries to load, these are inserted before the actual
dependencies in the executable's searchlist for symbol resolution. */ dependencies in the executable's searchlist for symbol resolution. */
@ -1724,10 +1730,10 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
? main_map->l_searchlist.r_list[i + 1] ? main_map->l_searchlist.r_list[i + 1]
: NULL); : NULL);
#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO #if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
if (sysinfo_map != NULL if (GLRO(dl_sysinfo_map) != NULL
&& GL(dl_rtld_map).l_prev->l_next == sysinfo_map && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
&& GL(dl_rtld_map).l_next != sysinfo_map) && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
GL(dl_rtld_map).l_prev = sysinfo_map; GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
#endif #endif
} }
else else

View File

@ -1,5 +1,5 @@
/* Operating system support for run-time dynamic linker. Generic Unix version. /* Operating system support for run-time dynamic linker. Generic Unix version.
Copyright (C) 1995-1998, 2000-2003, 2004 Free Software Foundation, Inc. Copyright (C) 1995-1998, 2000-2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -39,6 +39,12 @@
#include <hp-timing.h> #include <hp-timing.h>
#include <tls.h> #include <tls.h>
#ifdef _DL_FIRST_PLATFORM
# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
#else
# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
#endif
extern char **_environ attribute_hidden; extern char **_environ attribute_hidden;
extern void _end attribute_hidden; extern void _end attribute_hidden;
@ -149,7 +155,7 @@ _dl_sysdep_start (void **start_argptr,
GLRO(dl_platform) = av->a_un.a_ptr; GLRO(dl_platform) = av->a_un.a_ptr;
break; break;
case AT_HWCAP: case AT_HWCAP:
GLRO(dl_hwcap) = av->a_un.a_val; GLRO(dl_hwcap) = (unsigned long int) av->a_un.a_val;
break; break;
case AT_CLKTCK: case AT_CLKTCK:
GLRO(dl_clktck) = av->a_un.a_val; GLRO(dl_clktck) = av->a_un.a_val;
@ -172,10 +178,6 @@ _dl_sysdep_start (void **start_argptr,
#endif #endif
} }
#ifdef DL_SYSDEP_OSCHECK
DL_SYSDEP_OSCHECK (dl_fatal);
#endif
#ifndef HAVE_AUX_SECURE #ifndef HAVE_AUX_SECURE
if (seen != -1) if (seen != -1)
{ {
@ -343,7 +345,7 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
size_t *max_capstrlen) size_t *max_capstrlen)
{ {
/* Determine how many important bits are set. */ /* Determine how many important bits are set. */
unsigned long int masked = GLRO(dl_hwcap) & GLRO(dl_hwcap_mask); uint64_t masked = GLRO(dl_hwcap) & GLRO(dl_hwcap_mask);
size_t cnt = platform != NULL; size_t cnt = platform != NULL;
size_t n, m; size_t n, m;
size_t total; size_t total;
@ -353,18 +355,64 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
char *cp; char *cp;
/* Count the number of bits set in the masked value. */ /* Count the number of bits set in the masked value. */
for (n = 0; (~((1UL << n) - 1) & masked) != 0; ++n) for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n)
if ((masked & (1UL << n)) != 0) if ((masked & (1ULL << n)) != 0)
++cnt; ++cnt;
#if (defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO) && defined SHARED
/* The system-supplied DSO can contain a note of type 2, vendor "GNU".
This gives us a list of names to treat as fake hwcap bits. */
const char *dsocaps = NULL;
size_t dsocapslen = 0;
if (GLRO(dl_sysinfo_map) != NULL)
{
const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr;
const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum;
for (uint_fast16_t i = 0; i < phnum; ++i)
if (phdr[i].p_type == PT_NOTE)
{
const ElfW(Addr) start = (phdr[i].p_vaddr
+ GLRO(dl_sysinfo_map)->l_addr);
const struct
{
ElfW(Word) vendorlen;
ElfW(Word) datalen;
ElfW(Word) type;
} *note = (const void *) start;
while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
{
#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
if (note->type == 2
&& note->vendorlen == sizeof "GNU"
&& !memcmp ((note + 1), "GNU", sizeof "GNU")
&& note->datalen > 2 * sizeof (ElfW(Word)) + 2)
{
const ElfW(Word) *p = ((const void *) (note + 1)
+ ROUND (sizeof "GNU"));
cnt += *p++;
++p; /* Skip mask word. */
dsocaps = (const char *) p;
dsocapslen = note->datalen - sizeof *p;
break;
}
note = ((const void *) (note + 1)
+ ROUND (note->vendorlen) + ROUND (note->datalen));
}
if (dsocaps != NULL)
break;
}
}
#endif
#ifdef USE_TLS #ifdef USE_TLS
/* For TLS enabled builds always add 'tls'. */ /* For TLS enabled builds always add 'tls'. */
++cnt; ++cnt;
#else #else
if (cnt == 0) if (cnt == 0)
{ {
/* If we have platform name and no important capability we only have /* If we no have platform name and no important capability we only
the base directory to search. */ have the base directory to search. */
result = (struct r_strlenpair *) malloc (sizeof (*result)); result = (struct r_strlenpair *) malloc (sizeof (*result));
if (result == NULL) if (result == NULL)
goto no_memory; goto no_memory;
@ -380,12 +428,26 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
/* Create temporary data structure to generate result table. */ /* Create temporary data structure to generate result table. */
temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp)); temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp));
m = 0; m = 0;
#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
if (dsocaps != NULL)
{
GLRO(dl_hwcap) |= ((uint64_t) ((const ElfW(Word) *) dsocaps)[-1]
<< _DL_FIRST_EXTRA);
for (const char *p = dsocaps;
p < dsocaps + dsocapslen;
p += temp[m++].len + 1)
{
temp[m].str = p;
temp[m].len = strlen (p);
}
}
#endif
for (n = 0; masked != 0; ++n) for (n = 0; masked != 0; ++n)
if ((masked & (1UL << n)) != 0) if ((masked & (1ULL << n)) != 0)
{ {
temp[m].str = _dl_hwcap_string (n); temp[m].str = _dl_hwcap_string (n);
temp[m].len = strlen (temp[m].str); temp[m].len = strlen (temp[m].str);
masked ^= 1UL << n; masked ^= 1ULL << n;
++m; ++m;
} }
if (platform != NULL) if (platform != NULL)
@ -503,8 +565,8 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
++rp; ++rp;
} }
/* The second have starts right after the first part of the string of /* The second half starts right after the first part of the string of
corresponding entry in the first half. */ the corresponding entry in the first half. */
do do
{ {
rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1; rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1;

View File

@ -5,7 +5,7 @@ if test "$usetls" != no; then
# Check for support of thread-local storage handling in assembler and # Check for support of thread-local storage handling in assembler and
# linker. # linker.
echo "$as_me:$LINENO: checking for SH TLS support" >&5 echo "$as_me:$LINENO: checking for SH TLS support" >&5
echo $ECHO_N "checking for sh TLS support... $ECHO_C" >&6 echo $ECHO_N "checking for SH TLS support... $ECHO_C" >&6
if test "${libc_cv_sh_tls+set}" = set; then if test "${libc_cv_sh_tls+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6 echo $ECHO_N "(cached) $ECHO_C" >&6
else else

View File

@ -43,6 +43,45 @@ dl_fatal (const char *str)
static inline int __attribute__ ((always_inline)) static inline int __attribute__ ((always_inline))
_dl_discover_osversion (void) _dl_discover_osversion (void)
{ {
#if (defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO) && defined SHARED
if (GLRO(dl_sysinfo_map) != NULL)
{
/* If the kernel-supplied DSO contains a note indicating the kernel's
version, we don't need to call uname or parse any strings. */
static const struct
{
ElfW(Word) vendorlen;
ElfW(Word) datalen;
ElfW(Word) type;
char vendor[8];
} expected_note = { sizeof "Linux", sizeof (ElfW(Word)), 0, "Linux" };
const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr;
const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum;
for (uint_fast16_t i = 0; i < phnum; ++i)
if (phdr[i].p_type == PT_NOTE)
{
const ElfW(Addr) start = (phdr[i].p_vaddr
+ GLRO(dl_sysinfo_map)->l_addr);
const struct
{
ElfW(Word) vendorlen;
ElfW(Word) datalen;
ElfW(Word) type;
} *note = (const void *) start;
while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
{
if (!memcmp (note, &expected_note, sizeof expected_note))
return *(const ElfW(Word) *) ((const void *) note
+ sizeof expected_note);
#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
note = ((const void *) (note + 1)
+ ROUND (note->vendorlen) + ROUND (note->datalen));
}
}
}
#endif
char bufmem[64]; char bufmem[64];
char *buf = bufmem; char *buf = bufmem;
unsigned int version; unsigned int version;