import glibc-2.28-151.el8

This commit is contained in:
CentOS Sources 2021-05-18 02:37:04 -04:00 committed by Andrew Lukoshko
parent f43c687a7a
commit ae0e9842c1
194 changed files with 43907 additions and 23 deletions

View File

@ -0,0 +1,28 @@
commit 583dd860d5b833037175247230a328f0050dbfe9
Author: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon Jan 21 11:08:13 2019 -0800
regex: fix read overrun [BZ #24114]
Problem found by AddressSanitizer, reported by Hongxu Chen in:
https://debbugs.gnu.org/34140
* posix/regexec.c (proceed_next_node):
Do not read past end of input buffer.
diff --git a/posix/regexec.c b/posix/regexec.c
index 73644c2341336e66..06b8487c3e3eab0e 100644
--- a/posix/regexec.c
+++ b/posix/regexec.c
@@ -1289,8 +1289,10 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs,
else if (naccepted)
{
char *buf = (char *) re_string_get_buffer (&mctx->input);
- if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
- naccepted) != 0)
+ if (mctx->input.valid_len - *pidx < naccepted
+ || (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
+ naccepted)
+ != 0))
return -1;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,235 @@
commit 7d4ec75e111291851620c6aa2c4460647b7fd50d
Author: Arjun Shankar <arjun@redhat.com>
Date: Fri Sep 25 14:47:06 2020 +0200
intl: Handle translation output codesets with suffixes [BZ #26383]
Commit 91927b7c7643 (Rewrite iconv option parsing [BZ #19519]) did not
handle cases where the output codeset for translations (via the `gettext'
family of functions) might have a caller specified encoding suffix such as
TRANSLIT or IGNORE. This led to a regression where translations did not
work when the codeset had a suffix.
This commit fixes the above issue by parsing any suffixes passed to
__dcigettext and adds two new test-cases to intl/tst-codeset.c to
verify correct behaviour. The iconv-internal function __gconv_create_spec
and the static iconv-internal function gconv_destroy_spec are now visible
internally within glibc and used in intl/dcigettext.c.
diff --git a/iconv/Versions b/iconv/Versions
index 8a5f4cf780b18925..d51af52fa34b8793 100644
--- a/iconv/Versions
+++ b/iconv/Versions
@@ -6,7 +6,9 @@ libc {
GLIBC_PRIVATE {
# functions shared with iconv program
__gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db;
- __gconv_open; __gconv_create_spec;
+
+ # functions used elsewhere in glibc
+ __gconv_open; __gconv_create_spec; __gconv_destroy_spec;
# function used by the gconv modules
__gconv_transliterate;
diff --git a/iconv/gconv_charset.c b/iconv/gconv_charset.c
index 6ccd0773ccb6cd27..4ba0aa99f5dae7f7 100644
--- a/iconv/gconv_charset.c
+++ b/iconv/gconv_charset.c
@@ -216,3 +216,13 @@ out:
return ret;
}
libc_hidden_def (__gconv_create_spec)
+
+
+void
+__gconv_destroy_spec (struct gconv_spec *conv_spec)
+{
+ free (conv_spec->fromcode);
+ free (conv_spec->tocode);
+ return;
+}
+libc_hidden_def (__gconv_destroy_spec)
diff --git a/iconv/gconv_charset.h b/iconv/gconv_charset.h
index b85d80313030b649..4b98073389bd8707 100644
--- a/iconv/gconv_charset.h
+++ b/iconv/gconv_charset.h
@@ -48,33 +48,6 @@
#define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE"
-/* This function accepts the charset names of the source and destination of the
- conversion and populates *conv_spec with an equivalent conversion
- specification that may later be used by __gconv_open. The charset names
- might contain options in the form of suffixes that alter the conversion,
- e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
- and truncating any suffix options in fromcode, and processing and truncating
- any suffix options in tocode. Supported suffix options ("TRANSLIT" or
- "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
- to be set to true. Unrecognized suffix options are silently discarded. If
- the function succeeds, it returns conv_spec back to the caller. It returns
- NULL upon failure. */
-struct gconv_spec *
-__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
- const char *tocode);
-libc_hidden_proto (__gconv_create_spec)
-
-
-/* This function frees all heap memory allocated by __gconv_create_spec. */
-static void __attribute__ ((unused))
-gconv_destroy_spec (struct gconv_spec *conv_spec)
-{
- free (conv_spec->fromcode);
- free (conv_spec->tocode);
- return;
-}
-
-
/* This function copies in-order, characters from the source 's' that are
either alpha-numeric or one in one of these: "_-.,:/" - into the destination
'wp' while dropping all other characters. In the process, it converts all
diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h
index 4748e9b1fa3b5426..8067a341b0903e1b 100644
--- a/iconv/gconv_int.h
+++ b/iconv/gconv_int.h
@@ -170,6 +170,27 @@ extern int __gconv_open (struct gconv_spec *conv_spec,
__gconv_t *handle, int flags);
libc_hidden_proto (__gconv_open)
+/* This function accepts the charset names of the source and destination of the
+ conversion and populates *conv_spec with an equivalent conversion
+ specification that may later be used by __gconv_open. The charset names
+ might contain options in the form of suffixes that alter the conversion,
+ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
+ and truncating any suffix options in fromcode, and processing and truncating
+ any suffix options in tocode. Supported suffix options ("TRANSLIT" or
+ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
+ to be set to true. Unrecognized suffix options are silently discarded. If
+ the function succeeds, it returns conv_spec back to the caller. It returns
+ NULL upon failure. */
+extern struct gconv_spec *
+__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
+ const char *tocode);
+libc_hidden_proto (__gconv_create_spec)
+
+/* This function frees all heap memory allocated by __gconv_create_spec. */
+extern void
+__gconv_destroy_spec (struct gconv_spec *conv_spec);
+libc_hidden_proto (__gconv_destroy_spec)
+
/* Free resources associated with transformation descriptor CD. */
extern int __gconv_close (__gconv_t cd)
attribute_hidden;
diff --git a/iconv/iconv_open.c b/iconv/iconv_open.c
index 59d1ef4f07ed1022..46da33bca6c24af0 100644
--- a/iconv/iconv_open.c
+++ b/iconv/iconv_open.c
@@ -39,7 +39,7 @@ iconv_open (const char *tocode, const char *fromcode)
int res = __gconv_open (&conv_spec, &cd, 0);
- gconv_destroy_spec (&conv_spec);
+ __gconv_destroy_spec (&conv_spec);
if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
{
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
index 552efac81660e82a..e26e9d02ca4121a7 100644
--- a/iconv/iconv_prog.c
+++ b/iconv/iconv_prog.c
@@ -184,7 +184,7 @@ main (int argc, char *argv[])
/* Let's see whether we have these coded character sets. */
res = __gconv_open (&conv_spec, &cd, 0);
- gconv_destroy_spec (&conv_spec);
+ __gconv_destroy_spec (&conv_spec);
if (res != __GCONV_OK)
{
diff --git a/intl/dcigettext.c b/intl/dcigettext.c
index ed48fc8d3e96c7ba..7ebe67b4ac2113e9 100644
--- a/intl/dcigettext.c
+++ b/intl/dcigettext.c
@@ -1121,15 +1121,18 @@ _nl_find_msg (struct loaded_l10nfile *domain_file,
# ifdef _LIBC
- struct gconv_spec conv_spec
- = { .fromcode = norm_add_slashes (charset, ""),
- .tocode = norm_add_slashes (outcharset, ""),
- /* We always want to use transliteration. */
- .translit = true,
- .ignore = false
- };
+ struct gconv_spec conv_spec;
+
+ __gconv_create_spec (&conv_spec, charset, outcharset);
+
+ /* We always want to use transliteration. */
+ conv_spec.translit = true;
+
int r = __gconv_open (&conv_spec, &convd->conv,
GCONV_AVOID_NOCONV);
+
+ __gconv_destroy_spec (&conv_spec);
+
if (__builtin_expect (r != __GCONV_OK, 0))
{
/* If the output encoding is the same there is
diff --git a/intl/tst-codeset.c b/intl/tst-codeset.c
index e71382aeeeca477b..52e4aaa6ffd3afdb 100644
--- a/intl/tst-codeset.c
+++ b/intl/tst-codeset.c
@@ -22,13 +22,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <support/check.h>
static int
do_test (void)
{
- char *s;
- int result = 0;
-
unsetenv ("LANGUAGE");
unsetenv ("OUTPUT_CHARSET");
setlocale (LC_ALL, "de_DE.ISO-8859-1");
@@ -36,25 +34,21 @@ do_test (void)
bindtextdomain ("codeset", OBJPFX "domaindir");
/* Here we expect output in ISO-8859-1. */
- s = gettext ("cheese");
- if (strcmp (s, "K\344se"))
- {
- printf ("call 1 returned: %s\n", s);
- result = 1;
- }
+ TEST_COMPARE_STRING (gettext ("cheese"), "K\344se");
+ /* Here we expect output in UTF-8. */
bind_textdomain_codeset ("codeset", "UTF-8");
+ TEST_COMPARE_STRING (gettext ("cheese"), "K\303\244se");
- /* Here we expect output in UTF-8. */
- s = gettext ("cheese");
- if (strcmp (s, "K\303\244se"))
- {
- printf ("call 2 returned: %s\n", s);
- result = 1;
- }
-
- return result;
+ /* `a with umlaut' is transliterated to `ae'. */
+ bind_textdomain_codeset ("codeset", "ASCII//TRANSLIT");
+ TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
+
+ /* Transliteration also works by default even if not set. */
+ bind_textdomain_codeset ("codeset", "ASCII");
+ TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
+
+ return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>

View File

@ -0,0 +1,77 @@
commit 9a99c682144bdbd40792ebf822fe9264e0376fb5
Author: Arjun Shankar <arjun@redhat.com>
Date: Wed Nov 4 12:19:38 2020 +0100
iconv: Accept redundant shift sequences in IBM1364 [BZ #26224]
The IBM1364, IBM1371, IBM1388, IBM1390 and IBM1399 character sets
share converter logic (iconvdata/ibm1364.c) which would reject
redundant shift sequences when processing input in these character
sets. This led to a hang in the iconv program (CVE-2020-27618).
This commit adjusts the converter to ignore redundant shift sequences
and adds test cases for iconv_prog hangs that would be triggered upon
their rejection. This brings the implementation in line with other
converters that also ignore redundant shift sequences (e.g. IBM930
etc., fixed in commit 692de4b3960d).
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/iconv/tst-iconv_prog.sh b/iconv/tst-iconv_prog.sh
index 8298136b7f45d855..d8db7b335c1fcca2 100644
--- a/iconv/tst-iconv_prog.sh
+++ b/iconv/tst-iconv_prog.sh
@@ -102,12 +102,16 @@ hangarray=(
"\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE"
"\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE"
"\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE"
-# These are known hangs that are yet to be fixed:
-# "\x00\x0f;-c;IBM1364;UTF-8"
-# "\x00\x0f;-c;IBM1371;UTF-8"
-# "\x00\x0f;-c;IBM1388;UTF-8"
-# "\x00\x0f;-c;IBM1390;UTF-8"
-# "\x00\x0f;-c;IBM1399;UTF-8"
+"\x00\x0f;-c;IBM1364;UTF-8"
+"\x0e\x0e;-c;IBM1364;UTF-8"
+"\x00\x0f;-c;IBM1371;UTF-8"
+"\x0e\x0e;-c;IBM1371;UTF-8"
+"\x00\x0f;-c;IBM1388;UTF-8"
+"\x0e\x0e;-c;IBM1388;UTF-8"
+"\x00\x0f;-c;IBM1390;UTF-8"
+"\x0e\x0e;-c;IBM1390;UTF-8"
+"\x00\x0f;-c;IBM1399;UTF-8"
+"\x0e\x0e;-c;IBM1399;UTF-8"
"\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE"
"\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE"
"\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE"
diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c
index 517fe60813be0472..ecc3f8ddddbdbc8c 100644
--- a/iconvdata/ibm1364.c
+++ b/iconvdata/ibm1364.c
@@ -158,24 +158,14 @@ enum
\
if (__builtin_expect (ch, 0) == SO) \
{ \
- /* Shift OUT, change to DBCS converter. */ \
- if (curcs == db) \
- { \
- result = __GCONV_ILLEGAL_INPUT; \
- break; \
- } \
+ /* Shift OUT, change to DBCS converter (redundant escape okay). */ \
curcs = db; \
++inptr; \
continue; \
} \
if (__builtin_expect (ch, 0) == SI) \
{ \
- /* Shift IN, change to SBCS converter. */ \
- if (curcs == sb) \
- { \
- result = __GCONV_ILLEGAL_INPUT; \
- break; \
- } \
+ /* Shift IN, change to SBCS converter (redundant escape okay). */ \
curcs = sb; \
++inptr; \
continue; \

View File

@ -0,0 +1,66 @@
commit cce35a50c1de0cec5cd1f6c18979ff6ee3ea1dd1
Author: Arjun Shankar <arjun@redhat.com>
Date: Mon Nov 11 14:57:23 2019 +0100
support: Add xsetlocale function
diff --git a/support/Makefile b/support/Makefile
index 37d5dcc92a5c6dee..6afaa6836c944398 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -148,6 +148,7 @@ libsupport-routines = \
xrealloc \
xrecvfrom \
xsendto \
+ xsetlocale \
xsetsockopt \
xsigaction \
xsignal \
diff --git a/support/support.h b/support/support.h
index 61a10c34982134ff..97d142e9b6f68188 100644
--- a/support/support.h
+++ b/support/support.h
@@ -91,6 +91,7 @@ char *xasprintf (const char *format, ...)
__attribute__ ((format (printf, 1, 2), malloc));
char *xstrdup (const char *);
char *xstrndup (const char *, size_t);
+char *xsetlocale (int category, const char *locale);
/* These point to the TOP of the source/build tree, not your (or
support's) subdirectory. */
diff --git a/support/xsetlocale.c b/support/xsetlocale.c
new file mode 100644
index 0000000000000000..063ed4b0d63af884
--- /dev/null
+++ b/support/xsetlocale.c
@@ -0,0 +1,30 @@
+/* setlocale with error checking.
+ Copyright (C) 2019 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 <support/check.h>
+
+#include <locale.h>
+
+char *
+xsetlocale (int category, const char *locale)
+{
+ char *p = setlocale (category, locale);
+ if (p == NULL)
+ FAIL_EXIT1 ("error: setlocale (%d, \"%s\")\n", category, locale);
+ return p;
+}

View File

@ -0,0 +1,35 @@
The patch (glibc-rh1704868-1.patch) for commit 91927b7c7643
(Rewrite iconv option parsing) contains a test that depends on
commit 513aaa0d782f (Add Transliterations for Unicode Misc.
Mathematical Symbols-A/B), which is not applied in RHEL-8. This
patch edits the test so as not to depend on the unapplied patch
and its additional transliterations.
diff --git a/iconv/tst-iconv-opt.c b/iconv/tst-iconv-opt.c
index 669d812a6a9b8749..21e6d887501450a7 100644
--- a/iconv/tst-iconv-opt.c
+++ b/iconv/tst-iconv-opt.c
@@ -82,18 +82,18 @@ char u2a_ignore[] = "UTF-8 text with couple f non-ASCII characters";
/* 3. Invalid UTF-8 input and some corresponding expected outputs. \xff is
invalid UTF-8. It's followed by some valid but non-ASCII UTF-8. */
-char iutf8[] = "Invalid UTF-8 \xff\u27E6text\u27E7";
+char iutf8[] = "Invalid UTF-8 \xff\u00B7text\u00B7";
char iu2a[] = "Invalid UTF-8 ";
char iu2a_ignore[] = "Invalid UTF-8 text";
-char iu2a_both[] = "Invalid UTF-8 [|text|]";
+char iu2a_both[] = "Invalid UTF-8 .text.";
/* 4. Another invalid UTF-8 input and corresponding expected outputs. This time
the valid non-ASCII UTF-8 characters appear before the invalid \xff. */
-char jutf8[] = "Invalid \u27E6UTF-8\u27E7 \xfftext";
+char jutf8[] = "Invalid \u00B7UTF-8\u00B7 \xfftext";
char ju2a[] = "Invalid ";
-char ju2a_translit[] = "Invalid [|UTF-8|] ";
+char ju2a_translit[] = "Invalid .UTF-8. ";
char ju2a_ignore[] = "Invalid UTF-8 text";
-char ju2a_both[] = "Invalid [|UTF-8|] text";
+char ju2a_both[] = "Invalid .UTF-8. text";
/* We also test option handling for character set names that have the form
"A/B". In this test, we test conversions "ISO-10646/UTF-8", and either

View File

@ -0,0 +1,53 @@
commit 82c80ac2ebf9acc81ec460adfd951d4884836c7c
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Wed Aug 1 04:57:34 2018 -0700
x86: Rename get_common_indeces to get_common_indices
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
* sysdeps/x86/cpu-features.c (get_common_indeces): Renamed to
...
(get_common_indices): This.
(init_cpu_features): Updated.
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index ac74f408343191b0..41f2d15fa5c8a756 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -56,7 +56,7 @@ get_extended_indices (struct cpu_features *cpu_features)
}
static void
-get_common_indeces (struct cpu_features *cpu_features,
+get_common_indices (struct cpu_features *cpu_features,
unsigned int *family, unsigned int *model,
unsigned int *extended_model, unsigned int *stepping)
{
@@ -234,7 +234,7 @@ init_cpu_features (struct cpu_features *cpu_features)
kind = arch_kind_intel;
- get_common_indeces (cpu_features, &family, &model, &extended_model,
+ get_common_indices (cpu_features, &family, &model, &extended_model,
&stepping);
get_extended_indices (cpu_features);
@@ -356,7 +356,7 @@ init_cpu_features (struct cpu_features *cpu_features)
kind = arch_kind_amd;
- get_common_indeces (cpu_features, &family, &model, &extended_model,
+ get_common_indices (cpu_features, &family, &model, &extended_model,
&stepping);
get_extended_indices (cpu_features);
@@ -393,7 +393,7 @@ init_cpu_features (struct cpu_features *cpu_features)
else
{
kind = arch_kind_other;
- get_common_indeces (cpu_features, NULL, NULL, NULL, NULL);
+ get_common_indices (cpu_features, NULL, NULL, NULL, NULL);
}
/* Support i586 if CX8 is available. */

View File

@ -0,0 +1,41 @@
commit 2dd8e58cc533ee840d37725b11bc0dc0308a5dc0
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Sun Oct 21 00:37:11 2018 -0700
x86: Don't include <x86intrin.h>
Use __builtin_ia32_rdtsc directly since including <x86intrin.h> makes
building glibc very slow. On Intel Core i5-6260U, this patch reduces
x86-64 build time from 8 minutes 33 seconds to 3 minutes 48 seconds
with "make -j4" and GCC 8.2.1.
* sysdeps/x86/hp-timing.h: Don't include <x86intrin.h>.
(HP_TIMING_NOW): Replace _rdtsc with __builtin_ia32_rdtsc.
diff --git a/sysdeps/x86/hp-timing.h b/sysdeps/x86/hp-timing.h
index 1c20e9d8289cc15b..77a1360748ca4535 100644
--- a/sysdeps/x86/hp-timing.h
+++ b/sysdeps/x86/hp-timing.h
@@ -22,8 +22,6 @@
#include <isa.h>
#if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664
-# include <x86intrin.h>
-
/* We always assume having the timestamp register. */
# define HP_TIMING_AVAIL (1)
# define HP_SMALL_TIMING_AVAIL (1)
@@ -38,8 +36,11 @@ typedef unsigned long long int hp_timing_t;
might not be 100% accurate since there might be some more instructions
running in this moment. This could be changed by using a barrier like
'cpuid' right before the `rdtsc' instruciton. But we are not interested
- in accurate clock cycles here so we don't do this. */
-# define HP_TIMING_NOW(Var) ((Var) = _rdtsc ())
+ in accurate clock cycles here so we don't do this.
+
+ NB: Use __builtin_ia32_rdtsc directly since including <x86intrin.h>
+ makes building glibc very slow. */
+# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ())
# include <hp-timing-common.h>
#else

View File

@ -0,0 +1,82 @@
commit bb5fd5ce64b598085bdb8a05cb53777480fe093c
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Oct 9 10:13:14 2020 +0200
elf: Do not pass GLRO(dl_platform), GLRO(dl_platformlen) to _dl_important_hwcaps
In the current code, the function can easily obtain the information
on its own.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
index ae2e4ca7fe91d407..82ee89c36a1eb4ab 100644
--- a/elf/dl-hwcaps.c
+++ b/elf/dl-hwcaps.c
@@ -28,13 +28,12 @@
/* Return an array of useful/necessary hardware capability names. */
const struct r_strlenpair *
-_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
- size_t *max_capstrlen)
+_dl_important_hwcaps (size_t *sz, size_t *max_capstrlen)
{
uint64_t hwcap_mask = GET_HWCAP_MASK();
/* Determine how many important bits are set. */
uint64_t masked = GLRO(dl_hwcap) & hwcap_mask;
- size_t cnt = platform != NULL;
+ size_t cnt = GLRO (dl_platform) != NULL;
size_t n, m;
size_t total;
struct r_strlenpair *result;
@@ -60,10 +59,10 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
masked ^= 1ULL << n;
++m;
}
- if (platform != NULL)
+ if (GLRO (dl_platform) != NULL)
{
- temp[m].str = platform;
- temp[m].len = platform_len;
+ temp[m].str = GLRO (dl_platform);
+ temp[m].len = GLRO (dl_platformlen);
++m;
}
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 2eb4f35b2467f7d8..d2be21ea7d1545fe 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -697,8 +697,7 @@ _dl_init_paths (const char *llp, const char *source)
#ifdef SHARED
/* Get the capabilities. */
- capstr = _dl_important_hwcaps (GLRO(dl_platform), GLRO(dl_platformlen),
- &ncapstr, &max_capstrlen);
+ capstr = _dl_important_hwcaps (&ncapstr, &max_capstrlen);
#endif
/* First set up the rest of the default search directory entries. */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index aa006afafaf46dee..2c9fdeb286bdaadf 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1069,12 +1069,12 @@ extern void _dl_show_auxv (void) attribute_hidden;
other. */
extern char *_dl_next_ld_env_entry (char ***position) attribute_hidden;
-/* Return an array with the names of the important hardware capabilities. */
-extern const struct r_strlenpair *_dl_important_hwcaps (const char *platform,
- size_t paltform_len,
- size_t *sz,
- size_t *max_capstrlen)
- attribute_hidden;
+/* Return an array with the names of the important hardware
+ capabilities. The length of the array is written to *SZ, and the
+ maximum of all strings length is written to *MAX_CAPSTRLEN. */
+const struct r_strlenpair *_dl_important_hwcaps (size_t *sz,
+ size_t *max_capstrlen)
+ attribute_hidden;
/* Look up NAME in ld.so.cache and return the file name stored there,
or null if none is found. Caller must free returned string. */

View File

@ -0,0 +1,65 @@
commit 7674695cf7e28528be7243ceb30c9a600bbaa7b5
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Oct 8 08:19:15 2020 -0700
<sys/platform/x86.h>: Add Intel UINTR support
Add Intel UINTR support to <sys/platform/x86.h>.
diff --git a/manual/platform.texi b/manual/platform.texi
index 95b0ed0642c9f8a9..0dd12a4353a93bf2 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -583,6 +583,9 @@ using a TSC deadline value.
@item
@code{TSXLDTRK} -- TSXLDTRK instructions.
+@item
+@code{UINTR} -- User interrupts.
+
@item
@code{UMIP} -- User-mode instruction prevention.
diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h
index bcc81ab5f8ac8265..2760b81a56e6c7d7 100644
--- a/sysdeps/x86/sys/platform/x86.h
+++ b/sysdeps/x86/sys/platform/x86.h
@@ -241,7 +241,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
#define bit_cpu_AVX512_4VNNIW (1u << 2)
#define bit_cpu_AVX512_4FMAPS (1u << 3)
#define bit_cpu_FSRM (1u << 4)
-#define bit_cpu_INDEX_7_EDX_5 (1u << 5)
+#define bit_cpu_UINTR (1u << 5)
#define bit_cpu_INDEX_7_EDX_6 (1u << 6)
#define bit_cpu_INDEX_7_EDX_7 (1u << 7)
#define bit_cpu_AVX512_VP2INTERSECT (1u << 8)
@@ -460,7 +460,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
#define index_cpu_AVX512_4VNNIW COMMON_CPUID_INDEX_7
#define index_cpu_AVX512_4FMAPS COMMON_CPUID_INDEX_7
#define index_cpu_FSRM COMMON_CPUID_INDEX_7
-#define index_cpu_INDEX_7_EDX_5 COMMON_CPUID_INDEX_7
+#define index_cpu_UINTR COMMON_CPUID_INDEX_7
#define index_cpu_INDEX_7_EDX_6 COMMON_CPUID_INDEX_7
#define index_cpu_INDEX_7_EDX_7 COMMON_CPUID_INDEX_7
#define index_cpu_AVX512_VP2INTERSECT COMMON_CPUID_INDEX_7
@@ -679,7 +679,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
#define reg_AVX512_4VNNIW edx
#define reg_AVX512_4FMAPS edx
#define reg_FSRM edx
-#define reg_INDEX_7_EDX_5 edx
+#define reg_UINTR edx
#define reg_INDEX_7_EDX_6 edx
#define reg_INDEX_7_EDX_7 edx
#define reg_AVX512_VP2INTERSECT edx
diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c
index 3ec94e0c9a191f36..6fa092a8c10486a0 100644
--- a/sysdeps/x86/tst-get-cpu-features.c
+++ b/sysdeps/x86/tst-get-cpu-features.c
@@ -180,6 +180,7 @@ do_test (void)
CHECK_CPU_FEATURE (AVX512_4VNNIW);
CHECK_CPU_FEATURE (AVX512_4FMAPS);
CHECK_CPU_FEATURE (FSRM);
+ CHECK_CPU_FEATURE (UINTR);
CHECK_CPU_FEATURE (AVX512_VP2INTERSECT);
CHECK_CPU_FEATURE (MD_CLEAR);
CHECK_CPU_FEATURE (SERIALIZE);

View File

@ -0,0 +1,86 @@
commit ebe454bcca6a5421512ad228595a5391506e990a
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Oct 8 08:24:47 2020 -0700
<sys/platform/x86.h>: Add AVX512_FP16 support
Add AVX512_FP16 support to <sys/platform/x86.h>.
diff --git a/manual/platform.texi b/manual/platform.texi
index 0dd12a4353a93bf2..4f5fdff9d9ef16fd 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -210,6 +210,9 @@ The supported processor features are:
@item
@code{AVX512_BITALG} -- The AVX512_BITALG instruction extensions.
+@item
+@code{AVX512_FP16} -- The AVX512_FP16 instruction extensions.
+
@item
@code{AVX512_IFMA} -- The AVX512_IFMA instruction extensions.
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 7f2ff00f2b4b45f2..67f137259fccf4ad 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -175,6 +175,8 @@ update_usable (struct cpu_features *cpu_features)
AVX512_VP2INTERSECT);
/* Determine if AVX512_BF16 is usable. */
CPU_FEATURE_SET_USABLE (cpu_features, AVX512_BF16);
+ /* Determine if AVX512_FP16 is usable. */
+ CPU_FEATURE_SET_USABLE (cpu_features, AVX512_FP16);
}
}
}
diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h
index 2760b81a56e6c7d7..0b18257e20105ea4 100644
--- a/sysdeps/x86/sys/platform/x86.h
+++ b/sysdeps/x86/sys/platform/x86.h
@@ -259,7 +259,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
#define bit_cpu_IBT (1u << 20)
#define bit_cpu_INDEX_7_EDX_21 (1u << 21)
#define bit_cpu_AMX_BF16 (1u << 22)
-#define bit_cpu_INDEX_7_EDX_23 (1u << 23)
+#define bit_cpu_AVX512_FP16 (1u << 23)
#define bit_cpu_AMX_TILE (1u << 24)
#define bit_cpu_AMX_INT8 (1u << 25)
#define bit_cpu_IBRS_IBPB (1u << 26)
@@ -478,7 +478,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
#define index_cpu_IBT COMMON_CPUID_INDEX_7
#define index_cpu_INDEX_7_EDX_21 COMMON_CPUID_INDEX_7
#define index_cpu_AMX_BF16 COMMON_CPUID_INDEX_7
-#define index_cpu_INDEX_7_EDX_23 COMMON_CPUID_INDEX_7
+#define index_cpu_AVX512_FP16 COMMON_CPUID_INDEX_7
#define index_cpu_AMX_TILE COMMON_CPUID_INDEX_7
#define index_cpu_AMX_INT8 COMMON_CPUID_INDEX_7
#define index_cpu_IBRS_IBPB COMMON_CPUID_INDEX_7
@@ -697,7 +697,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
#define reg_IBT edx
#define reg_INDEX_7_EDX_21 edx
#define reg_AMX_BF16 edx
-#define reg_INDEX_7_EDX_23 edx
+#define reg_AVX512_FP16 edx
#define reg_AMX_TILE edx
#define reg_AMX_INT8 edx
#define reg_IBRS_IBPB edx
diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c
index 6fa092a8c10486a0..bcdeb243a82c4adc 100644
--- a/sysdeps/x86/tst-get-cpu-features.c
+++ b/sysdeps/x86/tst-get-cpu-features.c
@@ -189,6 +189,7 @@ do_test (void)
CHECK_CPU_FEATURE (PCONFIG);
CHECK_CPU_FEATURE (IBT);
CHECK_CPU_FEATURE (AMX_BF16);
+ CHECK_CPU_FEATURE (AVX512_FP16);
CHECK_CPU_FEATURE (AMX_TILE);
CHECK_CPU_FEATURE (AMX_INT8);
CHECK_CPU_FEATURE (IBRS_IBPB);
@@ -343,6 +344,7 @@ do_test (void)
CHECK_CPU_FEATURE_USABLE (TSXLDTRK);
CHECK_CPU_FEATURE_USABLE (PCONFIG);
CHECK_CPU_FEATURE_USABLE (AMX_BF16);
+ CHECK_CPU_FEATURE_USABLE (AVX512_FP16);
CHECK_CPU_FEATURE_USABLE (AMX_TILE);
CHECK_CPU_FEATURE_USABLE (AMX_INT8);
CHECK_CPU_FEATURE_USABLE (IBRS_IBPB);

View File

@ -0,0 +1,83 @@
commit 875a50ff63b2c86af770949d563ee851d08eb46e
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Oct 8 08:33:45 2020 -0700
<sys/platform/x86.h>: Add AVX-VNNI support
Add AVX-VNNI support to <sys/platform/x86.h>.
diff --git a/manual/platform.texi b/manual/platform.texi
index 4f5fdff9d9ef16fd..283f255679643d3e 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -198,6 +198,9 @@ The supported processor features are:
@item
@code{AVX2} -- The AVX2 instruction extensions.
+@item
+@code{AVX_VNNI} -- The AVX-VNNI instruction extensions.
+
@item
@code{AVX512_4FMAPS} -- The AVX512_4FMAPS instruction extensions.
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 67f137259fccf4ad..3e5b9341c9756009 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -119,6 +119,8 @@ update_usable (struct cpu_features *cpu_features)
cpu_features->preferred[index_arch_AVX_Fast_Unaligned_Load]
|= bit_arch_AVX_Fast_Unaligned_Load;
}
+ /* Determine if AVX-VNNI is usable. */
+ CPU_FEATURE_SET_USABLE (cpu_features, AVX_VNNI);
/* Determine if FMA is usable. */
CPU_FEATURE_SET_USABLE (cpu_features, FMA);
/* Determine if VAES is usable. */
diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h
index 0b18257e20105ea4..0942ad7a7f7d4ce2 100644
--- a/sysdeps/x86/sys/platform/x86.h
+++ b/sysdeps/x86/sys/platform/x86.h
@@ -311,6 +311,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
/* COMMON_CPUID_INDEX_7_ECX_1. */
/* EAX. */
+#define bit_cpu_AVX_VNNI (1u << 4)
#define bit_cpu_AVX512_BF16 (1u << 5)
/* COMMON_CPUID_INDEX_19. */
@@ -530,6 +531,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
/* COMMON_CPUID_INDEX_7_ECX_1. */
/* EAX. */
+#define index_cpu_AVX_VNNI COMMON_CPUID_INDEX_7_ECX_1
#define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1
/* COMMON_CPUID_INDEX_19. */
@@ -749,6 +751,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
/* COMMON_CPUID_INDEX_7_ECX_1. */
/* EAX. */
+#define reg_AVX_VNNI eax
#define reg_AVX512_BF16 eax
/* COMMON_CPUID_INDEX_19. */
diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c
index bcdeb243a82c4adc..8894d9f08ac36633 100644
--- a/sysdeps/x86/tst-get-cpu-features.c
+++ b/sysdeps/x86/tst-get-cpu-features.c
@@ -219,6 +219,7 @@ do_test (void)
CHECK_CPU_FEATURE (XFD);
CHECK_CPU_FEATURE (INVARIANT_TSC);
CHECK_CPU_FEATURE (WBNOINVD);
+ CHECK_CPU_FEATURE (AVX_VNNI);
CHECK_CPU_FEATURE (AVX512_BF16);
CHECK_CPU_FEATURE (AESKLE);
CHECK_CPU_FEATURE (WIDE_KL);
@@ -374,6 +375,7 @@ do_test (void)
CHECK_CPU_FEATURE_USABLE (XFD);
CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC);
CHECK_CPU_FEATURE_USABLE (WBNOINVD);
+ CHECK_CPU_FEATURE_USABLE (AVX_VNNI);
CHECK_CPU_FEATURE_USABLE (AVX512_BF16);
CHECK_CPU_FEATURE_USABLE (AESKLE);
CHECK_CPU_FEATURE_USABLE (WIDE_KL);

View File

@ -0,0 +1,62 @@
commit c712401bc641b66d9bd558884751d8979e2e0e96
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Oct 8 08:38:03 2020 -0700
<sys/platform/x86.h>: Add Intel HRESET support
Add Intel HRESET support to <sys/platform/x86.h>.
diff --git a/manual/platform.texi b/manual/platform.texi
index 283f255679643d3e..1e44525552f5bda5 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -346,6 +346,9 @@ extensions.
@item
@code{HTT} -- Max APIC IDs reserved field is Valid.
+@item
+@code{HRESET} -- History reset.
+
@item
@code{HYBRID} -- Hybrid processor.
diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h
index 0942ad7a7f7d4ce2..357c6f1c5605d82d 100644
--- a/sysdeps/x86/sys/platform/x86.h
+++ b/sysdeps/x86/sys/platform/x86.h
@@ -313,6 +313,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
/* EAX. */
#define bit_cpu_AVX_VNNI (1u << 4)
#define bit_cpu_AVX512_BF16 (1u << 5)
+#define bit_cpu_HRESET (1u << 22)
/* COMMON_CPUID_INDEX_19. */
@@ -533,6 +534,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
/* EAX. */
#define index_cpu_AVX_VNNI COMMON_CPUID_INDEX_7_ECX_1
#define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1
+#define index_cpu_HRESET COMMON_CPUID_INDEX_7_ECX_1
/* COMMON_CPUID_INDEX_19. */
@@ -753,6 +755,7 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
/* EAX. */
#define reg_AVX_VNNI eax
#define reg_AVX512_BF16 eax
+#define reg_HRESET eax
/* COMMON_CPUID_INDEX_19. */
diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c
index 8894d9f08ac36633..1516af1d461a801b 100644
--- a/sysdeps/x86/tst-get-cpu-features.c
+++ b/sysdeps/x86/tst-get-cpu-features.c
@@ -221,6 +221,7 @@ do_test (void)
CHECK_CPU_FEATURE (WBNOINVD);
CHECK_CPU_FEATURE (AVX_VNNI);
CHECK_CPU_FEATURE (AVX512_BF16);
+ CHECK_CPU_FEATURE (HRESET);
CHECK_CPU_FEATURE (AESKLE);
CHECK_CPU_FEATURE (WIDE_KL);

View File

@ -0,0 +1,107 @@
commit 428985c436f442e91e27173bccaf28f547233586
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Oct 8 08:50:44 2020 -0700
<sys/platform/x86.h>: Add FSRCS/FSRS/FZLRM support
Add Fast Short REP CMP and SCA (FSRCS), Fast Short REP STO (FSRS) and
Fast Zero-Length REP MOV (FZLRM) support to <sys/platform/x86.h>.
diff --git a/manual/platform.texi b/manual/platform.texi
index 1e44525552f5bda5..8fec2933d6442823 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -331,12 +331,21 @@ extensions.
@item
@code{FSGSBASE} -- RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE instructions.
+@item
+@code{FSRCS} -- Fast Short REP CMP and SCA.
+
@item
@code{FSRM} -- Fast Short REP MOV.
+@item
+@code{FSRS} -- Fast Short REP STO.
+
@item
@code{FXSR} -- FXSAVE and FXRSTOR instructions.
+@item
+@code{FZLRM} -- Fast Zero-Length REP MOV.
+
@item
@code{GFNI} -- GFNI instruction extensions.
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 3e5b9341c9756009..5f0548fe08134236 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -93,6 +93,9 @@ update_usable (struct cpu_features *cpu_features)
CPU_FEATURE_SET_USABLE (cpu_features, TBM);
CPU_FEATURE_SET_USABLE (cpu_features, RDTSCP);
CPU_FEATURE_SET_USABLE (cpu_features, WBNOINVD);
+ CPU_FEATURE_SET_USABLE (cpu_features, FZLRM);
+ CPU_FEATURE_SET_USABLE (cpu_features, FSRS);
+ CPU_FEATURE_SET_USABLE (cpu_features, FSRCS);
/* Can we call xgetbv? */
if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE))
diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h
index 357c6f1c5605d82d..e5cc7c683a20b5a0 100644
--- a/sysdeps/x86/sys/platform/x86.h
+++ b/sysdeps/x86/sys/platform/x86.h
@@ -313,6 +313,9 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
/* EAX. */
#define bit_cpu_AVX_VNNI (1u << 4)
#define bit_cpu_AVX512_BF16 (1u << 5)
+#define bit_cpu_FZLRM (1u << 10)
+#define bit_cpu_FSRS (1u << 11)
+#define bit_cpu_FSRCS (1u << 12)
#define bit_cpu_HRESET (1u << 22)
/* COMMON_CPUID_INDEX_19. */
@@ -534,6 +537,9 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
/* EAX. */
#define index_cpu_AVX_VNNI COMMON_CPUID_INDEX_7_ECX_1
#define index_cpu_AVX512_BF16 COMMON_CPUID_INDEX_7_ECX_1
+#define index_cpu_FZLRM COMMON_CPUID_INDEX_7_ECX_1
+#define index_cpu_FSRS COMMON_CPUID_INDEX_7_ECX_1
+#define index_cpu_FSRCS COMMON_CPUID_INDEX_7_ECX_1
#define index_cpu_HRESET COMMON_CPUID_INDEX_7_ECX_1
/* COMMON_CPUID_INDEX_19. */
@@ -755,6 +761,9 @@ extern const struct cpu_features *__x86_get_cpu_features (unsigned int)
/* EAX. */
#define reg_AVX_VNNI eax
#define reg_AVX512_BF16 eax
+#define reg_FZLRM eax
+#define reg_FSRS eax
+#define reg_FSRCS eax
#define reg_HRESET eax
/* COMMON_CPUID_INDEX_19. */
diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c
index 1516af1d461a801b..2763deb6d008597f 100644
--- a/sysdeps/x86/tst-get-cpu-features.c
+++ b/sysdeps/x86/tst-get-cpu-features.c
@@ -221,6 +221,9 @@ do_test (void)
CHECK_CPU_FEATURE (WBNOINVD);
CHECK_CPU_FEATURE (AVX_VNNI);
CHECK_CPU_FEATURE (AVX512_BF16);
+ CHECK_CPU_FEATURE (FZLRM);
+ CHECK_CPU_FEATURE (FSRS);
+ CHECK_CPU_FEATURE (FSRCS);
CHECK_CPU_FEATURE (HRESET);
CHECK_CPU_FEATURE (AESKLE);
CHECK_CPU_FEATURE (WIDE_KL);
@@ -378,6 +381,9 @@ do_test (void)
CHECK_CPU_FEATURE_USABLE (WBNOINVD);
CHECK_CPU_FEATURE_USABLE (AVX_VNNI);
CHECK_CPU_FEATURE_USABLE (AVX512_BF16);
+ CHECK_CPU_FEATURE_USABLE (FZLRM);
+ CHECK_CPU_FEATURE_USABLE (FSRS);
+ CHECK_CPU_FEATURE_USABLE (FSRCS);
CHECK_CPU_FEATURE_USABLE (AESKLE);
CHECK_CPU_FEATURE_USABLE (WIDE_KL);

View File

@ -0,0 +1,18 @@
commit 21181d1c7b181c4bb71e587c7944e100d923b393
Author: Matheus Castanho <msc@linux.ibm.com>
Date: Mon Oct 12 11:28:18 2020 +0200
elf: Add missing <dl-procinfo.h> header to elf/dl-usage.c
diff --git a/elf/dl-usage.c b/elf/dl-usage.c
index c07f43835bd771cf..796ad38b43c2211b 100644
--- a/elf/dl-usage.c
+++ b/elf/dl-usage.c
@@ -22,6 +22,7 @@
#include <unistd.h>
#include "version.h"
+#include <dl-procinfo.h>
#include <dl-hwcaps.h>
void

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,364 @@
commit de1a9197af7f67a89f929dcadb8ceca8c3846b1c
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Oct 30 11:57:59 2020 +0100
elf: Unify old and new format cache handling code in ld.so
struct file_entry_new starts with the fields of struct file_entry,
so the code can be shared if the size computation is made dynamic.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-cache.c b/elf/dl-cache.c
index ef37ca18fa9fb6e0..366a051dfcd26132 100644
--- a/elf/dl-cache.c
+++ b/elf/dl-cache.c
@@ -35,103 +35,141 @@ static struct cache_file *cache;
static struct cache_file_new *cache_new;
static size_t cachesize;
-/* 1 if cache_data + PTR points into the cache. */
-#define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size)
-
-#define SEARCH_CACHE(cache) \
-/* We use binary search since the table is sorted in the cache file. \
- The first matching entry in the table is returned. \
- It is important to use the same algorithm as used while generating \
- the cache file. */ \
-do \
- { \
- left = 0; \
- right = cache->nlibs - 1; \
- \
- while (left <= right) \
- { \
- __typeof__ (cache->libs[0].key) key; \
- \
- middle = (left + right) / 2; \
- \
- key = cache->libs[middle].key; \
- \
- /* Make sure string table indices are not bogus before using \
- them. */ \
- if (! _dl_cache_verify_ptr (key)) \
- { \
- cmpres = 1; \
- break; \
- } \
- \
- /* Actually compare the entry with the key. */ \
- cmpres = _dl_cache_libcmp (name, cache_data + key); \
- if (__glibc_unlikely (cmpres == 0)) \
- { \
- /* Found it. LEFT now marks the last entry for which we \
- know the name is correct. */ \
- left = middle; \
- \
- /* There might be entries with this name before the one we \
- found. So we have to find the beginning. */ \
- while (middle > 0) \
- { \
- __typeof__ (cache->libs[0].key) key; \
- \
- key = cache->libs[middle - 1].key; \
- /* Make sure string table indices are not bogus before \
- using them. */ \
- if (! _dl_cache_verify_ptr (key) \
- /* Actually compare the entry. */ \
- || _dl_cache_libcmp (name, cache_data + key) != 0) \
- break; \
- --middle; \
- } \
- \
- do \
- { \
- int flags; \
- __typeof__ (cache->libs[0]) *lib = &cache->libs[middle]; \
- \
- /* Only perform the name test if necessary. */ \
- if (middle > left \
- /* We haven't seen this string so far. Test whether the \
- index is ok and whether the name matches. Otherwise \
- we are done. */ \
- && (! _dl_cache_verify_ptr (lib->key) \
- || (_dl_cache_libcmp (name, cache_data + lib->key) \
- != 0))) \
- break; \
- \
- flags = lib->flags; \
- if (_dl_cache_check_flags (flags) \
- && _dl_cache_verify_ptr (lib->value)) \
- { \
- if (best == NULL || flags == GLRO(dl_correct_cache_id)) \
- { \
- HWCAP_CHECK; \
- best = cache_data + lib->value; \
- \
- if (flags == GLRO(dl_correct_cache_id)) \
- /* We've found an exact match for the shared \
- object and no general `ELF' release. Stop \
- searching. */ \
- break; \
- } \
- } \
- } \
- while (++middle <= right); \
- break; \
- } \
- \
- if (cmpres < 0) \
- left = middle + 1; \
- else \
- right = middle - 1; \
- } \
- } \
-while (0)
+/* True if PTR is a valid string table index. */
+static inline bool
+_dl_cache_verify_ptr (uint32_t ptr, size_t string_table_size)
+{
+ return ptr < string_table_size;
+}
+
+/* Compute the address of the element INDEX of the array at LIBS.
+ Conceptually, this is &LIBS[INDEX], but use ENTRY_SIZE for the size
+ of *LIBS. */
+static inline const struct file_entry *
+_dl_cache_file_entry (const struct file_entry *libs, size_t entry_size,
+ size_t index)
+{
+ return (const void *) libs + index * entry_size;
+}
+
+/* We use binary search since the table is sorted in the cache file.
+ The first matching entry in the table is returned. It is important
+ to use the same algorithm as used while generating the cache file.
+ STRING_TABLE_SIZE indicates the maximum offset in STRING_TABLE at
+ which data is mapped; it is not exact. */
+static const char *
+search_cache (const char *string_table, uint32_t string_table_size,
+ struct file_entry *libs, uint32_t nlibs, uint32_t entry_size,
+ const char *name)
+{
+ /* Used by the HWCAP check in the struct file_entry_new case. */
+ uint64_t platform = _dl_string_platform (GLRO (dl_platform));
+ if (platform != (uint64_t) -1)
+ platform = 1ULL << platform;
+ uint64_t hwcap_mask = GET_HWCAP_MASK ();
+#define _DL_HWCAP_TLS_MASK (1LL << 63)
+ uint64_t hwcap_exclude = ~((GLRO (dl_hwcap) & hwcap_mask)
+ | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK);
+
+ int left = 0;
+ int right = nlibs - 1;
+ const char *best = NULL;
+
+ while (left <= right)
+ {
+ int middle = (left + right) / 2;
+ uint32_t key = _dl_cache_file_entry (libs, entry_size, middle)->key;
+
+ /* Make sure string table indices are not bogus before using
+ them. */
+ if (!_dl_cache_verify_ptr (key, string_table_size))
+ return NULL;
+
+ /* Actually compare the entry with the key. */
+ int cmpres = _dl_cache_libcmp (name, string_table + key);
+ if (__glibc_unlikely (cmpres == 0))
+ {
+ /* Found it. LEFT now marks the last entry for which we
+ know the name is correct. */
+ left = middle;
+
+ /* There might be entries with this name before the one we
+ found. So we have to find the beginning. */
+ while (middle > 0)
+ {
+ key = _dl_cache_file_entry (libs, entry_size, middle - 1)->key;
+ /* Make sure string table indices are not bogus before
+ using them. */
+ if (!_dl_cache_verify_ptr (key, string_table_size)
+ /* Actually compare the entry. */
+ || _dl_cache_libcmp (name, string_table + key) != 0)
+ break;
+ --middle;
+ }
+
+ do
+ {
+ int flags;
+ const struct file_entry *lib
+ = _dl_cache_file_entry (libs, entry_size, middle);
+
+ /* Only perform the name test if necessary. */
+ if (middle > left
+ /* We haven't seen this string so far. Test whether the
+ index is ok and whether the name matches. Otherwise
+ we are done. */
+ && (! _dl_cache_verify_ptr (lib->key, string_table_size)
+ || (_dl_cache_libcmp (name, string_table + lib->key)
+ != 0)))
+ break;
+
+ flags = lib->flags;
+ if (_dl_cache_check_flags (flags)
+ && _dl_cache_verify_ptr (lib->value, string_table_size))
+ {
+ if (best == NULL || flags == GLRO (dl_correct_cache_id))
+ {
+ if (entry_size >= sizeof (struct file_entry_new))
+ {
+ /* The entry is large enough to include
+ HWCAP data. Check it. */
+ struct file_entry_new *libnew
+ = (struct file_entry_new *) lib;
+
+ if (libnew->hwcap & hwcap_exclude)
+ continue;
+ if (GLRO (dl_osversion)
+ && libnew->osversion > GLRO (dl_osversion))
+ continue;
+ if (_DL_PLATFORMS_COUNT
+ && (libnew->hwcap & _DL_HWCAP_PLATFORM) != 0
+ && ((libnew->hwcap & _DL_HWCAP_PLATFORM)
+ != platform))
+ continue;
+ }
+
+ best = string_table + lib->value;
+
+ if (flags == GLRO (dl_correct_cache_id))
+ /* We've found an exact match for the shared
+ object and no general `ELF' release. Stop
+ searching. */
+ break;
+ }
+ }
+ }
+ while (++middle <= right);
+ break;
+ }
+ if (cmpres < 0)
+ left = middle + 1;
+ else
+ right = middle - 1;
+ }
+
+ return best;
+}
int
_dl_cache_libcmp (const char *p1, const char *p2)
@@ -182,12 +220,6 @@ _dl_cache_libcmp (const char *p1, const char *p2)
char *
_dl_load_cache_lookup (const char *name)
{
- int left, right, middle;
- int cmpres;
- const char *cache_data;
- uint32_t cache_data_size;
- const char *best;
-
/* Print a message if the loading of libs is traced. */
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
_dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
@@ -247,51 +279,22 @@ _dl_load_cache_lookup (const char *name)
/* Previously looked for the cache file and didn't find it. */
return NULL;
- best = NULL;
-
+ const char *best;
if (cache_new != (void *) -1)
{
- uint64_t platform;
-
- /* This is where the strings start. */
- cache_data = (const char *) cache_new;
-
- /* Now we can compute how large the string table is. */
- cache_data_size = (const char *) cache + cachesize - cache_data;
-
- platform = _dl_string_platform (GLRO(dl_platform));
- if (platform != (uint64_t) -1)
- platform = 1ULL << platform;
-
- uint64_t hwcap_mask = GET_HWCAP_MASK();
-
-#define _DL_HWCAP_TLS_MASK (1LL << 63)
- uint64_t hwcap_exclude = ~((GLRO(dl_hwcap) & hwcap_mask)
- | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK);
-
- /* Only accept hwcap if it's for the right platform. */
-#define HWCAP_CHECK \
- if (lib->hwcap & hwcap_exclude) \
- continue; \
- if (GLRO(dl_osversion) && lib->osversion > GLRO(dl_osversion)) \
- continue; \
- if (_DL_PLATFORMS_COUNT \
- && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \
- && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \
- continue
- SEARCH_CACHE (cache_new);
+ const char *string_table = (const char *) cache_new;
+ best = search_cache (string_table, cachesize,
+ &cache_new->libs[0].entry, cache_new->nlibs,
+ sizeof (cache_new->libs[0]), name);
}
else
{
- /* This is where the strings start. */
- cache_data = (const char *) &cache->libs[cache->nlibs];
-
- /* Now we can compute how large the string table is. */
- cache_data_size = (const char *) cache + cachesize - cache_data;
-
-#undef HWCAP_CHECK
-#define HWCAP_CHECK do {} while (0)
- SEARCH_CACHE (cache);
+ const char *string_table = (const char *) &cache->libs[cache->nlibs];
+ uint32_t string_table_size
+ = (const char *) cache + cachesize - string_table;
+ best = search_cache (string_table, string_table_size,
+ &cache->libs[0], cache->nlibs,
+ sizeof (cache->libs[0]), name);
}
/* Print our result if wanted. */
diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h
index cf43f1cf3b441bc7..3c5730dfe42c7c88 100644
--- a/sysdeps/generic/dl-cache.h
+++ b/sysdeps/generic/dl-cache.h
@@ -59,8 +59,8 @@
*/
struct file_entry
{
- int flags; /* This is 1 for an ELF library. */
- unsigned int key, value; /* String table indices. */
+ int32_t flags; /* This is 1 for an ELF library. */
+ uint32_t key, value; /* String table indices. */
};
struct cache_file
@@ -77,8 +77,17 @@ struct cache_file
struct file_entry_new
{
- int32_t flags; /* This is 1 for an ELF library. */
- uint32_t key, value; /* String table indices. */
+ union
+ {
+ /* Fields shared with struct file_entry. */
+ struct file_entry entry;
+ /* Also expose these fields directly. */
+ struct
+ {
+ int32_t flags; /* This is 1 for an ELF library. */
+ uint32_t key, value; /* String table indices. */
+ };
+ };
uint32_t osversion; /* Required OS version. */
uint64_t hwcap; /* Hwcap entry. */
};

View File

@ -0,0 +1,67 @@
commit 5e598c2bbf938eac0f4045f5143f9dd723646672
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Oct 30 18:40:28 2020 +0100
elf: In ldconfig, extract the new_sub_entry function from search_dir
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 7c8fd29387463a8a..be730ceb075f6c1f 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -328,6 +328,23 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
"Andreas Jaeger");
}
+/* Allocate a new subdirectory with full path PATH under ENTRY, using
+ inode data from *ST. */
+static struct dir_entry *
+new_sub_entry (const struct dir_entry *entry, const char *path,
+ const struct stat64 *st)
+{
+ struct dir_entry *new_entry = xmalloc (sizeof (struct dir_entry));
+ new_entry->from_file = entry->from_file;
+ new_entry->from_line = entry->from_line;
+ new_entry->path = xstrdup (path);
+ new_entry->flag = entry->flag;
+ new_entry->next = NULL;
+ new_entry->ino = st->st_ino;
+ new_entry->dev = st->st_dev;
+ return new_entry;
+}
+
/* Add a single directory entry. */
static void
add_single_dir (struct dir_entry *entry, int verbose)
@@ -823,26 +840,17 @@ search_dir (const struct dir_entry *entry)
if (is_dir && is_hwcap_platform (direntry->d_name))
{
- /* Handle subdirectory later. */
- struct dir_entry *new_entry;
-
- new_entry = xmalloc (sizeof (struct dir_entry));
- new_entry->from_file = entry->from_file;
- new_entry->from_line = entry->from_line;
- new_entry->path = xstrdup (file_name);
- new_entry->flag = entry->flag;
- new_entry->next = NULL;
if (!is_link
&& direntry->d_type != DT_UNKNOWN
&& __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
{
error (0, errno, _("Cannot lstat %s"), file_name);
- free (new_entry->path);
- free (new_entry);
continue;
}
- new_entry->ino = lstat_buf.st_ino;
- new_entry->dev = lstat_buf.st_dev;
+
+ /* Handle subdirectory later. */
+ struct dir_entry *new_entry = new_sub_entry (entry, file_name,
+ &lstat_buf);
add_single_dir (new_entry, 0);
continue;
}

View File

@ -0,0 +1,79 @@
commit 7cc65773f04e0f4252428c40dcbb784a39b58cd1
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Wed Oct 24 02:19:15 2018 -0700
x86: Support RDTSCP for benchtests
RDTSCP waits until all previous instructions have executed and all
previous loads are globally visible before reading the counter. RDTSC
doesn't wait until all previous instructions have been executed before
reading the counter. All x86 processors since 2010 support RDTSCP
instruction. This patch adds RDTSCP support to benchtests.
* benchtests/Makefile (CPPFLAGS-nonlib): Add -DUSE_RDTSCP if
USE_RDTSCP is defined.
* sysdeps/x86/hp-timing.h (HP_TIMING_NOW): Use RDTSCP if
USE_RDTSCP is defined.
diff --git a/benchtests/Makefile b/benchtests/Makefile
index 28d6b0c43f5bd390..bde0caf140e8cf17 100644
--- a/benchtests/Makefile
+++ b/benchtests/Makefile
@@ -131,6 +131,12 @@ CPPFLAGS-nonlib += -DDURATION=$(BENCH_DURATION) -D_ISOMAC
# HP_TIMING if it is available.
ifdef USE_CLOCK_GETTIME
CPPFLAGS-nonlib += -DUSE_CLOCK_GETTIME
+else
+# On x86 processors, use RDTSCP, instead of RDTSC, to measure performance
+# of functions. All x86 processors since 2010 support RDTSCP instruction.
+ifdef USE_RDTSCP
+CPPFLAGS-nonlib += -DUSE_RDTSCP
+endif
endif
DETAILED_OPT :=
diff --git a/benchtests/README b/benchtests/README
index 4ddff794d136f65f..aaf0b659e2b25627 100644
--- a/benchtests/README
+++ b/benchtests/README
@@ -34,6 +34,15 @@ the benchmark to use clock_gettime by invoking make as follows:
Again, one must run `make bench-clean' before changing the measurement method.
+On x86 processors, RDTSCP instruction provides more precise timing data
+than RDTSC instruction. All x86 processors since 2010 support RDTSCP
+instruction. One can force the benchmark to use RDTSCP by invoking make
+as follows:
+
+ $ make USE_RDTSCP=1 bench
+
+One must run `make bench-clean' before changing the measurement method.
+
Running benchmarks on another target:
====================================
diff --git a/sysdeps/x86/hp-timing.h b/sysdeps/x86/hp-timing.h
index 77a1360748ca4535..0aa6f5e3f83e0d34 100644
--- a/sysdeps/x86/hp-timing.h
+++ b/sysdeps/x86/hp-timing.h
@@ -40,7 +40,19 @@ typedef unsigned long long int hp_timing_t;
NB: Use __builtin_ia32_rdtsc directly since including <x86intrin.h>
makes building glibc very slow. */
-# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ())
+# ifdef USE_RDTSCP
+/* RDTSCP waits until all previous instructions have executed and all
+ previous loads are globally visible before reading the counter.
+ RDTSC doesn't wait until all previous instructions have been executed
+ before reading the counter. */
+# define HP_TIMING_NOW(Var) \
+ (__extension__ ({ \
+ unsigned int __aux; \
+ (Var) = __builtin_ia32_rdtscp (&__aux); \
+ }))
+# else
+# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ())
+# endif
# include <hp-timing-common.h>
#else

View File

@ -0,0 +1,22 @@
commit df5f473ed5ee95e3179fcb239e33e971619626cd
Author: Shuo Wang <wangshuo47@huawei.com>
Date: Tue Nov 24 16:42:18 2020 -0300
elf: Fix uninitialized variable for _dl_write
Variable ret in elf/dl-write.c is uninitialized, which should get
return value from __writev.
diff --git a/elf/dl-write.c b/elf/dl-write.c
index 7350aff0035d4fbc..9b741c8a8fe12f6c 100644
--- a/elf/dl-write.c
+++ b/elf/dl-write.c
@@ -41,7 +41,7 @@ _dl_write (int fd, const void *buffer, size_t length)
else
{
__rtld_lock_lock_recursive (GL(dl_load_lock));
- __writev (fd, &iov, 1);
+ ret = __writev (fd, &iov, 1);
if (ret < 0)
ret = -errno;
__rtld_lock_unlock_recursive (GL(dl_load_lock));

View File

@ -0,0 +1,85 @@
commit 603ae243f6fe03208a3bb92adecf72403367bd95
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Nov 26 16:59:44 2020 +0100
support: Add support_copy_file
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/support/Makefile b/support/Makefile
index 895b83a426369b0c..35b21b19a248ba7f 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -46,6 +46,7 @@ libsupport-routines = \
support_capture_subprocess \
support_capture_subprocess_check \
support_chroot \
+ support_copy_file \
support_copy_file_range \
support_descriptor_supports_holes \
support_descriptors \
diff --git a/support/support.h b/support/support.h
index 3af87f85fe1b762d..6f7f804847f67600 100644
--- a/support/support.h
+++ b/support/support.h
@@ -115,6 +115,11 @@ extern const char support_install_rootsbindir[];
/* Corresponds to the install's compiled locale directory. */
extern const char support_complocaledir_prefix[];
+/* Copies the file at the path FROM to TO. If TO does not exist, it
+ is created. If TO is a regular file, it is truncated before
+ copying. The file mode is copied, but the permissions are not. */
+extern void support_copy_file (const char *from, const char *to);
+
extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *,
size_t, unsigned int);
diff --git a/support/support_copy_file.c b/support/support_copy_file.c
new file mode 100644
index 0000000000000000..c93e1e58c81b749d
--- /dev/null
+++ b/support/support_copy_file.c
@@ -0,0 +1,43 @@
+/* Copy a file from one path to another.
+ Copyright (C) 2020 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 <fcntl.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+
+void
+support_copy_file (const char *from, const char *to)
+{
+ struct stat64 st;
+ xstat (from, &st);
+ int fd_from = xopen (from, O_RDONLY, 0);
+ mode_t mode = st.st_mode & 0777;
+ int fd_to = xopen (to, O_WRONLY | O_TRUNC | O_CREAT, mode);
+ ssize_t ret = support_copy_file_range (fd_from, NULL, fd_to, NULL,
+ st.st_size, 0);
+ if (ret < 0)
+ FAIL_EXIT1 ("copying from \"%s\" to \"%s\": %m", from, to);
+ if (ret != st.st_size)
+ FAIL_EXIT1 ("copying from \"%s\" to \"%s\": only %zd of %llu bytes copied",
+ from, to, ret, (unsigned long long int) st.st_size);
+ if (fchmod (fd_to, mode) < 0)
+ FAIL_EXIT1 ("fchmod on %s to 0%o: %m", to, mode);
+ xclose (fd_to);
+ xclose (fd_from);
+}

View File

@ -0,0 +1,152 @@
commit db07fae8250401adb2b97ab3e53d41da2a6bd767
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Nov 26 16:59:44 2020 +0100
elf: Introduce enum opt_format in the ldconfig implementation
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/cache.c b/elf/cache.c
index c4cd825c30e00e8e..edcdd4b7cc1a6a0b 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -321,13 +321,13 @@ save_cache (const char *cache_name)
struct cache_file *file_entries = NULL;
size_t file_entries_size = 0;
- if (opt_format != 2)
+ if (opt_format != opt_format_new)
{
/* struct cache_file_new is 64-bit aligned on some arches while
only 32-bit aligned on other arches. Duplicate last old
cache entry so that new cache in ld.so.cache can be used by
both. */
- if (opt_format != 0)
+ if (opt_format != opt_format_old)
cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
/* And the list of all entries in the old format. */
@@ -345,7 +345,7 @@ save_cache (const char *cache_name)
struct cache_file_new *file_entries_new = NULL;
size_t file_entries_new_size = 0;
- if (opt_format != 0)
+ if (opt_format != opt_format_old)
{
/* And the list of all entries in the new format. */
file_entries_new_size = sizeof (struct cache_file_new)
@@ -370,7 +370,7 @@ save_cache (const char *cache_name)
table, we have to adjust all string indices for this so that
old libc5/glibc 2 dynamic linkers just ignore them. */
unsigned int str_offset;
- if (opt_format != 0)
+ if (opt_format != opt_format_old)
str_offset = file_entries_new_size;
else
str_offset = 0;
@@ -385,13 +385,13 @@ save_cache (const char *cache_name)
entry = entry->next, ++idx_new)
{
/* First the library. */
- if (opt_format != 2 && entry->hwcap == 0)
+ if (opt_format != opt_format_new && entry->hwcap == 0)
{
file_entries->libs[idx_old].flags = entry->flags;
/* XXX: Actually we can optimize here and remove duplicates. */
file_entries->libs[idx_old].key = str_offset + pad;
}
- if (opt_format != 0)
+ if (opt_format != opt_format_old)
{
/* We could subtract file_entries_new_size from str_offset -
not doing so makes the code easier, the string table
@@ -407,9 +407,9 @@ save_cache (const char *cache_name)
str = mempcpy (str, entry->lib, len);
str_offset += len;
/* Then the path. */
- if (opt_format != 2 && entry->hwcap == 0)
+ if (opt_format != opt_format_new && entry->hwcap == 0)
file_entries->libs[idx_old].value = str_offset + pad;
- if (opt_format != 0)
+ if (opt_format != opt_format_old)
file_entries_new->libs[idx_new].value = str_offset;
len = strlen (entry->path) + 1;
str = mempcpy (str, entry->path, len);
@@ -420,7 +420,7 @@ save_cache (const char *cache_name)
}
/* Duplicate last old cache entry if needed. */
- if (opt_format != 2
+ if (opt_format != opt_format_new
&& idx_old < cache_entry_old_count)
file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
@@ -438,16 +438,16 @@ save_cache (const char *cache_name)
temp_name);
/* Write contents. */
- if (opt_format != 2)
+ if (opt_format != opt_format_new)
{
if (write (fd, file_entries, file_entries_size)
!= (ssize_t) file_entries_size)
error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
}
- if (opt_format != 0)
+ if (opt_format != opt_format_old)
{
/* Align cache. */
- if (opt_format != 2)
+ if (opt_format != opt_format_new)
{
char zero[pad];
memset (zero, '\0', pad);
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index be730ceb075f6c1f..0fa5aef83f9cd86c 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -100,8 +100,7 @@ static int opt_print_cache;
int opt_verbose;
/* Format to support. */
-/* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */
-int opt_format = 2;
+enum opt_format opt_format = opt_format_new;
/* Build cache. */
static int opt_build_cache = 1;
@@ -281,11 +280,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'c':
if (strcmp (arg, "old") == 0)
- opt_format = 0;
+ opt_format = opt_format_old;
else if (strcmp (arg, "compat") == 0)
- opt_format = 1;
+ opt_format = opt_format_compat;
else if (strcmp (arg, "new") == 0)
- opt_format = 2;
+ opt_format = opt_format_new;
break;
default:
return ARGP_ERR_UNKNOWN;
diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h
index 6774212110d23eae..b15b142511829436 100644
--- a/sysdeps/generic/ldconfig.h
+++ b/sysdeps/generic/ldconfig.h
@@ -90,7 +90,14 @@ extern char *chroot_canon (const char *chroot, const char *name);
/* Declared in ldconfig.c. */
extern int opt_verbose;
-extern int opt_format;
+enum opt_format
+ {
+ opt_format_old = 0, /* Use struct cache_file. */
+ opt_format_compat = 1, /* Use both, old format followed by new. */
+ opt_format_new = 2, /* Use struct cache_file_new. */
+ };
+
+extern enum opt_format opt_format;
/* Prototypes for a few program-wide used functions. */
#include <programs/xmalloc.h>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,190 @@
commit 84ba719b260551918965d0a433914de683087645
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 4 09:13:43 2020 +0100
elf: Add endianness markup to ld.so.cache (bug 27008)
Use a reserved byte in the new format cache header to indicate whether
the file is in little endian or big endian format. Eventually, this
information could be used to provide a unified cache for qemu-user
and similiar scenarios.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/cache.c b/elf/cache.c
index edcdd4b7cc1a6a0b..28e4889d006d2f0b 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -152,6 +152,14 @@ print_entry (const char *lib, int flag, unsigned int osversion,
printf (") => %s\n", key);
}
+/* Print an error and exit if the new-file cache is internally
+ inconsistent. */
+static void
+check_new_cache (struct cache_file_new *cache)
+{
+ if (! cache_file_new_matches_endian (cache))
+ error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n"));
+}
/* Print the whole cache file, if a file contains the new cache format
hidden in the old one, print the contents of the new format. */
@@ -193,6 +201,7 @@ print_cache (const char *cache_name)
|| memcmp (cache_new->version, CACHE_VERSION,
sizeof CACHE_VERSION - 1))
error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
+ check_new_cache (cache_new);
format = 1;
/* This is where the strings start. */
cache_data = (const char *) cache_new;
@@ -222,6 +231,7 @@ print_cache (const char *cache_name)
&& memcmp (cache_new->version, CACHE_VERSION,
sizeof CACHE_VERSION - 1) == 0)
{
+ check_new_cache (cache_new);
cache_data = (const char *) cache_new;
format = 1;
}
@@ -361,6 +371,7 @@ save_cache (const char *cache_name)
file_entries_new->nlibs = cache_entry_count;
file_entries_new->len_strings = total_strlen;
+ file_entries_new->flags = cache_file_new_flags_endian_current;
}
/* Pad for alignment of cache_file_new. */
diff --git a/elf/dl-cache.c b/elf/dl-cache.c
index 366a051dfcd26132..de063faa8b2c88ae 100644
--- a/elf/dl-cache.c
+++ b/elf/dl-cache.c
@@ -242,6 +242,11 @@ _dl_load_cache_lookup (const char *name)
&& ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new)
>= ((struct cache_file_new *) file)->nlibs))
{
+ if (! cache_file_new_matches_endian (file))
+ {
+ __munmap (file, cachesize);
+ file = (void *) -1;
+ }
cache_new = file;
cache = file;
}
@@ -263,7 +268,20 @@ _dl_load_cache_lookup (const char *name)
if (cachesize < (offset + sizeof (struct cache_file_new))
|| memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
- cache_new = (void *) -1;
+ cache_new = (void *) -1;
+ else
+ {
+ if (! cache_file_new_matches_endian (cache_new))
+ {
+ /* The old-format part of the cache is bogus as well
+ if the endianness does not match. (But it is
+ unclear how the new header can be located if the
+ endianess does not match.) */
+ cache = (void *) -1;
+ cache_new = (void *) -1;
+ __munmap (file, cachesize);
+ }
+ }
}
else
{
diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h
index 3c5730dfe42c7c88..6ecfd6da0e59329c 100644
--- a/sysdeps/generic/dl-cache.h
+++ b/sysdeps/generic/dl-cache.h
@@ -16,6 +16,11 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#ifndef _DL_CACHE_H
+#define _DL_CACHE_H
+
+#include <endian.h>
+#include <stdbool.h>
#include <stdint.h>
#ifndef _DL_CACHE_DEFAULT_ID
@@ -92,17 +97,72 @@ struct file_entry_new
uint64_t hwcap; /* Hwcap entry. */
};
+/* See flags member of struct cache_file_new below. */
+enum
+ {
+ /* No endianness information available. An old ldconfig version
+ without endianness support wrote the file. */
+ cache_file_new_flags_endian_unset = 0,
+
+ /* Cache is invalid and should be ignored. */
+ cache_file_new_flags_endian_invalid = 1,
+
+ /* Cache format is little endian. */
+ cache_file_new_flags_endian_little = 2,
+
+ /* Cache format is big endian. */
+ cache_file_new_flags_endian_big = 3,
+
+ /* Bit mask to extract the cache_file_new_flags_endian_*
+ values. */
+ cache_file_new_flags_endian_mask = 3,
+
+ /* Expected value of the endian bits in the flags member for the
+ current architecture. */
+ cache_file_new_flags_endian_current
+ = (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ ? cache_file_new_flags_endian_little
+ : cache_file_new_flags_endian_big),
+ };
+
struct cache_file_new
{
char magic[sizeof CACHEMAGIC_NEW - 1];
char version[sizeof CACHE_VERSION - 1];
uint32_t nlibs; /* Number of entries. */
uint32_t len_strings; /* Size of string table. */
- uint32_t unused[5]; /* Leave space for future extensions
+
+ /* flags & cache_file_new_flags_endian_mask is one of the values
+ cache_file_new_flags_endian_unset, cache_file_new_flags_endian_invalid,
+ cache_file_new_flags_endian_little, cache_file_new_flags_endian_big.
+
+ The remaining bits are unused and should be generated as zero and
+ ignored by readers. */
+ uint8_t flags;
+
+ uint8_t padding_unsed[3]; /* Not used, for future extensions. */
+
+ uint32_t unused[4]; /* Leave space for future extensions
and align to 8 byte boundary. */
struct file_entry_new libs[0]; /* Entries describing libraries. */
/* After this the string table of size len_strings is found. */
};
+_Static_assert (sizeof (struct cache_file_new) == 48,
+ "size of struct cache_file_new");
+
+/* Returns false if *CACHE has the wrong endianness for this
+ architecture, and true if the endianness matches (or is
+ unknown). */
+static inline bool
+cache_file_new_matches_endian (const struct cache_file_new *cache)
+{
+ /* A zero value for cache->flags means that no endianness
+ information is available. */
+ return cache->flags == 0
+ || ((cache->flags & cache_file_new_flags_endian_big)
+ == cache_file_new_flags_endian_current);
+}
+
/* Used to align cache_file_new. */
#define ALIGN_CACHE(addr) \
@@ -110,3 +170,5 @@ struct cache_file_new
& (~(__alignof__ (struct cache_file_new) - 1)))
extern int _dl_cache_libcmp (const char *p1, const char *p2) attribute_hidden;
+
+#endif /* _DL_CACHE_H */

View File

@ -0,0 +1,312 @@
commit dfb3f101c5ef23adf60d389058a2b33e23303d04
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 4 09:13:43 2020 +0100
elf: Add extension mechanism to ld.so.cache
A previously unused new-format header field is used to record
the address of an extension directory.
This change adds a demo extension which records the version of
ldconfig which builds a file.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/cache.c b/elf/cache.c
index 28e4889d006d2f0b..5a8f1ad70cc3fead 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -15,6 +15,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
+#include <assert.h>
#include <errno.h>
#include <error.h>
#include <dirent.h>
@@ -33,6 +34,7 @@
#include <ldconfig.h>
#include <dl-cache.h>
+#include <version.h>
struct cache_entry
{
@@ -161,6 +163,21 @@ check_new_cache (struct cache_file_new *cache)
error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n"));
}
+/* Print the extension information at the cache at start address
+ FILE_BASE, of length FILE_SIZE bytes. The new-format cache header
+ is at CACHE, and the file name for diagnostics is CACHE_NAME. */
+static void
+print_extensions (struct cache_extension_all_loaded *ext)
+{
+ if (ext->sections[cache_extension_tag_generator].base != NULL)
+ {
+ fputs (_("Cache generated by: "), stdout);
+ fwrite (ext->sections[cache_extension_tag_generator].base, 1,
+ ext->sections[cache_extension_tag_generator].size, stdout);
+ putchar ('\n');
+ }
+}
+
/* Print the whole cache file, if a file contains the new cache format
hidden in the old one, print the contents of the new format. */
void
@@ -250,6 +267,11 @@ print_cache (const char *cache_name)
}
else if (format == 1)
{
+ struct cache_extension_all_loaded ext;
+ if (!cache_extension_load (cache_new, cache, cache_size, &ext))
+ error (EXIT_FAILURE, 0,
+ _("Malformed extension data in cache file %s\n"), cache_name);
+
printf (_("%d libs found in cache `%s'\n"),
cache_new->nlibs, cache_name);
@@ -260,6 +282,7 @@ print_cache (const char *cache_name)
cache_new->libs[i].osversion,
cache_new->libs[i].hwcap,
cache_data + cache_new->libs[i].value);
+ print_extensions (&ext);
}
/* Cleanup. */
munmap (cache, cache_size);
@@ -301,6 +324,45 @@ compare (const struct cache_entry *e1, const struct cache_entry *e2)
return res;
}
+/* Size of the cache extension directory. All tags are assumed to be
+ present. */
+enum
+ {
+ cache_extension_size = (offsetof (struct cache_extension, sections)
+ + (cache_extension_count
+ * sizeof (struct cache_extension_section)))
+ };
+
+/* Write the cache extensions to FD. The extension directory is
+ assumed to be located at CACHE_EXTENSION_OFFSET. */
+static void
+write_extensions (int fd, uint32_t cache_extension_offset)
+{
+ assert ((cache_extension_offset % 4) == 0);
+
+ struct cache_extension *ext = xmalloc (cache_extension_size);
+ ext->magic = cache_extension_magic;
+ ext->count = cache_extension_count;
+
+ for (int i = 0; i < cache_extension_count; ++i)
+ {
+ ext->sections[i].tag = i;
+ ext->sections[i].flags = 0;
+ }
+
+ const char *generator
+ = "ldconfig " PKGVERSION RELEASE " release version " VERSION;
+ ext->sections[cache_extension_tag_generator].offset
+ = cache_extension_offset + cache_extension_size;
+ ext->sections[cache_extension_tag_generator].size = strlen (generator);
+
+ if (write (fd, ext, cache_extension_size) != cache_extension_size
+ || write (fd, generator, strlen (generator)) != strlen (generator))
+ error (EXIT_FAILURE, errno, _("Writing of cache extension data failed"));
+
+ free (ext);
+}
+
/* Save the contents of the cache. */
void
save_cache (const char *cache_name)
@@ -435,6 +497,25 @@ save_cache (const char *cache_name)
&& idx_old < cache_entry_old_count)
file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
+ /* Compute the location of the extension directory. This
+ implementation puts the directory after the string table. The
+ size computation matches the write calls below. The extension
+ directory does not exist with format 0, so the value does not
+ matter. */
+ uint32_t extension_offset = 0;
+ if (opt_format != opt_format_new)
+ extension_offset += file_entries_size;
+ if (opt_format != opt_format_old)
+ {
+ if (opt_format != opt_format_new)
+ extension_offset += pad;
+ extension_offset += file_entries_new_size;
+ }
+ extension_offset += total_strlen;
+ extension_offset = roundup (extension_offset, 4); /* Provide alignment. */
+ if (opt_format != opt_format_old)
+ file_entries_new->extension_offset = extension_offset;
+
/* Write out the cache. */
/* Write cache first to a temporary file and rename it later. */
@@ -473,6 +554,14 @@ save_cache (const char *cache_name)
if (write (fd, strings, total_strlen) != (ssize_t) total_strlen)
error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
+ if (opt_format != opt_format_old)
+ {
+ /* Align file position to 4. */
+ off64_t old_offset = lseek64 (fd, extension_offset, SEEK_SET);
+ assert ((unsigned long long int) (extension_offset - old_offset) < 4);
+ write_extensions (fd, extension_offset);
+ }
+
/* Make sure user can always read cache file */
if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
error (EXIT_FAILURE, errno,
diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h
index 6ecfd6da0e59329c..259e843724531630 100644
--- a/sysdeps/generic/dl-cache.h
+++ b/sysdeps/generic/dl-cache.h
@@ -21,7 +21,9 @@
#include <endian.h>
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
+#include <string.h>
#ifndef _DL_CACHE_DEFAULT_ID
# define _DL_CACHE_DEFAULT_ID 3
@@ -142,7 +144,11 @@ struct cache_file_new
uint8_t padding_unsed[3]; /* Not used, for future extensions. */
- uint32_t unused[4]; /* Leave space for future extensions
+ /* File offset of the extension directory. See struct
+ cache_extension below. Must be a multiple of four. */
+ uint32_t extension_offset;
+
+ uint32_t unused[3]; /* Leave space for future extensions
and align to 8 byte boundary. */
struct file_entry_new libs[0]; /* Entries describing libraries. */
/* After this the string table of size len_strings is found. */
@@ -164,6 +170,121 @@ cache_file_new_matches_endian (const struct cache_file_new *cache)
}
+/* Randomly chosen magic value, which allows for additional
+ consistency verification. */
+enum { cache_extension_magic = (uint32_t) -358342284 };
+
+/* Tag values for different kinds of extension sections. Similar to
+ SHT_* constants. */
+enum cache_extension_tag
+ {
+ /* Array of bytes containing the glibc version that generated this
+ cache file. */
+ cache_extension_tag_generator,
+
+ /* Total number of known cache extension tags. */
+ cache_extension_count
+ };
+
+/* Element in the array following struct cache_extension. Similar to
+ an ELF section header. */
+struct cache_extension_section
+{
+ /* Type of the extension section. A enum cache_extension_tag value. */
+ uint32_t tag;
+
+ /* Extension-specific flags. Currently generated as zero. */
+ uint32_t flags;
+
+ /* Offset from the start of the file for the data in this extension
+ section. Specific extensions can have alignment constraints. */
+ uint32_t offset;
+
+ /* Length in bytes of the extension data. Specific extensions may
+ have size requirements. */
+ uint32_t size;
+};
+
+/* The extension directory in the cache. An array of struct
+ cache_extension_section entries. */
+struct cache_extension
+{
+ uint32_t magic; /* Always cache_extension_magic. */
+ uint32_t count; /* Number of following entries. */
+
+ /* count section descriptors of type struct cache_extension_section
+ follow. */
+ struct cache_extension_section sections[];
+};
+
+/* A relocated version of struct cache_extension_section. */
+struct cache_extension_loaded
+{
+ /* Address and size of this extension section. base is NULL if the
+ section is missing from the file. */
+ const void *base;
+ size_t size;
+
+ /* Flags from struct cache_extension_section. */
+ uint32_t flags;
+};
+
+/* All supported extension sections, relocated. Filled in by
+ cache_extension_load below. */
+struct cache_extension_all_loaded
+{
+ struct cache_extension_loaded sections[cache_extension_count];
+};
+
+static bool __attribute__ ((unused))
+cache_extension_load (const struct cache_file_new *cache,
+ const void *file_base, size_t file_size,
+ struct cache_extension_all_loaded *loaded)
+{
+ memset (loaded, 0, sizeof (*loaded));
+ if (cache->extension_offset == 0)
+ /* No extensions present. This is not a format error. */
+ return true;
+ if ((cache->extension_offset % 4) != 0)
+ /* Extension offset is misaligned. */
+ return false;
+ size_t size_tmp;
+ if (__builtin_add_overflow (cache->extension_offset,
+ sizeof (struct cache_extension), &size_tmp)
+ || size_tmp > file_size)
+ /* Extension extends beyond the end of the file. */
+ return false;
+ const struct cache_extension *ext = file_base + cache->extension_offset;
+ if (ext->magic != cache_extension_magic)
+ return false;
+ if (__builtin_mul_overflow (ext->count,
+ sizeof (struct cache_extension_section),
+ &size_tmp)
+ || __builtin_add_overflow (cache->extension_offset
+ + sizeof (struct cache_extension), size_tmp,
+ &size_tmp)
+ || size_tmp > file_size)
+ /* Extension array extends beyond the end of the file. */
+ return false;
+ for (uint32_t i = 0; i < ext->count; ++i)
+ {
+ if (__builtin_add_overflow (ext->sections[i].offset,
+ ext->sections[i].size, &size_tmp)
+ || size_tmp > file_size)
+ /* Extension data extends beyond the end of the file. */
+ return false;
+
+ uint32_t tag = ext->sections[i].tag;
+ if (tag >= cache_extension_count)
+ /* Tag is out of range and unrecognized. */
+ continue;
+ loaded->sections[tag].base = file_base + ext->sections[i].offset;
+ loaded->sections[tag].size = ext->sections[i].size;
+ loaded->sections[tag].flags = ext->sections[i].flags;
+ }
+ return true;
+}
+
/* Used to align cache_file_new. */
#define ALIGN_CACHE(addr) \
(((addr) + __alignof__ (struct cache_file_new) -1) \

View File

@ -0,0 +1,544 @@
commit 785969a047ad2f23f758901c6816422573544453
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 4 09:13:43 2020 +0100
elf: Implement a string table for ldconfig, with tail merging
This will be used in ldconfig to reduce the ld.so.cache size slightly.
Tail merging is an optimization where a pointer points into another
string if the first string is a suffix of the second string.
The hash function FNV-1a was chosen because it is simple and achieves
good dispersion even for short strings (so that the hash table bucket
count can be a power of two). It is clearly superior to the hsearch
hash and the ELF hash in this regard.
The hash table uses chaining for collision resolution.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/Makefile b/elf/Makefile
index f795617780b393ec..abb3e9d1179ef5cd 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -163,7 +163,7 @@ tests-container = \
tests := tst-tls9 tst-leaks1 \
tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
- tst-auxv
+ tst-auxv tst-stringtable
tests-internal := tst-tls1 tst-tls2 $(tests-static-internal)
tests-static := $(tests-static-normal) $(tests-static-internal)
diff --git a/elf/stringtable.c b/elf/stringtable.c
new file mode 100644
index 0000000000000000..099347d73ee70b8f
--- /dev/null
+++ b/elf/stringtable.c
@@ -0,0 +1,209 @@
+/* String tables for ld.so.cache construction. Implementation.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <error.h>
+#include <ldconfig.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringtable.h>
+
+static void
+stringtable_init (struct stringtable *table)
+{
+ table->count = 0;
+
+ /* This needs to be a power of two. 128 is sufficient to keep track
+ of 42 DSOs without resizing (assuming two strings per DSOs).
+ glibc itself comes with more than 20 DSOs, so 64 would likely to
+ be too small. */
+ table->allocated = 128;
+
+ table->entries = xcalloc (table->allocated, sizeof (table->entries[0]));
+}
+
+/* 32-bit FNV-1a hash function. */
+static uint32_t
+fnv1a (const char *string, size_t length)
+{
+ const unsigned char *p = (const unsigned char *) string;
+ uint32_t hash = 2166136261U;
+ for (size_t i = 0; i < length; ++i)
+ {
+ hash ^= p[i];
+ hash *= 16777619U;
+ }
+ return hash;
+}
+
+/* Double the capacity of the hash table. */
+static void
+stringtable_rehash (struct stringtable *table)
+{
+ /* This computation cannot overflow because the old total in-memory
+ size of the hash table is larger than the computed value. */
+ uint32_t new_allocated = table->allocated * 2;
+ struct stringtable_entry **new_entries
+ = xcalloc (new_allocated, sizeof (table->entries[0]));
+
+ uint32_t mask = new_allocated - 1;
+ for (uint32_t i = 0; i < table->allocated; ++i)
+ for (struct stringtable_entry *e = table->entries[i]; e != NULL; )
+ {
+ struct stringtable_entry *next = e->next;
+ uint32_t hash = fnv1a (e->string, e->length);
+ uint32_t new_index = hash & mask;
+ e->next = new_entries[new_index];
+ new_entries[new_index] = e;
+ e = next;
+ }
+
+ free (table->entries);
+ table->entries = new_entries;
+ table->allocated = new_allocated;
+}
+
+struct stringtable_entry *
+stringtable_add (struct stringtable *table, const char *string)
+{
+ /* Check for a zero-initialized table. */
+ if (table->allocated == 0)
+ stringtable_init (table);
+
+ size_t length = strlen (string);
+ if (length > (1U << 30))
+ error (EXIT_FAILURE, 0, _("String table string is too long"));
+ uint32_t hash = fnv1a (string, length);
+
+ /* Return a previously-existing entry. */
+ for (struct stringtable_entry *e
+ = table->entries[hash & (table->allocated - 1)];
+ e != NULL; e = e->next)
+ if (e->length == length && memcmp (e->string, string, length) == 0)
+ return e;
+
+ /* Increase the size of the table if necessary. Keep utilization
+ below two thirds. */
+ if (table->count >= (1U << 30))
+ error (EXIT_FAILURE, 0, _("String table has too many entries"));
+ if (table->count * 3 > table->allocated * 2)
+ stringtable_rehash (table);
+
+ /* Add the new table entry. */
+ ++table->count;
+ struct stringtable_entry *e
+ = xmalloc (offsetof (struct stringtable_entry, string) + length + 1);
+ uint32_t index = hash & (table->allocated - 1);
+ e->next = table->entries[index];
+ table->entries[index] = e;
+ e->length = length;
+ e->offset = 0;
+ memcpy (e->string, string, length + 1);
+ return e;
+}
+
+/* Sort reversed strings in reverse lexicographic order. This is used
+ for tail merging. */
+static int
+finalize_compare (const void *l, const void *r)
+{
+ struct stringtable_entry *left = *(struct stringtable_entry **) l;
+ struct stringtable_entry *right = *(struct stringtable_entry **) r;
+ size_t to_compare;
+ if (left->length < right->length)
+ to_compare = left->length;
+ else
+ to_compare = right->length;
+ for (size_t i = 1; i <= to_compare; ++i)
+ {
+ unsigned char lch = left->string[left->length - i];
+ unsigned char rch = right->string[right->length - i];
+ if (lch != rch)
+ return rch - lch;
+ }
+ if (left->length == right->length)
+ return 0;
+ else if (left->length < right->length)
+ /* Longer strings should come first. */
+ return 1;
+ else
+ return -1;
+}
+
+void
+stringtable_finalize (struct stringtable *table,
+ struct stringtable_finalized *result)
+{
+ if (table->count == 0)
+ {
+ result->strings = xstrdup ("");
+ result->size = 0;
+ return;
+ }
+
+ /* Optimize the order of the strings. */
+ struct stringtable_entry **array = xcalloc (table->count, sizeof (*array));
+ {
+ size_t j = 0;
+ for (uint32_t i = 0; i < table->allocated; ++i)
+ for (struct stringtable_entry *e = table->entries[i]; e != NULL;
+ e = e->next)
+ {
+ array[j] = e;
+ ++j;
+ }
+ assert (j == table->count);
+ }
+ qsort (array, table->count, sizeof (*array), finalize_compare);
+
+ /* Assign offsets, using tail merging (sharing suffixes) if possible. */
+ array[0]->offset = 0;
+ for (uint32_t j = 1; j < table->count; ++j)
+ {
+ struct stringtable_entry *previous = array[j - 1];
+ struct stringtable_entry *current = array[j];
+ if (previous->length >= current->length
+ && memcmp (&previous->string[previous->length - current->length],
+ current->string, current->length) == 0)
+ current->offset = (previous->offset + previous->length
+ - current->length);
+ else if (__builtin_add_overflow (previous->offset,
+ previous->length + 1,
+ &current->offset))
+ error (EXIT_FAILURE, 0, _("String table is too large"));
+ }
+
+ /* Allocate the result string. */
+ {
+ struct stringtable_entry *last = array[table->count - 1];
+ if (__builtin_add_overflow (last->offset, last->length + 1,
+ &result->size))
+ error (EXIT_FAILURE, 0, _("String table is too large"));
+ }
+ /* The strings are copied from the hash table, so the array is no
+ longer needed. */
+ free (array);
+ result->strings = xcalloc (result->size, 1);
+
+ /* Copy the strings. */
+ for (uint32_t i = 0; i < table->allocated; ++i)
+ for (struct stringtable_entry *e = table->entries[i]; e != NULL;
+ e = e->next)
+ if (result->strings[e->offset] == '\0')
+ memcpy (&result->strings[e->offset], e->string, e->length + 1);
+}
diff --git a/elf/stringtable.h b/elf/stringtable.h
new file mode 100644
index 0000000000000000..7d57d1bda9602947
--- /dev/null
+++ b/elf/stringtable.h
@@ -0,0 +1,64 @@
+/* String tables for ld.so.cache construction.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+#ifndef _STRINGTABLE_H
+#define _STRINGTABLE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* An entry in the string table. Only the length and string fields are
+ expected to be used outside the string table code. */
+struct stringtable_entry
+{
+ struct stringtable_entry *next; /* For collision resolution. */
+ uint32_t length; /* Length of then string. */
+ uint32_t offset; /* From start of finalized table. */
+ char string[]; /* Null-terminated string. */
+};
+
+/* A string table. Zero-initialization produces a valid atable. */
+struct stringtable
+{
+ struct stringtable_entry **entries; /* Array of hash table buckets. */
+ uint32_t count; /* Number of elements in the table. */
+ uint32_t allocated; /* Length of the entries array. */
+};
+
+/* Adds STRING to TABLE. May return the address of an existing entry. */
+struct stringtable_entry *stringtable_add (struct stringtable *table,
+ const char *string);
+
+/* Result of stringtable_finalize. SIZE bytes at STRINGS should be
+ written to the file. */
+struct stringtable_finalized
+{
+ char *strings;
+ size_t size;
+};
+
+/* Assigns offsets to string table entries and computes the serialized
+ form of the string table. */
+void stringtable_finalize (struct stringtable *table,
+ struct stringtable_finalized *result);
+
+/* Deallocate the string table (but not the TABLE pointer itself).
+ (The table can be re-used for adding more strings without
+ initialization.) */
+void stringtable_free (struct stringtable *table);
+
+#endif /* _STRINGTABLE_H */
diff --git a/elf/stringtable_free.c b/elf/stringtable_free.c
new file mode 100644
index 0000000000000000..8588a254705d4df8
--- /dev/null
+++ b/elf/stringtable_free.c
@@ -0,0 +1,33 @@
+/* String tables for ld.so.cache construction. Deallocation (for tests only).
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <stringtable.h>
+
+void
+stringtable_free (struct stringtable *table)
+{
+ for (uint32_t i = 0; i < table->allocated; ++i)
+ for (struct stringtable_entry *e = table->entries[i]; e != NULL; )
+ {
+ struct stringtable_entry *next = e->next;
+ free (e);
+ e = next;
+ }
+ free (table->entries);
+ *table = (struct stringtable) { 0, };
+}
diff --git a/elf/tst-stringtable.c b/elf/tst-stringtable.c
new file mode 100644
index 0000000000000000..3731086037567d57
--- /dev/null
+++ b/elf/tst-stringtable.c
@@ -0,0 +1,181 @@
+/* Unit test for ldconfig string tables.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringtable.h>
+#include <support/check.h>
+#include <support/support.h>
+
+static int
+do_test (void)
+{
+ /* Empty string table. */
+ {
+ struct stringtable s = { 0, };
+ struct stringtable_finalized f;
+ stringtable_finalize (&s, &f);
+ TEST_COMPARE_STRING (f.strings, "");
+ TEST_COMPARE (f.size, 0);
+ free (f.strings);
+ stringtable_free (&s);
+ }
+
+ /* String table with one empty string. */
+ {
+ struct stringtable s = { 0, };
+ struct stringtable_entry *e = stringtable_add (&s, "");
+ TEST_COMPARE_STRING (e->string, "");
+ TEST_COMPARE (e->length, 0);
+ TEST_COMPARE (s.count, 1);
+
+ struct stringtable_finalized f;
+ stringtable_finalize (&s, &f);
+ TEST_COMPARE (e->offset, 0);
+ TEST_COMPARE_STRING (f.strings, "");
+ TEST_COMPARE (f.size, 1);
+ free (f.strings);
+ stringtable_free (&s);
+ }
+
+ /* String table with one non-empty string. */
+ {
+ struct stringtable s = { 0, };
+ struct stringtable_entry *e = stringtable_add (&s, "name");
+ TEST_COMPARE_STRING (e->string, "name");
+ TEST_COMPARE (e->length, 4);
+ TEST_COMPARE (s.count, 1);
+
+ struct stringtable_finalized f;
+ stringtable_finalize (&s, &f);
+ TEST_COMPARE (e->offset, 0);
+ TEST_COMPARE_STRING (f.strings, "name");
+ TEST_COMPARE (f.size, 5);
+ free (f.strings);
+ stringtable_free (&s);
+ }
+
+ /* Two strings, one is a prefix of the other. Tail-merging can only
+ happen in one way in this case. */
+ {
+ struct stringtable s = { 0, };
+ struct stringtable_entry *suffix = stringtable_add (&s, "suffix");
+ TEST_COMPARE_STRING (suffix->string, "suffix");
+ TEST_COMPARE (suffix->length, 6);
+ TEST_COMPARE (s.count, 1);
+
+ struct stringtable_entry *prefix
+ = stringtable_add (&s, "prefix-suffix");
+ TEST_COMPARE_STRING (prefix->string, "prefix-suffix");
+ TEST_COMPARE (prefix->length, strlen ("prefix-suffix"));
+ TEST_COMPARE (s.count, 2);
+
+ struct stringtable_finalized f;
+ stringtable_finalize (&s, &f);
+ TEST_COMPARE (prefix->offset, 0);
+ TEST_COMPARE (suffix->offset, strlen ("prefix-"));
+ TEST_COMPARE_STRING (f.strings, "prefix-suffix");
+ TEST_COMPARE (f.size, sizeof ("prefix-suffix"));
+ free (f.strings);
+ stringtable_free (&s);
+ }
+
+ /* String table with various shared prefixes. Triggers hash
+ resizing. */
+ {
+ enum { count = 1500 };
+ char *strings[2 * count];
+ struct stringtable_entry *entries[2 * count];
+ struct stringtable s = { 0, };
+ for (int i = 0; i < count; ++i)
+ {
+ strings[i] = xasprintf ("%d", i);
+ entries[i] = stringtable_add (&s, strings[i]);
+ TEST_COMPARE (entries[i]->length, strlen (strings[i]));
+ TEST_COMPARE_STRING (entries[i]->string, strings[i]);
+ strings[i + count] = xasprintf ("prefix/%d", i);
+ entries[i + count] = stringtable_add (&s, strings[i + count]);
+ TEST_COMPARE (entries[i + count]->length, strlen (strings[i + count]));
+ TEST_COMPARE_STRING (entries[i + count]->string, strings[i + count]);
+ }
+
+ struct stringtable_finalized f;
+ stringtable_finalize (&s, &f);
+
+ for (int i = 0; i < 2 * count; ++i)
+ {
+ TEST_COMPARE (entries[i]->length, strlen (strings[i]));
+ TEST_COMPARE_STRING (entries[i]->string, strings[i]);
+ TEST_COMPARE_STRING (f.strings + entries[i]->offset, strings[i]);
+ free (strings[i]);
+ }
+
+ free (f.strings);
+ stringtable_free (&s);
+ }
+
+ /* Verify that maximum tail merging happens. */
+ {
+ struct stringtable s = { 0, };
+ const char *strings[] = {
+ "",
+ "a",
+ "b",
+ "aa",
+ "aaa",
+ "aa",
+ "bb",
+ "b",
+ "a",
+ "ba",
+ "baa",
+ };
+ struct stringtable_entry *entries[array_length (strings)];
+ for (int i = 0; i < array_length (strings); ++i)
+ entries[i] = stringtable_add (&s, strings[i]);
+ for (int i = 0; i < array_length (strings); ++i)
+ TEST_COMPARE_STRING (entries[i]->string, strings[i]);
+
+ struct stringtable_finalized f;
+ stringtable_finalize (&s, &f);
+
+ /* There are only four different strings, "aaa", "ba", "baa",
+ "bb". The rest is shared in an unspecified fashion. */
+ TEST_COMPARE (f.size, 4 + 3 + 4 + 3);
+
+ for (int i = 0; i < array_length (strings); ++i)
+ {
+ TEST_COMPARE_STRING (entries[i]->string, strings[i]);
+ TEST_COMPARE_STRING (f.strings + entries[i]->offset, strings[i]);
+ }
+
+ free (f.strings);
+ stringtable_free (&s);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
+
+/* Re-compile the string table implementation here. It is not
+ possible to link against the actual build because it was built for
+ use in ldconfig. */
+#define _(arg) arg
+#include "stringtable.c"
+#include "stringtable_free.c"

View File

@ -0,0 +1,209 @@
commit 73b6e50a22dea9ae6144beaaa675d2ac62c281ca
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 4 09:13:43 2020 +0100
elf: Implement tail merging of strings in ldconfig
This simplifies the string table construction in elf/cache.c
because there is no more need to keep track of offsets explicitly;
the string table implementation does this internally.
This change slightly reduces the size of the cache on disk. The
file format does not change as a result. The strings are
null-terminated, without explicit length, so tail merging is
transparent to readers.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/Makefile b/elf/Makefile
index abb3e9d1179ef5cd..a3e802a9a99b759c 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -112,7 +112,8 @@ others-static += ldconfig
others += ldconfig
install-rootsbin += ldconfig
-ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs
+ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs \
+ stringtable
extra-objs += $(ldconfig-modules:=.o)
others-extras = $(ldconfig-modules)
endif
diff --git a/elf/cache.c b/elf/cache.c
index 5a8f1ad70cc3fead..f773cacacf26db1c 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -35,11 +35,15 @@
#include <ldconfig.h>
#include <dl-cache.h>
#include <version.h>
+#include <stringtable.h>
+
+/* Used to store library names, paths, and other strings. */
+static struct stringtable strings;
struct cache_entry
{
- char *lib; /* Library name. */
- char *path; /* Path to find library. */
+ struct stringtable_entry *lib; /* Library name. */
+ struct stringtable_entry *path; /* Path to find library. */
int flags; /* Flags to indicate kind of library. */
unsigned int osversion; /* Required OS version. */
uint64_t hwcap; /* Important hardware capabilities. */
@@ -300,7 +304,7 @@ static int
compare (const struct cache_entry *e1, const struct cache_entry *e2)
{
/* We need to swap entries here to get the correct sort order. */
- int res = _dl_cache_libcmp (e2->lib, e1->lib);
+ int res = _dl_cache_libcmp (e2->lib->string, e1->lib->string);
if (res == 0)
{
if (e1->flags < e2->flags)
@@ -369,26 +373,24 @@ save_cache (const char *cache_name)
{
/* The cache entries are sorted already, save them in this order. */
- /* Count the length of all strings. */
- /* The old format doesn't contain hwcap entries and doesn't contain
- libraries in subdirectories with hwcaps entries. Count therefore
- also all entries with hwcap == 0. */
- size_t total_strlen = 0;
struct cache_entry *entry;
/* Number of cache entries. */
int cache_entry_count = 0;
- /* Number of normal cache entries. */
+ /* The old format doesn't contain hwcap entries and doesn't contain
+ libraries in subdirectories with hwcaps entries. Count therefore
+ also all entries with hwcap == 0. */
int cache_entry_old_count = 0;
for (entry = entries; entry != NULL; entry = entry->next)
{
- /* Account the final NULs. */
- total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
++cache_entry_count;
if (entry->hwcap == 0)
++cache_entry_old_count;
}
+ struct stringtable_finalized strings_finalized;
+ stringtable_finalize (&strings, &strings_finalized);
+
/* Create the on disk cache structure. */
struct cache_file *file_entries = NULL;
size_t file_entries_size = 0;
@@ -432,7 +434,7 @@ save_cache (const char *cache_name)
sizeof CACHE_VERSION - 1);
file_entries_new->nlibs = cache_entry_count;
- file_entries_new->len_strings = total_strlen;
+ file_entries_new->len_strings = strings_finalized.size;
file_entries_new->flags = cache_file_new_flags_endian_current;
}
@@ -449,20 +451,20 @@ save_cache (const char *cache_name)
str_offset = 0;
/* An array for all strings. */
- char *strings = xmalloc (total_strlen);
- char *str = strings;
int idx_old;
int idx_new;
for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
entry = entry->next, ++idx_new)
{
- /* First the library. */
if (opt_format != opt_format_new && entry->hwcap == 0)
{
file_entries->libs[idx_old].flags = entry->flags;
/* XXX: Actually we can optimize here and remove duplicates. */
file_entries->libs[idx_old].key = str_offset + pad;
+ file_entries->libs[idx_new].key = str_offset + entry->lib->offset;
+ file_entries->libs[idx_new].value
+ = str_offset + entry->path->offset;
}
if (opt_format != opt_format_old)
{
@@ -473,20 +475,12 @@ save_cache (const char *cache_name)
file_entries_new->libs[idx_new].flags = entry->flags;
file_entries_new->libs[idx_new].osversion = entry->osversion;
file_entries_new->libs[idx_new].hwcap = entry->hwcap;
- file_entries_new->libs[idx_new].key = str_offset;
+ file_entries_new->libs[idx_new].key
+ = str_offset + entry->lib->offset;
+ file_entries_new->libs[idx_new].value
+ = str_offset + entry->path->offset;
}
- size_t len = strlen (entry->lib) + 1;
- str = mempcpy (str, entry->lib, len);
- str_offset += len;
- /* Then the path. */
- if (opt_format != opt_format_new && entry->hwcap == 0)
- file_entries->libs[idx_old].value = str_offset + pad;
- if (opt_format != opt_format_old)
- file_entries_new->libs[idx_new].value = str_offset;
- len = strlen (entry->path) + 1;
- str = mempcpy (str, entry->path, len);
- str_offset += len;
/* Ignore entries with hwcap for old format. */
if (entry->hwcap == 0)
++idx_old;
@@ -511,7 +505,7 @@ save_cache (const char *cache_name)
extension_offset += pad;
extension_offset += file_entries_new_size;
}
- extension_offset += total_strlen;
+ extension_offset += strings_finalized.size;
extension_offset = roundup (extension_offset, 4); /* Provide alignment. */
if (opt_format != opt_format_old)
file_entries_new->extension_offset = extension_offset;
@@ -551,7 +545,8 @@ save_cache (const char *cache_name)
error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
}
- if (write (fd, strings, total_strlen) != (ssize_t) total_strlen)
+ if (write (fd, strings_finalized.strings, strings_finalized.size)
+ != (ssize_t) strings_finalized.size)
error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
if (opt_format != opt_format_old)
@@ -580,7 +575,7 @@ save_cache (const char *cache_name)
/* Free all allocated memory. */
free (file_entries_new);
free (file_entries);
- free (strings);
+ free (strings_finalized.strings);
while (entries)
{
@@ -596,14 +591,19 @@ void
add_to_cache (const char *path, const char *lib, int flags,
unsigned int osversion, uint64_t hwcap)
{
- size_t liblen = strlen (lib) + 1;
- size_t len = liblen + strlen (path) + 1;
- struct cache_entry *new_entry
- = xmalloc (sizeof (struct cache_entry) + liblen + len);
-
- new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
- new_entry->path = new_entry->lib + liblen;
- snprintf (new_entry->path, len, "%s/%s", path, lib);
+ struct cache_entry *new_entry = xmalloc (sizeof (*new_entry));
+
+ struct stringtable_entry *path_interned;
+ {
+ char *p;
+ if (asprintf (&p, "%s/%s", path, lib) < 0)
+ error (EXIT_FAILURE, errno, _("Could not create library path"));
+ path_interned = stringtable_add (&strings, p);
+ free (p);
+ }
+
+ new_entry->lib = stringtable_add (&strings, lib);
+ new_entry->path = path_interned;
new_entry->flags = flags;
new_entry->osversion = osversion;
new_entry->hwcap = hwcap;

View File

@ -0,0 +1,778 @@
commit b44ac4f4c7a8bbe5eaa2701aa9452eaf2c96e1dd
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 4 09:13:43 2020 +0100
elf: Process glibc-hwcaps subdirectories in ldconfig
Libraries from these subdirectories are added to the cache
with a special hwcap bit DL_CACHE_HWCAP_EXTENSION, so that
they are ignored by older dynamic loaders.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/cache.c b/elf/cache.c
index f773cacacf26db1c..dde3d7fefa4105f9 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -40,6 +40,105 @@
/* Used to store library names, paths, and other strings. */
static struct stringtable strings;
+/* Keeping track of "glibc-hwcaps" subdirectories. During cache
+ construction, a linear search by name is performed to deduplicate
+ entries. */
+struct glibc_hwcaps_subdirectory
+{
+ struct glibc_hwcaps_subdirectory *next;
+
+ /* Interned string with the subdirectory name. */
+ struct stringtable_entry *name;
+
+ /* Array index in the cache_extension_tag_glibc_hwcaps section in
+ the stored cached file. This is computed after all the
+ subdirectories have been processed, so that subdirectory names in
+ the extension section can be sorted. */
+ uint32_t section_index;
+
+ /* True if the subdirectory is actually used for anything. */
+ bool used;
+};
+
+const char *
+glibc_hwcaps_subdirectory_name (const struct glibc_hwcaps_subdirectory *dir)
+{
+ return dir->name->string;
+}
+
+/* Linked list of known hwcaps subdirecty names. */
+static struct glibc_hwcaps_subdirectory *hwcaps;
+
+struct glibc_hwcaps_subdirectory *
+new_glibc_hwcaps_subdirectory (const char *name)
+{
+ struct stringtable_entry *name_interned = stringtable_add (&strings, name);
+ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
+ if (p->name == name_interned)
+ return p;
+ struct glibc_hwcaps_subdirectory *p = xmalloc (sizeof (*p));
+ p->next = hwcaps;
+ p->name = name_interned;
+ p->section_index = 0;
+ p->used = false;
+ hwcaps = p;
+ return p;
+}
+
+/* Helper for sorting struct glibc_hwcaps_subdirectory elements by
+ name. */
+static int
+assign_glibc_hwcaps_indices_compare (const void *l, const void *r)
+{
+ const struct glibc_hwcaps_subdirectory *left
+ = *(struct glibc_hwcaps_subdirectory **)l;
+ const struct glibc_hwcaps_subdirectory *right
+ = *(struct glibc_hwcaps_subdirectory **)r;
+ return strcmp (glibc_hwcaps_subdirectory_name (left),
+ glibc_hwcaps_subdirectory_name (right));
+}
+
+/* Count the number of hwcaps subdirectories which are actually
+ used. */
+static size_t
+glibc_hwcaps_count (void)
+{
+ size_t count = 0;
+ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
+ if (p->used)
+ ++count;
+ return count;
+}
+
+/* Compute the section_index fields for all */
+static void
+assign_glibc_hwcaps_indices (void)
+{
+ /* Convert the linked list into an array, so that we can use qsort.
+ Only copy the subdirectories which are actually used. */
+ size_t count = glibc_hwcaps_count ();
+ struct glibc_hwcaps_subdirectory **array
+ = xmalloc (sizeof (*array) * count);
+ {
+ size_t i = 0;
+ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
+ if (p->used)
+ {
+ array[i] = p;
+ ++i;
+ }
+ assert (i == count);
+ }
+
+ qsort (array, count, sizeof (*array), assign_glibc_hwcaps_indices_compare);
+
+ /* Assign the array indices. */
+ for (size_t i = 0; i < count; ++i)
+ array[i]->section_index = i;
+
+ free (array);
+}
+
struct cache_entry
{
struct stringtable_entry *lib; /* Library name. */
@@ -48,6 +147,10 @@ struct cache_entry
unsigned int osversion; /* Required OS version. */
uint64_t hwcap; /* Important hardware capabilities. */
int bits_hwcap; /* Number of bits set in hwcap. */
+
+ /* glibc-hwcaps subdirectory. If not NULL, hwcap must be zero. */
+ struct glibc_hwcaps_subdirectory *hwcaps;
+
struct cache_entry *next; /* Next entry in list. */
};
@@ -60,7 +163,7 @@ static const char *flag_descr[] =
/* Print a single entry. */
static void
print_entry (const char *lib, int flag, unsigned int osversion,
- uint64_t hwcap, const char *key)
+ uint64_t hwcap, const char *hwcap_string, const char *key)
{
printf ("\t%s (", lib);
switch (flag & FLAG_TYPE_MASK)
@@ -132,7 +235,9 @@ print_entry (const char *lib, int flag, unsigned int osversion,
printf (",%d", flag & FLAG_REQUIRED_MASK);
break;
}
- if (hwcap != 0)
+ if (hwcap_string != NULL)
+ printf (", hwcap: \"%s\"", hwcap_string);
+ else if (hwcap != 0)
printf (", hwcap: %#.16" PRIx64, hwcap);
if (osversion != 0)
{
@@ -158,6 +263,29 @@ print_entry (const char *lib, int flag, unsigned int osversion,
printf (") => %s\n", key);
}
+/* Returns the string with the name of the glibcs-hwcaps subdirectory
+ associated with ENTRY->hwcap. file_base must be the base address
+ for string table indices. */
+static const char *
+glibc_hwcaps_string (struct cache_extension_all_loaded *ext,
+ const void *file_base, size_t file_size,
+ struct file_entry_new *entry)
+{
+ const uint32_t *hwcaps_array
+ = ext->sections[cache_extension_tag_glibc_hwcaps].base;
+ if (dl_cache_hwcap_extension (entry) && hwcaps_array != NULL)
+ {
+ uint32_t index = (uint32_t) entry->hwcap;
+ if (index < ext->sections[cache_extension_tag_glibc_hwcaps].size / 4)
+ {
+ uint32_t string_table_index = hwcaps_array[index];
+ if (string_table_index < file_size)
+ return file_base + string_table_index;
+ }
+ }
+ return NULL;
+}
+
/* Print an error and exit if the new-file cache is internally
inconsistent. */
static void
@@ -167,9 +295,7 @@ check_new_cache (struct cache_file_new *cache)
error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n"));
}
-/* Print the extension information at the cache at start address
- FILE_BASE, of length FILE_SIZE bytes. The new-format cache header
- is at CACHE, and the file name for diagnostics is CACHE_NAME. */
+/* Print the extension information in *EXT. */
static void
print_extensions (struct cache_extension_all_loaded *ext)
{
@@ -266,7 +392,7 @@ print_cache (const char *cache_name)
/* Print everything. */
for (unsigned int i = 0; i < cache->nlibs; i++)
print_entry (cache_data + cache->libs[i].key,
- cache->libs[i].flags, 0, 0,
+ cache->libs[i].flags, 0, 0, NULL,
cache_data + cache->libs[i].value);
}
else if (format == 1)
@@ -281,11 +407,16 @@ print_cache (const char *cache_name)
/* Print everything. */
for (unsigned int i = 0; i < cache_new->nlibs; i++)
- print_entry (cache_data + cache_new->libs[i].key,
- cache_new->libs[i].flags,
- cache_new->libs[i].osversion,
- cache_new->libs[i].hwcap,
- cache_data + cache_new->libs[i].value);
+ {
+ const char *hwcaps_string
+ = glibc_hwcaps_string (&ext, cache, cache_size,
+ &cache_new->libs[i]);
+ print_entry (cache_data + cache_new->libs[i].key,
+ cache_new->libs[i].flags,
+ cache_new->libs[i].osversion,
+ cache_new->libs[i].hwcap, hwcaps_string,
+ cache_data + cache_new->libs[i].value);
+ }
print_extensions (&ext);
}
/* Cleanup. */
@@ -311,8 +442,23 @@ compare (const struct cache_entry *e1, const struct cache_entry *e2)
return 1;
else if (e1->flags > e2->flags)
return -1;
+ /* Keep the glibc-hwcaps extension entries before the regular
+ entries, and sort them by their names. search_cache in
+ dl-cache.c stops searching once the first non-extension entry
+ is found, so the extension entries need to come first. */
+ else if (e1->hwcaps != NULL && e2->hwcaps == NULL)
+ return -1;
+ else if (e1->hwcaps == NULL && e2->hwcaps != NULL)
+ return 1;
+ else if (e1->hwcaps != NULL && e2->hwcaps != NULL)
+ {
+ res = strcmp (glibc_hwcaps_subdirectory_name (e1->hwcaps),
+ glibc_hwcaps_subdirectory_name (e2->hwcaps));
+ if (res != 0)
+ return res;
+ }
/* Sort by most specific hwcap. */
- else if (e2->bits_hwcap > e1->bits_hwcap)
+ if (e2->bits_hwcap > e1->bits_hwcap)
return 1;
else if (e2->bits_hwcap < e1->bits_hwcap)
return -1;
@@ -337,30 +483,65 @@ enum
* sizeof (struct cache_extension_section)))
};
-/* Write the cache extensions to FD. The extension directory is
- assumed to be located at CACHE_EXTENSION_OFFSET. */
+/* Write the cache extensions to FD. The string table is shifted by
+ STRING_TABLE_OFFSET. The extension directory is assumed to be
+ located at CACHE_EXTENSION_OFFSET. assign_glibc_hwcaps_indices
+ must have been called. */
static void
-write_extensions (int fd, uint32_t cache_extension_offset)
+write_extensions (int fd, uint32_t str_offset,
+ uint32_t cache_extension_offset)
{
assert ((cache_extension_offset % 4) == 0);
+ /* The length and contents of the glibc-hwcaps section. */
+ uint32_t hwcaps_count = glibc_hwcaps_count ();
+ uint32_t hwcaps_offset = cache_extension_offset + cache_extension_size;
+ uint32_t hwcaps_size = hwcaps_count * sizeof (uint32_t);
+ uint32_t *hwcaps_array = xmalloc (hwcaps_size);
+ for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
+ if (p->used)
+ hwcaps_array[p->section_index] = str_offset + p->name->offset;
+
+ /* This is the offset of the generator string. */
+ uint32_t generator_offset = hwcaps_offset;
+ if (hwcaps_count == 0)
+ /* There is no section for the hwcaps subdirectories. */
+ generator_offset -= sizeof (struct cache_extension_section);
+ else
+ /* The string table indices for the hwcaps subdirectories shift
+ the generator string backwards. */
+ generator_offset += hwcaps_size;
+
struct cache_extension *ext = xmalloc (cache_extension_size);
ext->magic = cache_extension_magic;
- ext->count = cache_extension_count;
- for (int i = 0; i < cache_extension_count; ++i)
- {
- ext->sections[i].tag = i;
- ext->sections[i].flags = 0;
- }
+ /* Extension index current being filled. */
+ size_t xid = 0;
const char *generator
= "ldconfig " PKGVERSION RELEASE " release version " VERSION;
- ext->sections[cache_extension_tag_generator].offset
- = cache_extension_offset + cache_extension_size;
- ext->sections[cache_extension_tag_generator].size = strlen (generator);
+ ext->sections[xid].tag = cache_extension_tag_generator;
+ ext->sections[xid].flags = 0;
+ ext->sections[xid].offset = generator_offset;
+ ext->sections[xid].size = strlen (generator);
+
+ if (hwcaps_count > 0)
+ {
+ ++xid;
+ ext->sections[xid].tag = cache_extension_tag_glibc_hwcaps;
+ ext->sections[xid].flags = 0;
+ ext->sections[xid].offset = hwcaps_offset;
+ ext->sections[xid].size = hwcaps_size;
+ }
+
+ ++xid;
+ ext->count = xid;
+ assert (xid <= cache_extension_count);
- if (write (fd, ext, cache_extension_size) != cache_extension_size
+ size_t ext_size = (offsetof (struct cache_extension, sections)
+ + xid * sizeof (struct cache_extension_section));
+ if (write (fd, ext, ext_size) != ext_size
+ || write (fd, hwcaps_array, hwcaps_size) != hwcaps_size
|| write (fd, generator, strlen (generator)) != strlen (generator))
error (EXIT_FAILURE, errno, _("Writing of cache extension data failed"));
@@ -373,6 +554,8 @@ save_cache (const char *cache_name)
{
/* The cache entries are sorted already, save them in this order. */
+ assign_glibc_hwcaps_indices ();
+
struct cache_entry *entry;
/* Number of cache entries. */
int cache_entry_count = 0;
@@ -474,7 +657,11 @@ save_cache (const char *cache_name)
struct. */
file_entries_new->libs[idx_new].flags = entry->flags;
file_entries_new->libs[idx_new].osversion = entry->osversion;
- file_entries_new->libs[idx_new].hwcap = entry->hwcap;
+ if (entry->hwcaps == NULL)
+ file_entries_new->libs[idx_new].hwcap = entry->hwcap;
+ else
+ file_entries_new->libs[idx_new].hwcap
+ = DL_CACHE_HWCAP_EXTENSION | entry->hwcaps->section_index;
file_entries_new->libs[idx_new].key
= str_offset + entry->lib->offset;
file_entries_new->libs[idx_new].value
@@ -554,7 +741,7 @@ save_cache (const char *cache_name)
/* Align file position to 4. */
off64_t old_offset = lseek64 (fd, extension_offset, SEEK_SET);
assert ((unsigned long long int) (extension_offset - old_offset) < 4);
- write_extensions (fd, extension_offset);
+ write_extensions (fd, str_offset, extension_offset);
}
/* Make sure user can always read cache file */
@@ -588,27 +775,35 @@ save_cache (const char *cache_name)
/* Add one library to the cache. */
void
-add_to_cache (const char *path, const char *lib, int flags,
- unsigned int osversion, uint64_t hwcap)
+add_to_cache (const char *path, const char *filename, const char *soname,
+ int flags, unsigned int osversion, uint64_t hwcap,
+ struct glibc_hwcaps_subdirectory *hwcaps)
{
struct cache_entry *new_entry = xmalloc (sizeof (*new_entry));
struct stringtable_entry *path_interned;
{
char *p;
- if (asprintf (&p, "%s/%s", path, lib) < 0)
+ if (asprintf (&p, "%s/%s", path, filename) < 0)
error (EXIT_FAILURE, errno, _("Could not create library path"));
path_interned = stringtable_add (&strings, p);
free (p);
}
- new_entry->lib = stringtable_add (&strings, lib);
+ new_entry->lib = stringtable_add (&strings, soname);
new_entry->path = path_interned;
new_entry->flags = flags;
new_entry->osversion = osversion;
new_entry->hwcap = hwcap;
+ new_entry->hwcaps = hwcaps;
new_entry->bits_hwcap = 0;
+ if (hwcaps != NULL)
+ {
+ assert (hwcap == 0);
+ hwcaps->used = true;
+ }
+
/* Count the number of bits set in the masked value. */
for (size_t i = 0;
(~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 0fa5aef83f9cd86c..8c66d7e5426d8cc4 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -16,6 +16,7 @@
along with this program; if not, see <http://www.gnu.org/licenses/>. */
#define PROCINFO_CLASS static
+#include <assert.h>
#include <alloca.h>
#include <argp.h>
#include <dirent.h>
@@ -41,6 +42,7 @@
#include <ldconfig.h>
#include <dl-cache.h>
+#include <dl-hwcaps.h>
#include <dl-procinfo.h>
@@ -85,6 +87,10 @@ struct dir_entry
dev_t dev;
const char *from_file;
int from_line;
+
+ /* Non-NULL for subdirectories under a glibc-hwcaps subdirectory. */
+ struct glibc_hwcaps_subdirectory *hwcaps;
+
struct dir_entry *next;
};
@@ -338,17 +344,20 @@ new_sub_entry (const struct dir_entry *entry, const char *path,
new_entry->from_line = entry->from_line;
new_entry->path = xstrdup (path);
new_entry->flag = entry->flag;
+ new_entry->hwcaps = NULL;
new_entry->next = NULL;
new_entry->ino = st->st_ino;
new_entry->dev = st->st_dev;
return new_entry;
}
-/* Add a single directory entry. */
-static void
+/* Add a single directory entry. Return true if the directory is
+ actually added (because it is not a duplicate). */
+static bool
add_single_dir (struct dir_entry *entry, int verbose)
{
struct dir_entry *ptr, *prev;
+ bool added = true;
ptr = dir_entries;
prev = ptr;
@@ -368,6 +377,7 @@ add_single_dir (struct dir_entry *entry, int verbose)
ptr->flag = entry->flag;
free (entry->path);
free (entry);
+ added = false;
break;
}
prev = ptr;
@@ -378,6 +388,73 @@ add_single_dir (struct dir_entry *entry, int verbose)
dir_entries = entry;
else if (ptr == NULL)
prev->next = entry;
+ return added;
+}
+
+/* Check if PATH contains a "glibc-hwcaps" subdirectory. If so, queue
+ its subdirectories for glibc-hwcaps processing. */
+static void
+add_glibc_hwcaps_subdirectories (struct dir_entry *entry, const char *path)
+{
+ /* glibc-hwcaps subdirectories do not nest. */
+ assert (entry->hwcaps == NULL);
+
+ char *glibc_hwcaps;
+ if (asprintf (&glibc_hwcaps, "%s/" GLIBC_HWCAPS_SUBDIRECTORY, path) < 0)
+ error (EXIT_FAILURE, errno, _("Could not form glibc-hwcaps path"));
+
+ DIR *dir = opendir (glibc_hwcaps);
+ if (dir != NULL)
+ {
+ while (true)
+ {
+ errno = 0;
+ struct dirent64 *e = readdir64 (dir);
+ if (e == NULL)
+ {
+ if (errno == 0)
+ break;
+ else
+ error (EXIT_FAILURE, errno, _("Listing directory %s"), path);
+ }
+
+ /* Ignore hidden subdirectories, including "." and "..", and
+ regular files. File names containing a ':' cannot be
+ looked up by the dynamic loader, so skip those as
+ well. */
+ if (e->d_name[0] == '.' || e->d_type == DT_REG
+ || strchr (e->d_name, ':') != NULL)
+ continue;
+
+ /* See if this entry eventually resolves to a directory. */
+ struct stat64 st;
+ if (fstatat64 (dirfd (dir), e->d_name, &st, 0) < 0)
+ /* Ignore unreadable entries. */
+ continue;
+
+ if (S_ISDIR (st.st_mode))
+ {
+ /* This is a directory, so it needs to be scanned for
+ libraries, associated with the hwcaps implied by the
+ subdirectory name. */
+ char *new_path;
+ if (asprintf (&new_path, "%s/" GLIBC_HWCAPS_SUBDIRECTORY "/%s",
+ /* Use non-canonicalized path here. */
+ entry->path, e->d_name) < 0)
+ error (EXIT_FAILURE, errno,
+ _("Could not form glibc-hwcaps path"));
+ struct dir_entry *new_entry = new_sub_entry (entry, new_path,
+ &st);
+ free (new_path);
+ new_entry->hwcaps = new_glibc_hwcaps_subdirectory (e->d_name);
+ add_single_dir (new_entry, 0);
+ }
+ }
+
+ closedir (dir);
+ }
+
+ free (glibc_hwcaps);
}
/* Add one directory to the list of directories to process. */
@@ -386,6 +463,7 @@ add_dir_1 (const char *line, const char *from_file, int from_line)
{
unsigned int i;
struct dir_entry *entry = xmalloc (sizeof (struct dir_entry));
+ entry->hwcaps = NULL;
entry->next = NULL;
entry->from_file = strdup (from_file);
@@ -443,7 +521,9 @@ add_dir_1 (const char *line, const char *from_file, int from_line)
entry->ino = stat_buf.st_ino;
entry->dev = stat_buf.st_dev;
- add_single_dir (entry, 1);
+ if (add_single_dir (entry, 1))
+ /* Add glibc-hwcaps subdirectories if present. */
+ add_glibc_hwcaps_subdirectories (entry, path);
}
if (opt_chroot)
@@ -695,15 +775,27 @@ struct dlib_entry
static void
search_dir (const struct dir_entry *entry)
{
- uint64_t hwcap = path_hwcap (entry->path);
- if (opt_verbose)
+ uint64_t hwcap;
+ if (entry->hwcaps == NULL)
{
- if (hwcap != 0)
- printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap);
- else
- printf ("%s:", entry->path);
- printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line);
+ hwcap = path_hwcap (entry->path);
+ if (opt_verbose)
+ {
+ if (hwcap != 0)
+ printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap);
+ else
+ printf ("%s:", entry->path);
+ }
}
+ else
+ {
+ hwcap = 0;
+ if (opt_verbose)
+ printf ("%s: (hwcap: \"%s\")", entry->path,
+ glibc_hwcaps_subdirectory_name (entry->hwcaps));
+ }
+ if (opt_verbose)
+ printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line);
char *dir_name;
char *real_file_name;
@@ -745,13 +837,15 @@ search_dir (const struct dir_entry *entry)
&& direntry->d_type != DT_DIR)
continue;
/* Does this file look like a shared library or is it a hwcap
- subdirectory? The dynamic linker is also considered as
+ subdirectory (if not already processing a glibc-hwcaps
+ subdirectory)? The dynamic linker is also considered as
shared library. */
if (((strncmp (direntry->d_name, "lib", 3) != 0
&& strncmp (direntry->d_name, "ld-", 3) != 0)
|| strstr (direntry->d_name, ".so") == NULL)
&& (direntry->d_type == DT_REG
- || !is_hwcap_platform (direntry->d_name)))
+ || (entry->hwcaps == NULL
+ && !is_hwcap_platform (direntry->d_name))))
continue;
size_t len = strlen (direntry->d_name);
@@ -799,7 +893,7 @@ search_dir (const struct dir_entry *entry)
}
struct stat64 stat_buf;
- int is_dir;
+ bool is_dir;
int is_link = S_ISLNK (lstat_buf.st_mode);
if (is_link)
{
@@ -837,7 +931,10 @@ search_dir (const struct dir_entry *entry)
else
is_dir = S_ISDIR (lstat_buf.st_mode);
- if (is_dir && is_hwcap_platform (direntry->d_name))
+ /* No descending into subdirectories if this directory is a
+ glibc-hwcaps subdirectory (which are not recursive). */
+ if (entry->hwcaps == NULL
+ && is_dir && is_hwcap_platform (direntry->d_name))
{
if (!is_link
&& direntry->d_type != DT_UNKNOWN
@@ -1028,13 +1125,31 @@ search_dir (const struct dir_entry *entry)
struct dlib_entry *dlib_ptr;
for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
{
- /* Don't create links to links. */
- if (dlib_ptr->is_link == 0)
- create_links (dir_name, entry->path, dlib_ptr->name,
- dlib_ptr->soname);
+ /* The cached file name is the soname for non-glibc-hwcaps
+ subdirectories (relying on symbolic links; this helps with
+ library updates that change the file name), and the actual
+ file for glibc-hwcaps subdirectories. */
+ const char *filename;
+ if (entry->hwcaps == NULL)
+ {
+ /* Don't create links to links. */
+ if (dlib_ptr->is_link == 0)
+ create_links (dir_name, entry->path, dlib_ptr->name,
+ dlib_ptr->soname);
+ filename = dlib_ptr->soname;
+ }
+ else
+ {
+ /* Do not create links in glibc-hwcaps subdirectories, but
+ still log the cache addition. */
+ if (opt_verbose)
+ printf ("\t%s -> %s\n", dlib_ptr->soname, dlib_ptr->name);
+ filename = dlib_ptr->name;
+ }
if (opt_build_cache)
- add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag,
- dlib_ptr->osversion, hwcap);
+ add_to_cache (entry->path, filename, dlib_ptr->soname,
+ dlib_ptr->flag, dlib_ptr->osversion,
+ hwcap, entry->hwcaps);
}
/* Free all resources. */
diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h
index 259e843724531630..6adbe3c79a32a4ec 100644
--- a/sysdeps/generic/dl-cache.h
+++ b/sysdeps/generic/dl-cache.h
@@ -99,6 +99,23 @@ struct file_entry_new
uint64_t hwcap; /* Hwcap entry. */
};
+/* This bit in the hwcap field of struct file_entry_new indicates that
+ the lower 32 bits contain an index into the
+ cache_extension_tag_glibc_hwcaps section. Older glibc versions do
+ not know about this HWCAP bit, so they will ignore these
+ entries. */
+#define DL_CACHE_HWCAP_EXTENSION (1ULL << 62)
+
+/* Return true if the ENTRY->hwcap value indicates that
+ DL_CACHE_HWCAP_EXTENSION is used. */
+static inline bool
+dl_cache_hwcap_extension (struct file_entry_new *entry)
+{
+ /* If DL_CACHE_HWCAP_EXTENSION is set, but other bits as well, this
+ is a different kind of extension. */
+ return (entry->hwcap >> 32) == (DL_CACHE_HWCAP_EXTENSION >> 32);
+}
+
/* See flags member of struct cache_file_new below. */
enum
{
@@ -182,6 +199,17 @@ enum cache_extension_tag
cache file. */
cache_extension_tag_generator,
+ /* glibc-hwcaps subdirectory information. An array of uint32_t
+ values, which are indices into the string table. The strings
+ are sorted lexicographically (according to strcmp). The extra
+ level of indirection (instead of using string table indices
+ directly) allows the dynamic loader to compute the preference
+ order of the hwcaps names more efficiently.
+
+ For this section, 4-byte alignment is required, and the section
+ size must be a multiple of 4. */
+ cache_extension_tag_glibc_hwcaps,
+
/* Total number of known cache extension tags. */
cache_extension_count
};
@@ -236,6 +264,27 @@ struct cache_extension_all_loaded
struct cache_extension_loaded sections[cache_extension_count];
};
+/* Performs basic data validation based on section tag, and removes
+ the sections which are invalid. */
+static void
+cache_extension_verify (struct cache_extension_all_loaded *loaded)
+{
+ {
+ /* Section must not be empty, it must be aligned at 4 bytes, and
+ the size must be a multiple of 4. */
+ struct cache_extension_loaded *hwcaps
+ = &loaded->sections[cache_extension_tag_glibc_hwcaps];
+ if (hwcaps->size == 0
+ || ((uintptr_t) hwcaps->base % 4) != 0
+ || (hwcaps->size % 4) != 0)
+ {
+ hwcaps->base = NULL;
+ hwcaps->size = 0;
+ hwcaps->flags = 0;
+ }
+ }
+}
+
static bool __attribute__ ((unused))
cache_extension_load (const struct cache_file_new *cache,
const void *file_base, size_t file_size,
@@ -282,6 +331,7 @@ cache_extension_load (const struct cache_file_new *cache,
loaded->sections[tag].size = ext->sections[i].size;
loaded->sections[tag].flags = ext->sections[i].flags;
}
+ cache_extension_verify (loaded);
return true;
}
diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h
index b15b142511829436..a8d22f143f867a3e 100644
--- a/sysdeps/generic/ldconfig.h
+++ b/sysdeps/generic/ldconfig.h
@@ -57,8 +57,22 @@ extern void init_cache (void);
extern void save_cache (const char *cache_name);
-extern void add_to_cache (const char *path, const char *lib, int flags,
- unsigned int osversion, uint64_t hwcap);
+struct glibc_hwcaps_subdirectory;
+
+/* Return a struct describing the subdirectory for NAME. Reuse an
+ existing struct if it exists. */
+struct glibc_hwcaps_subdirectory *new_glibc_hwcaps_subdirectory
+ (const char *name);
+
+/* Returns the name that was specified when
+ add_glibc_hwcaps_subdirectory was called. */
+const char *glibc_hwcaps_subdirectory_name
+ (const struct glibc_hwcaps_subdirectory *);
+
+extern void add_to_cache (const char *path, const char *filename,
+ const char *soname,
+ int flags, unsigned int osversion, uint64_t hwcap,
+ struct glibc_hwcaps_subdirectory *);
extern void init_aux_cache (void);

View File

@ -0,0 +1,659 @@
commit 600d9e0c87940da9b0fdeff492bf888df852d40c
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 4 09:13:43 2020 +0100
elf: Add glibc-hwcaps subdirectory support to ld.so cache processing
This recognizes the DL_CACHE_HWCAP_EXTENSION flag in cache entries,
and picks the supported cache entry with the highest priority.
The elf/tst-glibc-hwcaps-prepend-cache test documents a non-desired
aspect of the current cache implementation: If the cache selects a DSO
that does not exist on disk, _dl_map_object falls back to open_path,
which may or may not find an alternative implementation. This is an
existing limitation that also applies to the legacy hwcaps processing
for ld.so.cache.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/Makefile b/elf/Makefile
index a3e802a9a99b759c..f67b231c0f8e3aff 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -162,6 +162,12 @@ tst-tls1-static-non-pie-no-pie = yes
tests-container = \
tst-ldconfig-bad-aux-cache
+ifeq (no,$(build-hardcoded-path-in-tests))
+# This is an ld.so.cache test, and RPATH/RUNPATH in the executable
+# interferes with its test objectives.
+tests-container += tst-glibc-hwcaps-prepend-cache
+endif
+
tests := tst-tls9 tst-leaks1 \
tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
tst-auxv tst-stringtable
@@ -1784,6 +1790,14 @@ $(objpfx)tst-glibc-hwcaps-prepend.out: \
$< > $@; \
$(evaluate-test)
+# Like tst-glibc-hwcaps-prepend, but uses a container and loads the
+# library via ld.so.cache. Test setup is contained in the test
+# itself.
+$(objpfx)tst-glibc-hwcaps-prepend-cache: $(libdl)
+$(objpfx)tst-glibc-hwcaps-prepend-cache.out: \
+ $(objpfx)tst-glibc-hwcaps-prepend-cache $(objpfx)libmarkermod1-1.so \
+ $(objpfx)libmarkermod1-2.so $(objpfx)libmarkermod1-3.so
+
# tst-glibc-hwcaps-mask checks that --glibc-hwcaps-mask can be used to
# suppress all auto-detected subdirectories.
$(objpfx)tst-glibc-hwcaps-mask: $(objpfx)libmarkermod1-1.so
@@ -1795,3 +1809,7 @@ $(objpfx)tst-glibc-hwcaps-mask.out: \
--glibc-hwcaps-mask does-not-exist \
$< > $@; \
$(evaluate-test)
+
+# Generic dependency for sysdeps implementation of
+# tst-glibc-hwcaps-cache.
+$(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps
diff --git a/elf/dl-cache.c b/elf/dl-cache.c
index de063faa8b2c88ae..e75afdaee23226e6 100644
--- a/elf/dl-cache.c
+++ b/elf/dl-cache.c
@@ -35,6 +35,144 @@ static struct cache_file *cache;
static struct cache_file_new *cache_new;
static size_t cachesize;
+#ifdef SHARED
+/* This is used to cache the priorities of glibc-hwcaps
+ subdirectories. The elements of _dl_cache_priorities correspond to
+ the strings in the cache_extension_tag_glibc_hwcaps section. */
+static uint32_t *glibc_hwcaps_priorities;
+static uint32_t glibc_hwcaps_priorities_length;
+static uint32_t glibc_hwcaps_priorities_allocated;
+
+/* True if the full malloc was used to allocated the array. */
+static bool glibc_hwcaps_priorities_malloced;
+
+/* Deallocate the glibc_hwcaps_priorities array. */
+static void
+glibc_hwcaps_priorities_free (void)
+{
+ /* When the minimal malloc is in use, free does not do anything,
+ so it does not make sense to call it. */
+ if (glibc_hwcaps_priorities_malloced)
+ free (glibc_hwcaps_priorities);
+ glibc_hwcaps_priorities = NULL;
+ glibc_hwcaps_priorities_allocated = 0;
+}
+
+/* Ordered comparison of a hwcaps string from the cache on the left
+ (identified by its string table index) and a _dl_hwcaps_priorities
+ element on the right. */
+static int
+glibc_hwcaps_compare (uint32_t left_index, struct dl_hwcaps_priority *right)
+{
+ const char *left_name = (const char *) cache + left_index;
+ uint32_t left_name_length = strlen (left_name);
+ uint32_t to_compare;
+ if (left_name_length < right->name_length)
+ to_compare = left_name_length;
+ else
+ to_compare = right->name_length;
+ int cmp = memcmp (left_name, right->name, to_compare);
+ if (cmp != 0)
+ return cmp;
+ if (left_name_length < right->name_length)
+ return -1;
+ else if (left_name_length > right->name_length)
+ return 1;
+ else
+ return 0;
+}
+
+/* Initialize the glibc_hwcaps_priorities array and its length,
+ glibc_hwcaps_priorities_length. */
+static void
+glibc_hwcaps_priorities_init (void)
+{
+ struct cache_extension_all_loaded ext;
+ if (!cache_extension_load (cache_new, cache, cachesize, &ext))
+ return;
+
+ uint32_t length = (ext.sections[cache_extension_tag_glibc_hwcaps].size
+ / sizeof (uint32_t));
+ if (length > glibc_hwcaps_priorities_allocated)
+ {
+ glibc_hwcaps_priorities_free ();
+
+ uint32_t *new_allocation = malloc (length * sizeof (uint32_t));
+ if (new_allocation == NULL)
+ /* This effectively disables hwcaps on memory allocation
+ errors. */
+ return;
+
+ glibc_hwcaps_priorities = new_allocation;
+ glibc_hwcaps_priorities_allocated = length;
+ glibc_hwcaps_priorities_malloced = __rtld_malloc_is_complete ();
+ }
+
+ /* Compute the priorities for the subdirectories by merging the
+ array in the cache with the dl_hwcaps_priorities array. */
+ const uint32_t *left = ext.sections[cache_extension_tag_glibc_hwcaps].base;
+ const uint32_t *left_end = left + length;
+ struct dl_hwcaps_priority *right = _dl_hwcaps_priorities;
+ struct dl_hwcaps_priority *right_end = right + _dl_hwcaps_priorities_length;
+ uint32_t *result = glibc_hwcaps_priorities;
+
+ while (left < left_end && right < right_end)
+ {
+ if (*left < cachesize)
+ {
+ int cmp = glibc_hwcaps_compare (*left, right);
+ if (cmp == 0)
+ {
+ *result = right->priority;
+ ++result;
+ ++left;
+ ++right;
+ }
+ else if (cmp < 0)
+ {
+ *result = 0;
+ ++result;
+ ++left;
+ }
+ else
+ ++right;
+ }
+ else
+ {
+ *result = 0;
+ ++result;
+ }
+ }
+ while (left < left_end)
+ {
+ *result = 0;
+ ++result;
+ ++left;
+ }
+
+ glibc_hwcaps_priorities_length = length;
+}
+
+/* Return the priority of the cache_extension_tag_glibc_hwcaps section
+ entry at INDEX. Zero means do not use. Otherwise, lower values
+ indicate greater preference. */
+static uint32_t
+glibc_hwcaps_priority (uint32_t index)
+{
+ /* This does not need to repeated initialization attempts because
+ this function is only called if there is glibc-hwcaps data in the
+ cache, so the first call initializes the glibc_hwcaps_priorities
+ array. */
+ if (glibc_hwcaps_priorities_length == 0)
+ glibc_hwcaps_priorities_init ();
+
+ if (index < glibc_hwcaps_priorities_length)
+ return glibc_hwcaps_priorities[index];
+ else
+ return 0;
+}
+#endif /* SHARED */
+
/* True if PTR is a valid string table index. */
static inline bool
_dl_cache_verify_ptr (uint32_t ptr, size_t string_table_size)
@@ -74,6 +212,9 @@ search_cache (const char *string_table, uint32_t string_table_size,
int left = 0;
int right = nlibs - 1;
const char *best = NULL;
+#ifdef SHARED
+ uint32_t best_priority = 0;
+#endif
while (left <= right)
{
@@ -129,6 +270,11 @@ search_cache (const char *string_table, uint32_t string_table_size,
{
if (best == NULL || flags == GLRO (dl_correct_cache_id))
{
+ /* Named/extension hwcaps get slightly different
+ treatment: We keep searching for a better
+ match. */
+ bool named_hwcap = false;
+
if (entry_size >= sizeof (struct file_entry_new))
{
/* The entry is large enough to include
@@ -136,7 +282,18 @@ search_cache (const char *string_table, uint32_t string_table_size,
struct file_entry_new *libnew
= (struct file_entry_new *) lib;
- if (libnew->hwcap & hwcap_exclude)
+#ifdef SHARED
+ named_hwcap = dl_cache_hwcap_extension (libnew);
+#endif
+
+ /* The entries with named/extension hwcaps
+ have been exhausted. Return the best
+ match encountered so far if there is
+ one. */
+ if (!named_hwcap && best != NULL)
+ break;
+
+ if ((libnew->hwcap & hwcap_exclude) && !named_hwcap)
continue;
if (GLRO (dl_osversion)
&& libnew->osversion > GLRO (dl_osversion))
@@ -146,14 +303,41 @@ search_cache (const char *string_table, uint32_t string_table_size,
&& ((libnew->hwcap & _DL_HWCAP_PLATFORM)
!= platform))
continue;
+
+#ifdef SHARED
+ /* For named hwcaps, determine the priority
+ and see if beats what has been found so
+ far. */
+ if (named_hwcap)
+ {
+ uint32_t entry_priority
+ = glibc_hwcaps_priority (libnew->hwcap);
+ if (entry_priority == 0)
+ /* Not usable at all. Skip. */
+ continue;
+ else if (best == NULL
+ || entry_priority < best_priority)
+ /* This entry is of higher priority
+ than the previous one, or it is the
+ first entry. */
+ best_priority = entry_priority;
+ else
+ /* An entry has already been found,
+ but it is a better match. */
+ continue;
+ }
+#endif /* SHARED */
}
best = string_table + lib->value;
- if (flags == GLRO (dl_correct_cache_id))
+ if (flags == GLRO (dl_correct_cache_id)
+ && !named_hwcap)
/* We've found an exact match for the shared
object and no general `ELF' release. Stop
- searching. */
+ searching, but not if a named (extension)
+ hwcap is used. In this case, an entry with
+ a higher priority may come up later. */
break;
}
}
@@ -346,5 +530,9 @@ _dl_unload_cache (void)
__munmap (cache, cachesize);
cache = NULL;
}
+#ifdef SHARED
+ /* This marks the glibc_hwcaps_priorities array as out-of-date. */
+ glibc_hwcaps_priorities_length = 0;
+#endif
}
#endif
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
index e57d0d2d41741021..098173a84c43c1fd 100644
--- a/elf/dl-hwcaps.c
+++ b/elf/dl-hwcaps.c
@@ -89,6 +89,81 @@ copy_hwcaps (struct copy_hwcaps *target, const char *hwcaps,
}
}
+struct dl_hwcaps_priority *_dl_hwcaps_priorities;
+uint32_t _dl_hwcaps_priorities_length;
+
+/* Allocate _dl_hwcaps_priorities and fill it with data. */
+static void
+compute_priorities (size_t total_count, const char *prepend,
+ uint32_t bitmask, const char *mask)
+{
+ _dl_hwcaps_priorities = malloc (total_count
+ * sizeof (*_dl_hwcaps_priorities));
+ if (_dl_hwcaps_priorities == NULL)
+ _dl_signal_error (ENOMEM, NULL, NULL,
+ N_("cannot create HWCAP priorities"));
+ _dl_hwcaps_priorities_length = total_count;
+
+ /* First the prepended subdirectories. */
+ size_t i = 0;
+ {
+ struct dl_hwcaps_split sp;
+ _dl_hwcaps_split_init (&sp, prepend);
+ while (_dl_hwcaps_split (&sp))
+ {
+ _dl_hwcaps_priorities[i].name = sp.segment;
+ _dl_hwcaps_priorities[i].name_length = sp.length;
+ _dl_hwcaps_priorities[i].priority = i + 1;
+ ++i;
+ }
+ }
+
+ /* Then the built-in subdirectories that are actually active. */
+ {
+ struct dl_hwcaps_split_masked sp;
+ _dl_hwcaps_split_masked_init (&sp, _dl_hwcaps_subdirs, bitmask, mask);
+ while (_dl_hwcaps_split_masked (&sp))
+ {
+ _dl_hwcaps_priorities[i].name = sp.split.segment;
+ _dl_hwcaps_priorities[i].name_length = sp.split.length;
+ _dl_hwcaps_priorities[i].priority = i + 1;
+ ++i;
+ }
+ }
+ assert (i == total_count);
+}
+
+/* Sort the _dl_hwcaps_priorities array by name. */
+static void
+sort_priorities_by_name (void)
+{
+ /* Insertion sort. There is no need to link qsort into the dynamic
+ loader for such a short array. */
+ for (size_t i = 1; i < _dl_hwcaps_priorities_length; ++i)
+ for (size_t j = i; j > 0; --j)
+ {
+ struct dl_hwcaps_priority *previous = _dl_hwcaps_priorities + j - 1;
+ struct dl_hwcaps_priority *current = _dl_hwcaps_priorities + j;
+
+ /* Bail out if current is greater or equal to the previous
+ value. */
+ uint32_t to_compare;
+ if (current->name_length < previous->name_length)
+ to_compare = current->name_length;
+ else
+ to_compare = previous->name_length;
+ int cmp = memcmp (current->name, previous->name, to_compare);
+ if (cmp >= 0
+ || (cmp == 0 && current->name_length >= previous->name_length))
+ break;
+
+ /* Swap *previous and *current. */
+ struct dl_hwcaps_priority tmp = *previous;
+ *previous = *current;
+ *current = tmp;
+ }
+}
+
/* Return an array of useful/necessary hardware capability names. */
const struct r_strlenpair *
_dl_important_hwcaps (const char *glibc_hwcaps_prepend,
@@ -111,6 +186,9 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
update_hwcaps_counts (&hwcaps_counts, glibc_hwcaps_prepend, -1, NULL);
update_hwcaps_counts (&hwcaps_counts, _dl_hwcaps_subdirs,
hwcaps_subdirs_active, glibc_hwcaps_mask);
+ compute_priorities (hwcaps_counts.count, glibc_hwcaps_prepend,
+ hwcaps_subdirs_active, glibc_hwcaps_mask);
+ sort_priorities_by_name ();
/* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix
and a "/" suffix once stored in the result. */
diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h
index 3fcfbceb1a8fc1c8..769ecab3f886c6c4 100644
--- a/elf/dl-hwcaps.h
+++ b/elf/dl-hwcaps.h
@@ -132,4 +132,23 @@ _dl_hwcaps_subdirs_build_bitmask (int subdirs, int active)
return mask ^ ((1U << inactive) - 1);
}
+/* Pre-computed glibc-hwcaps subdirectory priorities. Used in
+ dl-cache.c to quickly find the proprieties for the stored HWCAP
+ names. */
+struct dl_hwcaps_priority
+{
+ /* The name consists of name_length bytes at name (not necessarily
+ null-terminated). */
+ const char *name;
+ uint32_t name_length;
+
+ /* Priority of this name. A positive number. */
+ uint32_t priority;
+};
+
+/* Pre-computed hwcaps priorities. Set up by
+ _dl_important_hwcaps. */
+extern struct dl_hwcaps_priority *_dl_hwcaps_priorities attribute_hidden;
+extern uint32_t _dl_hwcaps_priorities_length attribute_hidden;
+
#endif /* _DL_HWCAPS_H */
diff --git a/elf/tst-glibc-hwcaps-cache.c b/elf/tst-glibc-hwcaps-cache.c
new file mode 100644
index 0000000000000000..4bad56afc03451fc
--- /dev/null
+++ b/elf/tst-glibc-hwcaps-cache.c
@@ -0,0 +1,45 @@
+/* Wrapper to invoke tst-glibc-hwcaps in a container, to test ld.so.cache.
+ Copyright (C) 2020 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/>. */
+
+/* This program is just a wrapper that runs ldconfig followed by
+ tst-glibc-hwcaps. The actual test is provided via an
+ implementation in a sysdeps subdirectory. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/support.h>
+#include <unistd.h>
+
+int
+main (int argc, char **argv)
+{
+ /* Run ldconfig to populate the cache. */
+ {
+ char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir);
+ if (system (command) != 0)
+ return 1;
+ free (command);
+ }
+
+ /* Reuse tst-glibc-hwcaps. Since this code is running in a
+ container, we can launch it directly. */
+ char *path = xasprintf ("%s/elf/tst-glibc-hwcaps", support_objdir_root);
+ execv (path, argv);
+ printf ("error: execv of %s failed: %m\n", path);
+ return 1;
+}
diff --git a/elf/tst-glibc-hwcaps-cache.root/etc/ld.so.conf b/elf/tst-glibc-hwcaps-cache.root/etc/ld.so.conf
new file mode 100644
index 0000000000000000..e1e74dbda2bf3dfa
--- /dev/null
+++ b/elf/tst-glibc-hwcaps-cache.root/etc/ld.so.conf
@@ -0,0 +1,2 @@
+# This file was created to suppress a warning from ldconfig:
+# /sbin/ldconfig: Warning: ignoring configuration file that cannot be opened: /etc/ld.so.conf: No such file or directory
diff --git a/elf/tst-glibc-hwcaps-cache.root/postclean.req b/elf/tst-glibc-hwcaps-cache.root/postclean.req
new file mode 100644
index 0000000000000000..e69de29bb2d1d643
diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script
new file mode 100644
index 0000000000000000..6356d152089cdd9a
--- /dev/null
+++ b/elf/tst-glibc-hwcaps-cache.script
@@ -0,0 +1,6 @@
+# test-container does not support scripts in sysdeps directories, so
+# collect everything in one file.
+
+cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so
+cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so
+cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so
diff --git a/elf/tst-glibc-hwcaps-prepend-cache.c b/elf/tst-glibc-hwcaps-prepend-cache.c
new file mode 100644
index 0000000000000000..40509cebe2b5ba27
--- /dev/null
+++ b/elf/tst-glibc-hwcaps-prepend-cache.c
@@ -0,0 +1,149 @@
+/* Test that --glibc-hwcaps-prepend works, using dlopen and /etc/ld.so.cache.
+ Copyright (C) 2020 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 <dlfcn.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xdlfcn.h>
+#include <support/xunistd.h>
+
+/* Invoke /sbin/ldconfig with some error checking. */
+static void
+run_ldconfig (void)
+{
+ char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir);
+ TEST_COMPARE (system (command), 0);
+ free (command);
+}
+
+/* The library under test. */
+#define SONAME "libmarkermod1.so"
+
+static int
+do_test (void)
+{
+ if (dlopen (SONAME, RTLD_NOW) != NULL)
+ FAIL_EXIT1 (SONAME " is already on the search path");
+
+ /* Install the default implementation of libmarkermod1.so. */
+ xmkdirp ("/etc", 0777);
+ support_write_file_string ("/etc/ld.so.conf", "/glibc-test/lib\n");
+ xmkdirp ("/glibc-test/lib/glibc-hwcaps/prepend2", 0777);
+ xmkdirp ("/glibc-test/lib/glibc-hwcaps/prepend3", 0777);
+ {
+ char *src = xasprintf ("%s/elf/libmarkermod1-1.so", support_objdir_root);
+ support_copy_file (src, "/glibc-test/lib/" SONAME);
+ free (src);
+ }
+ run_ldconfig ();
+ {
+ /* The default implementation can now be loaded. */
+ void *handle = xdlopen (SONAME, RTLD_NOW);
+ int (*marker1) (void) = xdlsym (handle, "marker1");
+ TEST_COMPARE (marker1 (), 1);
+ xdlclose (handle);
+ }
+
+ /* Add the first override to the directory that is searched last. */
+ {
+ char *src = xasprintf ("%s/elf/libmarkermod1-2.so", support_objdir_root);
+ support_copy_file (src, "/glibc-test/lib/glibc-hwcaps/prepend2/"
+ SONAME);
+ free (src);
+ }
+ {
+ /* This is still the first implementation. The cache has not been
+ updated. */
+ void *handle = xdlopen (SONAME, RTLD_NOW);
+ int (*marker1) (void) = xdlsym (handle, "marker1");
+ TEST_COMPARE (marker1 (), 1);
+ xdlclose (handle);
+ }
+ run_ldconfig ();
+ {
+ /* After running ldconfig, it is the second implementation. */
+ void *handle = xdlopen (SONAME, RTLD_NOW);
+ int (*marker1) (void) = xdlsym (handle, "marker1");
+ TEST_COMPARE (marker1 (), 2);
+ xdlclose (handle);
+ }
+
+ /* Add the second override to the directory that is searched first. */
+ {
+ char *src = xasprintf ("%s/elf/libmarkermod1-3.so", support_objdir_root);
+ support_copy_file (src, "/glibc-test/lib/glibc-hwcaps/prepend3/"
+ SONAME);
+ free (src);
+ }
+ {
+ /* This is still the second implementation. */
+ void *handle = xdlopen (SONAME, RTLD_NOW);
+ int (*marker1) (void) = xdlsym (handle, "marker1");
+ TEST_COMPARE (marker1 (), 2);
+ xdlclose (handle);
+ }
+ run_ldconfig ();
+ {
+ /* After running ldconfig, it is the third implementation. */
+ void *handle = xdlopen (SONAME, RTLD_NOW);
+ int (*marker1) (void) = xdlsym (handle, "marker1");
+ TEST_COMPARE (marker1 (), 3);
+ xdlclose (handle);
+ }
+
+ /* Remove the second override again, without running ldconfig.
+ Ideally, this would revert to implementation 2. However, in the
+ current implementation, the cache returns exactly one file name
+ which does not exist after unlinking, so the dlopen fails. */
+ xunlink ("/glibc-test/lib/glibc-hwcaps/prepend3/" SONAME);
+ TEST_VERIFY (dlopen (SONAME, RTLD_NOW) == NULL);
+ run_ldconfig ();
+ {
+ /* After running ldconfig, the second implementation is available
+ once more. */
+ void *handle = xdlopen (SONAME, RTLD_NOW);
+ int (*marker1) (void) = xdlsym (handle, "marker1");
+ TEST_COMPARE (marker1 (), 2);
+ xdlclose (handle);
+ }
+
+ return 0;
+}
+
+static void
+prepare (int argc, char **argv)
+{
+ const char *no_restart = "no-restart";
+ if (argc == 2 && strcmp (argv[1], no_restart) == 0)
+ return;
+ /* Re-execute the test with an explicit loader invocation. */
+ execl (support_objdir_elf_ldso,
+ support_objdir_elf_ldso,
+ "--glibc-hwcaps-prepend", "prepend3:prepend2",
+ argv[0], no_restart,
+ NULL);
+ printf ("error: execv of %s failed: %m\n", argv[0]);
+ _exit (1);
+}
+
+#define PREPARE prepare
+#include <support/test-driver.c>
diff --git a/elf/tst-glibc-hwcaps-prepend-cache.root/postclean.req b/elf/tst-glibc-hwcaps-prepend-cache.root/postclean.req
new file mode 100644
index 0000000000000000..e69de29bb2d1d643

View File

@ -0,0 +1,38 @@
commit 2954daf00bb4dc27c69a48e6798d5960ea320741
Author: Andreas Schwab <schwab@suse.de>
Date: Tue Oct 23 09:40:14 2018 +0200
Add more checks for valid ld.so.cache file (bug 18093)
diff --git a/elf/cache.c b/elf/cache.c
index e63979da7d25560c..c4cd825c30e00e8e 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -199,6 +199,11 @@ print_cache (const char *cache_name)
}
else
{
+ /* Check for corruption, avoiding overflow. */
+ if ((cache_size - sizeof (struct cache_file)) / sizeof (struct file_entry)
+ < cache->nlibs)
+ error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
+
size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
+ (cache->nlibs
* sizeof (struct file_entry)));
diff --git a/elf/dl-cache.c b/elf/dl-cache.c
index 6ee5153ff9514872..6dd99a35b9f97cfb 100644
--- a/elf/dl-cache.c
+++ b/elf/dl-cache.c
@@ -204,7 +204,10 @@ _dl_load_cache_lookup (const char *name)
- only the new format
The following checks if the cache contains any of these formats. */
if (file != MAP_FAILED && cachesize > sizeof *cache
- && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0)
+ && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0
+ /* Check for corruption, avoiding overflow. */
+ && ((cachesize - sizeof *cache) / sizeof (struct file_entry)
+ >= ((struct cache_file *) file)->nlibs))
{
size_t offset;
/* Looks ok. */

View File

@ -0,0 +1,249 @@
commit f267e1c9dd7fb8852cc32d6eafd96bbcfd5cbb2b
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 4 09:13:43 2020 +0100
x86_64: Add glibc-hwcaps support
The subdirectories match those in the x86-64 psABI:
https://gitlab.com/x86-psABIs/x86-64-ABI/-/commit/77566eb03bc6a326811cb7e9a6b9396884b67c7c
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/Makefile b/elf/Makefile
index f67b231c0f8e3aff..7f2fc73877f0a4c8 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1751,7 +1751,7 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \
# glibc-hwcaps mechanism for this architecture). Used to obtain test
# coverage for some glibc-hwcaps tests for the widest possible range
# of systems.
-glibc-hwcaps-first-subdirs-for-tests =
+glibc-hwcaps-first-subdirs-for-tests = x86-64-v2
# The test modules are parameterized by preprocessor macros.
LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so
diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script
index 6356d152089cdd9a..66d6942402b7233b 100644
--- a/elf/tst-glibc-hwcaps-cache.script
+++ b/elf/tst-glibc-hwcaps-cache.script
@@ -4,3 +4,13 @@
cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so
cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so
cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so
+
+mkdirp 0770 $L/glibc-hwcaps/x86-64-v2
+cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so
+mkdirp 0770 $L/glibc-hwcaps/x86-64-v3
+cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod3.so
+cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/x86-64-v3/libmarkermod3.so
+mkdirp 0770 $L/glibc-hwcaps/x86-64-v4
+cp $B/elf/libmarkermod4-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod4.so
+cp $B/elf/libmarkermod4-3.so $L/glibc-hwcaps/x86-64-v3/libmarkermod4.so
+cp $B/elf/libmarkermod4-4.so $L/glibc-hwcaps/x86-64-v4/libmarkermod4.so
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
index 42b97c5cc73892cc..d1d7cb9d2eeca9c5 100644
--- a/sysdeps/x86_64/Makefile
+++ b/sysdeps/x86_64/Makefile
@@ -144,8 +144,47 @@ CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS)
CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS)
CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS)
endif
+
+$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so \
+ $(objpfx)libmarkermod3-1.so $(objpfx)libmarkermod4-1.so
+$(objpfx)tst-glibc-hwcaps.out: \
+ $(objpfx)libmarkermod2.so \
+ $(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod2.so \
+ $(objpfx)libmarkermod3.so \
+ $(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod3.so \
+ $(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod3.so \
+ $(objpfx)libmarkermod4.so \
+ $(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod4.so \
+ $(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod4.so \
+ $(objpfx)glibc-hwcaps/x86-64-v4/libmarkermod4.so \
+
+$(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod2.so: $(objpfx)libmarkermod2-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod3.so: $(objpfx)libmarkermod3-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod3.so: $(objpfx)libmarkermod3-3.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/x86-64-v2/libmarkermod4.so: $(objpfx)libmarkermod4-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/x86-64-v3/libmarkermod4.so: $(objpfx)libmarkermod4-3.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/x86-64-v4/libmarkermod4.so: $(objpfx)libmarkermod4-4.so
+ $(make-target-directory)
+ cp $< $@
+
+ifeq (no,$(build-hardcoded-path-in-tests))
+# This is an ld.so.cache test, and RPATH/RUNPATH in the executable
+# interferes with its test objectives.
+tests-container += tst-glibc-hwcaps-cache
endif
+endif # $(subdir) == elf
+
ifeq ($(subdir),csu)
gen-as-const-headers += tlsdesc.sym rtld-offsets.sym
endif
diff --git a/sysdeps/x86_64/dl-hwcaps-subdirs.c b/sysdeps/x86_64/dl-hwcaps-subdirs.c
new file mode 100644
index 0000000000000000..8810a822efe36962
--- /dev/null
+++ b/sysdeps/x86_64/dl-hwcaps-subdirs.c
@@ -0,0 +1,66 @@
+/* Architecture-specific glibc-hwcaps subdirectories. x86 version.
+ Copyright (C) 2020 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 <dl-hwcaps.h>
+#include <cpu-features.h>
+
+const char _dl_hwcaps_subdirs[] = "x86-64-v4:x86-64-v3:x86-64-v2";
+enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */
+
+uint32_t
+_dl_hwcaps_subdirs_active (void)
+{
+ int active = 0;
+
+ /* Test in reverse preference order. */
+
+ /* x86-64-v2. */
+ if (!(CPU_FEATURE_USABLE (CMPXCHG16B)
+ && CPU_FEATURE_USABLE (LAHF64_SAHF64)
+ && CPU_FEATURE_USABLE (POPCNT)
+ && CPU_FEATURE_USABLE (SSE3)
+ && CPU_FEATURE_USABLE (SSE4_1)
+ && CPU_FEATURE_USABLE (SSE4_2)
+ && CPU_FEATURE_USABLE (SSSE3)))
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ ++active;
+
+ /* x86-64-v3. */
+ if (!(CPU_FEATURE_USABLE (AVX)
+ && CPU_FEATURE_USABLE (AVX2)
+ && CPU_FEATURE_USABLE (BMI1)
+ && CPU_FEATURE_USABLE (BMI2)
+ && CPU_FEATURE_USABLE (F16C)
+ && CPU_FEATURE_USABLE (FMA)
+ && CPU_FEATURE_USABLE (LZCNT)
+ && CPU_FEATURE_USABLE (MOVBE)
+ && CPU_FEATURE_USABLE (OSXSAVE)))
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ ++active;
+
+ /* x86-64-v4. */
+ if (!(CPU_FEATURE_USABLE (AVX512F)
+ && CPU_FEATURE_USABLE (AVX512BW)
+ && CPU_FEATURE_USABLE (AVX512CD)
+ && CPU_FEATURE_USABLE (AVX512DQ)
+ && CPU_FEATURE_USABLE (AVX512VL)))
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ ++active;
+
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+}
diff --git a/sysdeps/x86_64/tst-glibc-hwcaps.c b/sysdeps/x86_64/tst-glibc-hwcaps.c
new file mode 100644
index 0000000000000000..3075a8286dc30768
--- /dev/null
+++ b/sysdeps/x86_64/tst-glibc-hwcaps.c
@@ -0,0 +1,76 @@
+/* glibc-hwcaps subdirectory test. x86_64 version.
+ Copyright (C) 2020 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 <stdio.h>
+#include <support/check.h>
+#include <sys/param.h>
+#include <sys/platform/x86.h>
+
+extern int marker2 (void);
+extern int marker3 (void);
+extern int marker4 (void);
+
+/* Return the x86-64-vN level, 1 for the baseline. */
+static int
+compute_level (void)
+{
+ const struct cpu_features *cpu_features
+ = __x86_get_cpu_features (COMMON_CPUID_INDEX_MAX);
+
+ if (!(CPU_FEATURE_USABLE_P (cpu_features, CMPXCHG16B)
+ && CPU_FEATURE_USABLE_P (cpu_features, LAHF64_SAHF64)
+ && CPU_FEATURE_USABLE_P (cpu_features, POPCNT)
+ && CPU_FEATURE_USABLE_P (cpu_features, MMX)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE2)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE3)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSSE3)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE4_1)
+ && CPU_FEATURE_USABLE_P (cpu_features, SSE4_2)))
+ return 1;
+ if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX2)
+ && CPU_FEATURE_USABLE_P (cpu_features, BMI1)
+ && CPU_FEATURE_USABLE_P (cpu_features, BMI2)
+ && CPU_FEATURE_USABLE_P (cpu_features, F16C)
+ && CPU_FEATURE_USABLE_P (cpu_features, FMA)
+ && CPU_FEATURE_USABLE_P (cpu_features, LZCNT)
+ && CPU_FEATURE_USABLE_P (cpu_features, MOVBE)
+ && CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE)))
+ return 2;
+ if (!(CPU_FEATURE_USABLE_P (cpu_features, AVX512F)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX512CD)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX512DQ)
+ && CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)))
+ return 3;
+ return 4;
+}
+
+static int
+do_test (void)
+{
+ int level = compute_level ();
+ printf ("info: detected x86-64 micro-architecture level: %d\n", level);
+ TEST_COMPARE (marker2 (), MIN (level, 2));
+ TEST_COMPARE (marker3 (), MIN (level, 3));
+ TEST_COMPARE (marker4 (), MIN (level, 4));
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,21 @@
commit 4f4bd9e47ba98ccfeeaa8c600c0b0c8bbabcebb3
Author: Matheus Castanho <msc@linux.ibm.com>
Date: Fri Dec 4 09:48:56 2020 -0300
elf: Add missing <stddef.h> header to elf/dl-hwcaps.h
The lack of this header makes size_t unavailable on builds configured
with --disable-tunables, causing compilation errors.
diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h
index 769ecab3f886c6c4..9a34088c17e97d7f 100644
--- a/elf/dl-hwcaps.h
+++ b/elf/dl-hwcaps.h
@@ -20,6 +20,7 @@
#define _DL_HWCAPS_H
#include <stdint.h>
+#include <stddef.h>
#include <elf/dl-tunables.h>

View File

@ -0,0 +1,20 @@
commit 2976082a385a7fb3d0294c6acf745b4f93e834ee
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Dec 3 15:02:44 2020 -0800
x86: Set RDRAND usable if CPU supports RDRAND
Set RDRAND usable if CPU supports RDRAND.
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 4c9c15a44b618fed..805d00a43309fc23 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -85,6 +85,7 @@ update_usable (struct cpu_features *cpu_features)
CPU_FEATURE_SET_USABLE (cpu_features, WAITPKG);
CPU_FEATURE_SET_USABLE (cpu_features, GFNI);
CPU_FEATURE_SET_USABLE (cpu_features, RDPID);
+ CPU_FEATURE_SET_USABLE (cpu_features, RDRAND);
CPU_FEATURE_SET_USABLE (cpu_features, CLDEMOTE);
CPU_FEATURE_SET_USABLE (cpu_features, MOVDIRI);
CPU_FEATURE_SET_USABLE (cpu_features, MOVDIR64B);

View File

@ -0,0 +1,65 @@
commit 93fda28693f0d9060b0aa71eeacaacfe9f16896e
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Dec 3 15:02:44 2020 -0800
x86: Adjust tst-cpu-features-supports.c for GCC 11
Check HAS_CPU_FEATURE instead of CPU_FEATURE_USABLE for FSGSBASE, IBT,
LM, SHSTK and XSAVES since FSGSBASE requires kernel support, IBT/SHSTK/LM
require OS support and XSAVES is supervisor-mode only.
diff --git a/sysdeps/x86/tst-cpu-features-supports.c b/sysdeps/x86/tst-cpu-features-supports.c
index bf881b531f4bc2ed..287cf01fbdfaeda1 100644
--- a/sysdeps/x86/tst-cpu-features-supports.c
+++ b/sysdeps/x86/tst-cpu-features-supports.c
@@ -40,6 +40,11 @@ check_supports (int supports, int usable, const char *supports_name,
#define CHECK_SUPPORTS(str, name) \
check_supports (__builtin_cpu_supports (#str), \
CPU_FEATURE_USABLE (name), \
+ #str, "CPU_FEATURE_USABLE (" #name ")");
+
+#define CHECK_CPU_SUPPORTS(str, name) \
+ check_supports (__builtin_cpu_supports (#str), \
+ HAS_CPU_FEATURE (name), \
#str, "HAS_CPU_FEATURE (" #name ")");
static int
@@ -118,7 +123,7 @@ do_test (int argc, char **argv)
fails += CHECK_SUPPORTS (fma4, FMA4);
#endif
#if __GNUC_PREREQ (11, 0)
- fails += CHECK_SUPPORTS (fsgsbase, FSGSBASE);
+ fails += CHECK_CPU_SUPPORTS (fsgsbase, FSGSBASE);
fails += CHECK_SUPPORTS (fxsave, FXSR);
#endif
#if __GNUC_PREREQ (8, 0)
@@ -126,9 +131,9 @@ do_test (int argc, char **argv)
#endif
#if __GNUC_PREREQ (11, 0)
fails += CHECK_SUPPORTS (hle, HLE);
- fails += CHECK_SUPPORTS (ibt, IBT);
+ fails += CHECK_CPU_SUPPORTS (ibt, IBT);
fails += CHECK_SUPPORTS (lahf_lm, LAHF64_SAHF64);
- fails += CHECK_SUPPORTS (lm, LM);
+ fails += CHECK_CPU_SUPPORTS (lm, LM);
fails += CHECK_SUPPORTS (lwp, LWP);
fails += CHECK_SUPPORTS (lzcnt, LZCNT);
#endif
@@ -150,7 +155,7 @@ do_test (int argc, char **argv)
fails += CHECK_SUPPORTS (rtm, RTM);
fails += CHECK_SUPPORTS (serialize, SERIALIZE);
fails += CHECK_SUPPORTS (sha, SHA);
- fails += CHECK_SUPPORTS (shstk, SHSTK);
+ fails += CHECK_CPU_SUPPORTS (shstk, SHSTK);
#endif
fails += CHECK_SUPPORTS (sse, SSE);
fails += CHECK_SUPPORTS (sse2, SSE2);
@@ -180,7 +185,7 @@ do_test (int argc, char **argv)
fails += CHECK_SUPPORTS (xsave, XSAVE);
fails += CHECK_SUPPORTS (xsavec, XSAVEC);
fails += CHECK_SUPPORTS (xsaveopt, XSAVEOPT);
- fails += CHECK_SUPPORTS (xsaves, XSAVES);
+ fails += CHECK_CPU_SUPPORTS (xsaves, XSAVES);
#endif
printf ("%d differences between __builtin_cpu_supports and glibc code.\n",

View File

@ -0,0 +1,187 @@
commit 4c38c1a229bc3628269ad98bd7e8d31d118d91f6
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 4 09:13:43 2020 +0100
powerpc64le: Add glibc-hwcaps support
The "power10" and "power9" subdirectories are selected in a way
that matches the -mcpu=power10 and -mcpu=power9 options of GCC.
diff --git a/elf/Makefile b/elf/Makefile
index 7f2fc73877f0a4c8..57e3a8982297f79a 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1751,7 +1751,7 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \
# glibc-hwcaps mechanism for this architecture). Used to obtain test
# coverage for some glibc-hwcaps tests for the widest possible range
# of systems.
-glibc-hwcaps-first-subdirs-for-tests = x86-64-v2
+glibc-hwcaps-first-subdirs-for-tests = power9 x86-64-v2
# The test modules are parameterized by preprocessor macros.
LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so
diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script
index 66d6942402b7233b..6a4675f9bd30e02f 100644
--- a/elf/tst-glibc-hwcaps-cache.script
+++ b/elf/tst-glibc-hwcaps-cache.script
@@ -5,6 +5,12 @@ cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so
cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so
cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so
+mkdirp 0770 $L/glibc-hwcaps/power9
+cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/power9/libmarkermod2.so
+mkdirp 0770 $L/glibc-hwcaps/power10
+cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/power9/libmarkermod3.so
+cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/power10/libmarkermod3.so
+
mkdirp 0770 $L/glibc-hwcaps/x86-64-v2
cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so
mkdirp 0770 $L/glibc-hwcaps/x86-64-v3
diff --git a/sysdeps/powerpc/powerpc64/le/Makefile b/sysdeps/powerpc/powerpc64/le/Makefile
index f59db1ca3c8ed454..7a4be6bfef729914 100644
--- a/sysdeps/powerpc/powerpc64/le/Makefile
+++ b/sysdeps/powerpc/powerpc64/le/Makefile
@@ -82,3 +82,31 @@ CFLAGS-printf_fp.c = -mfloat128
CFLAGS-printf_fphex.c = -mfloat128
CFLAGS-printf_size.c = -mfloat128
endif
+
+ifeq ($(subdir),elf)
+$(objpfx)tst-glibc-hwcaps: \
+ $(objpfx)libmarkermod2-1.so $(objpfx)libmarkermod3-1.so
+$(objpfx)tst-glibc-hwcaps.out: \
+ $(objpfx)libmarkermod2.so \
+ $(objpfx)glibc-hwcaps/power9/libmarkermod2.so \
+ $(objpfx)libmarkermod3.so \
+ $(objpfx)glibc-hwcaps/power9/libmarkermod3.so \
+ $(objpfx)glibc-hwcaps/power10/libmarkermod3.so \
+
+$(objpfx)glibc-hwcaps/power9/libmarkermod2.so: $(objpfx)libmarkermod2-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/power9/libmarkermod3.so: $(objpfx)libmarkermod3-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/power10/libmarkermod3.so: $(objpfx)libmarkermod3-3.so
+ $(make-target-directory)
+ cp $< $@
+
+ifeq (no,$(build-hardcoded-path-in-tests))
+# This is an ld.so.cache test, and RPATH/RUNPATH in the executable
+# interferes with its test objectives.
+tests-container += tst-glibc-hwcaps-cache
+endif
+
+endif # $(subdir) == elf
diff --git a/sysdeps/powerpc/powerpc64/le/dl-hwcaps-subdirs.c b/sysdeps/powerpc/powerpc64/le/dl-hwcaps-subdirs.c
new file mode 100644
index 0000000000000000..6a21d77649f44dd4
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/dl-hwcaps-subdirs.c
@@ -0,0 +1,46 @@
+/* Architecture-specific glibc-hwcaps subdirectories. powerpc64le version.
+ Copyright (C) 2020 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 <dl-hwcaps.h>
+#include <ldsodefs.h>
+
+const char _dl_hwcaps_subdirs[] = "power10:power9";
+enum { subdirs_count = 2 }; /* Number of components in _dl_hwcaps_subdirs. */
+
+uint32_t
+_dl_hwcaps_subdirs_active (void)
+{
+ int active = 0;
+
+ /* Test in reverse preference order. Altivec and VSX are implied by
+ the powerpc64le ABI definition. */
+
+ /* POWER9. GCC enables float128 hardware support for -mcpu=power9. */
+ if ((GLRO (dl_hwcap2) & PPC_FEATURE2_ARCH_3_00) == 0
+ || (GLRO (dl_hwcap2) & PPC_FEATURE2_HAS_IEEE128) == 0)
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ ++active;
+
+ /* POWER10. GCC defines __MMA__ for -mcpu=power10. */
+ if ((GLRO (dl_hwcap2) & PPC_FEATURE2_ARCH_3_1) == 0
+ || (GLRO (dl_hwcap2) & PPC_FEATURE2_MMA) == 0)
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ ++active;
+
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+}
diff --git a/sysdeps/powerpc/powerpc64/le/tst-glibc-hwcaps.c b/sysdeps/powerpc/powerpc64/le/tst-glibc-hwcaps.c
new file mode 100644
index 0000000000000000..e510fca80a22aaeb
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/le/tst-glibc-hwcaps.c
@@ -0,0 +1,54 @@
+/* glibc-hwcaps subdirectory test. powerpc64le version.
+ Copyright (C) 2020 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 <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <sys/auxv.h>
+#include <sys/param.h>
+
+extern int marker2 (void);
+extern int marker3 (void);
+
+/* Return the POWER level, 8 for the baseline. */
+static int
+compute_level (void)
+{
+ const char *platform = (const char *) getauxval (AT_PLATFORM);
+ if (strcmp (platform, "power8") == 0)
+ return 8;
+ if (strcmp (platform, "power9") == 0)
+ return 9;
+ if (strcmp (platform, "power10") == 0)
+ return 10;
+ printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform);
+ /* Assume that the new platform supports POWER10. */
+ return 10;
+}
+
+static int
+do_test (void)
+{
+ int level = compute_level ();
+ printf ("info: detected POWER level: %d\n", level);
+ TEST_COMPARE (marker2 (), MIN (level - 7, 2));
+ TEST_COMPARE (marker3 (), MIN (level - 7, 3));
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,21 @@
commit 0d4ed9d40efa84e8dc88e64cf337c8e95af7b045
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Dec 9 18:56:14 2020 +0100
elf: Fix incorrect comparison in sort_priorities_by_name
Reported-By: Stefan Liebler <stli@linux.ibm.com>
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
index 098173a84c43c1fd..50d764ae8707f46d 100644
--- a/elf/dl-hwcaps.c
+++ b/elf/dl-hwcaps.c
@@ -153,7 +153,7 @@ sort_priorities_by_name (void)
else
to_compare = previous->name_length;
int cmp = memcmp (current->name, previous->name, to_compare);
- if (cmp >= 0
+ if (cmp > 0
|| (cmp == 0 && current->name_length >= previous->name_length))
break;

View File

@ -0,0 +1,25 @@
commit 1bb8d05b9c751f6909e85ee96f6c78d536987bfd
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Dec 10 12:24:53 2020 +0100
elf: Fix run-time dependencies of tst-dlopen-fail-2
The misattributed dependencies can cause failures in parallel testing
if the dependencies have not been built yet.
Fixes commit a332bd1518af518c984fad73eba6f46dc5b2b2d4
("elf: Add elf/tst-dlopenfail-2 [BZ #25396]").
diff --git a/elf/Makefile b/elf/Makefile
index 57e3a8982297f79a..63c61ad63677ec63 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1655,7 +1655,7 @@ $(objpfx)tst-dlopenfailmod1.so: \
LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so
$(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library)
$(objpfx)tst-dlopenfail-2: $(libdl)
-$(objpfx)tst-dlopenfail.out: \
+$(objpfx)tst-dlopenfail-2.out: \
$(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so \
$(objpfx)tst-dlopenfailmod3.so

View File

@ -0,0 +1,241 @@
commit fdf8fbca455ca3ef57235bde907bcc6a624ac5aa
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Dec 10 13:51:18 2020 +0100
s390x: Add glibc-hwcaps support
Subdirectories z13, z14, z15 can be selected, mostly based on the
level of support for vector instructions.
Co-Authored-By: Stefan Liebler <stli@linux.ibm.com>
diff --git a/elf/Makefile b/elf/Makefile
index 63c61ad63677ec63..67029930dd2cb461 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1751,7 +1751,7 @@ $(objpfx)argv0test.out: tst-rtld-argv0.sh $(objpfx)ld.so \
# glibc-hwcaps mechanism for this architecture). Used to obtain test
# coverage for some glibc-hwcaps tests for the widest possible range
# of systems.
-glibc-hwcaps-first-subdirs-for-tests = power9 x86-64-v2
+glibc-hwcaps-first-subdirs-for-tests = power9 x86-64-v2 z13
# The test modules are parameterized by preprocessor macros.
LDFLAGS-libmarkermod1-1.so += -Wl,-soname,libmarkermod1.so
diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script
index 6a4675f9bd30e02f..c3271f61f9e50f2e 100644
--- a/elf/tst-glibc-hwcaps-cache.script
+++ b/elf/tst-glibc-hwcaps-cache.script
@@ -11,6 +11,16 @@ mkdirp 0770 $L/glibc-hwcaps/power10
cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/power9/libmarkermod3.so
cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/power10/libmarkermod3.so
+mkdirp 0770 $L/glibc-hwcaps/z13
+cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/z13/libmarkermod2.so
+mkdirp 0770 $L/glibc-hwcaps/z14
+cp $B/elf/libmarkermod3-2.so $L/glibc-hwcaps/z13/libmarkermod3.so
+cp $B/elf/libmarkermod3-3.so $L/glibc-hwcaps/z14/libmarkermod3.so
+mkdirp 0770 $L/glibc-hwcaps/z15
+cp $B/elf/libmarkermod4-2.so $L/glibc-hwcaps/z13/libmarkermod4.so
+cp $B/elf/libmarkermod4-3.so $L/glibc-hwcaps/z14/libmarkermod4.so
+cp $B/elf/libmarkermod4-4.so $L/glibc-hwcaps/z15/libmarkermod4.so
+
mkdirp 0770 $L/glibc-hwcaps/x86-64-v2
cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so
mkdirp 0770 $L/glibc-hwcaps/x86-64-v3
diff --git a/sysdeps/s390/s390-64/Makefile b/sysdeps/s390/s390-64/Makefile
index b4d793bb3dd1f703..e5da26871c862e63 100644
--- a/sysdeps/s390/s390-64/Makefile
+++ b/sysdeps/s390/s390-64/Makefile
@@ -6,4 +6,43 @@ ifeq ($(subdir),elf)
CFLAGS-rtld.c += -Wno-uninitialized -Wno-unused
CFLAGS-dl-load.c += -Wno-unused
CFLAGS-dl-reloc.c += -Wno-unused
+
+$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so \
+ $(objpfx)libmarkermod3-1.so $(objpfx)libmarkermod4-1.so
+$(objpfx)tst-glibc-hwcaps.out: \
+ $(objpfx)libmarkermod2.so \
+ $(objpfx)glibc-hwcaps/z13/libmarkermod2.so \
+ $(objpfx)libmarkermod3.so \
+ $(objpfx)glibc-hwcaps/z13/libmarkermod3.so \
+ $(objpfx)glibc-hwcaps/z14/libmarkermod3.so \
+ $(objpfx)libmarkermod4.so \
+ $(objpfx)glibc-hwcaps/z13/libmarkermod4.so \
+ $(objpfx)glibc-hwcaps/z14/libmarkermod4.so \
+ $(objpfx)glibc-hwcaps/z15/libmarkermod4.so \
+
+$(objpfx)glibc-hwcaps/z13/libmarkermod2.so: $(objpfx)libmarkermod2-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/z13/libmarkermod3.so: $(objpfx)libmarkermod3-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/z14/libmarkermod3.so: $(objpfx)libmarkermod3-3.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/z13/libmarkermod4.so: $(objpfx)libmarkermod4-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/z14/libmarkermod4.so: $(objpfx)libmarkermod4-3.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/z15/libmarkermod4.so: $(objpfx)libmarkermod4-4.so
+ $(make-target-directory)
+ cp $< $@
+
+ifeq (no,$(build-hardcoded-path-in-tests))
+# This is an ld.so.cache test, and RPATH/RUNPATH in the executable
+# interferes with its test objectives.
+tests-container += tst-glibc-hwcaps-cache
endif
+
+endif # $(subdir) == elf
diff --git a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c
new file mode 100644
index 0000000000000000..3673808a458350ad
--- /dev/null
+++ b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c
@@ -0,0 +1,54 @@
+/* Architecture-specific glibc-hwcaps subdirectories. s390x version.
+ Copyright (C) 2020 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 <dl-hwcaps.h>
+#include <ldsodefs.h>
+
+const char _dl_hwcaps_subdirs[] = "z15:z14:z13";
+enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */
+
+uint32_t
+_dl_hwcaps_subdirs_active (void)
+{
+ int active = 0;
+
+ /* Test in reverse preference order. */
+
+ /* z13. */
+ if (!(GLRO (dl_hwcap) & HWCAP_S390_VX))
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ ++active;
+
+ /* z14. */
+ if (!((GLRO (dl_hwcap) & HWCAP_S390_VXD)
+ && (GLRO (dl_hwcap) & HWCAP_S390_VXE)
+ && (GLRO (dl_hwcap) & HWCAP_S390_GS)))
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ ++active;
+
+ /* z15.
+ Note: We do not list HWCAP_S390_SORT and HWCAP_S390_DFLT here as,
+ according to the Principles of Operation, those may be replaced or removed
+ in future. */
+ if (!((GLRO (dl_hwcap) & HWCAP_S390_VXRS_EXT2)
+ && (GLRO (dl_hwcap) & HWCAP_S390_VXRS_PDE)))
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ ++active;
+
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+}
diff --git a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c
new file mode 100644
index 0000000000000000..690f0d5fab36eb59
--- /dev/null
+++ b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c
@@ -0,0 +1,82 @@
+/* glibc-hwcaps subdirectory test. s390x version.
+ Copyright (C) 2020 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 <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <sys/auxv.h>
+#include <sys/param.h>
+
+extern int marker2 (void);
+extern int marker3 (void);
+extern int marker4 (void);
+
+/* Return the arch level, 10 for the baseline libmarkermod*.so's. */
+static int
+compute_level (void)
+{
+ const char *platform = (const char *) getauxval (AT_PLATFORM);
+
+ /* The arch* versions refer to the edition of the Principles of
+ Operation, and they are off by two when compared with the recent
+ product names. (The code below should not be considered an
+ accurate mapping to Principles of Operation editions for earlier
+ AT_PLATFORM strings). */
+ if (strcmp (platform, "z900") == 0)
+ return 10;
+ if (strcmp (platform, "z990") == 0)
+ return 10;
+ if (strcmp (platform, "z9-109") == 0)
+ return 10;
+ if (strcmp (platform, "z10") == 0)
+ return 10;
+ if (strcmp (platform, "z196") == 0)
+ return 10;
+ if (strcmp (platform, "zEC12") == 0)
+ return 10;
+
+ /* If we are running on z13 or newer and the kernel was booted with novx,
+ then AT_PLATFORM is z13 or newer, but _dl_hwcaps_subdirs_active will
+ return zero and the _dl_hwcaps_subdirs are not searched. */
+ const unsigned long int hwcap = getauxval (AT_HWCAP);
+ if ((hwcap & HWCAP_S390_VX) == 0)
+ return 10;
+
+ if (strcmp (platform, "z13") == 0)
+ return 11;
+ if (strcmp (platform, "z14") == 0)
+ return 12;
+ if (strcmp (platform, "z15") == 0)
+ return 13;
+ printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform);
+ /* Assume that the new platform supports z15. */
+ return 13;
+}
+
+static int
+do_test (void)
+{
+ int level = compute_level ();
+ printf ("info: detected architecture level: arch%d\n", level);
+ TEST_COMPARE (marker2 (), MIN (level - 9, 2));
+ TEST_COMPARE (marker3 (), MIN (level - 9, 3));
+ TEST_COMPARE (marker4 (), MIN (level - 9, 4));
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,83 @@
commit 97476447edff96e526daa1a22d6ed3665181ff93
Author: DJ Delorie <dj@redhat.com>
Date: Wed Oct 23 17:52:26 2019 -0400
Install charmaps uncompressed in testroot
The testroot does not have a gunzip command, so the charmap files
should not be installed gzipped else they cannot be used (and thus
tested). With this patch, installing with INSTALL_UNCOMPRESSED=yes
installs uncompressed charmaps instead.
Note that we must purge the $(symbolic_link_list) as it contains
references to $(DESTDIR), which we change during the testroot
installation.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/Makefile b/Makefile
index 3748d6f7cfb6223b..6d73241bbc811c13 100644
--- a/Makefile
+++ b/Makefile
@@ -398,8 +398,15 @@ ifeq ($(run-built-tests),yes)
$(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\
done
endif
+ # $(symbolic-link-list) is a file that encodes $(DESTDIR) so we
+ # have to purge it
+ rm -f $(symbolic-link-list)
+ # Setting INSTALL_UNCOMPRESSED causes localedata/Makefile to
+ # install the charmaps uncompressed, as the testroot does not
+ # provide a gunzip program.
$(MAKE) install DESTDIR=$(objpfx)testroot.pristine \
- subdirs='$(sorted-subdirs)'
+ INSTALL_UNCOMPRESSED=yes subdirs='$(sorted-subdirs)'
+ rm -f $(symbolic-link-list)
touch $(objpfx)testroot.pristine/install.stamp
tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
diff --git a/localedata/Makefile b/localedata/Makefile
index 0fed95dcae6a9183..14fcc37fed21e740 100644
--- a/localedata/Makefile
+++ b/localedata/Makefile
@@ -167,9 +167,17 @@ endif
endif
# Files to install.
+ifeq ($(INSTALL_UNCOMPRESSED),yes)
+# This option is for testing inside the testroot container, as the
+# container does not include a working gunzip program.
+install-others := $(addprefix $(inst_i18ndir)/, \
+ $(charmaps) \
+ $(locales))
+else
install-others := $(addprefix $(inst_i18ndir)/, \
$(addsuffix .gz, $(charmaps)) \
$(locales))
+endif
tests: $(objdir)/iconvdata/gconv-modules
@@ -282,12 +290,22 @@ endif
include ../Rules
+ifeq ($(INSTALL_UNCOMPRESSED),yes)
+# Install the charmap files as-is. This option is for testing inside
+# the testroot container, as the container does not include a working
+# gunzip program.
+$(inst_i18ndir)/charmaps/%: charmaps/% $(+force)
+ $(make-target-directory)
+ rm -f $@
+ $(INSTALL_DATA) $< $@
+else
# Install the charmap files in gzipped format.
$(inst_i18ndir)/charmaps/%.gz: charmaps/% $(+force)
$(make-target-directory)
rm -f $(@:.gz=) $@
$(INSTALL_DATA) $< $(@:.gz=)
gzip -9n $(@:.gz=)
+endif
# Install the locale source files in the appropriate directory.
$(inst_i18ndir)/locales/%: locales/% $(+force); $(do-install)

View File

@ -0,0 +1,121 @@
commit de42613540de8d3d70b5f14a14923cab7bd694d0
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon May 25 18:17:27 2020 +0200
elf: Turn _dl_printf, _dl_error_printf, _dl_fatal_printf into functions
This change makes it easier to set a breakpoint on these calls.
This also addresses the issue that including <ldsodefs.h> without
<unistd.h> does not result usable _dl_*printf macros because of the
use of the STD*_FILENO macros there.
(The private symbol for _dl_fatal_printf will go away again
once the exception handling implementation is unified between
libc and ld.so.)
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/Versions b/elf/Versions
index 3be879c4adfa74c7..be88c48e6d45a937 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -58,7 +58,7 @@ ld {
_dl_allocate_tls; _dl_allocate_tls_init;
_dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info;
_dl_deallocate_tls; _dl_make_stack_executable;
- _dl_rtld_di_serinfo; _dl_starting_up;
+ _dl_rtld_di_serinfo; _dl_starting_up; _dl_fatal_printf;
_rtld_global; _rtld_global_ro;
# Only here for gdb while a better method is developed.
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index 3f28de3ee9d68368..508630e444d2a00c 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -302,6 +302,37 @@ _dl_dprintf (int fd, const char *fmt, ...)
va_end (arg);
}
+void
+_dl_printf (const char *fmt, ...)
+{
+ va_list arg;
+
+ va_start (arg, fmt);
+ _dl_debug_vdprintf (STDOUT_FILENO, 0, fmt, arg);
+ va_end (arg);
+}
+
+void
+_dl_error_printf (const char *fmt, ...)
+{
+ va_list arg;
+
+ va_start (arg, fmt);
+ _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
+ va_end (arg);
+}
+
+void
+_dl_fatal_printf (const char *fmt, ...)
+{
+ va_list arg;
+
+ va_start (arg, fmt);
+ _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
+ va_end (arg);
+ _exit (127);
+}
+rtld_hidden_def (_dl_fatal_printf)
/* Test whether given NAME matches any of the names of the given object. */
int
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 77923499d3de4366..6cbbaa808a596f77 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -762,24 +762,19 @@ ssize_t _dl_write (int fd, const void *buffer, size_t length)
/* Write a message on the specified descriptor standard output. The
parameters are interpreted as for a `printf' call. */
-#define _dl_printf(fmt, args...) \
- _dl_dprintf (STDOUT_FILENO, fmt, ##args)
+void _dl_printf (const char *fmt, ...)
+ attribute_hidden __attribute__ ((__format__ (__printf__, 1, 2)));
/* Write a message on the specified descriptor standard error. The
parameters are interpreted as for a `printf' call. */
-#define _dl_error_printf(fmt, args...) \
- _dl_dprintf (STDERR_FILENO, fmt, ##args)
+void _dl_error_printf (const char *fmt, ...)
+ attribute_hidden __attribute__ ((__format__ (__printf__, 1, 2)));
/* Write a message on the specified descriptor standard error and exit
the program. The parameters are interpreted as for a `printf' call. */
-#define _dl_fatal_printf(fmt, args...) \
- do \
- { \
- _dl_dprintf (STDERR_FILENO, fmt, ##args); \
- _exit (127); \
- } \
- while (1)
-
+void _dl_fatal_printf (const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2), __noreturn__));
+rtld_hidden_proto (_dl_fatal_printf)
/* An exception raised by the _dl_signal_error function family and
caught by _dl_catch_error function family. Exceptions themselves
diff --git a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data
index 4b9dbf5acc088cff..eb79216e3b494486 100644
--- a/sysdeps/mach/hurd/i386/localplt.data
+++ b/sysdeps/mach/hurd/i386/localplt.data
@@ -43,6 +43,7 @@ ld.so: _dl_allocate_tls_init
ld.so: _dl_exception_create
ld.so: _dl_exception_create_format
ld.so: _dl_exception_free
+ld.so: _dl_fatal_printf
ld.so: _dl_find_dso_for_object
ld.so: _dl_init_first
ld.so: _dl_mcount

View File

@ -0,0 +1,199 @@
commit a5275ba5378c9256d18e582572b4315e8edfcbfb
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Nov 29 14:15:01 2018 -0800
_dl_exception_create_format: Support %x/%lx/%zx
Add support for %x, %lx and %zx to _dl_exception_create_format and pad
to the full width with 0.
* elf/Makefile (tests-internal): Add tst-create_format1.
* elf/dl-exception.c (_dl_exception_create_format): Support
%x, %lx and %zx.
* elf/tst-create_format1.c: New file.
Conflicts:
elf/Makefile
(Different backport order of tests.)
diff --git a/elf/Makefile b/elf/Makefile
index 89dff92adfc417f5..6d1962b2e4deb871 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -198,7 +198,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
tests-internal += loadtest unload unload2 circleload1 \
neededtest neededtest2 neededtest3 neededtest4 \
tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
- tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym
+ tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \
+ tst-create_format1
tests-container += tst-pldd
ifeq ($(build-hardcoded-path-in-tests),yes)
tests += tst-dlopen-aout
diff --git a/elf/dl-exception.c b/elf/dl-exception.c
index 1c63e4a3a65b6d55..1e41d89a7db52683 100644
--- a/elf/dl-exception.c
+++ b/elf/dl-exception.c
@@ -111,6 +111,20 @@ _dl_exception_create_format (struct dl_exception *exception, const char *objname
case 's':
length += strlen (va_arg (ap, const char *));
break;
+ /* Recognize the l modifier. It is only important on some
+ platforms where long and int have a different size. We
+ can use the same code for size_t. */
+ case 'l':
+ case 'z':
+ if (p[1] == 'x')
+ {
+ length += LONG_WIDTH / 4;
+ ++p;
+ break;
+ }
+ case 'x':
+ length += INT_WIDTH / 4;
+ break;
default:
/* Assumed to be '%'. */
++length;
@@ -167,6 +181,32 @@ _dl_exception_create_format (struct dl_exception *exception, const char *objname
*wptr = '%';
++wptr;
break;
+ case 'x':
+ {
+ unsigned long int num = va_arg (ap, unsigned int);
+ char *start = wptr;
+ wptr += INT_WIDTH / 4;
+ char *cp = _itoa (num, wptr, 16, 0);
+ /* Pad to the full width with 0. */
+ while (cp != start)
+ *--cp = '0';
+ }
+ break;
+ case 'l':
+ case 'z':
+ if (p[1] == 'x')
+ {
+ unsigned long int num = va_arg (ap, unsigned long int);
+ char *start = wptr;
+ wptr += LONG_WIDTH / 4;
+ char *cp = _itoa (num, wptr, 16, 0);
+ /* Pad to the full width with 0. */
+ while (cp != start)
+ *--cp = '0';
+ ++p;
+ break;
+ }
+ /* FALLTHROUGH */
default:
_dl_fatal_printf ("Fatal error:"
" invalid format in exception string\n");
diff --git a/elf/tst-create_format1.c b/elf/tst-create_format1.c
new file mode 100644
index 0000000000000000..8b9edfdc69ea4ced
--- /dev/null
+++ b/elf/tst-create_format1.c
@@ -0,0 +1,103 @@
+/* Check _dl_exception_create_format.
+ Copyright (C) 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.
+
+ 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 <ldsodefs.h>
+#include <array_length.h>
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <support/capture_subprocess.h>
+
+#define TEST(es, objn, fmt, ...) \
+ ({ \
+ struct dl_exception exception; \
+ _dl_exception_create_format (&exception, objn, fmt, __VA_ARGS__); \
+ TEST_COMPARE_STRING (exception.objname, objn == NULL ? "" : objn); \
+ TEST_COMPARE_STRING (exception.errstring, es); \
+ _dl_exception_free (&exception); \
+ })
+
+static void
+do_test_invalid_conversion (void *closure)
+{
+ TEST ("(null)", NULL, "%p", NULL);
+}
+
+/* Exit status after abnormal termination. */
+static int invalid_status;
+
+static void
+init_invalid_status (void)
+{
+ pid_t pid = xfork ();
+ if (pid == 0)
+ _exit (127);
+ xwaitpid (pid, &invalid_status, 0);
+ if (WIFEXITED (invalid_status))
+ invalid_status = WEXITSTATUS (invalid_status);
+}
+
+static int
+do_test (void)
+{
+ init_invalid_status ();
+
+ TEST ("test", NULL, "%s", "test");
+ TEST ("test-test", NULL, "%s-test", "test");
+ TEST ("test", "test", "%s", "test");
+ TEST ("test-test", "test", "%s-test", "test");
+
+ TEST ("test%", NULL, "%s%%", "test");
+ TEST ("test%-test", NULL, "%s%%-test", "test");
+ TEST ("test%", "test", "%s%%", "test");
+ TEST ("test%-test", "test", "%s%%-test", "test");
+
+ TEST ("0000007b", NULL, "%x", 123);
+ TEST ("0000007b-test", NULL, "%x-test", 123);
+ TEST ("0000007b", "test", "%x", 123);
+ TEST ("0000007b-test", "test", "%x-test", 123);
+
+#define TEST_LONG(es, objn, fmt, ...) \
+ ({ \
+ if (sizeof (int) == sizeof (long int)) \
+ TEST (es, objn, fmt, __VA_ARGS__); \
+ else \
+ TEST ("ffffffff" es, objn, fmt, __VA_ARGS__); \
+ })
+
+ TEST_LONG ("fffffffd", NULL, "%lx", (long int)~2ul);
+ TEST_LONG ("fffffffd-test", NULL, "%lx-test", (long int)~2ul);
+ TEST_LONG ("fffffffd", "test", "%lx", (long int)~2ul);
+ TEST_LONG ("fffffffd-test", "test", "%lx-test", (long int)~2ul);
+
+ TEST_LONG ("fffffffe", NULL, "%zx", (size_t)~1ul);
+ TEST_LONG ("fffffffe-test", NULL, "%zx-test", (size_t)~1ul);
+ TEST_LONG ("fffffffe", "test", "%zx", (size_t)~1ul);
+ TEST_LONG ("fffffffe-test", "test", "%zx-test", (size_t)~1ul);
+
+ struct support_capture_subprocess result;
+ result = support_capture_subprocess (do_test_invalid_conversion, NULL);
+ support_capture_subprocess_check (&result, "dl-exception",
+ invalid_status, sc_allow_stderr);
+ TEST_COMPARE_STRING (result.err.buffer,
+ "Fatal error: invalid format in exception string\n");
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,22 @@
commit 8dddf0bd5a3d57fba8da27e93f3d1a7032fce184
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Oct 30 17:44:09 2019 +0100
resolv/tst-idna_name_classify: Isolate from system libraries
Loading NSS modules from static binaries uses installed system
libraries if LD_LIBRARY_PATH is not set.
diff --git a/inet/Makefile b/inet/Makefile
index 7782913b4c06f057..62d25f853538bb08 100644
--- a/inet/Makefile
+++ b/inet/Makefile
@@ -112,4 +112,8 @@ ifeq ($(build-static-nss),yes)
CFLAGS += -DSTATIC_NSS
endif
+# The test uses dlopen indirectly and would otherwise load system
+# objects.
+tst-idna_name_classify-ENV = \
+ LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
$(objpfx)tst-idna_name_classify.out: $(gen-locales)

View File

@ -0,0 +1,21 @@
commit 880433de13fa31e52587720f81b762a6c7797e4e
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Dec 10 15:47:26 2020 +0100
elf: Include <sys/param.h> in cache.c
The roundup macro is defined there. Relying on an indirect
definition is brittle.
diff --git a/elf/cache.c b/elf/cache.c
index dde3d7fefa4105f9..fdfedb0964bcd217 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -29,6 +29,7 @@
#include <stdint.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
+#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>

View File

@ -0,0 +1,33 @@
commit 2ee7711bdd7de9dd30073b223ce29d5cd50320f6
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Sun Dec 13 04:56:41 2020 -0800
x86: Remove the default REP MOVSB threshold tunable value [BZ #27061]
Since we can't tell if the tunable value is set by user or not:
https://sourceware.org/bugzilla/show_bug.cgi?id=27069
remove the default REP MOVSB threshold tunable value so that the correct
default value will be set correctly by init_cacheinfo ().
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list
index e066313a1d1dd009..89bf296626658900 100644
--- a/sysdeps/x86/dl-tunables.list
+++ b/sysdeps/x86/dl-tunables.list
@@ -39,9 +39,11 @@ glibc {
# REP MOVSB. Since larger register size can move more data with a
# single load and store, the threshold is higher with larger register
# size. Note: Since the REP MOVSB threshold must be greater than 8
- # times of vector size, the minium value must be updated at run-time.
+ # times of vector size and the default value is 2048 * (vector size
+ # / 16), the default value and the minimum value must be updated at
+ # run-time. NB: Don't set the default value since we can't tell if
+ # the tunable value is set by user or not [BZ #27069].
minval: 1
- default: 2048
}
x86_rep_stosb_threshold {
type: SIZE_T

View File

@ -0,0 +1,18 @@
commit 8a30bb4e0604aefcf28f20360fc8ba8ef8604b9c
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Dec 23 12:07:20 2020 +0100
elf: Account for glibc-hwcaps/ prefix in _dl_important_hwcaps
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
index 50d764ae8707f46d..2fc4ae67a0f5d051 100644
--- a/elf/dl-hwcaps.c
+++ b/elf/dl-hwcaps.c
@@ -192,6 +192,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
/* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix
and a "/" suffix once stored in the result. */
+ hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1;
size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
+ hwcaps_counts.total_length);

View File

@ -0,0 +1,22 @@
commit ce7387cc250a408d3fbb7a6fff7ad4d977166b00
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Nov 29 20:03:46 2018 -0800
elf/dl-exception.c: Include <_itoa.h> for _itoa prototype
Tested with build-many-glibcs.py.
* elf/dl-exception.c: Include <_itoa.h>.
diff --git a/elf/dl-exception.c b/elf/dl-exception.c
index 1e41d89a7db52683..3e8e0ba3f1442005 100644
--- a/elf/dl-exception.c
+++ b/elf/dl-exception.c
@@ -23,6 +23,7 @@
#include <stdint.h>
#include <string.h>
#include <unistd.h>
+#include <_itoa.h>
/* This message we return as a last resort. We define the string in a
variable since we have to avoid freeing it and so have to enable

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
commit b2e93de0ffedcfe2cfba100d47a4d4f6f85cea0b
Author: DJ Delorie <dj@redhat.com>
Date: Tue Dec 4 00:03:12 2018 -0500
test-container: add "su" command to run test as root, add unshare hints
* support/test-container.c (check_for_unshare_hints): New.
(main): Call it if unshare fails. Add support for "su" scriptlet
command.
diff --git a/support/test-container.c b/support/test-container.c
index fe0ebbd07df83da7..1d1aebeaf3412573 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -88,15 +88,22 @@ int verbose = 0;
* mytest.root/ is rsync'd into container
* mytest.root/preclean.req causes fresh rsync (with delete) before
test if present
- * mytest.root/mytset.script has a list of "commands" to run:
+ * mytest.root/mytest.script has a list of "commands" to run:
syntax:
# comment
+ su
mv FILE FILE
cp FILE FILE
rm FILE
FILE must start with $B/, $S/, $I/, $L/, or /
(expands to build dir, source dir, install dir, library dir
(in container), or container's root)
+ details:
+ - '#': A comment.
+ - 'su': Enables running test as root in the container.
+ - 'mv': A minimal move files command.
+ - 'cp': A minimal copy files command.
+ - 'rm': A minimal remove files command.
* mytest.root/postclean.req causes fresh rsync (with delete) after
test if present
@@ -349,6 +356,7 @@ recursive_remove (char *path)
switch (child) {
case -1:
+ perror("fork");
FAIL_EXIT1 ("Unable to fork");
case 0:
/* Child. */
@@ -610,6 +618,47 @@ rsync (char *src, char *dest, int and_delete)
}
+
+/* See if we can detect what the user needs to do to get unshare
+ support working for us. */
+void
+check_for_unshare_hints (void)
+{
+ FILE *f;
+ int i;
+
+ /* Default Debian Linux disables user namespaces, but allows a way
+ to enable them. */
+ f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
+ if (f != NULL)
+ {
+ i = 99; /* Sentinel. */
+ fscanf (f, "%d", &i);
+ if (i == 0)
+ {
+ printf ("To enable test-container, please run this as root:\n");
+ printf (" echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n");
+ }
+ fclose (f);
+ return;
+ }
+
+ /* ALT Linux has an alternate way of doing the same. */
+ f = fopen ("/proc/sys/kernel/userns_restrict", "r");
+ if (f != NULL)
+ {
+ i = 99; /* Sentinel. */
+ fscanf (f, "%d", &i);
+ if (i == 1)
+ {
+ printf ("To enable test-container, please run this as root:\n");
+ printf (" echo 0 > /proc/sys/kernel/userns_restrict\n");
+ }
+ fclose (f);
+ return;
+ }
+}
+
int
main (int argc, char **argv)
{
@@ -628,6 +677,8 @@ main (int argc, char **argv)
uid_t original_uid;
gid_t original_gid;
+ /* If set, the test runs as root instead of the user running the testsuite. */
+ int be_su = 0;
int UMAP;
int GMAP;
/* Used for "%lld %lld 1" so need not be large. */
@@ -857,6 +908,10 @@ main (int argc, char **argv)
{
maybe_xunlink (the_words[1]);
}
+ else if (nt == 1 && strcmp (the_words[0], "su") == 0)
+ {
+ be_su = 1;
+ }
else if (nt > 0 && the_words[0][0] != '#')
{
printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]);
@@ -910,7 +965,12 @@ main (int argc, char **argv)
/* Older kernels may not support all the options, or security
policy may block this call. */
if (errno == EINVAL || errno == EPERM)
- FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (errno));
+ {
+ int saved_errno = errno;
+ if (errno == EPERM)
+ check_for_unshare_hints ();
+ FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
+ }
else
FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno));
}
@@ -981,7 +1041,7 @@ main (int argc, char **argv)
FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
sprintf (tmp, "%lld %lld 1\n",
- (long long) original_uid, (long long) original_uid);
+ (long long) (be_su ? 0 : original_uid), (long long) original_uid);
write (UMAP, tmp, strlen (tmp));
xclose (UMAP);
@@ -1002,7 +1062,7 @@ main (int argc, char **argv)
FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
sprintf (tmp, "%lld %lld 1\n",
- (long long) original_gid, (long long) original_gid);
+ (long long) (be_su ? 0 : original_gid), (long long) original_gid);
write (GMAP, tmp, strlen (tmp));
xclose (GMAP);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,191 @@
commit 32db86d558193ad4ad5a00926ce3c350c89eb8df
Author: Joseph Myers <joseph@codesourcery.com>
Date: Tue Feb 12 10:30:34 2019 +0000
Add fall-through comments.
This patch adds fall-through comments in some cases where -Wextra
produces implicit-fallthrough warnings.
The patch is non-exhaustive. Apart from architecture-specific code
for non-x86_64 architectures, it does not change sunrpc/xdr.c (legacy
code, probably should have such changes, but left to be dealt with
separately), or places that already had comments about the
fall-through but not matching the form expected by
-Wimplicit-fallthrough=3 (the default level with -Wextra; my
inclination is to adjust those comments to match rather than
downgrading to -Wimplicit-fallthrough=1 to allow any comment), or one
place where I thought the implicit fallthrough was not correct and so
should be handled separately as a bug fix. I think the key thing to
consider in review of this patch is whether the fall-through is indeed
intended and correct in each place where such a comment is added.
Tested for x86_64.
* elf/dl-exception.c (_dl_exception_create_format): Add
fall-through comments.
* elf/ldconfig.c (parse_conf_include): Likewise.
* elf/rtld.c (print_statistics): Likewise.
* locale/programs/charmap.c (parse_charmap): Likewise.
* misc/mntent_r.c (__getmntent_r): Likewise.
* posix/wordexp.c (parse_arith): Likewise.
(parse_backtick): Likewise.
* resolv/ns_ttl.c (ns_parse_ttl): Likewise.
* sysdeps/x86/cpu-features.c (init_cpu_features): Likewise.
* sysdeps/x86_64/dl-machine.h (elf_machine_rela): Likewise.
diff --git a/elf/dl-exception.c b/elf/dl-exception.c
index 3e8e0ba3f1442005..d24bf30a5cf39bc2 100644
--- a/elf/dl-exception.c
+++ b/elf/dl-exception.c
@@ -123,6 +123,7 @@ _dl_exception_create_format (struct dl_exception *exception, const char *objname
++p;
break;
}
+ /* Fall through. */
case 'x':
length += INT_WIDTH / 4;
break;
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index fbdd814edf59bc77..ed7d9ab0412d93fd 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -1228,6 +1228,7 @@ parse_conf_include (const char *config_file, unsigned int lineno,
case GLOB_NOSPACE:
errno = ENOMEM;
+ /* Fall through. */
case GLOB_ABORTED:
if (opt_verbose)
error (0, errno, _("%s:%u: cannot read directory %s"),
diff --git a/elf/rtld.c b/elf/rtld.c
index 7f030f75a22c532e..8bb5f548a0ff8eb4 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2734,8 +2734,10 @@ print_statistics (hp_timing_t *rtld_total_timep)
{
case 3:
*wp++ = *cp++;
+ /* Fall through. */
case 2:
*wp++ = *cp++;
+ /* Fall through. */
case 1:
*wp++ = '.';
*wp++ = *cp++;
@@ -2797,8 +2799,10 @@ print_statistics (hp_timing_t *rtld_total_timep)
{
case 3:
*wp++ = *cp++;
+ /* Fall through. */
case 2:
*wp++ = *cp++;
+ /* Fall through. */
case 1:
*wp++ = '.';
*wp++ = *cp++;
diff --git a/locale/programs/charmap.c b/locale/programs/charmap.c
index 2d54dd3c027d11d2..8041a0e5d292f3f5 100644
--- a/locale/programs/charmap.c
+++ b/locale/programs/charmap.c
@@ -713,6 +713,7 @@ only WIDTH definitions are allowed to follow the CHARMAP definition"));
state = 95;
continue;
}
+ /* Fall through. */
case 96:
if (nowtok != tok_number)
diff --git a/misc/mntent_r.c b/misc/mntent_r.c
index 7bb224f044150ab4..add39d4537eaccb5 100644
--- a/misc/mntent_r.c
+++ b/misc/mntent_r.c
@@ -167,8 +167,10 @@ get_mnt_entry (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
{
case 0:
mp->mnt_freq = 0;
+ /* Fall through. */
case 1:
mp->mnt_passno = 0;
+ /* Fall through. */
case 2:
break;
}
diff --git a/posix/wordexp.c b/posix/wordexp.c
index 7548e0329fdeafaa..048a8068544c81fa 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -799,6 +799,7 @@ parse_arith (char **word, size_t *word_length, size_t *max_length,
case '(':
++paren_depth;
+ /* Fall through. */
default:
expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
if (expr == NULL)
@@ -2127,6 +2128,7 @@ parse_backtick (char **word, size_t *word_length, size_t *max_length,
case '\'':
squoting = 1 - squoting;
+ /* Fall through. */
default:
comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
if (comm == NULL)
diff --git a/resolv/ns_ttl.c b/resolv/ns_ttl.c
index 079948790b94b05e..d29d9dc00cfcab2c 100644
--- a/resolv/ns_ttl.c
+++ b/resolv/ns_ttl.c
@@ -113,9 +113,13 @@ ns_parse_ttl(const char *src, u_long *dst) {
ch = toupper(ch);
switch (ch) {
case 'W': tmp *= 7;
+ /* Fall through. */
case 'D': tmp *= 24;
+ /* Fall through. */
case 'H': tmp *= 60;
+ /* Fall through. */
case 'M': tmp *= 60;
+ /* Fall through. */
case 'S': break;
default: goto einval;
}
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 3a02a9c7d08f9603..ade37a9bb3de86cc 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -374,6 +374,7 @@ init_cpu_features (struct cpu_features *cpu_features)
of Core i3/i5/i7 processors if AVX is available. */
if (!CPU_FEATURES_CPU_P (cpu_features, AVX))
break;
+ /* Fall through. */
case 0x1a:
case 0x1e:
@@ -401,6 +402,7 @@ init_cpu_features (struct cpu_features *cpu_features)
/* Xeon E7 v3 with stepping >= 4 has working TSX. */
if (stepping >= 4)
break;
+ /* Fall through. */
case 0x3c:
case 0x45:
case 0x46:
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index 1942ed5061d18c68..23afb3c05dbe17d6 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -347,6 +347,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
/* Set to symbol size plus addend. */
value = sym->st_size;
# endif
+ /* Fall through. */
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
*reloc_addr = value + reloc->r_addend;
@@ -460,6 +461,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
/* Set to symbol size plus addend. */
value = sym->st_size;
# endif
+ /* Fall through. */
case R_X86_64_32:
value += reloc->r_addend;
*(unsigned int *) reloc_addr = value;

View File

@ -0,0 +1,408 @@
commit 3b856d093f5197637a5927c37d6c07dad8c86d45
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Feb 12 13:36:56 2019 +0100
elf: Ignore LD_AUDIT interfaces if la_version returns 0 [BZ #24122]
This change moves the audit module loading and early notification into
separate functions out of dl_main.
It restores the bug fix from commit
8e889c5da3c5981c5a46a93fec02de40131ac5a6 ("elf: Fix LD_AUDIT for
modules with invalid version (BZ#24122)") which was reverted in commit
83e6b59625f45db1eee93e5684091f740c52a083 ("[elf] Revert 8e889c5da3
(BZ#24122)").
The actual bug fix is the separate error message for the case when
la_version returns zero. The dynamic linker error message (which is
NULL in this case) is no longer used. Based on the intended use of
version zero (ignore this module due to explicit request), the message
is only printed if debugging is enabled.
diff --git a/elf/rtld.c b/elf/rtld.c
index 8bb5f548a0ff8eb4..375e0de8fa2e049e 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -864,6 +864,205 @@ handle_preload_list (const char *preloadlist, struct link_map *main_map,
return npreloads;
}
+/* Called if the audit DSO cannot be used: if it does not have the
+ appropriate interfaces, or it expects a more recent version library
+ version than what the dynamic linker provides. */
+static void
+unload_audit_module (struct link_map *map, int original_tls_idx)
+{
+#ifndef NDEBUG
+ Lmid_t ns = map->l_ns;
+#endif
+ _dl_close (map);
+
+ /* Make sure the namespace has been cleared entirely. */
+ assert (GL(dl_ns)[ns]._ns_loaded == NULL);
+ assert (GL(dl_ns)[ns]._ns_nloaded == 0);
+
+ GL(dl_tls_max_dtv_idx) = original_tls_idx;
+}
+
+/* Called to print an error message if loading of an audit module
+ failed. */
+static void
+report_audit_module_load_error (const char *name, const char *err_str,
+ bool malloced)
+{
+ _dl_error_printf ("\
+ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ name, err_str);
+ if (malloced)
+ free ((char *) err_str);
+}
+
+/* Load one audit module. */
+static void
+load_audit_module (const char *name, struct audit_ifaces **last_audit)
+{
+ int original_tls_idx = GL(dl_tls_max_dtv_idx);
+
+ struct dlmopen_args dlmargs;
+ dlmargs.fname = name;
+ dlmargs.map = NULL;
+
+ const char *objname;
+ const char *err_str = NULL;
+ bool malloced;
+ _dl_catch_error (&objname, &err_str, &malloced, dlmopen_doit, &dlmargs);
+ if (__glibc_unlikely (err_str != NULL))
+ {
+ report_audit_module_load_error (name, err_str, malloced);
+ return;
+ }
+
+ struct lookup_args largs;
+ largs.name = "la_version";
+ largs.map = dlmargs.map;
+ _dl_catch_error (&objname, &err_str, &malloced, lookup_doit, &largs);
+ if (__glibc_likely (err_str != NULL))
+ {
+ unload_audit_module (dlmargs.map, original_tls_idx);
+ report_audit_module_load_error (name, err_str, malloced);
+ return;
+ }
+
+ unsigned int (*laversion) (unsigned int) = largs.result;
+
+ /* A null symbol indicates that something is very wrong with the
+ loaded object because defined symbols are supposed to have a
+ valid, non-null address. */
+ assert (laversion != NULL);
+
+ unsigned int lav = laversion (LAV_CURRENT);
+ if (lav == 0)
+ {
+ /* Only print an error message if debugging because this can
+ happen deliberately. */
+ if (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
+ _dl_debug_printf ("\
+file=%s [%lu]; audit interface function la_version returned zero; ignored.\n",
+ dlmargs.map->l_name, dlmargs.map->l_ns);
+ unload_audit_module (dlmargs.map, original_tls_idx);
+ return;
+ }
+
+ if (lav > LAV_CURRENT)
+ {
+ _dl_debug_printf ("\
+ERROR: audit interface '%s' requires version %d (maximum supported version %d); ignored.\n",
+ name, lav, LAV_CURRENT);
+ unload_audit_module (dlmargs.map, original_tls_idx);
+ return;
+ }
+
+ enum { naudit_ifaces = 8 };
+ union
+ {
+ struct audit_ifaces ifaces;
+ void (*fptr[naudit_ifaces]) (void);
+ } *newp = malloc (sizeof (*newp));
+ if (newp == NULL)
+ _dl_fatal_printf ("Out of memory while loading audit modules\n");
+
+ /* Names of the auditing interfaces. All in one
+ long string. */
+ static const char audit_iface_names[] =
+ "la_activity\0"
+ "la_objsearch\0"
+ "la_objopen\0"
+ "la_preinit\0"
+#if __ELF_NATIVE_CLASS == 32
+ "la_symbind32\0"
+#elif __ELF_NATIVE_CLASS == 64
+ "la_symbind64\0"
+#else
+# error "__ELF_NATIVE_CLASS must be defined"
+#endif
+#define STRING(s) __STRING (s)
+ "la_" STRING (ARCH_LA_PLTENTER) "\0"
+ "la_" STRING (ARCH_LA_PLTEXIT) "\0"
+ "la_objclose\0";
+ unsigned int cnt = 0;
+ const char *cp = audit_iface_names;
+ do
+ {
+ largs.name = cp;
+ _dl_catch_error (&objname, &err_str, &malloced, lookup_doit, &largs);
+
+ /* Store the pointer. */
+ if (err_str == NULL && largs.result != NULL)
+ {
+ newp->fptr[cnt] = largs.result;
+
+ /* The dynamic linker link map is statically allocated,
+ initialize the data now. */
+ GL(dl_rtld_map).l_audit[cnt].cookie = (intptr_t) &GL(dl_rtld_map);
+ }
+ else
+ newp->fptr[cnt] = NULL;
+ ++cnt;
+
+ cp = rawmemchr (cp, '\0') + 1;
+ }
+ while (*cp != '\0');
+ assert (cnt == naudit_ifaces);
+
+ /* Now append the new auditing interface to the list. */
+ newp->ifaces.next = NULL;
+ if (*last_audit == NULL)
+ *last_audit = GLRO(dl_audit) = &newp->ifaces;
+ else
+ *last_audit = (*last_audit)->next = &newp->ifaces;
+ ++GLRO(dl_naudit);
+
+ /* Mark the DSO as being used for auditing. */
+ dlmargs.map->l_auditing = 1;
+}
+
+/* Notify the the audit modules that the object MAP has already been
+ loaded. */
+static void
+notify_audit_modules_of_loaded_object (struct link_map *map)
+{
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->objopen != NULL)
+ {
+ map->l_audit[cnt].bindflags
+ = afct->objopen (map, LM_ID_BASE, &map->l_audit[cnt].cookie);
+ map->l_audit_any_plt |= map->l_audit[cnt].bindflags != 0;
+ }
+
+ afct = afct->next;
+ }
+}
+
+/* Load all audit modules. */
+static void
+load_audit_modules (struct link_map *main_map)
+{
+ struct audit_ifaces *last_audit = NULL;
+ struct audit_list_iter al_iter;
+ audit_list_iter_init (&al_iter);
+
+ while (true)
+ {
+ const char *name = audit_list_iter_next (&al_iter);
+ if (name == NULL)
+ break;
+ load_audit_module (name, &last_audit);
+ }
+
+ /* Notify audit modules of the initially loaded modules (the main
+ program and the dynamic linker itself). */
+ if (GLRO(dl_naudit) > 0)
+ {
+ notify_audit_modules_of_loaded_object (main_map);
+ notify_audit_modules_of_loaded_object (&GL(dl_rtld_map));
+ }
+}
+
static void
dl_main (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
@@ -1402,10 +1601,6 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
if (__glibc_unlikely (audit_list != NULL)
|| __glibc_unlikely (audit_list_string != NULL))
{
- struct audit_ifaces *last_audit = NULL;
- struct audit_list_iter al_iter;
- audit_list_iter_init (&al_iter);
-
/* Since we start using the auditing DSOs right away we need to
initialize the data structures now. */
tcbp = init_tls ();
@@ -1417,164 +1612,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
security_init ();
need_security_init = false;
- while (true)
- {
- const char *name = audit_list_iter_next (&al_iter);
- if (name == NULL)
- break;
-
- int tls_idx = GL(dl_tls_max_dtv_idx);
-
- /* Now it is time to determine the layout of the static TLS
- block and allocate it for the initial thread. Note that we
- always allocate the static block, we never defer it even if
- no DF_STATIC_TLS bit is set. The reason is that we know
- glibc will use the static model. */
- struct dlmopen_args dlmargs;
- dlmargs.fname = name;
- dlmargs.map = NULL;
-
- const char *objname;
- const char *err_str = NULL;
- bool malloced;
- (void) _dl_catch_error (&objname, &err_str, &malloced, dlmopen_doit,
- &dlmargs);
- if (__glibc_unlikely (err_str != NULL))
- {
- not_loaded:
- _dl_error_printf ("\
-ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
- name, err_str);
- if (malloced)
- free ((char *) err_str);
- }
- else
- {
- struct lookup_args largs;
- largs.name = "la_version";
- largs.map = dlmargs.map;
-
- /* Check whether the interface version matches. */
- (void) _dl_catch_error (&objname, &err_str, &malloced,
- lookup_doit, &largs);
-
- unsigned int (*laversion) (unsigned int);
- unsigned int lav;
- if (err_str == NULL
- && (laversion = largs.result) != NULL
- && (lav = laversion (LAV_CURRENT)) > 0
- && lav <= LAV_CURRENT)
- {
- /* Allocate structure for the callback function pointers.
- This call can never fail. */
- union
- {
- struct audit_ifaces ifaces;
-#define naudit_ifaces 8
- void (*fptr[naudit_ifaces]) (void);
- } *newp = malloc (sizeof (*newp));
-
- /* Names of the auditing interfaces. All in one
- long string. */
- static const char audit_iface_names[] =
- "la_activity\0"
- "la_objsearch\0"
- "la_objopen\0"
- "la_preinit\0"
-#if __ELF_NATIVE_CLASS == 32
- "la_symbind32\0"
-#elif __ELF_NATIVE_CLASS == 64
- "la_symbind64\0"
-#else
-# error "__ELF_NATIVE_CLASS must be defined"
-#endif
-#define STRING(s) __STRING (s)
- "la_" STRING (ARCH_LA_PLTENTER) "\0"
- "la_" STRING (ARCH_LA_PLTEXIT) "\0"
- "la_objclose\0";
- unsigned int cnt = 0;
- const char *cp = audit_iface_names;
- do
- {
- largs.name = cp;
- (void) _dl_catch_error (&objname, &err_str, &malloced,
- lookup_doit, &largs);
-
- /* Store the pointer. */
- if (err_str == NULL && largs.result != NULL)
- {
- newp->fptr[cnt] = largs.result;
-
- /* The dynamic linker link map is statically
- allocated, initialize the data now. */
- GL(dl_rtld_map).l_audit[cnt].cookie
- = (intptr_t) &GL(dl_rtld_map);
- }
- else
- newp->fptr[cnt] = NULL;
- ++cnt;
-
- cp = (char *) rawmemchr (cp, '\0') + 1;
- }
- while (*cp != '\0');
- assert (cnt == naudit_ifaces);
-
- /* Now append the new auditing interface to the list. */
- newp->ifaces.next = NULL;
- if (last_audit == NULL)
- last_audit = GLRO(dl_audit) = &newp->ifaces;
- else
- last_audit = last_audit->next = &newp->ifaces;
- ++GLRO(dl_naudit);
-
- /* Mark the DSO as being used for auditing. */
- dlmargs.map->l_auditing = 1;
- }
- else
- {
- /* We cannot use the DSO, it does not have the
- appropriate interfaces or it expects something
- more recent. */
-#ifndef NDEBUG
- Lmid_t ns = dlmargs.map->l_ns;
-#endif
- _dl_close (dlmargs.map);
-
- /* Make sure the namespace has been cleared entirely. */
- assert (GL(dl_ns)[ns]._ns_loaded == NULL);
- assert (GL(dl_ns)[ns]._ns_nloaded == 0);
-
- GL(dl_tls_max_dtv_idx) = tls_idx;
- goto not_loaded;
- }
- }
- }
-
- /* If we have any auditing modules, announce that we already
- have two objects loaded. */
- if (__glibc_unlikely (GLRO(dl_naudit) > 0))
- {
- struct link_map *ls[2] = { main_map, &GL(dl_rtld_map) };
-
- for (unsigned int outer = 0; outer < 2; ++outer)
- {
- struct audit_ifaces *afct = GLRO(dl_audit);
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
- {
- if (afct->objopen != NULL)
- {
- ls[outer]->l_audit[cnt].bindflags
- = afct->objopen (ls[outer], LM_ID_BASE,
- &ls[outer]->l_audit[cnt].cookie);
-
- ls[outer]->l_audit_any_plt
- |= ls[outer]->l_audit[cnt].bindflags != 0;
- }
-
- afct = afct->next;
- }
- }
- }
+ load_audit_modules (main_map);
}
/* Keep track of the currently loaded modules to count how many

View File

@ -0,0 +1,401 @@
commit dce452dc5278f2985d21315721a6ba802537b862
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Aug 2 23:49:19 2018 +0530
Rename the glibc.tune namespace to glibc.cpu
The glibc.tune namespace is vaguely named since it is a 'tunable', so
give it a more specific name that describes what it refers to. Rename
the tunable namespace to 'cpu' to more accurately reflect what it
encompasses. Also rename glibc.tune.cpu to glibc.cpu.name since
glibc.cpu.cpu is weird.
* NEWS: Mention the change.
* elf/dl-tunables.list: Rename tune namespace to cpu.
* sysdeps/powerpc/dl-tunables.list: Likewise.
* sysdeps/x86/dl-tunables.list: Likewise.
* sysdeps/aarch64/dl-tunables.list: Rename tune.cpu to
cpu.name.
* elf/dl-hwcaps.c (_dl_important_hwcaps): Adjust.
* elf/dl-hwcaps.h (GET_HWCAP_MASK): Likewise.
* manual/README.tunables: Likewise.
* manual/tunables.texi: Likewise.
* sysdeps/powerpc/cpu-features.c: Likewise.
* sysdeps/unix/sysv/linux/aarch64/cpu-features.c
(init_cpu_features): Likewise.
* sysdeps/x86/cpu-features.c: Likewise.
* sysdeps/x86/cpu-features.h: Likewise.
* sysdeps/x86/cpu-tunables.c: Likewise.
* sysdeps/x86_64/Makefile: Likewise.
* sysdeps/x86/dl-cet.c: Likewise.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
manual/tunables.texi
(Earlier backport of non-temporal memcpy threshold.)
sysdeps/x86/Makefile
(Earlier CET backports.)
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
index 23482a88a1c9bca9..ecf00b457760e517 100644
--- a/elf/dl-hwcaps.c
+++ b/elf/dl-hwcaps.c
@@ -140,7 +140,7 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
string and bit like you can ignore an OS-supplied HWCAP bit. */
hwcap_mask |= (uint64_t) mask << _DL_FIRST_EXTRA;
#if HAVE_TUNABLES
- TUNABLE_SET (glibc, tune, hwcap_mask, uint64_t, hwcap_mask);
+ TUNABLE_SET (glibc, cpu, hwcap_mask, uint64_t, hwcap_mask);
#else
GLRO(dl_hwcap_mask) = hwcap_mask;
#endif
diff --git a/elf/dl-hwcaps.h b/elf/dl-hwcaps.h
index 17f0da4c73772425..d69ee11dc27bb5e5 100644
--- a/elf/dl-hwcaps.h
+++ b/elf/dl-hwcaps.h
@@ -19,7 +19,7 @@
#include <elf/dl-tunables.h>
#if HAVE_TUNABLES
-# define GET_HWCAP_MASK() TUNABLE_GET (glibc, tune, hwcap_mask, uint64_t, NULL)
+# define GET_HWCAP_MASK() TUNABLE_GET (glibc, cpu, hwcap_mask, uint64_t, NULL)
#else
# ifdef SHARED
# define GET_HWCAP_MASK() GLRO(dl_hwcap_mask)
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 1ff6fcb6f24f93a8..b7cc79f8bfe0a7c6 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -91,7 +91,7 @@ glibc {
security_level: SXID_IGNORE
}
}
- tune {
+ cpu {
hwcap_mask {
type: UINT_64
env_alias: LD_HWCAP_MASK
diff --git a/manual/README.tunables b/manual/README.tunables
index 3967679f432a6378..f87a31a65e0a3455 100644
--- a/manual/README.tunables
+++ b/manual/README.tunables
@@ -105,11 +105,11 @@ where 'check' is the tunable name, 'int32_t' is the C type of the tunable and
To get and set tunables in a different namespace from that module, use the full
form of the macros as follows:
- val = TUNABLE_GET_FULL (glibc, tune, hwcap_mask, uint64_t, NULL)
+ val = TUNABLE_GET_FULL (glibc, cpu, hwcap_mask, uint64_t, NULL)
- TUNABLE_SET_FULL (glibc, tune, hwcap_mask, uint64_t, val)
+ TUNABLE_SET_FULL (glibc, cpu, hwcap_mask, uint64_t, val)
-where 'glibc' is the top namespace, 'tune' is the tunable namespace and the
+where 'glibc' is the top namespace, 'cpu' is the tunable namespace and the
remaining arguments are the same as the short form macros.
When TUNABLE_NAMESPACE is not defined in a module, TUNABLE_GET is equivalent to
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 3e1e519dff153b09..ef10d2872cfc244e 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -307,23 +307,23 @@ The default value of this tunable is @samp{3}.
@cindex non_temporal_threshold tunables
@cindex tunables, non_temporal_threshold
-@deftp {Tunable namespace} glibc.tune
+@deftp {Tunable namespace} glibc.cpu
Behavior of @theglibc{} can be tuned to assume specific hardware capabilities
-by setting the following tunables in the @code{tune} namespace:
+by setting the following tunables in the @code{cpu} namespace:
@end deftp
-@deftp Tunable glibc.tune.hwcap_mask
+@deftp Tunable glibc.cpu.hwcap_mask
This tunable supersedes the @env{LD_HWCAP_MASK} environment variable and is
identical in features.
The @code{AT_HWCAP} key in the Auxiliary Vector specifies instruction set
extensions available in the processor at runtime for some architectures. The
-@code{glibc.tune.hwcap_mask} tunable allows the user to mask out those
+@code{glibc.cpu.hwcap_mask} tunable allows the user to mask out those
capabilities at runtime, thus disabling use of those extensions.
@end deftp
-@deftp Tunable glibc.tune.hwcaps
-The @code{glibc.tune.hwcaps=-xxx,yyy,-zzz...} tunable allows the user to
+@deftp Tunable glibc.cpu.hwcaps
+The @code{glibc.cpu.hwcaps=-xxx,yyy,-zzz...} tunable allows the user to
enable CPU/ARCH feature @code{yyy}, disable CPU/ARCH feature @code{xxx}
and @code{zzz} where the feature name is case-sensitive and has to match
the ones in @code{sysdeps/x86/cpu-features.h}.
@@ -331,8 +331,8 @@ the ones in @code{sysdeps/x86/cpu-features.h}.
This tunable is specific to i386 and x86-64.
@end deftp
-@deftp Tunable glibc.tune.cached_memopt
-The @code{glibc.tune.cached_memopt=[0|1]} tunable allows the user to
+@deftp Tunable glibc.cpu.cached_memopt
+The @code{glibc.cpu.cached_memopt=[0|1]} tunable allows the user to
enable optimizations recommended for cacheable memory. If set to
@code{1}, @theglibc{} assumes that the process memory image consists
of cacheable (non-device) memory only. The default, @code{0},
@@ -341,8 +341,8 @@ indicates that the process may use device memory.
This tunable is specific to powerpc, powerpc64 and powerpc64le.
@end deftp
-@deftp Tunable glibc.tune.cpu
-The @code{glibc.tune.cpu=xxx} tunable allows the user to tell @theglibc{} to
+@deftp Tunable glibc.cpu.name
+The @code{glibc.cpu.name=xxx} tunable allows the user to tell @theglibc{} to
assume that the CPU is @code{xxx} where xxx may have one of these values:
@code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99},
@code{thunderx2t99p1}.
@@ -350,20 +350,20 @@ assume that the CPU is @code{xxx} where xxx may have one of these values:
This tunable is specific to aarch64.
@end deftp
-@deftp Tunable glibc.tune.x86_data_cache_size
-The @code{glibc.tune.x86_data_cache_size} tunable allows the user to set
+@deftp Tunable glibc.cpu.x86_data_cache_size
+The @code{glibc.cpu.x86_data_cache_size} tunable allows the user to set
data cache size in bytes for use in memory and string routines.
This tunable is specific to i386 and x86-64.
@end deftp
-@deftp Tunable glibc.tune.x86_shared_cache_size
-The @code{glibc.tune.x86_shared_cache_size} tunable allows the user to
+@deftp Tunable glibc.cpu.x86_shared_cache_size
+The @code{glibc.cpu.x86_shared_cache_size} tunable allows the user to
set shared cache size in bytes for use in memory and string routines.
@end deftp
-@deftp Tunable glibc.tune.x86_non_temporal_threshold
-The @code{glibc.tune.x86_non_temporal_threshold} tunable allows the user
+@deftp Tunable glibc.cpu.x86_non_temporal_threshold
+The @code{glibc.cpu.x86_non_temporal_threshold} tunable allows the user
to set threshold in bytes for non temporal store. Non temporal stores
give a hint to the hardware to move data directly to memory without
displacing other data from the cache. This tunable is used by some
@@ -373,8 +373,8 @@ like memmove and memcpy.
This tunable is specific to i386 and x86-64.
@end deftp
-@deftp Tunable glibc.tune.x86_ibt
-The @code{glibc.tune.x86_ibt} tunable allows the user to control how
+@deftp Tunable glibc.cpu.x86_ibt
+The @code{glibc.cpu.x86_ibt} tunable allows the user to control how
indirect branch tracking (IBT) should be enabled. Accepted values are
@code{on}, @code{off}, and @code{permissive}. @code{on} always turns
on IBT regardless of whether IBT is enabled in the executable and its
@@ -386,8 +386,8 @@ IBT on non-CET executables and shared libraries.
This tunable is specific to i386 and x86-64.
@end deftp
-@deftp Tunable glibc.tune.x86_shstk
-The @code{glibc.tune.x86_shstk} tunable allows the user to control how
+@deftp Tunable glibc.cpu.x86_shstk
+The @code{glibc.cpu.x86_shstk} tunable allows the user to control how
the shadow stack (SHSTK) should be enabled. Accepted values are
@code{on}, @code{off}, and @code{permissive}. @code{on} always turns on
SHSTK regardless of whether SHSTK is enabled in the executable and its
diff --git a/sysdeps/aarch64/dl-tunables.list b/sysdeps/aarch64/dl-tunables.list
index f6a88168cc5ec7e6..cfcf940ebd15a9aa 100644
--- a/sysdeps/aarch64/dl-tunables.list
+++ b/sysdeps/aarch64/dl-tunables.list
@@ -17,8 +17,8 @@
# <http://www.gnu.org/licenses/>.
glibc {
- tune {
- cpu {
+ cpu {
+ name {
type: STRING
}
}
diff --git a/sysdeps/powerpc/cpu-features.c b/sysdeps/powerpc/cpu-features.c
index 955d4778a69db607..ad809b9815eb68f0 100644
--- a/sysdeps/powerpc/cpu-features.c
+++ b/sysdeps/powerpc/cpu-features.c
@@ -30,7 +30,7 @@ init_cpu_features (struct cpu_features *cpu_features)
tunables is enable, since for this case user can explicit disable
unaligned optimizations. */
#if HAVE_TUNABLES
- int32_t cached_memfunc = TUNABLE_GET (glibc, tune, cached_memopt, int32_t,
+ int32_t cached_memfunc = TUNABLE_GET (glibc, cpu, cached_memopt, int32_t,
NULL);
cpu_features->use_cached_memopt = (cached_memfunc > 0);
#else
diff --git a/sysdeps/powerpc/dl-tunables.list b/sysdeps/powerpc/dl-tunables.list
index d26636a16bfcd6d9..b3372555f75f8e38 100644
--- a/sysdeps/powerpc/dl-tunables.list
+++ b/sysdeps/powerpc/dl-tunables.list
@@ -17,7 +17,7 @@
# <http://www.gnu.org/licenses/>.
glibc {
- tune {
+ cpu {
cached_memopt {
type: INT_32
minval: 0
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index 39eba0186f55b5de..b4f348509eb1c6b3 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -57,7 +57,7 @@ init_cpu_features (struct cpu_features *cpu_features)
#if HAVE_TUNABLES
/* Get the tunable override. */
- const char *mcpu = TUNABLE_GET (glibc, tune, cpu, const char *, NULL);
+ const char *mcpu = TUNABLE_GET (glibc, cpu, name, const char *, NULL);
if (mcpu != NULL)
midr = get_midr_from_mcpu (mcpu);
#endif
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index d5f821e0831997ac..a936134a577e42a5 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -84,21 +84,21 @@ LDFLAGS-tst-cet-legacy-mod-6c.so = -Wl,--enable-new-dtags,-z,nodelete
ifneq (no,$(have-tunables))
$(objpfx)tst-cet-legacy-4a: $(libdl)
$(objpfx)tst-cet-legacy-4a.out: $(objpfx)tst-cet-legacy-mod-4.so
-tst-cet-legacy-4a-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=permissive
+tst-cet-legacy-4a-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=permissive
$(objpfx)tst-cet-legacy-4b: $(libdl)
$(objpfx)tst-cet-legacy-4b.out: $(objpfx)tst-cet-legacy-mod-4.so
-tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=on
+tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=on
$(objpfx)tst-cet-legacy-4c: $(libdl)
$(objpfx)tst-cet-legacy-4c.out: $(objpfx)tst-cet-legacy-mod-4.so
-tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=off
+tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=off
$(objpfx)tst-cet-legacy-5b: $(libdl)
$(objpfx)tst-cet-legacy-5b.out: $(objpfx)tst-cet-legacy-mod-5a.so \
$(objpfx)tst-cet-legacy-mod-5b.so
-tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off
+tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=off:glibc.cpu.x86_shstk=off
$(objpfx)tst-cet-legacy-6b: $(libdl)
$(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \
$(objpfx)tst-cet-legacy-mod-6b.so
-tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off
+tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=off:glibc.cpu.x86_shstk=off
endif
endif
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 41f2d15fa5c8a756..3b268efbce627e6c 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -22,7 +22,7 @@
#include <libc-pointer-arith.h>
#if HAVE_TUNABLES
-# define TUNABLE_NAMESPACE tune
+# define TUNABLE_NAMESPACE cpu
# include <unistd.h> /* Get STDOUT_FILENO for _dl_printf. */
# include <elf/dl-tunables.h>
@@ -424,7 +424,7 @@ no_cpuid:
/* Reuse dl_platform, dl_hwcap and dl_hwcap_mask for x86. */
#if !HAVE_TUNABLES && defined SHARED
- /* The glibc.tune.hwcap_mask tunable is initialized already, so no need to do
+ /* The glibc.cpu.hwcap_mask tunable is initialized already, so no need to do
this. */
GLRO(dl_hwcap_mask) = HWCAP_IMPORTANT;
#endif
@@ -499,7 +499,7 @@ no_cpuid:
/* Disable IBT and/or SHSTK if they are enabled by kernel, but
disabled by environment variable:
- GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK
+ GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
*/
unsigned int cet_feature = 0;
if (!HAS_CPU_FEATURE (IBT))
diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h
index 347a4b118d007fd8..4c6d08c709eea204 100644
--- a/sysdeps/x86/cpu-features.h
+++ b/sysdeps/x86/cpu-features.h
@@ -141,7 +141,7 @@ struct cpu_features
unsigned long int xsave_state_size;
/* The full state size for XSAVE when XSAVEC is disabled by
- GLIBC_TUNABLES=glibc.tune.hwcaps=-XSAVEC_Usable
+ GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable
*/
unsigned int xsave_state_full_size;
unsigned int feature[FEATURE_INDEX_MAX];
diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c
index fad6726882fa7e2d..2e5d37753713e975 100644
--- a/sysdeps/x86/cpu-tunables.c
+++ b/sysdeps/x86/cpu-tunables.c
@@ -17,7 +17,7 @@
<http://www.gnu.org/licenses/>. */
#if HAVE_TUNABLES
-# define TUNABLE_NAMESPACE tune
+# define TUNABLE_NAMESPACE cpu
# include <stdbool.h>
# include <stdint.h>
# include <unistd.h> /* Get STDOUT_FILENO for _dl_printf. */
@@ -116,7 +116,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
the hardware which wasn't available when the selection was made.
The environment variable:
- GLIBC_TUNABLES=glibc.tune.hwcaps=-xxx,yyy,-zzz,....
+ GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,-zzz,....
can be used to enable CPU/ARCH feature yyy, disable CPU/ARCH feature
yyy and zzz, where the feature name is case-sensitive and has to
diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c
index ebc0d577e414c807..d481bddc27e5d7cc 100644
--- a/sysdeps/x86/dl-cet.c
+++ b/sysdeps/x86/dl-cet.c
@@ -72,7 +72,7 @@ dl_cet_check (struct link_map *m, const char *program)
/* Enable IBT and SHSTK only if they are enabled in executable.
NB: IBT and SHSTK may be disabled by environment variable:
- GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK
+ GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
*/
enable_ibt &= (HAS_CPU_FEATURE (IBT)
&& (enable_ibt_type == cet_always_on
diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list
index 73886b1352316854..2a457d0eec9c3122 100644
--- a/sysdeps/x86/dl-tunables.list
+++ b/sysdeps/x86/dl-tunables.list
@@ -17,7 +17,7 @@
# <http://www.gnu.org/licenses/>.
glibc {
- tune {
+ cpu {
hwcaps {
type: STRING
}
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
index 9f1562f1b25a2df5..d51cf03ac92ebcc2 100644
--- a/sysdeps/x86_64/Makefile
+++ b/sysdeps/x86_64/Makefile
@@ -57,7 +57,7 @@ modules-names += x86_64/tst-x86_64mod-1
LDFLAGS-tst-x86_64mod-1.so = -Wl,-soname,tst-x86_64mod-1.so
ifneq (no,$(have-tunables))
# Test the state size for XSAVE when XSAVEC is disabled.
-tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.tune.hwcaps=-XSAVEC_Usable
+tst-x86_64-1-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC_Usable
endif
$(objpfx)tst-x86_64-1: $(objpfx)x86_64/tst-x86_64mod-1.so
@@ -74,7 +74,7 @@ $(objpfx)tst-platform-1.out: $(objpfx)x86_64/tst-platformmod-2.so
# Turn off AVX512F_Usable and AVX2_Usable so that GLRO(dl_platform) is
# always set to x86_64.
tst-platform-1-ENV = LD_PRELOAD=$(objpfx)\$$PLATFORM/tst-platformmod-2.so \
- GLIBC_TUNABLES=glibc.tune.hwcaps=-AVX512F_Usable,-AVX2_Usable
+ GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX512F_Usable,-AVX2_Usable
endif
tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \

View File

@ -0,0 +1,179 @@
commit b3fbfe81961a1d14d7b54d1c9757e1f487073bcb
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Tue Feb 12 13:51:43 2019 +0100
elf: Test for LD_AUDIT module returning zero from la_version [BZ #24122]
This includes the original test case from commit
8e889c5da3c5981c5a46a93fec02de40131ac5a6 ("elf: Fix LD_AUDIT for
modules with invalid version (BZ#24122)).
Conflicts:
elf/Makefile
(Different backport order of tests.)
diff --git a/elf/Makefile b/elf/Makefile
index 6d1962b2e4deb871..4e1356b9172aee02 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -191,6 +191,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
+ tst-audit13 \
tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \
tst-dlopenfail tst-dlopenfail-2 \
tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen
@@ -300,7 +301,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \
tst-absolute-zero-lib tst-big-note-lib \
- tst-sonamemove-linkmod1 \
+ tst-audit13mod1 tst-sonamemove-linkmod1 \
tst-sonamemove-runmod1 tst-sonamemove-runmod2 \
tst-initlazyfailmod tst-finilazyfailmod \
tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
@@ -1428,6 +1429,10 @@ tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so
$(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so
LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map
+$(objpfx)tst-audit13.out: $(objpfx)tst-audit13mod1.so
+LDFLAGS-tst-audit13mod1.so = -Wl,-z,lazy
+tst-audit13-ENV = LD_AUDIT=$(objpfx)tst-audit13mod1.so
+
# tst-sonamemove links against an older implementation of the library.
LDFLAGS-tst-sonamemove-linkmod1.so = \
-Wl,--version-script=tst-sonamemove-linkmod1.map \
diff --git a/elf/tst-audit13.c b/elf/tst-audit13.c
new file mode 100644
index 0000000000000000..6f587baf581ce32c
--- /dev/null
+++ b/elf/tst-audit13.c
@@ -0,0 +1,28 @@
+/* Check for invalid audit version (BZ#24122).
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ puts ("plt call");
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-audit13mod1.c b/elf/tst-audit13mod1.c
new file mode 100644
index 0000000000000000..cf017e235c7ae030
--- /dev/null
+++ b/elf/tst-audit13mod1.c
@@ -0,0 +1,93 @@
+/* Check for invalid audit version (BZ#24122).
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <stdlib.h>
+
+unsigned int
+la_version (unsigned int version)
+{
+ /* The audit specification says that a version of 0 or a version
+ greater than any version supported by the dynamic loader shall
+ cause the module to be ignored. */
+ return 0;
+}
+
+void
+la_activity (uintptr_t *cookie, unsigned int flag)
+{
+ exit (EXIT_FAILURE);
+}
+
+char *
+la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag)
+{
+ exit (EXIT_FAILURE);
+}
+
+unsigned int
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t * cookie)
+{
+ exit (EXIT_FAILURE);
+}
+
+void
+la_preinit (uintptr_t * cookie)
+{
+ exit (EXIT_FAILURE);
+}
+
+uintptr_t
+#if __ELF_NATIVE_CLASS == 32
+la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+#else
+la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+#endif
+{
+ exit (EXIT_FAILURE);
+}
+
+unsigned int
+la_objclose (uintptr_t * cookie)
+{
+ exit (EXIT_FAILURE);
+}
+
+#include <tst-audit.h>
+#if (!defined (pltenter) || !defined (pltexit) || !defined (La_regs) \
+ || !defined (La_retval) || !defined (int_retval))
+# error "architecture specific code needed in sysdeps/CPU/tst-audit.h"
+#endif
+
+ElfW(Addr)
+pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, La_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ exit (EXIT_FAILURE);
+}
+
+unsigned int
+pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const La_regs *inregs, La_retval *outregs,
+ const char *symname)
+{
+ exit (EXIT_FAILURE);
+}

View File

@ -0,0 +1,29 @@
commit 86140c6223b5d14d773cf3050ffd0d14977c2c2d
Author: Joseph Myers <joseph@codesourcery.com>
Date: Wed Feb 13 13:34:24 2019 +0000
Avoid fall-through in test-container if execlp fails.
One of the implicit-fallthrough warnings from compiling glibc with
-Wextra appears to indicate an actual bug: the test-container code
could fall through inappropriately if execlp returns (which only
occurs on error). This patch adds appropriate error handling in this
case to avoid that fall-through.
Tested for x86_64.
* support/test-container.c (recursive_remove): Use FAIL_EXIT1 if
execlp returns.
diff --git a/support/test-container.c b/support/test-container.c
index 1d1aebeaf3412573..f0d9e3060e80bda5 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -361,6 +361,7 @@ recursive_remove (char *path)
case 0:
/* Child. */
execlp ("rm", "rm", "-rf", path, NULL);
+ FAIL_EXIT1 ("exec rm: %m");
default:
/* Parent. */
waitpid (child, &status, 0);

View File

@ -0,0 +1,223 @@
commit 77b6f5534778b5403c87fa5415625aeb4c3cbf44
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Wed Jan 16 17:30:07 2019 +0000
linux: Assume clock_getres CLOCK_{PROCESS,THREAD}_CPUTIME_ID
The Linux 3.2 clock_getres kernel code (kernel/posix-cpu-timers.c)
issued for clock_getres CLOCK_PROCESS_CPUTIME_ID (process_cpu_clock_getres)
and CLOCK_THREAD_CPUTIME_ID (thread_cpu_clock_getres) call
posix_cpu_clock_getres. And it fails on check_clock only if an invalid
clock is used (not the case) or if we pass an invalid the pid/tid in
29 msb of clock_id (not the case either).
This patch assumes that clock_getres syscall always support
CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID, so there is no need
to fallback to hp-timing support for _SC_MONOTONIC_CLOCK neither to issue
the syscall to certify the clock_id is supported bt the kernel. This
allows simplify the sysconf support to always use the syscall.
it also removes ia64 itc drift check and assume kernel handles it correctly.
Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu.
* sysdeps/unix/sysv/linux/ia64/has_cpuclock.c: Remove file.
* sysdeps/unix/sysv/linux/ia64/sysconf.c: Likewise.
* sysdeps/unix/sysv/linux/sysconf.c (has_cpuclock): Remove function.
(__sysconf): Assume kernel support for _SC_MONOTONIC_CLOCK,
_SC_CPUTIME, and _SC_THREAD_CPUTIME.
Conflicts:
sysdeps/unix/sysv/linux/ia64/has_cpuclock.c
sysdeps/unix/sysv/linux/ia64/sysconf.c
(Removal after copyright year update.)
diff --git a/sysdeps/unix/sysv/linux/ia64/has_cpuclock.c b/sysdeps/unix/sysv/linux/ia64/has_cpuclock.c
deleted file mode 100644
index 75f3ef9f4d1366fb..0000000000000000
--- a/sysdeps/unix/sysv/linux/ia64/has_cpuclock.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2000-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.
-
- 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 <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <not-cancel.h>
-
-static int itc_usable;
-
-static int
-has_cpuclock (void)
-{
- if (__builtin_expect (itc_usable == 0, 0))
- {
- int newval = 1;
- int fd = __open_nocancel ("/proc/sal/itc_drift", O_RDONLY);
- if (__builtin_expect (fd != -1, 1))
- {
- char buf[16];
- /* We expect the file to contain a single digit followed by
- a newline. If the format changes we better not rely on
- the file content. */
- if (__read_nocancel (fd, buf, sizeof buf) != 2
- || buf[0] != '0' || buf[1] != '\n')
- newval = -1;
-
- __close_nocancel_nostatus (fd);
- }
-
- itc_usable = newval;
- }
-
- return itc_usable;
-}
diff --git a/sysdeps/unix/sysv/linux/ia64/sysconf.c b/sysdeps/unix/sysv/linux/ia64/sysconf.c
deleted file mode 100644
index 6c39db5a4af3e15a..0000000000000000
--- a/sysdeps/unix/sysv/linux/ia64/sysconf.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Get file-specific information about a file. Linux/ia64 version.
- Copyright (C) 2003-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.
-
- 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 <assert.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-
-#include "has_cpuclock.c"
-#define HAS_CPUCLOCK(name) (has_cpuclock () ? _POSIX_VERSION : -1)
-
-
-/* Now the generic Linux version. */
-#include <sysdeps/unix/sysv/linux/sysconf.c>
diff --git a/sysdeps/unix/sysv/linux/sysconf.c b/sysdeps/unix/sysv/linux/sysconf.c
index 4e49ebaa7a25748c..6fab1601034e4724 100644
--- a/sysdeps/unix/sysv/linux/sysconf.c
+++ b/sysdeps/unix/sysv/linux/sysconf.c
@@ -35,34 +35,6 @@
static long int posix_sysconf (int name);
-#ifndef HAS_CPUCLOCK
-static long int
-has_cpuclock (int name)
-{
-# if defined __NR_clock_getres || HP_TIMING_AVAIL
- /* If we have HP_TIMING, we will fall back on that if the system
- call does not work, so we support it either way. */
-# if !HP_TIMING_AVAIL
- /* Check using the clock_getres system call. */
- struct timespec ts;
- INTERNAL_SYSCALL_DECL (err);
- int r = INTERNAL_SYSCALL (clock_getres, err, 2,
- (name == _SC_CPUTIME
- ? CLOCK_PROCESS_CPUTIME_ID
- : CLOCK_THREAD_CPUTIME_ID),
- &ts);
- if (INTERNAL_SYSCALL_ERROR_P (r, err))
- return -1;
-# endif
- return _POSIX_VERSION;
-# else
- return -1;
-# endif
-}
-# define HAS_CPUCLOCK(name) has_cpuclock (name)
-#endif
-
-
/* Get the value of the system variable NAME. */
long int
__sysconf (int name)
@@ -71,29 +43,20 @@ __sysconf (int name)
switch (name)
{
- struct rlimit rlimit;
-#ifdef __NR_clock_getres
case _SC_MONOTONIC_CLOCK:
- /* Check using the clock_getres system call. */
- {
- struct timespec ts;
- INTERNAL_SYSCALL_DECL (err);
- int r;
- r = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts);
- return INTERNAL_SYSCALL_ERROR_P (r, err) ? -1 : _POSIX_VERSION;
- }
-#endif
-
case _SC_CPUTIME:
case _SC_THREAD_CPUTIME:
- return HAS_CPUCLOCK (name);
+ return _POSIX_VERSION;
case _SC_ARG_MAX:
- /* Use getrlimit to get the stack limit. */
- if (__getrlimit (RLIMIT_STACK, &rlimit) == 0)
- return MAX (legacy_ARG_MAX, rlimit.rlim_cur / 4);
+ {
+ struct rlimit rlimit;
+ /* Use getrlimit to get the stack limit. */
+ if (__getrlimit (RLIMIT_STACK, &rlimit) == 0)
+ return MAX (legacy_ARG_MAX, rlimit.rlim_cur / 4);
- return legacy_ARG_MAX;
+ return legacy_ARG_MAX;
+ }
case _SC_NGROUPS_MAX:
/* Try to read the information from the /proc/sys/kernel/ngroups_max
@@ -102,11 +65,14 @@ __sysconf (int name)
break;
case _SC_SIGQUEUE_MAX:
- if (__getrlimit (RLIMIT_SIGPENDING, &rlimit) == 0)
- return rlimit.rlim_cur;
+ {
+ struct rlimit rlimit;
+ if (__getrlimit (RLIMIT_SIGPENDING, &rlimit) == 0)
+ return rlimit.rlim_cur;
- /* The /proc/sys/kernel/rtsig-max file contains the answer. */
- procfname = "/proc/sys/kernel/rtsig-max";
+ /* The /proc/sys/kernel/rtsig-max file contains the answer. */
+ procfname = "/proc/sys/kernel/rtsig-max";
+ }
break;
default:

View File

@ -0,0 +1,211 @@
commit 359653aaacad463d916323f03c0ac3c47405aafa
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Wed Jan 16 18:10:56 2019 +0000
Do not use HP_TIMING_NOW for random bits
This patch removes the HP_TIMING_BITS usage for fast random bits and replace
with clock_gettime (CLOCK_MONOTONIC). It has unspecified starting time and
nano-second accuracy, so its randomness is significantly better than
gettimeofday.
Althoug it should incur in more overhead (specially for architecture that
support hp-timing), the symbol is also common implemented as a vDSO.
Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. I also
checked on a i686-gnu build.
* include/random-bits.h: New file.
* resolv/res_mkquery.c [HP_TIMING_AVAIL] (RANDOM_BITS,
(__res_context_mkquery): Remove usage hp-timing usage and replace with
random_bits.
* resolv/res_send.c [HP_TIMING_AVAIL] (nameserver_offset): Likewise.
* sysdeps/posix/tempname.c [HP_TIMING_AVAIL] (__gen_tempname):
Likewise.
diff --git a/include/random-bits.h b/include/random-bits.h
new file mode 100644
index 0000000000000000..a0651a5a34f80a8d
--- /dev/null
+++ b/include/random-bits.h
@@ -0,0 +1,41 @@
+/* Fast pseudo-random bits based on clock_gettime.
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _RANDOM_BITS_H
+# define _RANDOM_BITS_H
+
+#include <time.h>
+#include <stdint.h>
+
+/* Provides fast pseudo-random bits through clock_gettime. It has unspecified
+ starting time, nano-second accuracy, its randomness is significantly better
+ than gettimeofday, and for mostly architectures it is implemented through
+ vDSO instead of a syscall. Since the source is a system clock, the upper
+ bits will have less entropy. */
+static inline uint32_t
+random_bits (void)
+{
+ struct timespec tv;
+ __clock_gettime (CLOCK_MONOTONIC, &tv);
+ /* Shuffle the lower bits to minimize the clock bias. */
+ uint32_t ret = tv.tv_nsec ^ tv.tv_sec;
+ ret ^= (ret << 24) | (ret >> 8);
+ return ret;
+}
+
+#endif
diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
index 213abeefadf7ece5..4471a8838b1de7ee 100644
--- a/resolv/res_mkquery.c
+++ b/resolv/res_mkquery.c
@@ -82,6 +82,7 @@
* SOFTWARE.
*/
+#include <stdint.h>
#include <sys/types.h>
#include <sys/param.h>
#include <netinet/in.h>
@@ -92,12 +93,7 @@
#include <string.h>
#include <sys/time.h>
#include <shlib-compat.h>
-
-#include <hp-timing.h>
-#include <stdint.h>
-#if HP_TIMING_AVAIL
-# define RANDOM_BITS(Var) { uint64_t v64; HP_TIMING_NOW (v64); Var = v64; }
-#endif
+#include <random-bits.h>
int
__res_context_mkquery (struct resolv_context *ctx, int op, const char *dname,
@@ -120,16 +116,7 @@ __res_context_mkquery (struct resolv_context *ctx, int op, const char *dname,
/* We randomize the IDs every time. The old code just incremented
by one after the initial randomization which still predictable if
the application does multiple requests. */
- int randombits;
-#ifdef RANDOM_BITS
- RANDOM_BITS (randombits);
-#else
- struct timeval tv;
- __gettimeofday (&tv, NULL);
- randombits = (tv.tv_sec << 8) ^ tv.tv_usec;
-#endif
-
- hp->id = randombits;
+ hp->id = random_bits ();
hp->opcode = op;
hp->rd = (ctx->resp->options & RES_RECURSE) != 0;
hp->rcode = NOERROR;
diff --git a/resolv/res_send.c b/resolv/res_send.c
index ac19627634281c2f..55e7fa438e7baac1 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -109,7 +109,7 @@
#include <unistd.h>
#include <kernel-features.h>
#include <libc-diag.h>
-#include <hp-timing.h>
+#include <random-bits.h>
#if PACKETSZ > 65536
#define MAXPACKET PACKETSZ
@@ -309,15 +309,7 @@ nameserver_offset (struct __res_state *statp)
if ((offset & 1) == 0)
{
/* Initialization is required. */
-#if HP_TIMING_AVAIL
- uint64_t ticks;
- HP_TIMING_NOW (ticks);
- offset = ticks;
-#else
- struct timeval tv;
- __gettimeofday (&tv, NULL);
- offset = ((tv.tv_sec << 8) ^ tv.tv_usec);
-#endif
+ offset = random_bits ();
/* The lowest bit is the most random. Preserve it. */
offset <<= 1;
diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c
index 432262a03b6ecc23..3d26f378021680ae 100644
--- a/sysdeps/posix/tempname.c
+++ b/sysdeps/posix/tempname.c
@@ -71,22 +71,15 @@
#endif
#ifdef _LIBC
-# include <hp-timing.h>
-# if HP_TIMING_AVAIL
-# define RANDOM_BITS(Var) \
- if (__glibc_unlikely (value == UINT64_C (0))) \
- { \
- /* If this is the first time this function is used initialize \
- the variable we accumulate the value in to some somewhat \
- random value. If we'd not do this programs at startup time \
- might have a reduced set of possible names, at least on slow \
- machines. */ \
- struct timeval tv; \
- __gettimeofday (&tv, NULL); \
- value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \
- } \
- HP_TIMING_NOW (Var)
-# endif
+# include <random-bits.h>
+# define RANDOM_BITS(Var) ((Var) = random_bits ())
+# else
+# define RANDOM_BITS(Var) \
+ { \
+ struct timeval tv; \
+ __gettimeofday (&tv, NULL); \
+ (Var) = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \
+ }
#endif
/* Use the widest available unsigned type if uint64_t is not
@@ -193,8 +186,7 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
{
int len;
char *XXXXXX;
- static uint64_t value;
- uint64_t random_time_bits;
+ uint64_t value;
unsigned int count;
int fd = -1;
int save_errno = errno;
@@ -227,16 +219,8 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
XXXXXX = &tmpl[len - 6 - suffixlen];
/* Get some more or less random data. */
-#ifdef RANDOM_BITS
- RANDOM_BITS (random_time_bits);
-#else
- {
- struct timeval tv;
- __gettimeofday (&tv, NULL);
- random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
- }
-#endif
- value += random_time_bits ^ __getpid ();
+ RANDOM_BITS (value);
+ value ^= (uint64_t)__getpid () << 32;
for (count = 0; count < attempts; value += 7777, ++count)
{

View File

@ -0,0 +1,702 @@
commit 1e372ded4f83362509c8672ff501cba871bb1edc
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu Jan 24 12:46:59 2019 +0000
Refactor hp-timing rtld usage
This patch refactor how hp-timing is used on loader code for statistics
report. The HP_TIMING_AVAIL and HP_SMALL_TIMING_AVAIL are removed and
HP_TIMING_INLINE is used instead to check for hp-timing avaliability.
For alpha, which only defines HP_SMALL_TIMING_AVAIL, the HP_TIMING_INLINE
is set iff for IS_IN(rtld).
Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu. I also
checked the builds for all afected ABIs.
* benchtests/bench-timing.h: Replace HP_TIMING_AVAIL with
HP_TIMING_INLINE.
* nptl/descr.h: Likewise.
* elf/rtld.c (RLTD_TIMING_DECLARE, RTLD_TIMING_NOW, RTLD_TIMING_DIFF,
RTLD_TIMING_ACCUM_NT, RTLD_TIMING_SET): Define.
(dl_start_final_info, _dl_start_final, dl_main, print_statistics):
Abstract hp-timing usage with RTLD_* macros.
* sysdeps/alpha/hp-timing.h (HP_TIMING_INLINE): Define iff IS_IN(rtld).
(HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL): Remove.
* sysdeps/generic/hp-timing.h (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL,
HP_TIMING_NONAVAIL): Likewise.
* sysdeps/ia64/hp-timing.h (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL):
Likewise.
* sysdeps/powerpc/powerpc32/power4/hp-timing.h (HP_TIMING_AVAIL,
HP_SMALL_TIMING_AVAIL): Likewise.
* sysdeps/powerpc/powerpc64/hp-timing.h (HP_TIMING_AVAIL,
HP_SMALL_TIMING_AVAIL): Likewise.
* sysdeps/sparc/sparc32/sparcv9/hp-timing.h (HP_TIMING_AVAIL,
HP_SMALL_TIMING_AVAIL): Likewise.
* sysdeps/sparc/sparc64/hp-timing.h (HP_TIMING_AVAIL,
HP_SMALL_TIMING_AVAIL): Likewise.
* sysdeps/x86/hp-timing.h (HP_TIMING_AVAIL, HP_SMALL_TIMING_AVAIL):
Likewise.
* sysdeps/generic/hp-timing-common.h: Update comment with
HP_TIMING_AVAIL removal.
diff --git a/benchtests/bench-timing.h b/benchtests/bench-timing.h
index 96cde1e8be2e0c2f..8ba6be51d5b6d4e1 100644
--- a/benchtests/bench-timing.h
+++ b/benchtests/bench-timing.h
@@ -21,7 +21,7 @@
#include <hp-timing.h>
#include <stdint.h>
-#if HP_TIMING_AVAIL && !defined USE_CLOCK_GETTIME
+#if HP_TIMING_INLINE && !defined USE_CLOCK_GETTIME
# define GL(x) _##x
# define GLRO(x) _##x
typedef hp_timing_t timing_t;
diff --git a/elf/rtld.c b/elf/rtld.c
index 375e0de8fa2e049e..ffbd8f4553bb3425 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -46,6 +46,49 @@
#include <assert.h>
+/* Only enables rtld profiling for architectures which provides non generic
+ hp-timing support. The generic support requires either syscall
+ (clock_gettime), which will incur in extra overhead on loading time.
+ Using vDSO is also an option, but it will require extra support on loader
+ to setup the vDSO pointer before its usage. */
+#if HP_TIMING_INLINE
+# define RLTD_TIMING_DECLARE(var, classifier,...) \
+ classifier hp_timing_t var __VA_ARGS__
+# define RTLD_TIMING_VAR(var) RLTD_TIMING_DECLARE (var, )
+# define RTLD_TIMING_SET(var, value) (var) = (value)
+# define RTLD_TIMING_REF(var) &(var)
+
+static inline void
+rtld_timer_start (hp_timing_t *var)
+{
+ HP_TIMING_NOW (*var);
+}
+
+static inline void
+rtld_timer_stop (hp_timing_t *var, hp_timing_t start)
+{
+ hp_timing_t stop;
+ HP_TIMING_NOW (stop);
+ HP_TIMING_DIFF (*var, start, stop);
+}
+
+static inline void
+rtld_timer_accum (hp_timing_t *sum, hp_timing_t start)
+{
+ hp_timing_t stop;
+ rtld_timer_stop (&stop, start);
+ HP_TIMING_ACCUM_NT(*sum, stop);
+}
+#else
+# define RLTD_TIMING_DECLARE(var, classifier...)
+# define RTLD_TIMING_SET(var, value)
+# define RTLD_TIMING_VAR(var)
+# define RTLD_TIMING_REF(var) 0
+# define rtld_timer_start(var)
+# define rtld_timer_stop(var, start)
+# define rtld_timer_accum(sum, start)
+#endif
+
/* Avoid PLT use for our local calls at startup. */
extern __typeof (__mempcpy) __mempcpy attribute_hidden;
@@ -62,7 +105,7 @@ static void print_missing_version (int errcode, const char *objname,
const char *errsting);
/* Print the various times we collected. */
-static void print_statistics (hp_timing_t *total_timep);
+static void print_statistics (const hp_timing_t *total_timep);
/* Add audit objects. */
static void process_dl_audit (char *str);
@@ -303,11 +346,9 @@ static struct libname_list _dl_rtld_libname;
static struct libname_list _dl_rtld_libname2;
/* Variable for statistics. */
-#ifndef HP_TIMING_NONAVAIL
-static hp_timing_t relocate_time;
-static hp_timing_t load_time attribute_relro;
-static hp_timing_t start_time attribute_relro;
-#endif
+RLTD_TIMING_DECLARE (relocate_time, static);
+RLTD_TIMING_DECLARE (load_time, static, attribute_relro);
+RLTD_TIMING_DECLARE (start_time, static, attribute_relro);
/* Additional definitions needed by TLS initialization. */
#ifdef TLS_INIT_HELPER
@@ -335,9 +376,7 @@ static ElfW(Addr) _dl_start_final (void *arg);
struct dl_start_final_info
{
struct link_map l;
-#if !defined HP_TIMING_NONAVAIL && HP_TIMING_INLINE
- hp_timing_t start_time;
-#endif
+ RTLD_TIMING_VAR (start_time);
};
static ElfW(Addr) _dl_start_final (void *arg,
struct dl_start_final_info *info);
@@ -371,16 +410,11 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
{
ElfW(Addr) start_addr;
- if (HP_SMALL_TIMING_AVAIL)
- {
- /* If it hasn't happen yet record the startup time. */
- if (! HP_TIMING_INLINE)
- HP_TIMING_NOW (start_time);
-#if !defined DONT_USE_BOOTSTRAP_MAP && !defined HP_TIMING_NONAVAIL
- else
- start_time = info->start_time;
+ /* If it hasn't happen yet record the startup time. */
+ rtld_timer_start (&start_time);
+#if !defined DONT_USE_BOOTSTRAP_MAP
+ RTLD_TIMING_SET (start_time, info->start_time);
#endif
- }
/* Transfer data about ourselves to the permanent link_map structure. */
#ifndef DONT_USE_BOOTSTRAP_MAP
@@ -412,27 +446,11 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
entry point on the same stack we entered on. */
start_addr = _dl_sysdep_start (arg, &dl_main);
-#ifndef HP_TIMING_NONAVAIL
- hp_timing_t rtld_total_time;
- if (HP_SMALL_TIMING_AVAIL)
- {
- hp_timing_t end_time;
-
- /* Get the current time. */
- HP_TIMING_NOW (end_time);
-
- /* Compute the difference. */
- HP_TIMING_DIFF (rtld_total_time, start_time, end_time);
- }
-#endif
-
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
{
-#ifndef HP_TIMING_NONAVAIL
- print_statistics (&rtld_total_time);
-#else
- print_statistics (NULL);
-#endif
+ RTLD_TIMING_VAR (rtld_total_time);
+ rtld_timer_stop (&rtld_total_time, start_time);
+ print_statistics (RTLD_TIMING_REF(rtld_total_time));
}
return start_addr;
@@ -457,11 +475,10 @@ _dl_start (void *arg)
#define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP
#include "dynamic-link.h"
- if (HP_TIMING_INLINE && HP_SMALL_TIMING_AVAIL)
#ifdef DONT_USE_BOOTSTRAP_MAP
- HP_TIMING_NOW (start_time);
+ rtld_timer_start (&start_time);
#else
- HP_TIMING_NOW (info.start_time);
+ rtld_timer_start (&info.start_time);
#endif
/* Partly clean the `bootstrap_map' structure up. Don't use
@@ -1078,11 +1095,6 @@ dl_main (const ElfW(Phdr) *phdr,
unsigned int i;
bool prelinked = false;
bool rtld_is_main = false;
-#ifndef HP_TIMING_NONAVAIL
- hp_timing_t start;
- hp_timing_t stop;
- hp_timing_t diff;
-#endif
void *tcbp = NULL;
GL(dl_init_static_tls) = &_dl_nothread_init_static_tls;
@@ -1256,12 +1268,11 @@ of this helper program; chances are you did not intend to run this program.\n\
}
else
{
- HP_TIMING_NOW (start);
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
_dl_map_object (NULL, rtld_progname, lt_executable, 0,
__RTLD_OPENEXEC, LM_ID_BASE);
- HP_TIMING_NOW (stop);
-
- HP_TIMING_DIFF (load_time, start, stop);
+ rtld_timer_stop (&load_time, start);
}
/* Now the map for the main executable is available. */
@@ -1664,20 +1675,18 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
if (__glibc_unlikely (preloadlist != NULL))
{
- HP_TIMING_NOW (start);
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD");
- HP_TIMING_NOW (stop);
- HP_TIMING_DIFF (diff, start, stop);
- HP_TIMING_ACCUM_NT (load_time, diff);
+ rtld_timer_accum (&load_time, start);
}
if (__glibc_unlikely (preloadarg != NULL))
{
- HP_TIMING_NOW (start);
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
npreloads += handle_preload_list (preloadarg, main_map, "--preload");
- HP_TIMING_NOW (stop);
- HP_TIMING_DIFF (diff, start, stop);
- HP_TIMING_ACCUM_NT (load_time, diff);
+ rtld_timer_accum (&load_time, start);
}
/* There usually is no ld.so.preload file, it should only be used
@@ -1737,7 +1746,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
file[file_size - 1] = '\0';
}
- HP_TIMING_NOW (start);
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
if (file != problem)
{
@@ -1755,9 +1765,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
npreloads += do_preload (p, main_map, preload_file);
}
- HP_TIMING_NOW (stop);
- HP_TIMING_DIFF (diff, start, stop);
- HP_TIMING_ACCUM_NT (load_time, diff);
+ rtld_timer_accum (&load_time, start);
/* We don't need the file anymore. */
__munmap (file, file_size);
@@ -1781,11 +1789,12 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
/* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD
specified some libraries to load, these are inserted before the actual
dependencies in the executable's searchlist for symbol resolution. */
- HP_TIMING_NOW (start);
- _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
- HP_TIMING_NOW (stop);
- HP_TIMING_DIFF (diff, start, stop);
- HP_TIMING_ACCUM_NT (load_time, diff);
+ {
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
+ _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
+ rtld_timer_accum (&load_time, start);
+ }
/* Mark all objects as being in the global scope. */
for (i = main_map->l_searchlist.r_nlist; i > 0; )
@@ -2178,12 +2187,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
{
ElfW(Rela) *conflict, *conflictend;
-#ifndef HP_TIMING_NONAVAIL
- hp_timing_t start;
- hp_timing_t stop;
-#endif
- HP_TIMING_NOW (start);
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
+
assert (main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
conflict = (ElfW(Rela) *)
main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
@@ -2191,8 +2198,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
((char *) conflict
+ main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
_dl_resolve_conflicts (main_map, conflict, conflictend);
- HP_TIMING_NOW (stop);
- HP_TIMING_DIFF (relocate_time, start, stop);
+
+ rtld_timer_stop (&relocate_time, start);
}
@@ -2220,15 +2227,12 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
know that because it is self-contained). */
int consider_profiling = GLRO(dl_profile) != NULL;
-#ifndef HP_TIMING_NONAVAIL
- hp_timing_t start;
- hp_timing_t stop;
-#endif
/* If we are profiling we also must do lazy reloaction. */
GLRO(dl_lazy) |= consider_profiling;
- HP_TIMING_NOW (start);
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
unsigned i = main_map->l_searchlist.r_nlist;
while (i-- > 0)
{
@@ -2255,9 +2259,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
if (l->l_tls_blocksize != 0 && tls_init_tp_called)
_dl_add_to_slotinfo (l, true);
}
- HP_TIMING_NOW (stop);
-
- HP_TIMING_DIFF (relocate_time, start, stop);
+ rtld_timer_stop (&relocate_time, start);
/* Now enable profiling if needed. Like the previous call,
this has to go here because the calls it makes should use the
@@ -2300,19 +2302,14 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
re-relocation, we might call a user-supplied function
(e.g. calloc from _dl_relocate_object) that uses TLS data. */
-#ifndef HP_TIMING_NONAVAIL
- hp_timing_t start;
- hp_timing_t stop;
- hp_timing_t add;
-#endif
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
- HP_TIMING_NOW (start);
/* Mark the link map as not yet relocated again. */
GL(dl_rtld_map).l_relocated = 0;
_dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
- HP_TIMING_NOW (stop);
- HP_TIMING_DIFF (add, start, stop);
- HP_TIMING_ACCUM_NT (relocate_time, add);
+
+ rtld_timer_accum (&relocate_time, start);
}
/* Do any necessary cleanups for the startup OS interface code.
@@ -2744,46 +2741,51 @@ process_envvars (enum mode *modep)
}
}
+#if HP_TIMING_INLINE
+static void
+print_statistics_item (const char *title, hp_timing_t time,
+ hp_timing_t total)
+{
+ char cycles[HP_TIMING_PRINT_SIZE];
+ HP_TIMING_PRINT (cycles, sizeof (cycles), time);
+
+ char relative[3 * sizeof (hp_timing_t) + 2];
+ char *cp = _itoa ((1000ULL * time) / total, relative + sizeof (relative),
+ 10, 0);
+ /* Sets the decimal point. */
+ char *wp = relative;
+ switch (relative + sizeof (relative) - cp)
+ {
+ case 3:
+ *wp++ = *cp++;
+ /* Fall through. */
+ case 2:
+ *wp++ = *cp++;
+ /* Fall through. */
+ case 1:
+ *wp++ = '.';
+ *wp++ = *cp++;
+ }
+ *wp = '\0';
+ _dl_debug_printf ("%s: %s cycles (%s%%)\n", title, cycles, relative);
+}
+#endif
/* Print the various times we collected. */
static void
__attribute ((noinline))
-print_statistics (hp_timing_t *rtld_total_timep)
+print_statistics (const hp_timing_t *rtld_total_timep)
{
-#ifndef HP_TIMING_NONAVAIL
- char buf[200];
- char *cp;
- char *wp;
-
- /* Total time rtld used. */
- if (HP_SMALL_TIMING_AVAIL)
- {
- HP_TIMING_PRINT (buf, sizeof (buf), *rtld_total_timep);
- _dl_debug_printf ("\nruntime linker statistics:\n"
- " total startup time in dynamic loader: %s\n", buf);
-
- /* Print relocation statistics. */
- char pbuf[30];
- HP_TIMING_PRINT (buf, sizeof (buf), relocate_time);
- cp = _itoa ((1000ULL * relocate_time) / *rtld_total_timep,
- pbuf + sizeof (pbuf), 10, 0);
- wp = pbuf;
- switch (pbuf + sizeof (pbuf) - cp)
- {
- case 3:
- *wp++ = *cp++;
- /* Fall through. */
- case 2:
- *wp++ = *cp++;
- /* Fall through. */
- case 1:
- *wp++ = '.';
- *wp++ = *cp++;
- }
- *wp = '\0';
- _dl_debug_printf ("\
- time needed for relocation: %s (%s%%)\n", buf, pbuf);
- }
+#if HP_TIMING_INLINE
+ {
+ char cycles[HP_TIMING_PRINT_SIZE];
+ HP_TIMING_PRINT (cycles, sizeof (cycles), *rtld_total_timep);
+ _dl_debug_printf ("\nruntime linker statistics:\n"
+ " total startup time in dynamic loader: %s cycles\n",
+ cycles);
+ print_statistics_item (" time needed for relocation",
+ relocate_time, *rtld_total_timep);
+ }
#endif
unsigned long int num_relative_relocations = 0;
@@ -2824,31 +2826,8 @@ print_statistics (hp_timing_t *rtld_total_timep)
GL(dl_num_cache_relocations),
num_relative_relocations);
-#ifndef HP_TIMING_NONAVAIL
- /* Time spend while loading the object and the dependencies. */
- if (HP_SMALL_TIMING_AVAIL)
- {
- char pbuf[30];
- HP_TIMING_PRINT (buf, sizeof (buf), load_time);
- cp = _itoa ((1000ULL * load_time) / *rtld_total_timep,
- pbuf + sizeof (pbuf), 10, 0);
- wp = pbuf;
- switch (pbuf + sizeof (pbuf) - cp)
- {
- case 3:
- *wp++ = *cp++;
- /* Fall through. */
- case 2:
- *wp++ = *cp++;
- /* Fall through. */
- case 1:
- *wp++ = '.';
- *wp++ = *cp++;
- }
- *wp = '\0';
- _dl_debug_printf ("\
- time needed to load objects: %s (%s%%)\n",
- buf, pbuf);
- }
+#if HP_TIMING_INLINE
+ print_statistics_item (" time needed to load objects",
+ load_time, *rtld_total_timep);
#endif
}
diff --git a/nptl/descr.h b/nptl/descr.h
index c3b81d8b27839502..98ba730bfeb7e4dd 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -342,7 +342,7 @@ struct pthread
/* Lock for synchronizing setxid calls. */
unsigned int setxid_futex;
-#if HP_TIMING_AVAIL
+#if HP_TIMING_INLINE
hp_timing_t cpuclock_offset_ununsed;
#endif
diff --git a/sysdeps/alpha/hp-timing.h b/sysdeps/alpha/hp-timing.h
index 62284e003acbca64..d6b603e2c51d1688 100644
--- a/sysdeps/alpha/hp-timing.h
+++ b/sysdeps/alpha/hp-timing.h
@@ -17,16 +17,13 @@
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
-#ifndef _HP_TIMING_H
-#define _HP_TIMING_H 1
+#ifndef _HP_TIMING_ALPHA_H
+#define _HP_TIMING_ALPHA_H 1
+#if IS_IN(rtld)
/* We always have the timestamp register, but it's got only a 4 second
range. Use it for ld.so profiling only. */
-#define HP_TIMING_AVAIL (0)
-#define HP_SMALL_TIMING_AVAIL (1)
-
-/* We indeed have inlined functions. */
-#define HP_TIMING_INLINE (1)
+# define HP_TIMING_INLINE (1)
/* We use 32 bit values for the times. */
typedef unsigned int hp_timing_t;
@@ -34,13 +31,16 @@ typedef unsigned int hp_timing_t;
/* The "rpcc" instruction returns a 32-bit counting half and a 32-bit
"virtual cycle counter displacement". Subtracting the two gives us
a virtual cycle count. */
-#define HP_TIMING_NOW(VAR) \
+# define HP_TIMING_NOW(VAR) \
do { \
unsigned long int x_; \
asm volatile ("rpcc %0" : "=r"(x_)); \
(VAR) = (int) (x_) - (int) (x_ >> 32); \
} while (0)
+# include <hp-timing-common.h>
-#include <hp-timing-common.h>
+#else
+# include <sysdeps/generic/hp-timing.h>
+#endif /* IS_IN(rtld) */
#endif /* hp-timing.h */
diff --git a/sysdeps/generic/hp-timing-common.h b/sysdeps/generic/hp-timing-common.h
index 505c6bf5d2ee9395..ce338c990bd9fccd 100644
--- a/sysdeps/generic/hp-timing-common.h
+++ b/sysdeps/generic/hp-timing-common.h
@@ -20,8 +20,6 @@
/* In case a platform supports timers in the hardware the following macros
and types must be defined:
- - HP_TIMING_AVAIL: test for availability.
-
- HP_TIMING_INLINE: this macro is non-zero if the functionality is not
implemented using function calls but instead uses some inlined code
which might simply consist of a few assembler instructions. We have to
@@ -47,16 +45,16 @@
/* Accumulate ADD into SUM. No attempt is made to be thread-safe. */
#define HP_TIMING_ACCUM_NT(Sum, Diff) ((Sum) += (Diff))
+#define HP_TIMING_PRINT_SIZE (3 * sizeof (hp_timing_t) + 1)
+
/* Write a decimal representation of the timing value into the given string. */
#define HP_TIMING_PRINT(Dest, Len, Val) \
do { \
- char __buf[20]; \
+ char __buf[HP_TIMING_PRINT_SIZE]; \
char *__dest = (Dest); \
size_t __len = (Len); \
char *__cp = _itoa ((Val), __buf + sizeof (__buf), 10, 0); \
size_t __cp_len = MIN (__buf + sizeof (__buf) - __cp, __len); \
memcpy (__dest, __cp, __cp_len); \
- memcpy (__dest + __cp_len, " cycles", \
- MIN (__len - __cp_len, sizeof (" cycles"))); \
__dest[__len - 1] = '\0'; \
} while (0)
diff --git a/sysdeps/generic/hp-timing.h b/sysdeps/generic/hp-timing.h
index e2c02c2bc0fd1564..97598099db29d69d 100644
--- a/sysdeps/generic/hp-timing.h
+++ b/sysdeps/generic/hp-timing.h
@@ -25,8 +25,6 @@
the system call might be too high. */
/* Provide dummy definitions. */
-#define HP_TIMING_AVAIL (0)
-#define HP_SMALL_TIMING_AVAIL (0)
#define HP_TIMING_INLINE (0)
typedef int hp_timing_t;
#define HP_TIMING_NOW(var)
@@ -34,7 +32,4 @@ typedef int hp_timing_t;
#define HP_TIMING_ACCUM_NT(Sum, Diff)
#define HP_TIMING_PRINT(Buf, Len, Val)
-/* Since this implementation is not available we tell the user about it. */
-#define HP_TIMING_NONAVAIL 1
-
#endif /* hp-timing.h */
diff --git a/sysdeps/ia64/hp-timing.h b/sysdeps/ia64/hp-timing.h
index d8d1d7bf2c21f6e6..5ebbbc45746d5cf2 100644
--- a/sysdeps/ia64/hp-timing.h
+++ b/sysdeps/ia64/hp-timing.h
@@ -20,10 +20,6 @@
#ifndef _HP_TIMING_H
#define _HP_TIMING_H 1
-/* We always assume having the timestamp register. */
-#define HP_TIMING_AVAIL (1)
-#define HP_SMALL_TIMING_AVAIL (1)
-
/* We indeed have inlined functions. */
#define HP_TIMING_INLINE (1)
diff --git a/sysdeps/powerpc/powerpc32/power4/hp-timing.h b/sysdeps/powerpc/powerpc32/power4/hp-timing.h
index 10efcac481349ee3..0e81f4fe6a46ab86 100644
--- a/sysdeps/powerpc/powerpc32/power4/hp-timing.h
+++ b/sysdeps/powerpc/powerpc32/power4/hp-timing.h
@@ -20,10 +20,6 @@
#ifndef _HP_TIMING_H
#define _HP_TIMING_H 1
-/* We always assume having the timestamp register. */
-#define HP_TIMING_AVAIL (1)
-#define HP_SMALL_TIMING_AVAIL (1)
-
/* We indeed have inlined functions. */
#define HP_TIMING_INLINE (1)
diff --git a/sysdeps/powerpc/powerpc64/hp-timing.h b/sysdeps/powerpc/powerpc64/hp-timing.h
index c0aa3642f6ff1a42..77fe5e85bb32c163 100644
--- a/sysdeps/powerpc/powerpc64/hp-timing.h
+++ b/sysdeps/powerpc/powerpc64/hp-timing.h
@@ -20,10 +20,6 @@
#ifndef _HP_TIMING_H
#define _HP_TIMING_H 1
-/* We always assume having the timestamp register. */
-#define HP_TIMING_AVAIL (1)
-#define HP_SMALL_TIMING_AVAIL (1)
-
/* We indeed have inlined functions. */
#define HP_TIMING_INLINE (1)
diff --git a/sysdeps/sparc/sparc32/sparcv9/hp-timing.h b/sysdeps/sparc/sparc32/sparcv9/hp-timing.h
index 42451966f6192bcb..aedf9c031a0daad9 100644
--- a/sysdeps/sparc/sparc32/sparcv9/hp-timing.h
+++ b/sysdeps/sparc/sparc32/sparcv9/hp-timing.h
@@ -20,8 +20,6 @@
#ifndef _HP_TIMING_H
#define _HP_TIMING_H 1
-#define HP_TIMING_AVAIL (1)
-#define HP_SMALL_TIMING_AVAIL (1)
#define HP_TIMING_INLINE (1)
typedef unsigned long long int hp_timing_t;
diff --git a/sysdeps/sparc/sparc64/hp-timing.h b/sysdeps/sparc/sparc64/hp-timing.h
index 66325641067e1198..ee22729063745944 100644
--- a/sysdeps/sparc/sparc64/hp-timing.h
+++ b/sysdeps/sparc/sparc64/hp-timing.h
@@ -20,8 +20,6 @@
#ifndef _HP_TIMING_H
#define _HP_TIMING_H 1
-#define HP_TIMING_AVAIL (1)
-#define HP_SMALL_TIMING_AVAIL (1)
#define HP_TIMING_INLINE (1)
typedef unsigned long int hp_timing_t;
diff --git a/sysdeps/x86/hp-timing.h b/sysdeps/x86/hp-timing.h
index 0aa6f5e3f83e0d34..4dbd2aa8af69f95e 100644
--- a/sysdeps/x86/hp-timing.h
+++ b/sysdeps/x86/hp-timing.h
@@ -22,10 +22,6 @@
#include <isa.h>
#if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664
-/* We always assume having the timestamp register. */
-# define HP_TIMING_AVAIL (1)
-# define HP_SMALL_TIMING_AVAIL (1)
-
/* We indeed have inlined functions. */
# define HP_TIMING_INLINE (1)

View File

@ -0,0 +1,113 @@
commit b2af6fb2ed23930c148bae382ca85fad4d1cf32e
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Tue Apr 30 16:11:57 2019 -0300
elf: Fix elf/tst-pldd with --enable-hardcoded-path-in-tests (BZ#24506)
The elf/tst-pldd (added by 1a4c27355e146 to fix BZ#18035) test does
not expect the hardcoded paths that are output by pldd when the test
is built with --enable-hardcoded-path-in-tests. Instead of showing
the ABI installed library names for loader and libc (such as
ld-linux-x86-64.so.2 and libc.so.6 for x86_64), pldd shows the default
built ld.so and libc.so.
It makes the tests fail with an invalid expected loader/libc name.
This patch fixes the elf-pldd test by adding the canonical ld.so and
libc.so names in the expected list of possible outputs when parsing
the result output from pldd. The test now handles both default
build and --enable-hardcoded-path-in-tests option.
Checked on x86_64-linux-gnu (built with and without
--enable-hardcoded-path-in-tests) and i686-linux-gnu.
* elf/tst-pldd.c (in_str_list): New function.
(do_test): Add default names for ld and libc as one option.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
elf/tst-pldd.c
(Original backport uses spaces instead of tabs.)
diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c
index 0f51c95935ffb2cf..40abee9efb9e7484 100644
--- a/elf/tst-pldd.c
+++ b/elf/tst-pldd.c
@@ -20,7 +20,6 @@
#include <string.h>
#include <unistd.h>
#include <stdint.h>
-#include <libgen.h>
#include <stdbool.h>
#include <array_length.h>
@@ -39,6 +38,15 @@ target_process (void *arg)
/* The test runs in a container because pldd does not support tracing
a binary started by the loader iself (as with testrun.sh). */
+static bool
+in_str_list (const char *libname, const char *const strlist[])
+{
+ for (const char *const *str = strlist; *str != NULL; str++)
+ if (strcmp (libname, *str) == 0)
+ return true;
+ return false;
+}
+
static int
do_test (void)
{
@@ -82,26 +90,32 @@ do_test (void)
{
/* Ignore vDSO. */
if (buffer[0] != '/')
- continue;
-
- /* Remove newline so baseline (buffer) can compare against the
- LD_SO and LIBC_SO macros unmodified. */
- if (buffer[strlen(buffer)-1] == '\n')
- buffer[strlen(buffer)-1] = '\0';
-
- if (strcmp (basename (buffer), LD_SO) == 0)
- {
- TEST_COMPARE (interpreter_found, false);
- interpreter_found = true;
- continue;
- }
-
- if (strcmp (basename (buffer), LIBC_SO) == 0)
- {
- TEST_COMPARE (libc_found, false);
- libc_found = true;
- continue;
- }
+ continue;
+
+ /* Remove newline so baseline (buffer) can compare against the
+ LD_SO and LIBC_SO macros unmodified. */
+ if (buffer[strlen(buffer)-1] == '\n')
+ buffer[strlen(buffer)-1] = '\0';
+
+ const char *libname = basename (buffer);
+
+ /* It checks for default names in case of build configure with
+ --enable-hardcoded-path-in-tests (BZ #24506). */
+ if (in_str_list (libname,
+ (const char *const []) { "ld.so", LD_SO, NULL }))
+ {
+ TEST_COMPARE (interpreter_found, false);
+ interpreter_found = true;
+ continue;
+ }
+
+ if (in_str_list (libname,
+ (const char *const []) { "libc.so", LIBC_SO, NULL }))
+ {
+ TEST_COMPARE (libc_found, false);
+ libc_found = true;
+ continue;
+ }
}
TEST_COMPARE (interpreter_found, true);
TEST_COMPARE (libc_found, true);

View File

@ -0,0 +1,54 @@
commit da2b83ef6ba6f4c974664f69e715cc85b9173938
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon May 13 13:13:46 2019 -0300
elf: Fix tst-pldd for non-default --prefix and/or --bindir (BZ#24544)
Use a new libsupport support_bindir_prefix instead of a hardcoded
/usr/bin to create the pldd path on container directory.
Checked on x86_64-linux-gnu with default and non-default --prefix and
--bindir paths, as well with --enable-hardcoded-path-in-tests.
[BZ #24544]
* elf/tst-pldd.c (do_test): Use support_bindir_prefix instead of
pre-defined value.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c
index 40abee9efb9e7484..e2de31282a131166 100644
--- a/elf/tst-pldd.c
+++ b/elf/tst-pldd.c
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
@@ -28,6 +29,7 @@
#include <support/subprocess.h>
#include <support/capture_subprocess.h>
#include <support/check.h>
+#include <support/support.h>
static void
target_process (void *arg)
@@ -60,12 +62,14 @@ do_test (void)
char pid[3 * sizeof (uint32_t) + 1];
snprintf (pid, array_length (pid), "%d", target.pid);
- const char prog[] = "/usr/bin/pldd";
+ char *prog = xasprintf ("%s/pldd", support_bindir_prefix);
pldd = support_capture_subprogram (prog,
(char *const []) { (char *) prog, pid, NULL });
support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
+
+ free (prog);
}
/* Check 'pldd' output. The test is expected to be linked against only

View File

@ -0,0 +1,49 @@
commit 75c51570c710aa9c6df6b7a1e131392e1408c63f
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon May 20 21:08:40 2019 +0200
support: Expose sbindir as support_sbindir_prefix
diff --git a/support/Makefile b/support/Makefile
index 6afaa6836c944398..65b16299573af1ed 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -178,6 +178,7 @@ CFLAGS-support_paths.c = \
-DINSTDIR_PATH=\"$(prefix)\" \
-DLIBDIR_PATH=\"$(libdir)\" \
-DBINDIR_PATH=\"$(bindir)\" \
+ -DSBINDIR_PATH=\"$(sbindir)\" \
-DROOTSBINDIR_PATH=\"$(rootsbindir)\"
ifeq (,$(CXX))
diff --git a/support/support.h b/support/support.h
index 97d142e9b6f68188..121cc9e9b7c98ca6 100644
--- a/support/support.h
+++ b/support/support.h
@@ -109,6 +109,8 @@ extern const char support_libdir_prefix[];
/* Corresponds to the install's bin/ directory. */
extern const char support_bindir_prefix[];
/* Corresponds to the install's sbin/ directory. */
+extern const char support_sbindir_prefix[];
+/* Corresponds to the install's sbin/ directory (without prefix). */
extern const char support_install_rootsbindir[];
extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *,
diff --git a/support/support_paths.c b/support/support_paths.c
index a37a0720dc7339f0..eb2390227433aa70 100644
--- a/support/support_paths.c
+++ b/support/support_paths.c
@@ -65,6 +65,13 @@ const char support_bindir_prefix[] = BINDIR_PATH;
# error please -DBINDIR_PATH=something in the Makefile
#endif
+#ifdef SBINDIR_PATH
+/* Corresponds to the install's bin/ directory. */
+const char support_sbindir_prefix[] = SBINDIR_PATH;
+#else
+# error please -DSBINDIR_PATH=something in the Makefile
+#endif
+
#ifdef ROOTSBINDIR_PATH
/* Corresponds to the install's sbin/ directory. */
const char support_install_rootsbindir[] = ROOTSBINDIR_PATH;

View File

@ -0,0 +1,58 @@
commit d039da1c00e01f8d3c3d74f439a971eb73e3045e
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Wed Jun 26 15:07:18 2019 -0700
x86: Add sysdeps/x86/dl-lookupcfg.h
Since sysdeps/i386/dl-lookupcfg.h and sysdeps/x86_64/dl-lookupcfg.h are
identical, we can replace them with sysdeps/x86/dl-lookupcfg.h.
* sysdeps/i386/dl-lookupcfg.h: Moved to ...
* sysdeps/x86/dl-lookupcfg.h: Here.
* sysdeps/x86_64/dl-lookupcfg.h: Removed.
Conflicts:
sysdeps/x86_64/dl-lookupcfg.h
(Removal after copyright year update.)
diff --git a/sysdeps/i386/dl-lookupcfg.h b/sysdeps/x86/dl-lookupcfg.h
similarity index 100%
rename from sysdeps/i386/dl-lookupcfg.h
rename to sysdeps/x86/dl-lookupcfg.h
diff --git a/sysdeps/x86_64/dl-lookupcfg.h b/sysdeps/x86_64/dl-lookupcfg.h
deleted file mode 100644
index 5399cf25abde592d..0000000000000000
--- a/sysdeps/x86_64/dl-lookupcfg.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Configuration of lookup functions.
- Copyright (C) 2005-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.
-
- 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/>. */
-
-#define DL_UNMAP_IS_SPECIAL
-
-#include_next <dl-lookupcfg.h>
-
-/* Address of protected data defined in the shared library may be
- external due to copy relocation. */
-#define DL_EXTERN_PROTECTED_DATA
-
-struct link_map;
-
-extern void _dl_unmap (struct link_map *map) attribute_hidden;
-
-#define DL_UNMAP(map) _dl_unmap (map)

View File

@ -0,0 +1,109 @@
commit 23d2e5faf0bca6d9b31bef4aa162b95ee64cbfc6
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Aug 15 14:37:50 2019 +0200
elf: Self-dlopen failure with explict loader invocation [BZ #24900]
In case of an explicit loader invocation, ld.so essentially performs
a dlopen call to load the main executable. Since the pathname of
the executable is known at this point, it gets stored in the link
map. In regular mode, the pathname is not known and "" is used
instead.
As a result, if a program calls dlopen on the pathname of the main
program, the dlopen call succeeds and returns a handle for the main
map. This results in an unnecessary difference between glibc
testing (without --enable-hardcoded-path-in-tests) and production
usage.
This commit discards the names when building the link map in
_dl_new_object for the main executable, but it still determines
the origin at this point in case of an explict loader invocation.
The reason is that the specified pathname has to be used; the kernel
has a different notion of the main executable.
Conflicts:
elf/Makefile
elf/tst-dlopen-aout.c
(Differences due to the complicated history of the test.
The new test elf/tst-dlopen-aout-container is not backported
here.)
diff --git a/elf/dl-object.c b/elf/dl-object.c
index b37bcc1295f475f6..f6544a8fec45bdce 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -57,14 +57,30 @@ struct link_map *
_dl_new_object (char *realname, const char *libname, int type,
struct link_map *loader, int mode, Lmid_t nsid)
{
+#ifdef SHARED
+ unsigned int naudit;
+ if (__glibc_unlikely ((mode & __RTLD_OPENEXEC) != 0))
+ {
+ assert (type == lt_executable);
+ assert (nsid == LM_ID_BASE);
+
+ /* Ignore the specified libname for the main executable. It is
+ only known with an explicit loader invocation. */
+ libname = "";
+
+ /* We create the map for the executable before we know whether
+ we have auditing libraries and if yes, how many. Assume the
+ worst. */
+ naudit = DL_NNS;
+ }
+ else
+ naudit = GLRO (dl_naudit);
+#endif
+
size_t libname_len = strlen (libname) + 1;
struct link_map *new;
struct libname_list *newname;
#ifdef SHARED
- /* We create the map for the executable before we know whether we have
- auditing libraries and if yes, how many. Assume the worst. */
- unsigned int naudit = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC)
- ? DL_NNS : 0);
size_t audit_space = naudit * sizeof (new->l_audit[0]);
#else
# define audit_space 0
@@ -91,8 +107,20 @@ _dl_new_object (char *realname, const char *libname, int type,
and won't get dumped during core file generation. Therefore to assist
gdb and to create more self-contained core files we adjust l_name to
point at the newly allocated copy (which will get dumped) instead of
- the ld.so rodata copy. */
- new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1;
+ the ld.so rodata copy.
+
+ Furthermore, in case of explicit loader invocation, discard the
+ name of the main executable, to match the regular behavior, where
+ name of the executable is not known. */
+#ifdef SHARED
+ if (*realname != '\0' && (mode & __RTLD_OPENEXEC) == 0)
+#else
+ if (*realname != '\0')
+#endif
+ new->l_name = realname;
+ else
+ new->l_name = (char *) newname->name + libname_len - 1;
+
new->l_type = type;
/* If we set the bit now since we know it is never used we avoid
dirtying the cache line later. */
@@ -149,7 +177,14 @@ _dl_new_object (char *realname, const char *libname, int type,
new->l_local_scope[0] = &new->l_searchlist;
- /* Don't try to find the origin for the main map which has the name "". */
+ /* Determine the origin. If allocating the link map for the main
+ executable, the realname is not known and "". In this case, the
+ origin needs to be determined by other means. However, in case
+ of an explicit loader invocation, the pathname of the main
+ executable is known and needs to be processed here: From the
+ point of view of the kernel, the main executable is the
+ dynamic loader, and this would lead to a computation of the wrong
+ origin. */
if (realname[0] != '\0')
{
size_t realname_len = strlen (realname) + 1;

View File

@ -0,0 +1,56 @@
commit ae67f2e562603a0b58f59aef4f31aa33de05ba88
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Fri Aug 3 06:40:48 2018 -0700
x86: Cleanup cpu-features-offsets.sym
Remove the unused macros. There is no code changes in libc.so nor
ld.so on i686 and x86-64.
* sysdeps/x86/cpu-features-offsets.sym
(rtld_global_ro_offsetof): Removed.
(CPU_FEATURES_SIZE): Likewise.
(CPUID_OFFSET): Likewise.
(CPUID_SIZE): Likewise.
(CPUID_EAX_OFFSET): Likewise.
(CPUID_EBX_OFFSET): Likewise.
(CPUID_ECX_OFFSET): Likewise.
(CPUID_EDX_OFFSET): Likewise.
(FAMILY_OFFSET): Likewise.
(MODEL_OFFSET): Likewise.
(FEATURE_OFFSET): Likewise.
(FEATURE_SIZ): Likewise.
(COMMON_CPUID_INDEX_1): Likewise.
(COMMON_CPUID_INDEX_7): Likewise.
(FEATURE_INDEX_1): Likewise.
(RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET): Updated.
diff --git a/sysdeps/x86/cpu-features-offsets.sym b/sysdeps/x86/cpu-features-offsets.sym
index 33dd094e37f0fec7..6d03cea8e8fcdc36 100644
--- a/sysdeps/x86/cpu-features-offsets.sym
+++ b/sysdeps/x86/cpu-features-offsets.sym
@@ -2,23 +2,5 @@
#include <ldsodefs.h>
-#define rtld_global_ro_offsetof(mem) offsetof (struct rtld_global_ro, mem)
-
-RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET rtld_global_ro_offsetof (_dl_x86_cpu_features)
-
-CPU_FEATURES_SIZE sizeof (struct cpu_features)
-CPUID_OFFSET offsetof (struct cpu_features, cpuid)
-CPUID_SIZE sizeof (struct cpuid_registers)
-CPUID_EAX_OFFSET offsetof (struct cpuid_registers, eax)
-CPUID_EBX_OFFSET offsetof (struct cpuid_registers, ebx)
-CPUID_ECX_OFFSET offsetof (struct cpuid_registers, ecx)
-CPUID_EDX_OFFSET offsetof (struct cpuid_registers, edx)
-FAMILY_OFFSET offsetof (struct cpu_features, family)
-MODEL_OFFSET offsetof (struct cpu_features, model)
+RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET offsetof (struct rtld_global_ro, _dl_x86_cpu_features)
XSAVE_STATE_SIZE_OFFSET offsetof (struct cpu_features, xsave_state_size)
-FEATURE_OFFSET offsetof (struct cpu_features, feature)
-FEATURE_SIZE sizeof (unsigned int)
-
-COMMON_CPUID_INDEX_1
-COMMON_CPUID_INDEX_7
-FEATURE_INDEX_1

View File

@ -0,0 +1,141 @@
commit edd8d70b91e1ccef549a7c668499596cc4d56ad1
Author: Mihailo Stojanovic <mihailo.stojanovic@rt-rk.com>
Date: Fri Aug 23 16:47:27 2019 +0000
[MIPS] Raise highest supported EI_ABIVERSION value [BZ #24916]
This bumps the highest valid EI_ABIVERSION value to ABSOLUTE ABI.
New testcase loads the symbol from the GOT with the "lb" instruction
so that the EI_ABIVERSION header field of the shared object is set
to ABSOLUTE (it doesn't actually check the value of the symbol), and
makes sure that the main executable is executed without "ABI version
invalid" error.
Tested for all three ABIs (o32, n32, n64) using both static linker which
handles undefined weak symbols correctly [1] (and sets the EI_ABIVERSION
of the test module) and the one that doesn't (EI_ABIVERSION left as 0).
[1] https://sourceware.org/ml/binutils/2018-07/msg00268.html
[BZ #24916]
* sysdeps/mips/Makefile [$(subdir) = elf] (tests): Add
tst-undefined-weak.
[$(subdir) = elf] (modules-names): Add tst-undefined-weak-lib.
[$(subdir) = elf] ($(objpfx)tst-undefined-weak): Add dependency.
* sysdeps/mips/tst-undefined-weak-lib.S: New file.
* sysdeps/mips/tst-undefined-weak.c: Likewise.
* sysdeps/unix/sysv/linux/mips/ldsodefs.h (VALID_ELF_ABIVERSION):
Increment highest valid ABIVERSION value.
diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile
index 7ac6fa50311d60b7..6ad69e9ef9e88728 100644
--- a/sysdeps/mips/Makefile
+++ b/sysdeps/mips/Makefile
@@ -82,3 +82,10 @@ $(objpfx)tst-mode-switch-2: $(shared-thread-library)
endif
endif
endif
+
+ifeq ($(subdir),elf)
+tests += tst-undefined-weak
+modules-names += tst-undefined-weak-lib
+
+$(objpfx)tst-undefined-weak: $(objpfx)tst-undefined-weak-lib.so
+endif
diff --git a/sysdeps/mips/tst-undefined-weak-lib.S b/sysdeps/mips/tst-undefined-weak-lib.S
new file mode 100644
index 0000000000000000..a175ebf90e01b372
--- /dev/null
+++ b/sysdeps/mips/tst-undefined-weak-lib.S
@@ -0,0 +1,43 @@
+/* Undefined weak symbol loading shared module.
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <sgidefs.h>
+
+ .text
+ .globl x
+ .set nomips16
+ .set nomicromips
+ .ent x
+ .type x, @function
+x:
+ .set noreorder
+#if _MIPS_SIM == _ABIO32
+ .cpload $25
+ jr $31
+ lb $2,%got(a)($28)
+#else
+ .cpsetup $25,$24,x
+ lb $2,%got_disp(a)($28)
+ jr $31
+ .cpreturn
+#endif
+ .set reorder
+ .end x
+ .size x, .-x
+ .weak a
+ .hidden a
diff --git a/sysdeps/mips/tst-undefined-weak.c b/sysdeps/mips/tst-undefined-weak.c
new file mode 100644
index 0000000000000000..1231da6912508c19
--- /dev/null
+++ b/sysdeps/mips/tst-undefined-weak.c
@@ -0,0 +1,28 @@
+/* Undefined weak symbol loading main executable.
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+int *x (void);
+
+int
+do_test (void)
+{
+ x ();
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/mips/ldsodefs.h b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
index 68a0a99bb1f1ec85..d2912cadabfd6877 100644
--- a/sysdeps/unix/sysv/linux/mips/ldsodefs.h
+++ b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
@@ -34,7 +34,7 @@ extern void _dl_static_init (struct link_map *map);
#undef VALID_ELF_ABIVERSION
#define VALID_ELF_ABIVERSION(osabi,ver) \
(ver == 0 \
- || (osabi == ELFOSABI_SYSV && ver < 4) \
+ || (osabi == ELFOSABI_SYSV && ver < 5) \
|| (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX))
#endif /* ldsodefs.h */

View File

@ -0,0 +1,241 @@
commit 23c1c256ae7b0f010d0fcaff60682b620887b164
Author: Mihailo Stojanovic <mihailo.stojanovic@rt-rk.com>
Date: Thu Aug 29 20:11:42 2019 +0000
MIPS support for GNU hash
This patch is a reimplementation of [1], which was submitted back in
2015. Copyright issue has been sorted [2] last year. It proposed a new
section (.gnu.xhash) and related dynamic tag (GT_GNU_XHASH). The new
section would be virtually identical to the existing .gnu.hash except
for the translation table (xlat) which would contain correct MIPS
.dynsym indexes corresponding to the hashvals in chains. This is because
MIPS ABI imposes a different ordering of the dynsyms than the one
expected by the .gnu.hash section. Another addition would be a leading
word at the beggining of the section, which would contain the number of
entries in the translation table.
In this patch, the new section name and dynamic tag are changed to
reflect the fact that the section should be treated as MIPS specific
(.MIPS.xhash and DT_MIPS_XHASH).
This patch addresses the alignment issue reported in [3] which is caused
by the leading word of the .MIPS.xhash section. Leading word is now
removed in the corresponding binutils patch, and the number of entries
in the translation table is computed using DT_MIPS_SYMTABNO dynamic tag.
Since the MIPS specific dl-lookup.c file was removed following the
initial patch submission, I opted for the definition of three new macros
in the generic ldsodefs.h. ELF_MACHINE_GNU_HASH_ADDRIDX defines the
index of the dynamic tag in the l_info array. ELF_MACHINE_HASH_SYMIDX is
used to calculate the index of a symbol in GNU hash. On MIPS, it is
defined to look up the symbol index in the translation table.
ELF_MACHINE_XHASH_SETUP is defined for MIPS only. It initializes the
.MIPS.xhash pointer in the link_map_machine struct.
The other major change is bumping the highest EI_ABIVERSION value for
MIPS to suggest that the dynamic linker now supports GNU hash.
The patch was tested by running the glibc testsuite for the three MIPS
ABIs (o32, n32 and n64) and for x86_64-linux-gnu.
[1] https://sourceware.org/ml/binutils/2015-10/msg00057.html
[2] https://sourceware.org/ml/binutils/2018-03/msg00025.html
[3] https://sourceware.org/ml/binutils/2016-01/msg00006.html
* elf/dl-addr.c (determine_info): Calculate the symbol index
using the newly defined ELF_MACHINE_HASH_SYMIDX macro.
* elf/dl-lookup.c (do_lookup_x): Ditto.
(_dl_setup_hash): Initialize MIPS xhash translation table.
* elf/elf.h (SHT_MIPS_XHASH): New define.
(DT_MIPS_XHASH): New define.
* sysdeps/generic/ldsodefs.h (ELF_MACHINE_GNU_HASH_ADDRIDX): New
define.
(ELF_MACHINE_HASH_SYMIDX): Ditto.
(ELF_MACHINE_XHASH_SETUP): Ditto.
* sysdeps/mips/ldsodefs.h (ELF_MACHINE_GNU_HASH_ADDRIDX): New
define.
(ELF_MACHINE_HASH_SYMIDX): Ditto.
(ELF_MACHINE_XHASH_SETUP): Ditto.
* sysdeps/mips/linkmap.h (struct link_map_machine): New member.
* sysdeps/unix/sysv/linux/mips/ldsodefs.h: Increment valid ABI
version.
* sysdeps/unix/sysv/linux/mips/libc-abis: New ABI version.
diff --git a/elf/dl-addr.c b/elf/dl-addr.c
index e6c7d020945c51d2..b146fed09a46ff76 100644
--- a/elf/dl-addr.c
+++ b/elf/dl-addr.c
@@ -42,7 +42,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val;
const ElfW(Sym) *matchsym = NULL;
- if (match->l_info[ADDRIDX (DT_GNU_HASH)] != NULL)
+ if (match->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL)
{
/* We look at all symbol table entries referenced by the hash
table. */
@@ -57,6 +57,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
{
/* The hash table never references local symbols so
we can omit that test here. */
+ symndx = ELF_MACHINE_HASH_SYMIDX (match, hasharr);
if ((symtab[symndx].st_shndx != SHN_UNDEF
|| symtab[symndx].st_value != 0)
&& symtab[symndx].st_shndx != SHN_ABS
@@ -65,8 +66,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
matchsym, addr)
&& symtab[symndx].st_name < strtabsize)
matchsym = (ElfW(Sym) *) &symtab[symndx];
-
- ++symndx;
}
while ((*hasharr++ & 1u) == 0);
}
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 01724a54f8840f9f..42fdaed99296137f 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -432,7 +432,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
do
if (((*hasharr ^ new_hash) >> 1) == 0)
{
- symidx = hasharr - map->l_gnu_chain_zero;
+ symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr);
sym = check_match (undef_name, ref, version, flags,
type_class, &symtab[symidx], symidx,
strtab, map, &versioned_sym,
@@ -961,10 +961,10 @@ _dl_setup_hash (struct link_map *map)
{
Elf_Symndx *hash;
- if (__glibc_likely (map->l_info[ADDRIDX (DT_GNU_HASH)] != NULL))
+ if (__glibc_likely (map->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL))
{
Elf32_Word *hash32
- = (void *) D_PTR (map, l_info[ADDRIDX (DT_GNU_HASH)]);
+ = (void *) D_PTR (map, l_info[ELF_MACHINE_GNU_HASH_ADDRIDX]);
map->l_nbuckets = *hash32++;
Elf32_Word symbias = *hash32++;
Elf32_Word bitmask_nwords = *hash32++;
@@ -979,6 +979,10 @@ _dl_setup_hash (struct link_map *map)
map->l_gnu_buckets = hash32;
hash32 += map->l_nbuckets;
map->l_gnu_chain_zero = hash32 - symbias;
+
+ /* Initialize MIPS xhash translation table. */
+ ELF_MACHINE_XHASH_SETUP (hash32, symbias, map);
+
return;
}
diff --git a/elf/elf.h b/elf/elf.h
index 74f7f479ce817040..d6506ea1c7160dea 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1698,6 +1698,7 @@ typedef struct
#define SHT_MIPS_EH_REGION 0x70000027
#define SHT_MIPS_XLATE_OLD 0x70000028
#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+#define SHT_MIPS_XHASH 0x7000002b
/* Legal values for sh_flags field of Elf32_Shdr. */
@@ -1945,7 +1946,9 @@ typedef struct
in a PIE as it stores a relative offset from the address of the tag
rather than an absolute address. */
#define DT_MIPS_RLD_MAP_REL 0x70000035
-#define DT_MIPS_NUM 0x36
+/* GNU-style hash table with xlat. */
+#define DT_MIPS_XHASH 0x70000036
+#define DT_MIPS_NUM 0x37
/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index f0185ce0d16c0f69..3bdbdd6e67dacc85 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -47,6 +47,23 @@ __BEGIN_DECLS
#define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
+/* Type of GNU hash which the machine uses. */
+#ifndef ELF_MACHINE_GNU_HASH_ADDRIDX
+# define ELF_MACHINE_GNU_HASH_ADDRIDX ADDRIDX (DT_GNU_HASH)
+#endif
+
+/* Calculate the index of a symbol in GNU hash. */
+#ifndef ELF_MACHINE_HASH_SYMIDX
+# define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \
+ ((hasharr) - (map)->l_gnu_chain_zero)
+#endif
+
+/* Setup MIPS xhash. Defined only for MIPS. */
+#ifndef ELF_MACHINE_XHASH_SETUP
+# define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map) \
+ ((void) (hash32), (void) (symbias), (void) (map))
+#endif
+
/* We use this macro to refer to ELF types independent of the native wordsize.
`ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */
#define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type)
diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h
index c6e5ce7e660325c1..35043b7c6d416c50 100644
--- a/sysdeps/mips/ldsodefs.h
+++ b/sysdeps/mips/ldsodefs.h
@@ -26,6 +26,21 @@ struct La_mips_32_retval;
struct La_mips_64_regs;
struct La_mips_64_retval;
+#define ELF_MACHINE_GNU_HASH_ADDRIDX (DT_MIPS_XHASH - DT_LOPROC + DT_NUM)
+
+/* Calculate the index of a symbol in MIPS xhash. */
+#define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \
+ ((map)->l_mach.mips_xlat_zero[(hasharr) - (map)->l_gnu_chain_zero])
+
+/* Setup MIPS xhash. */
+#define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map) \
+ do \
+ { \
+ (hash32) += (map)->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val - (symbias); \
+ (map)->l_mach.mips_xlat_zero = (hash32) - (symbias); \
+ } \
+ while (0)
+
#define ARCH_PLTENTER_MEMBERS \
Elf32_Addr (*mips_o32_gnu_pltenter) (Elf32_Sym *, unsigned int, \
uintptr_t *, uintptr_t *, \
diff --git a/sysdeps/mips/linkmap.h b/sysdeps/mips/linkmap.h
index 1fb9678a6d1625fd..1e640c3ba9bd18e4 100644
--- a/sysdeps/mips/linkmap.h
+++ b/sysdeps/mips/linkmap.h
@@ -3,4 +3,5 @@ struct link_map_machine
ElfW(Addr) plt; /* Address of .plt */
ElfW(Word) fpabi; /* FP ABI of the object */
unsigned int odd_spreg; /* Does the object require odd_spreg support? */
+ const Elf32_Word *mips_xlat_zero; /* .MIPS.xhash */
};
diff --git a/sysdeps/unix/sysv/linux/mips/ldsodefs.h b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
index d2912cadabfd6877..03f3e12f202a0563 100644
--- a/sysdeps/unix/sysv/linux/mips/ldsodefs.h
+++ b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
@@ -34,7 +34,7 @@ extern void _dl_static_init (struct link_map *map);
#undef VALID_ELF_ABIVERSION
#define VALID_ELF_ABIVERSION(osabi,ver) \
(ver == 0 \
- || (osabi == ELFOSABI_SYSV && ver < 5) \
+ || (osabi == ELFOSABI_SYSV && ver < 6) \
|| (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX))
#endif /* ldsodefs.h */
diff --git a/sysdeps/unix/sysv/linux/mips/libc-abis b/sysdeps/unix/sysv/linux/mips/libc-abis
index eaea558720f42a48..c0b67dae3ece1511 100644
--- a/sysdeps/unix/sysv/linux/mips/libc-abis
+++ b/sysdeps/unix/sysv/linux/mips/libc-abis
@@ -16,3 +16,5 @@ UNIQUE
MIPS_O32_FP64 mips*-*-linux*
# Absolute (SHN_ABS) symbols working correctly.
ABSOLUTE
+# GNU-style hash table with translation table.
+MIPS_XHASH

View File

@ -0,0 +1,254 @@
commit 2f9046fb059e94fe254c9a4ff5bcd52182069e44
Author: Stefan Liebler <stli@linux.ibm.com>
Date: Wed Sep 18 12:40:00 2019 +0200
Add UNSUPPORTED check in elf/tst-pldd.
The testcase forks a child process and runs pldd with PID of
this child. On systems where /proc/sys/kernel/yama/ptrace_scope
differs from zero, pldd will fail with
/usr/bin/pldd: cannot attach to process 3: Operation not permitted
This patch checks if ptrace_scope exists, is zero "classic ptrace permissions"
or one "restricted ptrace". If ptrace_scope exists and has a higher
restriction, then the test is marked as UNSUPPORTED.
The case "restricted ptrace" is handled by rearranging the processes involved
during the test. Now we have the following process tree:
-parent: do_test (performs output checks)
--subprocess 1: pldd_process (becomes pldd via execve)
---subprocess 2: target_process (ptraced via pldd)
ChangeLog:
* elf/tst-pldd.c (do_test): Add UNSUPPORTED check.
Rearrange subprocesses.
(pldd_process): New function.
* support/Makefile (libsupport-routines): Add support_ptrace.
* support/xptrace.h: New file.
* support/support_ptrace.c: Likewise.
Conflicts:
elf/tst-pldd.c
(Original backport uses spaces instead of tabs.)
diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c
index e2de31282a131166..f381cb0fa7e6b93d 100644
--- a/elf/tst-pldd.c
+++ b/elf/tst-pldd.c
@@ -30,6 +30,11 @@
#include <support/capture_subprocess.h>
#include <support/check.h>
#include <support/support.h>
+#include <support/xptrace.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <signal.h>
static void
target_process (void *arg)
@@ -37,6 +42,34 @@ target_process (void *arg)
pause ();
}
+static void
+pldd_process (void *arg)
+{
+ pid_t *target_pid_ptr = (pid_t *) arg;
+
+ /* Create a copy of current test to check with pldd. As the
+ target_process is a child of this pldd_process, pldd is also able
+ to attach to target_process if YAMA is configured to 1 =
+ "restricted ptrace". */
+ struct support_subprocess target = support_subprocess (target_process, NULL);
+
+ /* Store the pid of target-process as do_test needs it in order to
+ e.g. terminate it at end of the test. */
+ *target_pid_ptr = target.pid;
+
+ /* Three digits per byte plus null terminator. */
+ char pid[3 * sizeof (uint32_t) + 1];
+ snprintf (pid, array_length (pid), "%d", target.pid);
+
+ char *prog = xasprintf ("%s/pldd", support_bindir_prefix);
+
+ /* Run pldd and use the pid of target_process as argument. */
+ execve (prog, (char *const []) { (char *) prog, pid, NULL },
+ (char *const []) { NULL });
+
+ FAIL_EXIT1 ("Returned from execve: errno=%d=%m\n", errno);
+}
+
/* The test runs in a container because pldd does not support tracing
a binary started by the loader iself (as with testrun.sh). */
@@ -52,25 +85,22 @@ in_str_list (const char *libname, const char *const strlist[])
static int
do_test (void)
{
- /* Create a copy of current test to check with pldd. */
- struct support_subprocess target = support_subprocess (target_process, NULL);
-
- /* Run 'pldd' on test subprocess. */
- struct support_capture_subprocess pldd;
+ /* Check if our subprocess can be debugged with ptrace. */
{
- /* Three digits per byte plus null terminator. */
- char pid[3 * sizeof (uint32_t) + 1];
- snprintf (pid, array_length (pid), "%d", target.pid);
-
- char *prog = xasprintf ("%s/pldd", support_bindir_prefix);
-
- pldd = support_capture_subprogram (prog,
- (char *const []) { (char *) prog, pid, NULL });
+ int ptrace_scope = support_ptrace_scope ();
+ if (ptrace_scope >= 2)
+ FAIL_UNSUPPORTED ("/proc/sys/kernel/yama/ptrace_scope >= 2");
+ }
- support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
+ pid_t *target_pid_ptr = (pid_t *) xmmap (NULL, sizeof (pid_t),
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1);
- free (prog);
- }
+ /* Run 'pldd' on test subprocess which will be created in pldd_process.
+ The pid of the subprocess will be written to target_pid_ptr. */
+ struct support_capture_subprocess pldd;
+ pldd = support_capture_subprocess (pldd_process, target_pid_ptr);
+ support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
/* Check 'pldd' output. The test is expected to be linked against only
loader and libc. */
@@ -85,15 +115,15 @@ do_test (void)
/* First line is in the form of <pid>: <full path of executable> */
TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2);
- TEST_COMPARE (pid, target.pid);
+ TEST_COMPARE (pid, *target_pid_ptr);
TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0);
/* It expects only one loader and libc loaded by the program. */
bool interpreter_found = false, libc_found = false;
while (fgets (buffer, array_length (buffer), out) != NULL)
{
- /* Ignore vDSO. */
- if (buffer[0] != '/')
+ /* Ignore vDSO. */
+ if (buffer[0] != '/')
continue;
/* Remove newline so baseline (buffer) can compare against the
@@ -128,7 +158,9 @@ do_test (void)
}
support_capture_subprocess_free (&pldd);
- support_process_terminate (&target);
+ if (kill (*target_pid_ptr, SIGKILL) != 0)
+ FAIL_EXIT1 ("Unable to kill target_process: errno=%d=%m\n", errno);
+ xmunmap (target_pid_ptr, sizeof (pid_t));
return 0;
}
diff --git a/support/Makefile b/support/Makefile
index 65b16299573af1ed..79d03bd6bfe02540 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -58,6 +58,7 @@ libsupport-routines = \
support_format_hostent \
support_format_netent \
support_isolate_in_subprocess \
+ support_ptrace \
support_openpty \
support_paths \
support_quote_blob \
diff --git a/support/support_ptrace.c b/support/support_ptrace.c
new file mode 100644
index 0000000000000000..616b08cff33022ef
--- /dev/null
+++ b/support/support_ptrace.c
@@ -0,0 +1,44 @@
+/* Support functions handling ptrace_scope.
+ Copyright (C) 2019 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 <support/check.h>
+#include <support/xstdio.h>
+#include <support/xptrace.h>
+#include <sys/prctl.h>
+
+int
+support_ptrace_scope (void)
+{
+ int ptrace_scope = -1;
+
+#ifdef __linux__
+ /* YAMA may be not enabled. Otherwise it contains a value from 0 to 3:
+ - 0 classic ptrace permissions
+ - 1 restricted ptrace
+ - 2 admin-only attach
+ - 3 no attach */
+ FILE *f = fopen ("/proc/sys/kernel/yama/ptrace_scope", "r");
+ if (f != NULL)
+ {
+ TEST_COMPARE (fscanf (f, "%d", &ptrace_scope), 1);
+ xfclose (f);
+ }
+#endif
+
+ return ptrace_scope;
+}
diff --git a/support/xptrace.h b/support/xptrace.h
new file mode 100644
index 0000000000000000..7af892680578fffd
--- /dev/null
+++ b/support/xptrace.h
@@ -0,0 +1,32 @@
+/* Support functions handling ptrace_scope.
+ Copyright (C) 2019 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/>. */
+
+#ifndef SUPPORT_PTRACE_H
+#define SUPPORT_PTRACE_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Return the current YAMA mode set on the machine (0 to 3) or -1
+ if YAMA is not supported. */
+int support_ptrace_scope (void);
+
+__END_DECLS
+
+#endif

View File

@ -0,0 +1,29 @@
commit 64fab3633aecc8eadc1338aa8953f8b2f37e3ebf
Author: Stefan Liebler <stli@linux.ibm.com>
Date: Thu Sep 19 12:26:18 2019 +0200
Fix building support_ptrace.c on i686-gnu.
On i686-gnu the build is broken:
In file included from support_ptrace.c:22:
../include/sys/prctl.h:2:15: fatal error: sys/prctl.h: No such file or directory
#include_next <sys/prctl.h>
This patch just removes the unused prctl.h inclusion.
ChangeLog:
* support/support_ptrace.c: Remove inclusion of sys/prctl.h.
diff --git a/support/support_ptrace.c b/support/support_ptrace.c
index 616b08cff33022ef..a733adf2c8dfd073 100644
--- a/support/support_ptrace.c
+++ b/support/support_ptrace.c
@@ -19,7 +19,6 @@
#include <support/check.h>
#include <support/xstdio.h>
#include <support/xptrace.h>
-#include <sys/prctl.h>
int
support_ptrace_scope (void)

View File

@ -0,0 +1,155 @@
commit 4052fa22f69c0964bb42c0f13daa791617253de5
Author: DJ Delorie <dj@redhat.com>
Date: Wed Oct 2 14:46:46 2019 -0400
Add wait-for-debugger test harness hooks
If WAIT_FOR_DEBUGGER is set to a non-zero value in the environment,
any test that runs will print some useful gdb information and wait
for gdb to attach to it and clear the "wait_for_debugger" variable.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/support/support_test_main.c b/support/support_test_main.c
index fa3c2e06dee5ae0f..def84d803928176b 100644
--- a/support/support_test_main.c
+++ b/support/support_test_main.c
@@ -19,6 +19,7 @@
#include <support/test-driver.h>
#include <support/check.h>
#include <support/temp_file-internal.h>
+#include <support/support.h>
#include <assert.h>
#include <errno.h>
@@ -36,6 +37,8 @@
#include <time.h>
#include <unistd.h>
+#include <xstdio.h>
+
static const struct option default_options[] =
{
TEST_DEFAULT_OPTIONS
@@ -176,10 +179,55 @@ signal_handler (int sig)
exit (1);
}
+/* This must be volatile as it will be modified by the debugger. */
+static volatile int wait_for_debugger = 0;
+
/* Run test_function or test_function_argv. */
static int
run_test_function (int argc, char **argv, const struct test_config *config)
{
+ const char *wfd = getenv("WAIT_FOR_DEBUGGER");
+ if (wfd != NULL)
+ wait_for_debugger = atoi (wfd);
+ if (wait_for_debugger)
+ {
+ pid_t mypid;
+ FILE *gdb_script;
+ char *gdb_script_name;
+ int inside_container = 0;
+
+ mypid = getpid();
+ if (mypid < 3)
+ {
+ const char *outside_pid = getenv("PID_OUTSIDE_CONTAINER");
+ if (outside_pid)
+ {
+ mypid = atoi (outside_pid);
+ inside_container = 1;
+ }
+ }
+
+ gdb_script_name = (char *) xmalloc (strlen (argv[0]) + strlen (".gdb") + 1);
+ sprintf (gdb_script_name, "%s.gdb", argv[0]);
+ gdb_script = xfopen (gdb_script_name, "w");
+
+ fprintf (stderr, "Waiting for debugger, test process is pid %d\n", mypid);
+ fprintf (stderr, "gdb -x %s\n", gdb_script_name);
+ if (inside_container)
+ fprintf (gdb_script, "set sysroot %s/testroot.root\n", support_objdir_root);
+ fprintf (gdb_script, "file\n");
+ fprintf (gdb_script, "file %s\n", argv[0]);
+ fprintf (gdb_script, "symbol-file %s\n", argv[0]);
+ fprintf (gdb_script, "exec-file %s\n", argv[0]);
+ fprintf (gdb_script, "attach %ld\n", (long int) mypid);
+ fprintf (gdb_script, "set wait_for_debugger = 0\n");
+ fclose (gdb_script);
+ }
+
+ /* Wait for the debugger to set wait_for_debugger to zero. */
+ while (wait_for_debugger)
+ usleep (1000);
+
if (config->test_function != NULL)
return config->test_function ();
else if (config->test_function_argv != NULL)
@@ -229,6 +277,11 @@ support_test_main (int argc, char **argv, const struct test_config *config)
unsigned int timeoutfactor = 1;
pid_t termpid;
+ /* If we're debugging the test, we need to disable timeouts and use
+ the initial pid (esp if we're running inside a container). */
+ if (getenv("WAIT_FOR_DEBUGGER") != NULL)
+ direct = 1;
+
if (!config->no_mallopt)
{
/* Make uses of freed and uninitialized memory known. Do not
diff --git a/support/test-container.c b/support/test-container.c
index f0d9e3060e80bda5..6503cea90309b9b0 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -676,6 +676,9 @@ main (int argc, char **argv)
char *so_base;
int do_postclean = 0;
+ int pipes[2];
+ char pid_buf[20];
+
uid_t original_uid;
gid_t original_gid;
/* If set, the test runs as root instead of the user running the testsuite. */
@@ -999,6 +1002,11 @@ main (int argc, char **argv)
if (chdir (new_cwd_path) < 0)
FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path);
+ /* This is to pass the "outside" PID to the child, which will be PID
+ 1. */
+ if (pipe2 (pipes, O_CLOEXEC) < 0)
+ FAIL_EXIT1 ("Can't create pid pipe");
+
/* To complete the containerization, we need to fork () at least
once. We can't exec, nor can we somehow link the new child to
our parent. So we run the child and propogate it's exit status
@@ -1010,6 +1018,12 @@ main (int argc, char **argv)
{
/* Parent. */
int status;
+
+ /* Send the child's "outside" pid to it. */
+ write (pipes[1], &child, sizeof(child));
+ close (pipes[0]);
+ close (pipes[1]);
+
waitpid (child, &status, 0);
if (WIFEXITED (status))
@@ -1028,6 +1042,14 @@ main (int argc, char **argv)
/* The rest is the child process, which is now PID 1 and "in" the
new root. */
+ /* Get our "outside" pid from our parent. We use this to help with
+ debugging from outside the container. */
+ read (pipes[0], &child, sizeof(child));
+ close (pipes[0]);
+ close (pipes[1]);
+ sprintf (pid_buf, "%lu", (long unsigned)child);
+ setenv ("PID_OUTSIDE_CONTAINER", pid_buf, 0);
+
maybe_xmkdir ("/tmp", 0755);
/* Now that we're pid 1 (effectively "root") we can mount /proc */

View File

@ -0,0 +1,421 @@
commit c7bf5ceab6ec776ac7350d3b0190776bf532ac54
Author: Florian Weimer <fweimer@redhat.com>
Date: Sat Nov 2 21:55:35 2019 +0100
Properly initialize audit cookie for the dynamic loader [BZ #25157]
The l_audit array is indexed by audit module, not audit function.
Change-Id: I180eb3573dc1c57433750f5d8cb18271460ba5f2
Conflicts:
elf/Makefile
(Test backport differences.)
diff --git a/elf/Makefile b/elf/Makefile
index 4e1356b9172aee02..4ab73dc48d9ac126 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -192,7 +192,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
tst-audit13 \
- tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \
+ tst-sonamemove-link tst-sonamemove-dlopen \
+ tst-auditmany tst-initfinilazyfail \
tst-dlopenfail tst-dlopenfail-2 \
tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen
# reldep9
@@ -303,6 +304,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-absolute-zero-lib tst-big-note-lib \
tst-audit13mod1 tst-sonamemove-linkmod1 \
tst-sonamemove-runmod1 tst-sonamemove-runmod2 \
+ tst-auditmanymod1 tst-auditmanymod2 tst-auditmanymod3 \
+ tst-auditmanymod4 tst-auditmanymod5 tst-auditmanymod6 \
+ tst-auditmanymod7 tst-auditmanymod8 tst-auditmanymod9 \
tst-initlazyfailmod tst-finilazyfailmod \
tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
tst-dlopenfailmod3 \
@@ -1433,6 +1437,14 @@ $(objpfx)tst-audit13.out: $(objpfx)tst-audit13mod1.so
LDFLAGS-tst-audit13mod1.so = -Wl,-z,lazy
tst-audit13-ENV = LD_AUDIT=$(objpfx)tst-audit13mod1.so
+$(objpfx)tst-auditmany.out: $(objpfx)tst-auditmanymod1.so \
+ $(objpfx)tst-auditmanymod2.so $(objpfx)tst-auditmanymod3.so \
+ $(objpfx)tst-auditmanymod4.so $(objpfx)tst-auditmanymod5.so \
+ $(objpfx)tst-auditmanymod6.so $(objpfx)tst-auditmanymod7.so \
+ $(objpfx)tst-auditmanymod8.so $(objpfx)tst-auditmanymod9.so
+tst-auditmany-ENV = \
+ LD_AUDIT=tst-auditmanymod1.so:tst-auditmanymod2.so:tst-auditmanymod3.so:tst-auditmanymod4.so:tst-auditmanymod5.so:tst-auditmanymod6.so:tst-auditmanymod7.so:tst-auditmanymod8.so:tst-auditmanymod9.so
+
# tst-sonamemove links against an older implementation of the library.
LDFLAGS-tst-sonamemove-linkmod1.so = \
-Wl,--version-script=tst-sonamemove-linkmod1.map \
diff --git a/elf/rtld.c b/elf/rtld.c
index ffbd8f4553bb3425..f557f39a70669c09 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1008,13 +1008,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
/* Store the pointer. */
if (err_str == NULL && largs.result != NULL)
- {
- newp->fptr[cnt] = largs.result;
-
- /* The dynamic linker link map is statically allocated,
- initialize the data now. */
- GL(dl_rtld_map).l_audit[cnt].cookie = (intptr_t) &GL(dl_rtld_map);
- }
+ newp->fptr[cnt] = largs.result;
else
newp->fptr[cnt] = NULL;
++cnt;
@@ -1030,6 +1024,12 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
*last_audit = GLRO(dl_audit) = &newp->ifaces;
else
*last_audit = (*last_audit)->next = &newp->ifaces;
+
+ /* The dynamic linker link map is statically allocated, initialize
+ the data now. */
+ GL (dl_rtld_map).l_audit[GLRO (dl_naudit)].cookie
+ = (intptr_t) &GL (dl_rtld_map);
+
++GLRO(dl_naudit);
/* Mark the DSO as being used for auditing. */
diff --git a/elf/tst-auditmany.c b/elf/tst-auditmany.c
new file mode 100644
index 0000000000000000..9d68105b9e707b46
--- /dev/null
+++ b/elf/tst-auditmany.c
@@ -0,0 +1,26 @@
+/* Check cookie initialization for many auditors. Main program.
+ Copyright (C) 2019 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/>. */
+
+/* It does not make sense to use the test harness for this test
+ because the testing happens in auditors. */
+
+int
+main (void)
+{
+ return 0;
+}
diff --git a/elf/tst-auditmanymod.h b/elf/tst-auditmanymod.h
new file mode 100644
index 0000000000000000..d1d89e08431ce32f
--- /dev/null
+++ b/elf/tst-auditmanymod.h
@@ -0,0 +1,64 @@
+/* Check cookie initialization for many auditors. Auditor template.
+ Copyright (C) 2019 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/>. */
+
+/* The macro MOD must be defined to the number of this auditor (an
+ integer) before including this file. */
+
+#include <link.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* Error counter for delayed error reporting. */
+static int errors;
+
+unsigned int
+la_version (unsigned int version)
+{
+ return version;
+}
+
+unsigned int
+la_objopen (struct link_map *map, Lmid_t lmid,
+ uintptr_t *cookie)
+{
+ struct link_map *cookie_map = (struct link_map *) *cookie;
+ printf ("info: %d, la_objopen: map=%p name=%s cookie=%p:%p diff=%td\n",
+ MOD, map, map->l_name, cookie, cookie_map,
+ (char *) cookie - (char *) map);
+ fflush (stdout);
+ if (map != cookie_map)
+ {
+ printf ("error: %d, la_objopen:"
+ " map address does not match cookie value\n",
+ MOD);
+ fflush (stdout);
+ ++errors;
+ }
+ return 0;
+}
+
+extern unsigned int
+la_objclose (uintptr_t *__cookie)
+{
+ if (errors != 0)
+ {
+ printf ("error: exiting due to previous errors");
+ _exit (1);
+ }
+ return 0;
+}
diff --git a/elf/tst-auditmanymod1.c b/elf/tst-auditmanymod1.c
new file mode 100644
index 0000000000000000..c7de49d446a7e52d
--- /dev/null
+++ b/elf/tst-auditmanymod1.c
@@ -0,0 +1,20 @@
+/* Check cookie initialization for many auditors. Auditor 1.
+ Copyright (C) 2019 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/>. */
+
+#define MOD 1
+#include "tst-auditmanymod.h"
diff --git a/elf/tst-auditmanymod2.c b/elf/tst-auditmanymod2.c
new file mode 100644
index 0000000000000000..4254f022a177b844
--- /dev/null
+++ b/elf/tst-auditmanymod2.c
@@ -0,0 +1,20 @@
+/* Check cookie initialization for many auditors. Auditor 2.
+ Copyright (C) 2019 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/>. */
+
+#define MOD 2
+#include "tst-auditmanymod.h"
diff --git a/elf/tst-auditmanymod3.c b/elf/tst-auditmanymod3.c
new file mode 100644
index 0000000000000000..ee90f4eb3a5c1b35
--- /dev/null
+++ b/elf/tst-auditmanymod3.c
@@ -0,0 +1,20 @@
+/* Check cookie initialization for many auditors. Auditor 3.
+ Copyright (C) 2019 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/>. */
+
+#define MOD 3
+#include "tst-auditmanymod.h"
diff --git a/elf/tst-auditmanymod4.c b/elf/tst-auditmanymod4.c
new file mode 100644
index 0000000000000000..6379fa1d55014998
--- /dev/null
+++ b/elf/tst-auditmanymod4.c
@@ -0,0 +1,20 @@
+/* Check cookie initialization for many auditors. Auditor 4.
+ Copyright (C) 2019 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/>. */
+
+#define MOD 4
+#include "tst-auditmanymod.h"
diff --git a/elf/tst-auditmanymod5.c b/elf/tst-auditmanymod5.c
new file mode 100644
index 0000000000000000..17c0f617aa4d1893
--- /dev/null
+++ b/elf/tst-auditmanymod5.c
@@ -0,0 +1,20 @@
+/* Check cookie initialization for many auditors. Auditor 5.
+ Copyright (C) 2019 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/>. */
+
+#define MOD 5
+#include "tst-auditmanymod.h"
diff --git a/elf/tst-auditmanymod6.c b/elf/tst-auditmanymod6.c
new file mode 100644
index 0000000000000000..86bc6801a4454742
--- /dev/null
+++ b/elf/tst-auditmanymod6.c
@@ -0,0 +1,20 @@
+/* Check cookie initialization for many auditors. Auditor 6.
+ Copyright (C) 2019 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/>. */
+
+#define MOD 6
+#include "tst-auditmanymod.h"
diff --git a/elf/tst-auditmanymod7.c b/elf/tst-auditmanymod7.c
new file mode 100644
index 0000000000000000..92b0bf6006876dff
--- /dev/null
+++ b/elf/tst-auditmanymod7.c
@@ -0,0 +1,20 @@
+/* Check cookie initialization for many auditors. Auditor 7.
+ Copyright (C) 2019 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/>. */
+
+#define MOD 7
+#include "tst-auditmanymod.h"
diff --git a/elf/tst-auditmanymod8.c b/elf/tst-auditmanymod8.c
new file mode 100644
index 0000000000000000..d42f884d2f24f4c0
--- /dev/null
+++ b/elf/tst-auditmanymod8.c
@@ -0,0 +1,20 @@
+/* Check cookie initialization for many auditors. Auditor 8.
+ Copyright (C) 2019 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/>. */
+
+#define MOD 8
+#include "tst-auditmanymod.h"
diff --git a/elf/tst-auditmanymod9.c b/elf/tst-auditmanymod9.c
new file mode 100644
index 0000000000000000..6bee81d69c6d3c22
--- /dev/null
+++ b/elf/tst-auditmanymod9.c
@@ -0,0 +1,20 @@
+/* Check cookie initialization for many auditors. Auditor 9.
+ Copyright (C) 2019 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/>. */
+
+#define MOD 9
+#include "tst-auditmanymod.h"

View File

@ -0,0 +1,340 @@
commit e1d559f337de2c8ab68a6749dfe873477c883807
Author: Florian Weimer <fweimer@redhat.com>
Date: Sat Nov 2 20:04:02 2019 +0100
Introduce link_map_audit_state accessor function
To improve GCC 10 compatibility, it is necessary to remove the l_audit
zero-length array from the end of struct link_map. In preparation of
that, this commit introduces an accessor function for the audit state,
so that it is possible to change the representation of the audit state
without adjusting the code that accesses it.
Tested on x86_64-linux-gnu. Built on i686-gnu.
Change-Id: Id815673c29950fc011ae5301d7cde12624f658df
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 494132368f8fe486..dfbf195328239a17 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -272,7 +272,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->preinit != NULL)
- afct->preinit (&head->l_audit[cnt].cookie);
+ afct->preinit (&link_map_audit_state (head, cnt)->cookie);
afct = afct->next;
}
diff --git a/elf/dl-close.c b/elf/dl-close.c
index a9ecdff62dba88fb..1ece0ae1dd062d1e 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -305,8 +305,12 @@ _dl_close_worker (struct link_map *map, bool force)
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->objclose != NULL)
- /* Return value is ignored. */
- (void) afct->objclose (&imap->l_audit[cnt].cookie);
+ {
+ struct auditstate *state
+ = link_map_audit_state (imap, cnt);
+ /* Return value is ignored. */
+ (void) afct->objclose (&state->cookie);
+ }
afct = afct->next;
}
@@ -481,7 +485,10 @@ _dl_close_worker (struct link_map *map, bool force)
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_DELETE);
+ {
+ struct auditstate *state = link_map_audit_state (head, cnt);
+ afct->activity (&state->cookie, LA_ACT_DELETE);
+ }
afct = afct->next;
}
@@ -781,7 +788,10 @@ _dl_close_worker (struct link_map *map, bool force)
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
+ {
+ struct auditstate *state = link_map_audit_state (head, cnt);
+ afct->activity (&state->cookie, LA_ACT_CONSISTENT);
+ }
afct = afct->next;
}
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index 3cfc262400da4db9..915ceb104e1c81d6 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -152,9 +152,12 @@ _dl_fini (void)
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->objclose != NULL)
- /* Return value is ignored. */
- (void) afct->objclose (&l->l_audit[cnt].cookie);
-
+ {
+ struct auditstate *state
+ = link_map_audit_state (l, cnt);
+ /* Return value is ignored. */
+ (void) afct->objclose (&state->cookie);
+ }
afct = afct->next;
}
}
diff --git a/elf/dl-load.c b/elf/dl-load.c
index b190b28e32e47391..8f8869ff524ab9f2 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -979,7 +979,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_ADD);
+ afct->activity (&link_map_audit_state (head, cnt)->cookie,
+ LA_ACT_ADD);
afct = afct->next;
}
@@ -1418,10 +1419,9 @@ cannot enable executable stack as shared object requires");
{
if (afct->objopen != NULL)
{
- l->l_audit[cnt].bindflags
- = afct->objopen (l, nsid, &l->l_audit[cnt].cookie);
-
- l->l_audit_any_plt |= l->l_audit[cnt].bindflags != 0;
+ struct auditstate *state = link_map_audit_state (l, cnt);
+ state->bindflags = afct->objopen (l, nsid, &state->cookie);
+ l->l_audit_any_plt |= state->bindflags != 0;
}
afct = afct->next;
@@ -1527,8 +1527,8 @@ open_verify (const char *name, int fd,
{
if (afct->objsearch != NULL)
{
- name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
- whatcode);
+ struct auditstate *state = link_map_audit_state (loader, cnt);
+ name = afct->objsearch (name, &state->cookie, whatcode);
if (name == NULL)
/* Ignore the path. */
return -1;
@@ -1998,8 +1998,8 @@ _dl_map_object (struct link_map *loader, const char *name,
if (afct->objsearch != NULL)
{
const char *before = name;
- name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
- LA_SER_ORIG);
+ struct auditstate *state = link_map_audit_state (loader, cnt);
+ name = afct->objsearch (name, &state->cookie, LA_SER_ORIG);
if (name == NULL)
{
/* Do not try anything further. */
diff --git a/elf/dl-object.c b/elf/dl-object.c
index f6544a8fec45bdce..05a7750c65305771 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -81,7 +81,7 @@ _dl_new_object (char *realname, const char *libname, int type,
struct link_map *new;
struct libname_list *newname;
#ifdef SHARED
- size_t audit_space = naudit * sizeof (new->l_audit[0]);
+ size_t audit_space = naudit * sizeof (struct auditstate);
#else
# define audit_space 0
#endif
@@ -134,10 +134,8 @@ _dl_new_object (char *realname, const char *libname, int type,
#ifdef SHARED
for (unsigned int cnt = 0; cnt < naudit; ++cnt)
- {
- new->l_audit[cnt].cookie = (uintptr_t) new;
- /* new->l_audit[cnt].bindflags = 0; */
- }
+ /* No need to initialize bindflags due to calloc. */
+ link_map_audit_state (new, cnt)->cookie = (uintptr_t) new;
#endif
/* new->l_global = 0; We use calloc therefore not necessary. */
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 46a4c1e5a3f8d2dd..7113c4a04f0fddbc 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -589,7 +589,10 @@ dl_open_worker (void *a)
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
+ {
+ struct auditstate *state = link_map_audit_state (head, cnt);
+ afct->activity (&state->cookie, LA_ACT_CONSISTENT);
+ }
afct = afct->next;
}
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 3d2f4a7a76e616e3..72b03e000dcf190e 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -325,15 +325,18 @@ _dl_profile_fixup (
{
/* XXX Check whether both DSOs must request action or
only one */
- if ((l->l_audit[cnt].bindflags & LA_FLG_BINDFROM) != 0
- && (result->l_audit[cnt].bindflags & LA_FLG_BINDTO) != 0)
+ struct auditstate *l_state = link_map_audit_state (l, cnt);
+ struct auditstate *result_state
+ = link_map_audit_state (result, cnt);
+ if ((l_state->bindflags & LA_FLG_BINDFROM) != 0
+ && (result_state->bindflags & LA_FLG_BINDTO) != 0)
{
if (afct->symbind != NULL)
{
uintptr_t new_value
= afct->symbind (&sym, reloc_result->boundndx,
- &l->l_audit[cnt].cookie,
- &result->l_audit[cnt].cookie,
+ &l_state->cookie,
+ &result_state->cookie,
&flags,
strtab2 + defsym->st_name);
if (new_value != (uintptr_t) sym.st_value)
@@ -421,10 +424,13 @@ _dl_profile_fixup (
& (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
{
long int new_framesize = -1;
+ struct auditstate *l_state = link_map_audit_state (l, cnt);
+ struct auditstate *bound_state
+ = link_map_audit_state (reloc_result->bound, cnt);
uintptr_t new_value
= afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
- &l->l_audit[cnt].cookie,
- &reloc_result->bound->l_audit[cnt].cookie,
+ &l_state->cookie,
+ &bound_state->cookie,
regs, &flags, symname,
&new_framesize);
if (new_value != (uintptr_t) sym.st_value)
@@ -504,9 +510,11 @@ _dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_arg,
&& (reloc_result->enterexit
& (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
{
+ struct auditstate *l_state = link_map_audit_state (l, cnt);
+ struct auditstate *bound_state
+ = link_map_audit_state (reloc_result->bound, cnt);
afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
- &l->l_audit[cnt].cookie,
- &reloc_result->bound->l_audit[cnt].cookie,
+ &l_state->cookie, &bound_state->cookie,
inregs, outregs, symname);
}
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 189628adc05aedf1..286cf7e27fd59f20 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -198,17 +198,20 @@ RTLD_NEXT used in code not dynamically loaded"));
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
+ struct auditstate *match_audit
+ = link_map_audit_state (match, cnt);
+ struct auditstate *result_audit
+ = link_map_audit_state (result, cnt);
if (afct->symbind != NULL
- && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
- != 0
- || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
+ && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
+ || ((result_audit->bindflags & LA_FLG_BINDTO)
!= 0)))
{
unsigned int flags = altvalue | LA_SYMB_DLSYM;
uintptr_t new_value
= afct->symbind (&sym, ndx,
- &match->l_audit[cnt].cookie,
- &result->l_audit[cnt].cookie,
+ &match_audit->cookie,
+ &result_audit->cookie,
&flags, strtab + ref->st_name);
if (new_value != (uintptr_t) sym.st_value)
{
diff --git a/elf/rtld.c b/elf/rtld.c
index f557f39a70669c09..18335bc666f2b89d 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1025,9 +1025,9 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
else
*last_audit = (*last_audit)->next = &newp->ifaces;
- /* The dynamic linker link map is statically allocated, initialize
- the data now. */
- GL (dl_rtld_map).l_audit[GLRO (dl_naudit)].cookie
+ /* The dynamic linker link map is statically allocated, so the
+ cookie in _dl_new_object has not happened. */
+ link_map_audit_state (&GL (dl_rtld_map), GLRO (dl_naudit))->cookie
= (intptr_t) &GL (dl_rtld_map);
++GLRO(dl_naudit);
@@ -1046,9 +1046,9 @@ notify_audit_modules_of_loaded_object (struct link_map *map)
{
if (afct->objopen != NULL)
{
- map->l_audit[cnt].bindflags
- = afct->objopen (map, LM_ID_BASE, &map->l_audit[cnt].cookie);
- map->l_audit_any_plt |= map->l_audit[cnt].bindflags != 0;
+ struct auditstate *state = link_map_audit_state (map, cnt);
+ state->bindflags = afct->objopen (map, LM_ID_BASE, &state->cookie);
+ map->l_audit_any_plt |= state->bindflags != 0;
}
afct = afct->next;
@@ -1660,7 +1660,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
- afct->activity (&main_map->l_audit[cnt].cookie, LA_ACT_ADD);
+ afct->activity (&link_map_audit_state (main_map, cnt)->cookie,
+ LA_ACT_ADD);
afct = afct->next;
}
@@ -2331,7 +2332,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
if (afct->activity != NULL)
- afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
+ afct->activity (&link_map_audit_state (head, cnt)->cookie,
+ LA_ACT_CONSISTENT);
afct = afct->next;
}
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 3bdbdd6e67dacc85..a8fb0d211426e4b1 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1197,7 +1197,13 @@ rtld_active (void)
initialized and active ld.so copy. */
return GLRO(dl_init_all_dirs) != NULL;
}
-#endif
+
+static inline struct auditstate *
+link_map_audit_state (struct link_map *l, size_t index)
+{
+ return &l->l_audit[index];
+}
+#endif /* SHARED */
__END_DECLS

View File

@ -0,0 +1,80 @@
commit 4a2ab5843a5cc4a5db1b3b79916a520ea8b115dc
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Nov 8 15:48:51 2019 +0100
dlsym: Do not determine caller link map if not needed
Obtaining the link map is potentially very slow because it requires
iterating over all loaded objects in the current implementation. If
the caller supplied an explicit handle (i.e., not one of the RTLD_*
constants), the dlsym implementation does not need the identity of the
caller (except in the special case of auditing), so this change
avoids computing it in that case.
Even in the minimal case (dlsym called from a main program linked with
-dl), this shows a small speedup, perhaps around five percent. The
performance improvement can be arbitrarily large in principle (if
_dl_find_dso_for_object has to iterate over many link maps).
Change-Id: Ide5d9e2cc7ac25a0ffae8fb4c26def0c898efa29
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 286cf7e27fd59f20..b133850a3c6657a4 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -80,6 +80,18 @@ call_dl_lookup (void *ptr)
args->flags, NULL);
}
+/* Return the link map containing the caller address. */
+static inline struct link_map *
+find_caller_link_map (ElfW(Addr) caller)
+{
+ struct link_map *l = _dl_find_dso_for_object (caller);
+ if (l != NULL)
+ return l;
+ else
+ /* If the address is not recognized the call comes from the main
+ program (we hope). */
+ return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+}
static void *
do_sym (void *handle, const char *name, void *who,
@@ -89,13 +101,13 @@ do_sym (void *handle, const char *name, void *who,
lookup_t result;
ElfW(Addr) caller = (ElfW(Addr)) who;
- struct link_map *l = _dl_find_dso_for_object (caller);
- /* If the address is not recognized the call comes from the main
- program (we hope). */
- struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+ /* Link map of the caller if needed. */
+ struct link_map *match = NULL;
if (handle == RTLD_DEFAULT)
{
+ match = find_caller_link_map (caller);
+
/* Search the global scope. We have the simple case where
we look up in the scope of an object which was part of
the initial binary. And then the more complex part
@@ -128,6 +140,8 @@ do_sym (void *handle, const char *name, void *who,
}
else if (handle == RTLD_NEXT)
{
+ match = find_caller_link_map (caller);
+
if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
{
if (match == NULL
@@ -187,6 +201,9 @@ RTLD_NEXT used in code not dynamically loaded"));
unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
l_info[DT_SYMTAB]));
+ if (match == NULL)
+ match = find_caller_link_map (caller);
+
if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
{
unsigned int altvalue = 0;

View File

@ -0,0 +1,211 @@
commit 4f79b3e2fb3eba003240ec38a0e68702b9a60b86
Author: DJ Delorie <dj@redhat.com>
Date: Mon Feb 3 14:49:25 2020 -0500
test-container: add exec, cwd
exec <path_to_test_binary> [optional_argv_0]
copies test binary to specified location and runs it from
there. If the second argument is provided, that will
be used for argv[0]
cwd <directory>
attempts to chdir(directory) before running test
Note: "cwd" not "cd" as it takes effect just before the
test binary runs, not when it's encountered in the script,
so it can't be used as a path shortcut like "cd" would imply.
cleanup: use xstrdup() instead of strdup()
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/support/test-container.c b/support/test-container.c
index 6503cea90309b9b0..9488ec7b4a824380 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -95,6 +95,8 @@ int verbose = 0;
mv FILE FILE
cp FILE FILE
rm FILE
+ cwd PATH
+ exec FILE
FILE must start with $B/, $S/, $I/, $L/, or /
(expands to build dir, source dir, install dir, library dir
(in container), or container's root)
@@ -104,6 +106,8 @@ int verbose = 0;
- 'mv': A minimal move files command.
- 'cp': A minimal copy files command.
- 'rm': A minimal remove files command.
+ - 'cwd': set test working directory
+ - 'exec': change test binary location (may end in /)
* mytest.root/postclean.req causes fresh rsync (with delete) after
test if present
@@ -147,7 +151,7 @@ maybe_xmkdir (const char *path, mode_t mode)
}
/* Temporarily concatenate multiple strings into one. Allows up to 10
- temporary results; use strdup () if you need them to be
+ temporary results; use xstrdup () if you need them to be
permanent. */
static char *
concat (const char *str, ...)
@@ -670,11 +674,13 @@ main (int argc, char **argv)
char *new_objdir_path;
char *new_srcdir_path;
char **new_child_proc;
+ char *new_child_exec;
char *command_root;
char *command_base;
char *command_basename;
char *so_base;
int do_postclean = 0;
+ char *change_cwd = NULL;
int pipes[2];
char pid_buf[20];
@@ -701,7 +707,7 @@ main (int argc, char **argv)
if (argc < 2)
{
- fprintf (stderr, "Usage: containerize <program to run> <args...>\n");
+ fprintf (stderr, "Usage: test-container <program to run> <args...>\n");
exit (1);
}
@@ -746,12 +752,13 @@ main (int argc, char **argv)
}
}
- pristine_root_path = strdup (concat (support_objdir_root,
+ pristine_root_path = xstrdup (concat (support_objdir_root,
"/testroot.pristine", NULL));
- new_root_path = strdup (concat (support_objdir_root,
+ new_root_path = xstrdup (concat (support_objdir_root,
"/testroot.root", NULL));
new_cwd_path = get_current_dir_name ();
new_child_proc = argv + 1;
+ new_child_exec = argv[1];
lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL),
O_CREAT | O_TRUNC | O_RDWR, 0666);
@@ -778,10 +785,10 @@ main (int argc, char **argv)
command_root = concat (support_srcdir_root,
argv[1] + strlen (support_objdir_root),
".root", NULL);
- command_root = strdup (command_root);
+ command_root = xstrdup (command_root);
/* This cuts off the ".root" we appended above. */
- command_base = strdup (command_root);
+ command_base = xstrdup (command_root);
command_base[strlen (command_base) - 5] = 0;
/* This is the basename of the test we're running. */
@@ -792,7 +799,7 @@ main (int argc, char **argv)
++command_basename;
/* Shared object base directory. */
- so_base = strdup (argv[1]);
+ so_base = xstrdup (argv[1]);
if (strrchr (so_base, '/') != NULL)
strrchr (so_base, '/')[1] = 0;
@@ -806,9 +813,9 @@ main (int argc, char **argv)
&& S_ISDIR (st.st_mode))
rsync (command_root, new_root_path, 0);
- new_objdir_path = strdup (concat (new_root_path,
+ new_objdir_path = xstrdup (concat (new_root_path,
support_objdir_root, NULL));
- new_srcdir_path = strdup (concat (new_root_path,
+ new_srcdir_path = xstrdup (concat (new_root_path,
support_srcdir_root, NULL));
/* new_cwd_path starts with '/' so no "/" needed between the two. */
@@ -868,7 +875,10 @@ main (int argc, char **argv)
the_words[i] = concat (new_root_path,
support_libdir_prefix,
the_words[i] + 2, NULL);
- else if (the_words[i][0] == '/')
+ /* "exec" and "cwd" use inside-root paths. */
+ else if (strcmp (the_words[0], "exec") != 0
+ && strcmp (the_words[0], "cwd") != 0
+ && the_words[i][0] == '/')
the_words[i] = concat (new_root_path,
the_words[i], NULL);
}
@@ -912,13 +922,49 @@ main (int argc, char **argv)
{
maybe_xunlink (the_words[1]);
}
+ else if (nt >= 2 && strcmp (the_words[0], "exec") == 0)
+ {
+ /* The first argument is the desired location and name
+ of the test binary as we wish to exec it; we will
+ copy the binary there. The second (optional)
+ argument is the value to pass as argv[0], it
+ defaults to the same as the first argument. */
+ char *new_exec_path = the_words[1];
+
+ /* If the new exec path ends with a slash, that's the
+ * directory, and use the old test base name. */
+ if (new_exec_path [strlen(new_exec_path) - 1] == '/')
+ new_exec_path = concat (new_exec_path,
+ basename (new_child_proc[0]),
+ NULL);
+
+
+ /* new_child_proc is in the build tree, so has the
+ same path inside the chroot as outside. The new
+ exec path is, by definition, relative to the
+ chroot. */
+ copy_one_file (new_child_proc[0], concat (new_root_path,
+ new_exec_path,
+ NULL));
+
+ new_child_exec = xstrdup (new_exec_path);
+ if (the_words[2])
+ new_child_proc[0] = xstrdup (the_words[2]);
+ else
+ new_child_proc[0] = new_child_exec;
+ }
+ else if (nt == 2 && strcmp (the_words[0], "cwd") == 0)
+ {
+ change_cwd = xstrdup (the_words[1]);
+ }
else if (nt == 1 && strcmp (the_words[0], "su") == 0)
{
be_su = 1;
}
else if (nt > 0 && the_words[0][0] != '#')
{
- printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]);
+ fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]);
+ exit (1);
}
}
fclose (f);
@@ -1089,11 +1135,17 @@ main (int argc, char **argv)
write (GMAP, tmp, strlen (tmp));
xclose (GMAP);
+ if (change_cwd)
+ {
+ if (chdir (change_cwd) < 0)
+ FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd);
+ }
+
/* Now run the child. */
- execvp (new_child_proc[0], new_child_proc);
+ execvp (new_child_exec, new_child_proc);
/* Or don't run the child? */
- FAIL_EXIT1 ("Unable to exec %s\n", new_child_proc[0]);
+ FAIL_EXIT1 ("Unable to exec %s\n", new_child_exec);
/* Because gcc won't know error () never returns... */
exit (EXIT_UNSUPPORTED);

View File

@ -0,0 +1,50 @@
commit abcc039d2e26b3c9c723d6419e086753a791b3d5
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Feb 7 20:06:32 2020 +0100
elf: Introduce the rtld-stubbed-symbols makefile variable
This generalizes a mechanism used for stack-protector support, so
that it can be applied to other symbols if required.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/Makefile b/elf/Makefile
index 4ab73dc48d9ac126..a1ea44f231d8cec5 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -474,21 +474,25 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os)
# are compiled with special flags, and puts these modules into rtld-libc.a
# for us. Then we do the real link using rtld-libc.a instead of libc_pic.a.
-# If the compiler can do SSP, build the mapfile with dummy __stack_chk_fail
-# and __stack_chk_fail_local symbols defined, to prevent the real things
-# being dragged into rtld even though rtld is never built with stack-
-# protection.
+# These symbols need to be stubbed out during symbol discovery because
+# their implementation is provided differently in rtld, and the symbol
+# discovery mechanism is not compatible with the libc implementation
+# when compiled for libc.
+rtld-stubbed-symbols =
+
+# The GCC arguments that implement $(rtld-stubbed-symbols).
+rtld-stubbed-symbols-args = \
+ $(patsubst %,-Wl$(comma)--defsym=%=0, $(rtld-stubbed-symbols))
ifeq ($(have-ssp),yes)
-dummy-stack-chk-fail := -Wl,--defsym='__stack_chk_fail=0' \
- -Wl,--defsym='__stack_chk_fail_local=0'
-else
-dummy-stack-chk-fail :=
+# rtld is not built with the stack protector, so these references will
+# go away in the rebuilds.
+rtld-stubbed-symbols += __stack_chk_fail __stack_chk_fail_local
endif
$(objpfx)librtld.map: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a
@-rm -f $@T
- $(reloc-link) -o $@.o $(dummy-stack-chk-fail) \
+ $(reloc-link) -o $@.o $(rtld-stubbed-symbols-args) \
'-Wl,-(' $^ -lgcc '-Wl,-)' -Wl,-Map,$@T
rm -f $@.o
mv -f $@T $@

View File

@ -0,0 +1,64 @@
commit 430388d5dc0e1861b869096f4f5d946d7d74232a
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Fri Aug 3 08:04:49 2018 -0700
x86: Don't include <init-arch.h> in assembly codes
There is no need to include <init-arch.h> in assembly codes since all
x86 IFUNC selector functions are written in C. Tested on i686 and
x86-64. There is no code change in libc.so, ld.so and libmvec.so.
* sysdeps/i386/i686/multiarch/bzero-ia32.S: Don't include
<init-arch.h>.
* sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S: Likewise.
* sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S: Likewise.
* sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S: Likewise.
diff --git a/sysdeps/i386/i686/multiarch/bzero-ia32.S b/sysdeps/i386/i686/multiarch/bzero-ia32.S
index 68ff9e1e903f7c4c..94d13e88f7532bc0 100644
--- a/sysdeps/i386/i686/multiarch/bzero-ia32.S
+++ b/sysdeps/i386/i686/multiarch/bzero-ia32.S
@@ -17,7 +17,6 @@
<http://www.gnu.org/licenses/>. */
#include <sysdep.h>
-#include <init-arch.h>
#if IS_IN (libc)
# define __bzero __bzero_ia32
diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S
index b64c3390d6169d18..87536a06a3ed54c6 100644
--- a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S
+++ b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core-avx2.S
@@ -17,7 +17,6 @@
<http://www.gnu.org/licenses/>. */
#include <sysdep.h>
-#include <init-arch.h>
#define _ZGVeN8v_sin _ZGVeN8v_sin_avx2_wrapper
#include "../svml_d_sin8_core.S"
diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S
index e0b7fd787fa6428d..16713ba7142ecad6 100644
--- a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S
+++ b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core-avx2.S
@@ -17,7 +17,6 @@
<http://www.gnu.org/licenses/>. */
#include <sysdep.h>
-#include <init-arch.h>
#define _ZGVeN16v_expf _ZGVeN16v_expf_avx2_wrapper
#include "../svml_s_expf16_core.S"
diff --git a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S
index be6671759beaaa84..56b81f5cc5288808 100644
--- a/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S
+++ b/sysdeps/x86_64/multiarch/memset-sse2-unaligned-erms.S
@@ -19,7 +19,6 @@
#include <sysdep.h>
#include <shlib-compat.h>
-#include <init-arch.h>
#if IS_IN (libc)
# define MEMSET_SYMBOL(p,s) p##_sse2_##s

View File

@ -0,0 +1,248 @@
commit c76147afe917ef7d309ee893f8f017a3c2934aac
Author: Florian Weimer <fweimer@redhat.com>
Date: Sat Feb 8 15:00:28 2020 +0100
elf: Extract _dl_sym_post, _dl_sym_find_caller_map from elf/dl-sym.c
The definitions are moved into a new file, elf/dl-sym-post.h, so that
this code can be used by the dynamic loader as well.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/dl-sym-post.h b/elf/dl-sym-post.h
new file mode 100644
index 0000000000000000..4c4f574633497789
--- /dev/null
+++ b/elf/dl-sym-post.h
@@ -0,0 +1,106 @@
+/* Post-processing of a symbol produced by dlsym, dlvsym.
+ Copyright (C) 1999-2020 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/>. */
+
+
+/* Return the link map containing the caller address. */
+static struct link_map *
+_dl_sym_find_caller_link_map (ElfW(Addr) caller)
+{
+ struct link_map *l = _dl_find_dso_for_object (caller);
+ if (l != NULL)
+ return l;
+ else
+ /* If the address is not recognized the call comes from the main
+ program (we hope). */
+ return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+}
+
+/* Translates RESULT, *REF, VALUE into a symbol address from the point
+ of view of MATCH. Performs IFUNC resolution and auditing if
+ necessary. If MATCH is NULL, CALLER is used to determine it. */
+static void *
+_dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value,
+ ElfW(Addr) caller, struct link_map *match)
+{
+ /* Resolve indirect function address. */
+ if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
+ {
+ DL_FIXUP_VALUE_TYPE fixup
+ = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
+ fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
+ value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
+ }
+
+#ifdef SHARED
+ /* Auditing checkpoint: we have a new binding. Provide the
+ auditing libraries the possibility to change the value and
+ tell us whether further auditing is wanted. */
+ if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+ const char *strtab = (const char *) D_PTR (result,
+ l_info[DT_STRTAB]);
+ /* Compute index of the symbol entry in the symbol table of
+ the DSO with the definition. */
+ unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
+ l_info[DT_SYMTAB]));
+
+ if (match == NULL)
+ match = _dl_sym_find_caller_link_map (caller);
+
+ if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
+ {
+ unsigned int altvalue = 0;
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ /* Synthesize a symbol record where the st_value field is
+ the result. */
+ ElfW(Sym) sym = *ref;
+ sym.st_value = (ElfW(Addr)) value;
+
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ struct auditstate *match_audit
+ = link_map_audit_state (match, cnt);
+ struct auditstate *result_audit
+ = link_map_audit_state (result, cnt);
+ if (afct->symbind != NULL
+ && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
+ || ((result_audit->bindflags & LA_FLG_BINDTO)
+ != 0)))
+ {
+ unsigned int flags = altvalue | LA_SYMB_DLSYM;
+ uintptr_t new_value
+ = afct->symbind (&sym, ndx,
+ &match_audit->cookie,
+ &result_audit->cookie,
+ &flags, strtab + ref->st_name);
+ if (new_value != (uintptr_t) sym.st_value)
+ {
+ altvalue = LA_SYMB_ALTVALUE;
+ sym.st_value = new_value;
+ }
+ }
+
+ afct = afct->next;
+ }
+
+ value = (void *) sym.st_value;
+ }
+ }
+#endif
+ return value;
+}
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index b133850a3c6657a4..5698fd7874a0ce48 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -28,6 +28,7 @@
#include <sysdep-cancel.h>
#include <dl-tls.h>
#include <dl-irel.h>
+#include <dl-sym-post.h>
#ifdef SHARED
@@ -80,19 +81,6 @@ call_dl_lookup (void *ptr)
args->flags, NULL);
}
-/* Return the link map containing the caller address. */
-static inline struct link_map *
-find_caller_link_map (ElfW(Addr) caller)
-{
- struct link_map *l = _dl_find_dso_for_object (caller);
- if (l != NULL)
- return l;
- else
- /* If the address is not recognized the call comes from the main
- program (we hope). */
- return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
-}
-
static void *
do_sym (void *handle, const char *name, void *who,
struct r_found_version *vers, int flags)
@@ -106,7 +94,7 @@ do_sym (void *handle, const char *name, void *who,
if (handle == RTLD_DEFAULT)
{
- match = find_caller_link_map (caller);
+ match = _dl_sym_find_caller_link_map (caller);
/* Search the global scope. We have the simple case where
we look up in the scope of an object which was part of
@@ -140,7 +128,7 @@ do_sym (void *handle, const char *name, void *who,
}
else if (handle == RTLD_NEXT)
{
- match = find_caller_link_map (caller);
+ match = _dl_sym_find_caller_link_map (caller);
if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
{
@@ -179,73 +167,7 @@ RTLD_NEXT used in code not dynamically loaded"));
#endif
value = DL_SYMBOL_ADDRESS (result, ref);
- /* Resolve indirect function address. */
- if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
- {
- DL_FIXUP_VALUE_TYPE fixup
- = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
- fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
- value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
- }
-
-#ifdef SHARED
- /* Auditing checkpoint: we have a new binding. Provide the
- auditing libraries the possibility to change the value and
- tell us whether further auditing is wanted. */
- if (__glibc_unlikely (GLRO(dl_naudit) > 0))
- {
- const char *strtab = (const char *) D_PTR (result,
- l_info[DT_STRTAB]);
- /* Compute index of the symbol entry in the symbol table of
- the DSO with the definition. */
- unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
- l_info[DT_SYMTAB]));
-
- if (match == NULL)
- match = find_caller_link_map (caller);
-
- if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
- {
- unsigned int altvalue = 0;
- struct audit_ifaces *afct = GLRO(dl_audit);
- /* Synthesize a symbol record where the st_value field is
- the result. */
- ElfW(Sym) sym = *ref;
- sym.st_value = (ElfW(Addr)) value;
-
- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
- {
- struct auditstate *match_audit
- = link_map_audit_state (match, cnt);
- struct auditstate *result_audit
- = link_map_audit_state (result, cnt);
- if (afct->symbind != NULL
- && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
- || ((result_audit->bindflags & LA_FLG_BINDTO)
- != 0)))
- {
- unsigned int flags = altvalue | LA_SYMB_DLSYM;
- uintptr_t new_value
- = afct->symbind (&sym, ndx,
- &match_audit->cookie,
- &result_audit->cookie,
- &flags, strtab + ref->st_name);
- if (new_value != (uintptr_t) sym.st_value)
- {
- altvalue = LA_SYMB_ALTVALUE;
- sym.st_value = new_value;
- }
- }
-
- afct = afct->next;
- }
-
- value = (void *) sym.st_value;
- }
- }
-#endif
-
- return value;
+ return _dl_sym_post (result, ref, value, caller, match);
}
return NULL;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
commit 758599bc9dcc5764e862bd9e1613c5d1e6efc5d3
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Feb 26 15:58:23 2020 +0100
elf: Apply attribute_relro to pointers in elf/dl-minimal.c
The present code leaves the function pointers unprotected, but moves
some of the static functions into .data.rel.ro instead. This causes
the linker to produce an allocatable, executable, writable section
and eventually an RWX load segment. Not only do we really do not
want that, it also breaks valgrind because valgrind does not load
debuginfo from the mmap interceptor if all it sees are RX and RWX
mappings.
Fixes commit 3a0ecccb599a6b1ad4b149dc569c0080e92d057b ("ld.so: Do not
export free/calloc/malloc/realloc functions [BZ #25486]").
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c
index 95ea7b024044864f..4335f1bd24289b01 100644
--- a/elf/dl-minimal.c
+++ b/elf/dl-minimal.c
@@ -39,16 +39,16 @@
implementation below. Before the final relocation,
__rtld_malloc_init_real is called to replace the pointers with the
real implementation. */
-__typeof (calloc) *__rtld_calloc;
-__typeof (free) *__rtld_free;
-__typeof (malloc) *__rtld_malloc;
-__typeof (realloc) *__rtld_realloc;
+__typeof (calloc) *__rtld_calloc attribute_relro;
+__typeof (free) *__rtld_free attribute_relro;
+__typeof (malloc) *__rtld_malloc attribute_relro;
+__typeof (realloc) *__rtld_realloc attribute_relro;
/* Defined below. */
-static __typeof (calloc) rtld_calloc attribute_relro;
-static __typeof (free) rtld_free attribute_relro;
-static __typeof (malloc) rtld_malloc attribute_relro;
-static __typeof (realloc) rtld_realloc attribute_relro;
+static __typeof (calloc) rtld_calloc;
+static __typeof (free) rtld_free;
+static __typeof (malloc) rtld_malloc;
+static __typeof (realloc) rtld_realloc;
void
__rtld_malloc_init_stubs (void)

View File

@ -0,0 +1,356 @@
commit dfe9aa91564c1bf2a23b5589a5db42f9da5d29b5
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Tue Nov 19 17:17:05 2019 -0300
support: Add support_process_state_wait
It allows parent process to wait for child state using a polling
strategy over procfs on Linux. The polling is used over ptrace to
avoid the need to handle signals on the target pid and to handle some
system specific limitation (such as YAMA).
The polling has some limitations, such as resource consumption due
the procfs read in a loop and the lack of synchronization after the
state is obtained.
The interface idea is to simplify some sleep synchronization waitid
tests and is to reduce timeouts by replacing arbitrary waits.
diff --git a/support/Makefile b/support/Makefile
index 79d03bd6bfe02540..117cfdd4f22fc405 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -58,6 +58,7 @@ libsupport-routines = \
support_format_hostent \
support_format_netent \
support_isolate_in_subprocess \
+ support_process_state \
support_ptrace \
support_openpty \
support_paths \
@@ -90,6 +91,7 @@ libsupport-routines = \
xfopen \
xfork \
xftruncate \
+ xgetline \
xgetsockname \
xlisten \
xlseek \
@@ -217,6 +219,7 @@ tests = \
tst-support_capture_subprocess \
tst-support_descriptors \
tst-support_format_dns_packet \
+ tst-support-process_state \
tst-support_quote_blob \
tst-support_quote_string \
tst-support_record_failure \
diff --git a/support/process_state.h b/support/process_state.h
new file mode 100644
index 0000000000000000..6c19afdbb7462277
--- /dev/null
+++ b/support/process_state.h
@@ -0,0 +1,43 @@
+/* Wait for process state.
+ Copyright (C) 2020 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/>. */
+
+#ifndef SUPPORT_PROCESS_STATE_H
+#define SUPPORT_PROCESS_STATE_H
+
+#include <sys/types.h>
+
+enum support_process_state
+{
+ support_process_state_running = 0x01, /* R (running). */
+ support_process_state_sleeping = 0x02, /* S (sleeping). */
+ support_process_state_disk_sleep = 0x04, /* D (disk sleep). */
+ support_process_state_stopped = 0x08, /* T (stopped). */
+ support_process_state_tracing_stop = 0x10, /* t (tracing stop). */
+ support_process_state_dead = 0x20, /* X (dead). */
+ support_process_state_zombie = 0x40, /* Z (zombie). */
+ support_process_state_parked = 0x80, /* P (parked). */
+};
+
+/* Wait for process PID to reach state STATE. It can be a combination of
+ multiple possible states ('process_state_running | process_state_sleeping')
+ where the function return when any of these state are observed.
+ For an invalid state not represented by SUPPORT_PROCESS_STATE, it fallbacks
+ to a 2 second sleep. */
+void support_process_state_wait (pid_t pid, enum support_process_state state);
+
+#endif
diff --git a/support/support_process_state.c b/support/support_process_state.c
new file mode 100644
index 0000000000000000..76dc798728ece0d9
--- /dev/null
+++ b/support/support_process_state.c
@@ -0,0 +1,92 @@
+/* Wait for process state.
+ Copyright (C) 2020 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 <stdlib.h>
+#include <time.h>
+#include <string.h>
+
+#include <array_length.h>
+
+#include <support/process_state.h>
+#include <support/xstdio.h>
+#include <support/check.h>
+
+void
+support_process_state_wait (pid_t pid, enum support_process_state state)
+{
+#ifdef __linux__
+ /* For Linux it does a polling check on /proc/<pid>/status checking on
+ third field. */
+
+ /* It mimics the kernel states from fs/proc/array.c */
+ static const struct process_states
+ {
+ enum support_process_state s;
+ char v;
+ } process_states[] = {
+ { support_process_state_running, 'R' },
+ { support_process_state_sleeping, 'S' },
+ { support_process_state_disk_sleep, 'D' },
+ { support_process_state_stopped, 'T' },
+ { support_process_state_tracing_stop, 't' },
+ { support_process_state_dead, 'X' },
+ { support_process_state_zombie, 'Z' },
+ { support_process_state_parked, 'P' },
+ };
+
+ char spath[sizeof ("/proc/" + 3) * sizeof (pid_t) + sizeof ("/status") + 1];
+ snprintf (spath, sizeof (spath), "/proc/%i/status", pid);
+
+ FILE *fstatus = xfopen (spath, "r");
+ char *line = NULL;
+ size_t linesiz = 0;
+
+ for (;;)
+ {
+ char cur_state = -1;
+ while (xgetline (&line, &linesiz, fstatus) != -1)
+ if (strncmp (line, "State:", strlen ("State:")) == 0)
+ {
+ TEST_COMPARE (sscanf (line, "%*s %c", &cur_state), 1);
+ break;
+ }
+ /* Fallback to nanosleep for invalid state. */
+ if (cur_state == -1)
+ break;
+
+ for (size_t i = 0; i < array_length (process_states); ++i)
+ if (state & process_states[i].s && cur_state == process_states[i].v)
+ {
+ free (line);
+ xfclose (fstatus);
+ return;
+ }
+
+ rewind (fstatus);
+ fflush (fstatus);
+
+ if (nanosleep (&(struct timespec) { 0, 10000000 }, NULL) != 0)
+ FAIL_EXIT1 ("nanosleep: %m");
+ }
+
+ free (line);
+ xfclose (fstatus);
+ /* Fallback to nanosleep if an invalid state is found. */
+#endif
+ nanosleep (&(struct timespec) { 2, 0 }, NULL);
+}
diff --git a/support/tst-support-process_state.c b/support/tst-support-process_state.c
new file mode 100644
index 0000000000000000..3fc103ab9205ddb0
--- /dev/null
+++ b/support/tst-support-process_state.c
@@ -0,0 +1,105 @@
+/* Wait for process state tests.
+ Copyright (C) 2020 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 <stdio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <support/test-driver.h>
+#include <support/process_state.h>
+#include <support/check.h>
+#include <support/xsignal.h>
+#include <support/xunistd.h>
+
+#ifndef WEXITED
+# define WEXITED 0
+#endif
+
+static void
+sigusr1_handler (int signo)
+{
+}
+
+static void
+test_child (void)
+{
+ xsignal (SIGUSR1, sigusr1_handler);
+
+ raise (SIGSTOP);
+
+ TEST_COMPARE (pause (), -1);
+ TEST_COMPARE (errno, EINTR);
+
+ while (1)
+ asm ("");
+}
+
+static int
+do_test (void)
+{
+ pid_t pid = xfork ();
+ if (pid == 0)
+ {
+ test_child ();
+ _exit (127);
+ }
+
+ /* Adding process_state_tracing_stop ('t') allows the test to work under
+ trace programs such as ptrace. */
+ enum support_process_state stop_state = support_process_state_stopped
+ | support_process_state_tracing_stop;
+
+ if (test_verbose)
+ printf ("info: waiting pid %d, state_stopped/state_tracing_stop\n",
+ (int) pid);
+ support_process_state_wait (pid, stop_state);
+
+ if (kill (pid, SIGCONT) != 0)
+ FAIL_RET ("kill (%d, SIGCONT): %m\n", pid);
+
+ if (test_verbose)
+ printf ("info: waiting pid %d, state_sleeping\n", (int) pid);
+ support_process_state_wait (pid, support_process_state_sleeping);
+
+ if (kill (pid, SIGUSR1) != 0)
+ FAIL_RET ("kill (%d, SIGUSR1): %m\n", pid);
+
+ if (test_verbose)
+ printf ("info: waiting pid %d, state_running\n", (int) pid);
+ support_process_state_wait (pid, support_process_state_running);
+
+ if (kill (pid, SIGKILL) != 0)
+ FAIL_RET ("kill (%d, SIGKILL): %m\n", pid);
+
+ if (test_verbose)
+ printf ("info: waiting pid %d, state_zombie\n", (int) pid);
+ support_process_state_wait (pid, support_process_state_zombie);
+
+ siginfo_t info;
+ int r = waitid (P_PID, pid, &info, WEXITED);
+ TEST_COMPARE (r, 0);
+ TEST_COMPARE (info.si_signo, SIGCHLD);
+ TEST_COMPARE (info.si_code, CLD_KILLED);
+ TEST_COMPARE (info.si_status, SIGKILL);
+ TEST_COMPARE (info.si_pid, pid);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/xgetline.c b/support/xgetline.c
new file mode 100644
index 0000000000000000..180bc2db95a9c5d4
--- /dev/null
+++ b/support/xgetline.c
@@ -0,0 +1,33 @@
+/* fopen with error checking.
+ Copyright (C) 2020 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 <support/xstdio.h>
+#include <support/check.h>
+#include <errno.h>
+
+ssize_t
+xgetline (char **lineptr, size_t *n, FILE *stream)
+{
+ int old_errno = errno;
+ errno = 0;
+ size_t ret = getline (lineptr, n, stream);
+ if (!feof (stream) && ferror (stream))
+ FAIL_EXIT1 ("getline failed: %m");
+ errno = old_errno;
+ return ret;
+}
diff --git a/support/xstdio.h b/support/xstdio.h
index e7d0274474706380..9446b1f27b0f881e 100644
--- a/support/xstdio.h
+++ b/support/xstdio.h
@@ -27,6 +27,8 @@ __BEGIN_DECLS
FILE *xfopen (const char *path, const char *mode);
void xfclose (FILE *);
+ssize_t xgetline (char **lineptr, size_t *n, FILE *stream);
+
__END_DECLS
#endif /* SUPPORT_XSTDIO_H */

View File

@ -0,0 +1,24 @@
commit 083d644d420f49c992667f4c7a54848ad3dee54d
Author: Michael Hudson-Doyle <michael.hudson@canonical.com>
Date: Wed Mar 11 13:05:25 2020 +1300
test-container: print errno when execvp fails
I'm debugging a situation where lots of tests using test-container fail
and it's possible knowing errno would help understand why.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/support/test-container.c b/support/test-container.c
index 9488ec7b4a824380..9eff8baeef0e9d8a 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -1145,7 +1145,7 @@ main (int argc, char **argv)
execvp (new_child_exec, new_child_proc);
/* Or don't run the child? */
- FAIL_EXIT1 ("Unable to exec %s\n", new_child_exec);
+ FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec, strerror (errno));
/* Because gcc won't know error () never returns... */
exit (EXIT_UNSUPPORTED);

View File

@ -0,0 +1,106 @@
commit b7176cc2aff4a8883e4834ddf65f8a6fdb1f160e
Author: DJ Delorie <dj@redhat.com>
Date: Wed Feb 19 12:31:38 2020 -0500
ldconfig: trace origin paths with -v
With this patch, -v turns on a "from" trace for each directory
searched, that tells you WHY that directory is being searched -
is it a builtin, from the command line, or from some config file?
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index ed7d9ab0412d93fd..5e6516688a1c192a 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -79,6 +79,8 @@ struct dir_entry
int flag;
ino64_t ino;
dev_t dev;
+ const char *from_file;
+ int from_line;
struct dir_entry *next;
};
@@ -344,7 +346,12 @@ add_single_dir (struct dir_entry *entry, int verbose)
if (ptr->ino == entry->ino && ptr->dev == entry->dev)
{
if (opt_verbose && verbose)
- error (0, 0, _("Path `%s' given more than once"), entry->path);
+ {
+ error (0, 0, _("Path `%s' given more than once"), entry->path);
+ fprintf (stderr, _("(from %s:%d and %s:%d)\n"),
+ entry->from_file, entry->from_line,
+ ptr->from_file, ptr->from_line);
+ }
/* Use the newer information. */
ptr->flag = entry->flag;
free (entry->path);
@@ -363,12 +370,15 @@ add_single_dir (struct dir_entry *entry, int verbose)
/* Add one directory to the list of directories to process. */
static void
-add_dir (const char *line)
+add_dir_1 (const char *line, const char *from_file, int from_line)
{
unsigned int i;
struct dir_entry *entry = xmalloc (sizeof (struct dir_entry));
entry->next = NULL;
+ entry->from_file = strdup (from_file);
+ entry->from_line = from_line;
+
/* Search for an '=' sign. */
entry->path = xstrdup (line);
char *equal_sign = strchr (entry->path, '=');
@@ -428,6 +438,11 @@ add_dir (const char *line)
free (path);
}
+static void
+add_dir (const char *line)
+{
+ add_dir_1 (line, "<builtin>", 0);
+}
static int
chroot_stat (const char *real_path, const char *path, struct stat64 *st)
@@ -672,9 +687,10 @@ search_dir (const struct dir_entry *entry)
if (opt_verbose)
{
if (hwcap != 0)
- printf ("%s: (hwcap: %#.16" PRIx64 ")\n", entry->path, hwcap);
+ printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap);
else
- printf ("%s:\n", entry->path);
+ printf ("%s:", entry->path);
+ printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line);
}
char *dir_name;
@@ -815,6 +831,8 @@ search_dir (const struct dir_entry *entry)
struct dir_entry *new_entry;
new_entry = xmalloc (sizeof (struct dir_entry));
+ new_entry->from_file = entry->from_file;
+ new_entry->from_line = entry->from_line;
new_entry->path = xstrdup (file_name);
new_entry->flag = entry->flag;
new_entry->next = NULL;
@@ -1174,7 +1192,7 @@ Warning: ignoring configuration file that cannot be opened: %s"),
}
}
else
- add_dir (cp);
+ add_dir_1 (cp, filename, lineno);
}
while (!feof_unlocked (file));
@@ -1282,7 +1300,7 @@ main (int argc, char **argv)
_("relative path `%s' used to build cache"),
argv[i]);
else
- add_dir (argv[i]);
+ add_dir_1 (argv[i], "<cmdline>", 0);
}
/* The last entry in hwcap_extra is reserved for the "tls" pseudo-hwcap which

View File

@ -0,0 +1,83 @@
commit cea56af185eae45b1f0963351e3d4daa1cbde521
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Apr 2 17:09:36 2020 +0200
support: Change xgetline to return 0 on EOF
The advantage is that the buffer will always contain the number
of characters as returned from the function, which allows one to use
a sequence like
/* No more audit module output. */
line_length = xgetline (&buffer, &buffer_length, fp);
TEST_COMPARE_BLOB ("", 0, buffer, line_length);
to check for an expected EOF, while also reporting any unexpected
extra data encountered.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/support/support_process_state.c b/support/support_process_state.c
index 76dc798728ece0d9..e303c78fc874b2f9 100644
--- a/support/support_process_state.c
+++ b/support/support_process_state.c
@@ -59,7 +59,7 @@ support_process_state_wait (pid_t pid, enum support_process_state state)
for (;;)
{
char cur_state = -1;
- while (xgetline (&line, &linesiz, fstatus) != -1)
+ while (xgetline (&line, &linesiz, fstatus) > 0)
if (strncmp (line, "State:", strlen ("State:")) == 0)
{
TEST_COMPARE (sscanf (line, "%*s %c", &cur_state), 1);
diff --git a/support/xgetline.c b/support/xgetline.c
index 180bc2db95a9c5d4..d91c09ac108b4c75 100644
--- a/support/xgetline.c
+++ b/support/xgetline.c
@@ -18,16 +18,22 @@
#include <support/xstdio.h>
#include <support/check.h>
-#include <errno.h>
-ssize_t
+size_t
xgetline (char **lineptr, size_t *n, FILE *stream)
{
- int old_errno = errno;
- errno = 0;
- size_t ret = getline (lineptr, n, stream);
- if (!feof (stream) && ferror (stream))
- FAIL_EXIT1 ("getline failed: %m");
- errno = old_errno;
+ TEST_VERIFY (!ferror (stream));
+ ssize_t ret = getline (lineptr, n, stream);
+ if (ferror (stream))
+ {
+ TEST_VERIFY (ret < 0);
+ FAIL_EXIT1 ("getline: %m");
+ }
+ if (feof (stream))
+ {
+ TEST_VERIFY (ret <= 0);
+ return 0;
+ }
+ TEST_VERIFY (ret > 0);
return ret;
}
diff --git a/support/xstdio.h b/support/xstdio.h
index 9446b1f27b0f881e..36071cf78822ec8d 100644
--- a/support/xstdio.h
+++ b/support/xstdio.h
@@ -27,7 +27,10 @@ __BEGIN_DECLS
FILE *xfopen (const char *path, const char *mode);
void xfclose (FILE *);
-ssize_t xgetline (char **lineptr, size_t *n, FILE *stream);
+/* Read a line from FP, using getline. *BUFFER must be NULL, or a
+ heap-allocated pointer of *LENGTH bytes. Return the number of
+ bytes in the line if a line was read, or 0 on EOF. */
+size_t xgetline (char **lineptr, size_t *n, FILE *stream);
__END_DECLS

View File

@ -0,0 +1,373 @@
commit 4c6e0415ef206a595c62d5d37e3b9a821782c533
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Apr 3 13:17:48 2020 +0200
elf: Simplify handling of lists of audit strings
All list elements are colon-separated strings, and there is a hard
upper limit for the number of audit modules, so it is possible to
pre-allocate a fixed-size array of strings to which the LD_AUDIT
environment variable and --audit arguments are added.
Also eliminate the global variables for the audit list because
the list is only needed briefly during startup.
There is a slight behavior change: All duplicate LD_AUDIT environment
variables are now processed, not just the last one as before. However,
such environment vectors are invalid anyway.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/rtld.c b/elf/rtld.c
index f755dc30331f799f..c39cb8f2cd4bb1cc 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -43,6 +43,7 @@
#include <stap-probe.h>
#include <stackinfo.h>
#include <not-cancel.h>
+#include <array_length.h>
#include <assert.h>
@@ -107,8 +108,53 @@ static void print_missing_version (int errcode, const char *objname,
/* Print the various times we collected. */
static void print_statistics (const hp_timing_t *total_timep);
-/* Add audit objects. */
-static void process_dl_audit (char *str);
+/* Length limits for names and paths, to protect the dynamic linker,
+ particularly when __libc_enable_secure is active. */
+#ifdef NAME_MAX
+# define SECURE_NAME_LIMIT NAME_MAX
+#else
+# define SECURE_NAME_LIMIT 255
+#endif
+#ifdef PATH_MAX
+# define SECURE_PATH_LIMIT PATH_MAX
+#else
+# define SECURE_PATH_LIMIT 1024
+#endif
+
+/* Strings containing colon-separated lists of audit modules. */
+struct audit_list
+{
+ /* Array of strings containing colon-separated path lists. Each
+ audit module needs its own namespace, so pre-allocate the largest
+ possible list. */
+ const char *audit_strings[DL_NNS];
+
+ /* Number of entries added to audit_strings. */
+ size_t length;
+
+ /* Index into the audit_strings array (for the iteration phase). */
+ size_t current_index;
+
+ /* Tail of audit_strings[current_index] which still needs
+ processing. */
+ const char *current_tail;
+
+ /* Scratch buffer for returning a name which is part of the strings
+ in audit_strings. */
+ char fname[SECURE_NAME_LIMIT];
+};
+
+/* Creates an empty audit list. */
+static void audit_list_init (struct audit_list *);
+
+/* Add a string to the end of the audit list, for later parsing. Must
+ not be called after audit_list_next. */
+static void audit_list_add_string (struct audit_list *, const char *);
+
+/* Extract the next audit module from the audit list. Only modules
+ for which dso_name_valid_for_suid is true are returned. Must be
+ called after all the audit_list_add_string calls. */
+static const char *audit_list_next (struct audit_list *);
/* This is a list of all the modes the dynamic loader can be in. */
enum mode { normal, list, verify, trace };
@@ -116,7 +162,7 @@ enum mode { normal, list, verify, trace };
/* Process all environments variables the dynamic linker must recognize.
Since all of them start with `LD_' we are a bit smarter while finding
all the entries. */
-static void process_envvars (enum mode *modep);
+static void process_envvars (enum mode *modep, struct audit_list *);
#ifdef DL_ARGV_NOT_RELRO
int _dl_argc attribute_hidden;
@@ -144,19 +190,6 @@ uintptr_t __pointer_chk_guard_local
strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
#endif
-/* Length limits for names and paths, to protect the dynamic linker,
- particularly when __libc_enable_secure is active. */
-#ifdef NAME_MAX
-# define SECURE_NAME_LIMIT NAME_MAX
-#else
-# define SECURE_NAME_LIMIT 255
-#endif
-#ifdef PATH_MAX
-# define SECURE_PATH_LIMIT PATH_MAX
-#else
-# define SECURE_PATH_LIMIT 1024
-#endif
-
/* Check that AT_SECURE=0, or that the passed name does not contain
directories and is not overly long. Reject empty names
unconditionally. */
@@ -174,89 +207,75 @@ dso_name_valid_for_suid (const char *p)
return *p != '\0';
}
-/* LD_AUDIT variable contents. Must be processed before the
- audit_list below. */
-const char *audit_list_string;
-
-/* Cyclic list of auditing DSOs. audit_list->next is the first
- element. */
-static struct audit_list
+static void
+audit_list_init (struct audit_list *list)
{
- const char *name;
- struct audit_list *next;
-} *audit_list;
+ list->length = 0;
+ list->current_index = 0;
+ list->current_tail = NULL;
+}
-/* Iterator for audit_list_string followed by audit_list. */
-struct audit_list_iter
+static void
+audit_list_add_string (struct audit_list *list, const char *string)
{
- /* Tail of audit_list_string still needing processing, or NULL. */
- const char *audit_list_tail;
+ /* Empty strings do not load anything. */
+ if (*string == '\0')
+ return;
- /* The list element returned in the previous iteration. NULL before
- the first element. */
- struct audit_list *previous;
+ if (list->length == array_length (list->audit_strings))
+ _dl_fatal_printf ("Fatal glibc error: Too many audit modules requested\n");
- /* Scratch buffer for returning a name which is part of
- audit_list_string. */
- char fname[SECURE_NAME_LIMIT];
-};
+ list->audit_strings[list->length++] = string;
-/* Initialize an audit list iterator. */
-static void
-audit_list_iter_init (struct audit_list_iter *iter)
-{
- iter->audit_list_tail = audit_list_string;
- iter->previous = NULL;
+ /* Initialize processing of the first string for
+ audit_list_next. */
+ if (list->length == 1)
+ list->current_tail = string;
}
-/* Iterate through both audit_list_string and audit_list. */
static const char *
-audit_list_iter_next (struct audit_list_iter *iter)
+audit_list_next (struct audit_list *list)
{
- if (iter->audit_list_tail != NULL)
+ if (list->current_tail == NULL)
+ return NULL;
+
+ while (true)
{
- /* First iterate over audit_list_string. */
- while (*iter->audit_list_tail != '\0')
+ /* Advance to the next string in audit_strings if the current
+ string has been exhausted. */
+ while (*list->current_tail == '\0')
{
- /* Split audit list at colon. */
- size_t len = strcspn (iter->audit_list_tail, ":");
- if (len > 0 && len < sizeof (iter->fname))
+ ++list->current_index;
+ if (list->current_index == list->length)
{
- memcpy (iter->fname, iter->audit_list_tail, len);
- iter->fname[len] = '\0';
+ list->current_tail = NULL;
+ return NULL;
}
- else
- /* Do not return this name to the caller. */
- iter->fname[0] = '\0';
-
- /* Skip over the substring and the following delimiter. */
- iter->audit_list_tail += len;
- if (*iter->audit_list_tail == ':')
- ++iter->audit_list_tail;
-
- /* If the name is valid, return it. */
- if (dso_name_valid_for_suid (iter->fname))
- return iter->fname;
- /* Otherwise, wrap around and try the next name. */
+ list->current_tail = list->audit_strings[list->current_index];
}
- /* Fall through to the procesing of audit_list. */
- }
- if (iter->previous == NULL)
- {
- if (audit_list == NULL)
- /* No pre-parsed audit list. */
- return NULL;
- /* Start of audit list. The first list element is at
- audit_list->next (cyclic list). */
- iter->previous = audit_list->next;
- return iter->previous->name;
+ /* Split the in-string audit list at the next colon colon. */
+ size_t len = strcspn (list->current_tail, ":");
+ if (len > 0 && len < sizeof (list->fname))
+ {
+ memcpy (list->fname, list->current_tail, len);
+ list->fname[len] = '\0';
+ }
+ else
+ /* Mark the name as unusable for dso_name_valid_for_suid. */
+ list->fname[0] = '\0';
+
+ /* Skip over the substring and the following delimiter. */
+ list->current_tail += len;
+ if (*list->current_tail == ':')
+ ++list->current_tail;
+
+ /* If the name is valid, return it. */
+ if (dso_name_valid_for_suid (list->fname))
+ return list->fname;
+
+ /* Otherwise wrap around to find the next list element. . */
}
- if (iter->previous == audit_list)
- /* Cyclic list wrap-around. */
- return NULL;
- iter->previous = iter->previous->next;
- return iter->previous->name;
}
/* Set nonzero during loading and initialization of executable and
@@ -1060,15 +1079,13 @@ notify_audit_modules_of_loaded_object (struct link_map *map)
/* Load all audit modules. */
static void
-load_audit_modules (struct link_map *main_map)
+load_audit_modules (struct link_map *main_map, struct audit_list *audit_list)
{
struct audit_ifaces *last_audit = NULL;
- struct audit_list_iter al_iter;
- audit_list_iter_init (&al_iter);
while (true)
{
- const char *name = audit_list_iter_next (&al_iter);
+ const char *name = audit_list_next (audit_list);
if (name == NULL)
break;
load_audit_module (name, &last_audit);
@@ -1100,6 +1117,9 @@ dl_main (const ElfW(Phdr) *phdr,
bool rtld_is_main = false;
void *tcbp = NULL;
+ struct audit_list audit_list;
+ audit_list_init (&audit_list);
+
GL(dl_init_static_tls) = &_dl_nothread_init_static_tls;
#if defined SHARED && defined _LIBC_REENTRANT \
@@ -1113,7 +1133,7 @@ dl_main (const ElfW(Phdr) *phdr,
GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable;
/* Process the environment variable which control the behaviour. */
- process_envvars (&mode);
+ process_envvars (&mode, &audit_list);
/* Set up a flag which tells we are just starting. */
_dl_starting_up = 1;
@@ -1185,7 +1205,7 @@ dl_main (const ElfW(Phdr) *phdr,
}
else if (! strcmp (_dl_argv[1], "--audit") && _dl_argc > 2)
{
- process_dl_audit (_dl_argv[2]);
+ audit_list_add_string (&audit_list, _dl_argv[2]);
_dl_skip_args += 2;
_dl_argc -= 2;
@@ -1612,8 +1632,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
/* If we have auditing DSOs to load, do it now. */
bool need_security_init = true;
- if (__glibc_unlikely (audit_list != NULL)
- || __glibc_unlikely (audit_list_string != NULL))
+ if (audit_list.length > 0)
{
/* Since we start using the auditing DSOs right away we need to
initialize the data structures now. */
@@ -1626,7 +1645,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
security_init ();
need_security_init = false;
- load_audit_modules (main_map);
+ load_audit_modules (main_map, &audit_list);
}
/* Keep track of the currently loaded modules to count how many
@@ -2500,30 +2519,6 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n");
}
}
-static void
-process_dl_audit (char *str)
-{
- /* The parameter is a colon separated list of DSO names. */
- char *p;
-
- while ((p = (strsep) (&str, ":")) != NULL)
- if (dso_name_valid_for_suid (p))
- {
- /* This is using the local malloc, not the system malloc. The
- memory can never be freed. */
- struct audit_list *newp = malloc (sizeof (*newp));
- newp->name = p;
-
- if (audit_list == NULL)
- audit_list = newp->next = newp;
- else
- {
- newp->next = audit_list->next;
- audit_list = audit_list->next = newp;
- }
- }
-}
-
/* Process all environments variables the dynamic linker must recognize.
Since all of them start with `LD_' we are a bit smarter while finding
all the entries. */
@@ -2531,7 +2526,7 @@ extern char **_environ attribute_hidden;
static void
-process_envvars (enum mode *modep)
+process_envvars (enum mode *modep, struct audit_list *audit_list)
{
char **runp = _environ;
char *envline;
@@ -2571,7 +2566,7 @@ process_envvars (enum mode *modep)
break;
}
if (memcmp (envline, "AUDIT", 5) == 0)
- audit_list_string = &envline[6];
+ audit_list_add_string (audit_list, &envline[6]);
break;
case 7:

View File

@ -0,0 +1,379 @@
commit 8f7a75d700af809eeb4363895078fabfb3a9d7c3
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Feb 17 16:49:40 2020 +0100
elf: Implement DT_AUDIT, DT_DEPAUDIT support [BZ #24943]
binutils ld has supported --audit, --depaudit for a long time,
only support in glibc has been missing.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
elf/Makefile
(Test backport differences.)
diff --git a/elf/Makefile b/elf/Makefile
index 5b0aeccb0a53c182..a6601ba84c8f4017 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -195,7 +195,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
tst-sonamemove-link tst-sonamemove-dlopen \
tst-auditmany tst-initfinilazyfail \
tst-dlopenfail tst-dlopenfail-2 \
- tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen
+ tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \
+ tst-audit14 tst-audit15 tst-audit16
# reldep9
tests-internal += loadtest unload unload2 circleload1 \
neededtest neededtest2 neededtest3 neededtest4 \
@@ -310,7 +311,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-initlazyfailmod tst-finilazyfailmod \
tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
tst-dlopenfailmod3 \
- tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee
+ tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee \
+ tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3
# Most modules build with _ISOMAC defined, but those filtered out
# depend on internal headers.
@@ -1453,6 +1455,22 @@ $(objpfx)tst-auditmany.out: $(objpfx)tst-auditmanymod1.so \
tst-auditmany-ENV = \
LD_AUDIT=tst-auditmanymod1.so:tst-auditmanymod2.so:tst-auditmanymod3.so:tst-auditmanymod4.so:tst-auditmanymod5.so:tst-auditmanymod6.so:tst-auditmanymod7.so:tst-auditmanymod8.so:tst-auditmanymod9.so
+LDFLAGS-tst-audit14 = -Wl,--audit=tst-auditlogmod-1.so
+$(objpfx)tst-auditlogmod-1.so: $(libsupport)
+$(objpfx)tst-audit14.out: $(objpfx)tst-auditlogmod-1.so
+LDFLAGS-tst-audit15 = \
+ -Wl,--audit=tst-auditlogmod-1.so,--depaudit=tst-auditlogmod-2.so
+$(objpfx)tst-auditlogmod-2.so: $(libsupport)
+$(objpfx)tst-audit15.out: \
+ $(objpfx)tst-auditlogmod-1.so $(objpfx)tst-auditlogmod-2.so
+LDFLAGS-tst-audit16 = \
+ -Wl,--audit=tst-auditlogmod-1.so:tst-auditlogmod-2.so \
+ -Wl,--depaudit=tst-auditlogmod-3.so
+$(objpfx)tst-auditlogmod-3.so: $(libsupport)
+$(objpfx)tst-audit16.out: \
+ $(objpfx)tst-auditlogmod-1.so $(objpfx)tst-auditlogmod-2.so \
+ $(objpfx)tst-auditlogmod-3.so
+
# tst-sonamemove links against an older implementation of the library.
LDFLAGS-tst-sonamemove-linkmod1.so = \
-Wl,--version-script=tst-sonamemove-linkmod1.map \
diff --git a/elf/rtld.c b/elf/rtld.c
index c39cb8f2cd4bb1cc..d44facf5343b3301 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -151,9 +151,17 @@ static void audit_list_init (struct audit_list *);
not be called after audit_list_next. */
static void audit_list_add_string (struct audit_list *, const char *);
+/* Add the audit strings from the link map, found in the dynamic
+ segment at TG (either DT_AUDIT and DT_DEPAUDIT). Must be called
+ before audit_list_next. */
+static void audit_list_add_dynamic_tag (struct audit_list *,
+ struct link_map *,
+ unsigned int tag);
+
/* Extract the next audit module from the audit list. Only modules
for which dso_name_valid_for_suid is true are returned. Must be
- called after all the audit_list_add_string calls. */
+ called after all the audit_list_add_string,
+ audit_list_add_dynamic_tags calls. */
static const char *audit_list_next (struct audit_list *);
/* This is a list of all the modes the dynamic loader can be in. */
@@ -233,6 +241,16 @@ audit_list_add_string (struct audit_list *list, const char *string)
list->current_tail = string;
}
+static void
+audit_list_add_dynamic_tag (struct audit_list *list, struct link_map *main_map,
+ unsigned int tag)
+{
+ ElfW(Dyn) *info = main_map->l_info[ADDRIDX (tag)];
+ const char *strtab = (const char *) D_PTR (main_map, l_info[DT_STRTAB]);
+ if (info != NULL)
+ audit_list_add_string (list, strtab + info->d_un.d_val);
+}
+
static const char *
audit_list_next (struct audit_list *list)
{
@@ -1630,6 +1648,9 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
/* Assign a module ID. Do this before loading any audit modules. */
GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
+ audit_list_add_dynamic_tag (&audit_list, main_map, DT_AUDIT);
+ audit_list_add_dynamic_tag (&audit_list, main_map, DT_DEPAUDIT);
+
/* If we have auditing DSOs to load, do it now. */
bool need_security_init = true;
if (audit_list.length > 0)
diff --git a/elf/tst-audit14.c b/elf/tst-audit14.c
new file mode 100644
index 0000000000000000..27ff8db9480a98cc
--- /dev/null
+++ b/elf/tst-audit14.c
@@ -0,0 +1,46 @@
+/* Main program with DT_AUDIT. One audit module.
+ Copyright (C) 2020 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 <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+
+static int
+do_test (void)
+{
+ /* Verify what the audit module has written. This test assumes that
+ standard output has been redirected to a regular file. */
+ FILE *fp = xfopen ("/dev/stdout", "r");
+
+ char *buffer = NULL;
+ size_t buffer_length = 0;
+ size_t line_length = xgetline (&buffer, &buffer_length, fp);
+ const char *message = "info: tst-auditlogmod-1.so loaded\n";
+ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length);
+
+ /* No more audit module output. */
+ line_length = xgetline (&buffer, &buffer_length, fp);
+ TEST_COMPARE_BLOB ("", 0, buffer, line_length);
+
+ free (buffer);
+ xfclose (fp);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-audit15.c b/elf/tst-audit15.c
new file mode 100644
index 0000000000000000..cbd1589ec40653d1
--- /dev/null
+++ b/elf/tst-audit15.c
@@ -0,0 +1,50 @@
+/* Main program with DT_AUDIT and DT_DEPAUDIT. Two audit modules.
+ Copyright (C) 2020 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 <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+
+static int
+do_test (void)
+{
+ /* Verify what the audit modules have written. This test assumes
+ that standard output has been redirected to a regular file. */
+ FILE *fp = xfopen ("/dev/stdout", "r");
+
+ char *buffer = NULL;
+ size_t buffer_length = 0;
+ size_t line_length = xgetline (&buffer, &buffer_length, fp);
+ const char *message = "info: tst-auditlogmod-1.so loaded\n";
+ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length);
+
+ line_length = xgetline (&buffer, &buffer_length, fp);
+ message = "info: tst-auditlogmod-2.so loaded\n";
+ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length);
+
+ /* No more audit module output. */
+ line_length = xgetline (&buffer, &buffer_length, fp);
+ TEST_COMPARE_BLOB ("", 0, buffer, line_length);
+
+ free (buffer);
+ xfclose (fp);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-audit16.c b/elf/tst-audit16.c
new file mode 100644
index 0000000000000000..dd6ce189ea6fffa3
--- /dev/null
+++ b/elf/tst-audit16.c
@@ -0,0 +1,54 @@
+/* Main program with DT_AUDIT and DT_DEPAUDIT. Three audit modules.
+ Copyright (C) 2020 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 <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+
+static int
+do_test (void)
+{
+ /* Verify what the audit modules have written. This test assumes
+ that standard output has been redirected to a regular file. */
+ FILE *fp = xfopen ("/dev/stdout", "r");
+
+ char *buffer = NULL;
+ size_t buffer_length = 0;
+ size_t line_length = xgetline (&buffer, &buffer_length, fp);
+ const char *message = "info: tst-auditlogmod-1.so loaded\n";
+ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length);
+
+ line_length = xgetline (&buffer, &buffer_length, fp);
+ message = "info: tst-auditlogmod-2.so loaded\n";
+ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length);
+
+ line_length = xgetline (&buffer, &buffer_length, fp);
+ message = "info: tst-auditlogmod-3.so loaded\n";
+ TEST_COMPARE_BLOB (message, strlen (message), buffer, line_length);
+
+ /* No more audit module output. */
+ line_length = xgetline (&buffer, &buffer_length, fp);
+ TEST_COMPARE_BLOB ("", 0, buffer, line_length);
+
+ free (buffer);
+ xfclose (fp);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-auditlogmod-1.c b/elf/tst-auditlogmod-1.c
new file mode 100644
index 0000000000000000..db9dac4c01a58dcd
--- /dev/null
+++ b/elf/tst-auditlogmod-1.c
@@ -0,0 +1,27 @@
+/* Audit module which logs that it was loaded. Variant 1.
+ Copyright (C) 2020 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 <link.h>
+#include <support/support.h>
+
+unsigned int
+la_version (unsigned int v)
+{
+ write_message ("info: tst-auditlogmod-1.so loaded\n");
+ return LAV_CURRENT;
+}
diff --git a/elf/tst-auditlogmod-2.c b/elf/tst-auditlogmod-2.c
new file mode 100644
index 0000000000000000..871c22641c47fed0
--- /dev/null
+++ b/elf/tst-auditlogmod-2.c
@@ -0,0 +1,27 @@
+/* Audit module which logs that it was loaded. Variant 2.
+ Copyright (C) 2020 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 <link.h>
+#include <support/support.h>
+
+unsigned int
+la_version (unsigned int v)
+{
+ write_message ("info: tst-auditlogmod-2.so loaded\n");
+ return LAV_CURRENT;
+}
diff --git a/elf/tst-auditlogmod-3.c b/elf/tst-auditlogmod-3.c
new file mode 100644
index 0000000000000000..da2ee19d4ab9e861
--- /dev/null
+++ b/elf/tst-auditlogmod-3.c
@@ -0,0 +1,27 @@
+/* Audit module which logs that it was loaded. Variant 3.
+ Copyright (C) 2020 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 <link.h>
+#include <support/support.h>
+
+unsigned int
+la_version (unsigned int v)
+{
+ write_message ("info: tst-auditlogmod-3.so loaded\n");
+ return LAV_CURRENT;
+}

View File

@ -0,0 +1,163 @@
commit 50a2d83c08a94a10f88a1fedeb7a6e3667a6b732
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Apr 24 22:13:03 2020 +0200
elf: Introduce <elf_machine_sym_no_match.h>
MIPS needs to ignore certain existing symbols during symbol lookup.
The old scheme uses the ELF_MACHINE_SYM_NO_MATCH macro, with an
inline function, within its own header, with a sysdeps override for
MIPS. This allows re-use of the function from another file (without
having to include <dl-machine.h> or providing the default definition
for ELF_MACHINE_SYM_NO_MATCH).
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index e4c479de9a1fd6ec..47acd134600b44b5 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -28,18 +28,12 @@
#include <libc-lock.h>
#include <tls.h>
#include <atomic.h>
+#include <elf_machine_sym_no_match.h>
#include <assert.h>
-/* Return nonzero if check_match should consider SYM to fail to match a
- symbol reference for some machine-specific reason. */
-#ifndef ELF_MACHINE_SYM_NO_MATCH
-# define ELF_MACHINE_SYM_NO_MATCH(sym) 0
-#endif
-
#define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
-
struct sym_val
{
const ElfW(Sym) *s;
@@ -78,7 +72,7 @@ check_match (const char *const undef_name,
if (__glibc_unlikely ((sym->st_value == 0 /* No value. */
&& sym->st_shndx != SHN_ABS
&& stt != STT_TLS)
- || ELF_MACHINE_SYM_NO_MATCH (sym)
+ || elf_machine_sym_no_match (sym)
|| (type_class & (sym->st_shndx == SHN_UNDEF))))
return NULL;
diff --git a/sysdeps/generic/elf_machine_sym_no_match.h b/sysdeps/generic/elf_machine_sym_no_match.h
new file mode 100644
index 0000000000000000..27155de4c0358460
--- /dev/null
+++ b/sysdeps/generic/elf_machine_sym_no_match.h
@@ -0,0 +1,34 @@
+/* Function to ignore certain symbol matches for machine-specific reasons.
+ Copyright (C) 2020 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/>. */
+
+#ifndef _ELF_MACHINE_SYM_NO_MATCH_H
+#define _ELF_MACHINE_SYM_NO_MATCH_H
+
+#include <link.h>
+#include <stdbool.h>
+
+/* This can be customized to ignore certain symbols during lookup in
+ case there are machine-specific rules to disregard some
+ symbols. */
+static inline bool
+elf_machine_sym_no_match (const ElfW(Sym) *sym)
+{
+ return false;
+}
+
+#endif /* _ELF_MACHINE_SYM_NO_MATCH_H */
diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h
index 91fc640388a735c7..b41e10647d81843b 100644
--- a/sysdeps/mips/dl-machine.h
+++ b/sysdeps/mips/dl-machine.h
@@ -467,21 +467,6 @@ elf_machine_plt_value (struct link_map *map, const ElfW(Rel) *reloc,
return value;
}
-/* The semantics of zero/non-zero values of undefined symbols differs
- depending on whether the non-PIC ABI is in use. Under the non-PIC
- ABI, a non-zero value indicates that there is an address reference
- to the symbol and thus it must always be resolved (except when
- resolving a jump slot relocation) to the PLT entry whose address is
- provided as the symbol's value; a zero value indicates that this
- canonical-address behaviour is not required. Yet under the classic
- MIPS psABI, a zero value indicates that there is an address
- reference to the function and the dynamic linker must resolve the
- symbol immediately upon loading. To avoid conflict, symbols for
- which the dynamic linker must assume the non-PIC ABI semantics are
- marked with the STO_MIPS_PLT flag. */
-#define ELF_MACHINE_SYM_NO_MATCH(sym) \
- ((sym)->st_shndx == SHN_UNDEF && !((sym)->st_other & STO_MIPS_PLT))
-
#endif /* !dl_machine_h */
#ifdef RESOLVE_MAP
diff --git a/sysdeps/mips/elf_machine_sym_no_match.h b/sysdeps/mips/elf_machine_sym_no_match.h
new file mode 100644
index 0000000000000000..9d09e5fa2db1ff6c
--- /dev/null
+++ b/sysdeps/mips/elf_machine_sym_no_match.h
@@ -0,0 +1,43 @@
+/* MIPS-specific handling of undefined symbols.
+ Copyright (C) 2008-2020 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/>. */
+
+#ifndef _ELF_MACHINE_SYM_NO_MATCH_H
+#define _ELF_MACHINE_SYM_NO_MATCH_H
+
+#include <link.h>
+#include <stdbool.h>
+
+/* The semantics of zero/non-zero values of undefined symbols differs
+ depending on whether the non-PIC ABI is in use. Under the non-PIC
+ ABI, a non-zero value indicates that there is an address reference
+ to the symbol and thus it must always be resolved (except when
+ resolving a jump slot relocation) to the PLT entry whose address is
+ provided as the symbol's value; a zero value indicates that this
+ canonical-address behaviour is not required. Yet under the classic
+ MIPS psABI, a zero value indicates that there is an address
+ reference to the function and the dynamic linker must resolve the
+ symbol immediately upon loading. To avoid conflict, symbols for
+ which the dynamic linker must assume the non-PIC ABI semantics are
+ marked with the STO_MIPS_PLT flag. */
+static inline bool
+elf_machine_sym_no_match (const ElfW(Sym) *sym)
+{
+ return sym->st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT);
+}
+
+#endif /* _ELF_MACHINE_SYM_NO_MATCH_H */

View File

@ -0,0 +1,82 @@
commit fb4c32aef64500c65c7fc95ca06d7e17d467be45
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Mon Aug 6 06:25:28 2018 -0700
x86: Move STATE_SAVE_OFFSET/STATE_SAVE_MASK to sysdep.h
Move STATE_SAVE_OFFSET and STATE_SAVE_MASK to sysdep.h to make
sysdeps/x86/cpu-features.h a C header file.
* sysdeps/x86/cpu-features.h (STATE_SAVE_OFFSET): Removed.
(STATE_SAVE_MASK): Likewise.
Don't check __ASSEMBLER__ to include <cpu-features-offsets.h>.
* sysdeps/x86/sysdep.h (STATE_SAVE_OFFSET): New.
(STATE_SAVE_MASK): Likewise.
* sysdeps/x86_64/dl-trampoline.S: Include <cpu-features-offsets.h>
instead of <cpu-features.h>.
diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h
index 4c6d08c709eea204..d342664c64ab7aa1 100644
--- a/sysdeps/x86/cpu-features.h
+++ b/sysdeps/x86/cpu-features.h
@@ -92,18 +92,6 @@
/* The current maximum size of the feature integer bit array. */
#define FEATURE_INDEX_MAX 1
-/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need
- space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be
- aligned to 16 bytes for fxsave and 64 bytes for xsave. */
-#define STATE_SAVE_OFFSET (8 * 7 + 8)
-
-/* Save SSE, AVX, AVX512, mask and bound registers. */
-#define STATE_SAVE_MASK \
- ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7))
-
-#ifdef __ASSEMBLER__
-# include <cpu-features-offsets.h>
-#else /* __ASSEMBLER__ */
enum
{
COMMON_CPUID_INDEX_1 = 0,
@@ -267,8 +255,6 @@ extern const struct cpu_features *__get_cpu_features (void)
# define index_arch_XSAVEC_Usable FEATURE_INDEX_1
# define index_arch_Prefer_FSRM FEATURE_INDEX_1
-#endif /* !__ASSEMBLER__ */
-
#ifdef __x86_64__
# define HAS_CPUID 1
#elif defined __i586__ || defined __pentium__
diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h
index 8776ad8374e056d3..f41f4ebd425cfbaf 100644
--- a/sysdeps/x86/sysdep.h
+++ b/sysdeps/x86/sysdep.h
@@ -48,6 +48,15 @@ enum cf_protection_level
# define SHSTK_ENABLED 0
#endif
+/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need
+ space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be
+ aligned to 16 bytes for fxsave and 64 bytes for xsave. */
+#define STATE_SAVE_OFFSET (8 * 7 + 8)
+
+/* Save SSE, AVX, AVX512, mask and bound registers. */
+#define STATE_SAVE_MASK \
+ ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7))
+
#ifdef __ASSEMBLER__
/* Syntactic details of assembler. */
diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S
index ef1425cbb909529a..fd918510fe155733 100644
--- a/sysdeps/x86_64/dl-trampoline.S
+++ b/sysdeps/x86_64/dl-trampoline.S
@@ -18,7 +18,7 @@
#include <config.h>
#include <sysdep.h>
-#include <cpu-features.h>
+#include <cpu-features-offsets.h>
#include <link-defines.h>
#ifndef DL_STACK_ALIGNMENT

View File

@ -0,0 +1,538 @@
commit ec935dea6332cb22f9881cd1162bad156173f4b0
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Apr 24 22:31:15 2020 +0200
elf: Implement __libc_early_init
This function is defined in libc.so, and the dynamic loader calls
right after relocation has been finished, before any ELF constructors
or the preinit function is invoked. It is also used in the static
build for initializing parts of the static libc.
To locate __libc_early_init, a direct symbol lookup function is used,
_dl_lookup_direct. It does not search the entire symbol scope and
consults merely a single link map. This function could also be used
to implement lookups in the vDSO (as an optimization).
A per-namespace variable (libc_map) is added for locating libc.so,
to avoid repeated traversals of the search scope. It is similar to
GL(dl_initfirst). An alternative would have been to thread a context
argument from _dl_open down to _dl_map_object_from_fd (where libc.so
is identified). This could have avoided the global variable, but
the change would be larger as a result. It would not have been
possible to use this to replace GL(dl_initfirst) because that global
variable is used to pass the function pointer past the stack switch
from dl_main to the main program. Replacing that requires adding
a new argument to _dl_init, which in turn needs changes to the
architecture-specific libc.so startup code written in assembler.
__libc_early_init should not be used to replace _dl_var_init (as
it exists today on some architectures). Instead, _dl_lookup_direct
should be used to look up a new variable symbol in libc.so, and
that should then be initialized from the dynamic loader, immediately
after the object has been loaded in _dl_map_object_from_fd (before
relocation is run). This way, more IFUNC resolvers which depend on
these variables will work.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/csu/init-first.c b/csu/init-first.c
index 289373f9d8bd98f4..544229151ef79c67 100644
--- a/csu/init-first.c
+++ b/csu/init-first.c
@@ -16,7 +16,6 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
@@ -80,9 +79,6 @@ _init (int argc, char **argv, char **envp)
__init_misc (argc, argv, envp);
- /* Initialize ctype data. */
- __ctype_init ();
-
#if defined SHARED && !defined NO_CTORS_DTORS_SECTIONS
__libc_global_ctors ();
#endif
diff --git a/csu/libc-start.c b/csu/libc-start.c
index dfbf195328239a17..d9c3248219d8f84f 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -22,6 +22,7 @@
#include <ldsodefs.h>
#include <exit-thread.h>
#include <libc-internal.h>
+#include <elf/libc-early-init.h>
#include <elf/dl-tunables.h>
@@ -238,6 +239,10 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
__cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL);
#ifndef SHARED
+ /* Perform early initialization. In the shared case, this function
+ is called from the dynamic loader as early as possible. */
+ __libc_early_init ();
+
/* Call the initializer of the libc. This is only needed here if we
are compiling for the static library in which case we haven't
run the constructors in `_dl_start_user'. */
diff --git a/elf/Makefile b/elf/Makefile
index a6601ba84c8f4017..cbced7605ebe2443 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -25,7 +25,7 @@ headers = elf.h bits/elfclass.h link.h bits/link.h
routines = $(all-dl-routines) dl-support dl-iteratephdr \
dl-addr dl-addr-obj enbl-secure dl-profstub \
dl-origin dl-libc dl-sym dl-sysdep dl-error \
- dl-reloc-static-pie
+ dl-reloc-static-pie libc_early_init
# The core dynamic linking functions are in libc for the static and
# profiled libraries.
@@ -33,7 +33,8 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \
runtime init fini debug misc \
version profile tls origin scope \
execstack open close trampoline \
- exception sort-maps)
+ exception sort-maps lookup-direct \
+ call-libc-early-init)
ifeq (yes,$(use-ldconfig))
dl-routines += dl-cache
endif
diff --git a/elf/Versions b/elf/Versions
index 705489fc51f4ac5f..3be879c4adfa74c7 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -26,6 +26,7 @@ libc {
_dl_open_hook; _dl_open_hook2;
_dl_sym; _dl_vsym;
__libc_dlclose; __libc_dlopen_mode; __libc_dlsym; __libc_dlvsym;
+ __libc_early_init;
# Internal error handling support. Interposes the functions in ld.so.
_dl_signal_exception; _dl_catch_exception;
diff --git a/elf/dl-call-libc-early-init.c b/elf/dl-call-libc-early-init.c
new file mode 100644
index 0000000000000000..41e9ad9aad8b5b46
--- /dev/null
+++ b/elf/dl-call-libc-early-init.c
@@ -0,0 +1,41 @@
+/* Invoke the early initialization function in libc.so.
+ Copyright (C) 2020 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 <assert.h>
+#include <ldsodefs.h>
+#include <libc-early-init.h>
+#include <link.h>
+#include <stddef.h>
+
+void
+_dl_call_libc_early_init (struct link_map *libc_map)
+{
+ /* There is nothing to do if we did not actually load libc.so. */
+ if (libc_map == NULL)
+ return;
+
+ const ElfW(Sym) *sym
+ = _dl_lookup_direct (libc_map, "__libc_early_init",
+ 0x069682ac, /* dl_new_hash output. */
+ "GLIBC_PRIVATE",
+ 0x0963cf85); /* _dl_elf_hash output. */
+ assert (sym != NULL);
+ __typeof (__libc_early_init) *early_init
+ = DL_SYMBOL_ADDRESS (libc_map, sym);
+ early_init ();
+}
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 8f8869ff524ab9f2..64da5323d0e368c1 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -30,6 +30,7 @@
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <gnu/lib-names.h>
/* Type for the buffer we put the ELF header and hopefully the program
header. This buffer does not really have to be too large. In most
@@ -1390,6 +1391,14 @@ cannot enable executable stack as shared object requires");
add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
+ l->l_info[DT_SONAME]->d_un.d_val));
+ /* If we have newly loaded libc.so, update the namespace
+ description. */
+ if (GL(dl_ns)[nsid].libc_map == NULL
+ && l->l_info[DT_SONAME] != NULL
+ && strcmp (((const char *) D_PTR (l, l_info[DT_STRTAB])
+ + l->l_info[DT_SONAME]->d_un.d_val), LIBC_SO) == 0)
+ GL(dl_ns)[nsid].libc_map = l;
+
/* _dl_close can only eventually undo the module ID assignment (via
remove_slotinfo) if this function returns a pointer to a link
map. Therefore, delay this step until all possibilities for
diff --git a/elf/dl-lookup-direct.c b/elf/dl-lookup-direct.c
new file mode 100644
index 0000000000000000..5637ae89de8a9d61
--- /dev/null
+++ b/elf/dl-lookup-direct.c
@@ -0,0 +1,116 @@
+/* Look up a symbol in a single specified object.
+ Copyright (C) 1995-2020 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 <ldsodefs.h>
+#include <string.h>
+#include <elf_machine_sym_no_match.h>
+#include <dl-hash.h>
+
+/* This function corresponds to do_lookup_x in elf/dl-lookup.c. The
+ variant here is simplified because it requires symbol
+ versioning. */
+static const ElfW(Sym) *
+check_match (const struct link_map *const map, const char *const undef_name,
+ const char *version, uint32_t version_hash,
+ const Elf_Symndx symidx)
+{
+ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ const ElfW(Sym) *sym = &symtab[symidx];
+
+ unsigned int stt = ELFW(ST_TYPE) (sym->st_info);
+ if (__glibc_unlikely ((sym->st_value == 0 /* No value. */
+ && sym->st_shndx != SHN_ABS
+ && stt != STT_TLS)
+ || elf_machine_sym_no_match (sym)))
+ return NULL;
+
+ /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC,
+ STT_COMMON, STT_TLS, and STT_GNU_IFUNC since these are no
+ code/data definitions. */
+#define ALLOWED_STT \
+ ((1 << STT_NOTYPE) | (1 << STT_OBJECT) | (1 << STT_FUNC) \
+ | (1 << STT_COMMON) | (1 << STT_TLS) | (1 << STT_GNU_IFUNC))
+ if (__glibc_unlikely (((1 << stt) & ALLOWED_STT) == 0))
+ return NULL;
+
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+ if (strcmp (strtab + sym->st_name, undef_name) != 0)
+ /* Not the symbol we are looking for. */
+ return NULL;
+
+ ElfW(Half) ndx = map->l_versyms[symidx] & 0x7fff;
+ if (map->l_versions[ndx].hash != version_hash
+ || strcmp (map->l_versions[ndx].name, version) != 0)
+ /* It's not the version we want. */
+ return NULL;
+
+ return sym;
+}
+
+
+/* This function corresponds to do_lookup_x in elf/dl-lookup.c. The
+ variant here is simplified because it does not search object
+ dependencies. It is optimized for a successful lookup. */
+const ElfW(Sym) *
+_dl_lookup_direct (struct link_map *map,
+ const char *undef_name, uint32_t new_hash,
+ const char *version, uint32_t version_hash)
+{
+ const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
+ if (__glibc_likely (bitmask != NULL))
+ {
+ Elf32_Word bucket = map->l_gnu_buckets[new_hash % map->l_nbuckets];
+ if (bucket != 0)
+ {
+ const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
+
+ do
+ if (((*hasharr ^ new_hash) >> 1) == 0)
+ {
+ Elf_Symndx symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr);
+ const ElfW(Sym) *sym = check_match (map, undef_name,
+ version, version_hash,
+ symidx);
+ if (sym != NULL)
+ return sym;
+ }
+ while ((*hasharr++ & 1u) == 0);
+ }
+ }
+ else
+ {
+ /* Fallback code for lack of GNU_HASH support. */
+ uint32_t old_hash = _dl_elf_hash (undef_name);
+
+ /* Use the old SysV-style hash table. Search the appropriate
+ hash bucket in this object's symbol table for a definition
+ for the same symbol name. */
+ for (Elf_Symndx symidx = map->l_buckets[old_hash % map->l_nbuckets];
+ symidx != STN_UNDEF;
+ symidx = map->l_chain[symidx])
+ {
+ const ElfW(Sym) *sym = check_match (map, undef_name,
+ version, version_hash, symidx);
+ if (sym != NULL)
+ return sym;
+ }
+ }
+
+ return NULL;
+}
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 7113c4a04f0fddbc..1a77ec833cad6c55 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -34,6 +34,7 @@
#include <atomic.h>
#include <libc-internal.h>
#include <array_length.h>
+#include <libc-early-init.h>
#include <dl-dst.h>
#include <dl-prop.h>
@@ -57,6 +58,13 @@ struct dl_open_args
(non-negative). */
unsigned int original_global_scope_pending_adds;
+ /* Set to true by dl_open_worker if libc.so was already loaded into
+ the namespace at the time dl_open_worker was called. This is
+ used to determine whether libc.so early initialization has
+ already been done before, and whether to roll back the cached
+ libc_map value in the namespace in case of a dlopen failure. */
+ bool libc_already_loaded;
+
/* Original parameters to the program and the current environment. */
int argc;
char **argv;
@@ -500,6 +508,11 @@ dl_open_worker (void *a)
args->nsid = call_map->l_ns;
}
+ /* The namespace ID is now known. Keep track of whether libc.so was
+ already loaded, to determine whether it is necessary to call the
+ early initialization routine (or clear libc_map on error). */
+ args->libc_already_loaded = GL(dl_ns)[args->nsid].libc_map != NULL;
+
/* Retain the old value, so that it can be restored. */
args->original_global_scope_pending_adds
= GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds;
@@ -734,6 +747,11 @@ dl_open_worker (void *a)
if (relocation_in_progress)
LIBC_PROBE (reloc_complete, 3, args->nsid, r, new);
+ /* If libc.so was not there before, attempt to call its early
+ initialization routine. */
+ if (!args->libc_already_loaded)
+ _dl_call_libc_early_init (GL(dl_ns)[args->nsid].libc_map);
+
#ifndef SHARED
DL_STATIC_INIT (new);
#endif
@@ -828,6 +846,8 @@ no more namespaces available for dlmopen()"));
args.caller_dlopen = caller_dlopen;
args.map = NULL;
args.nsid = nsid;
+ /* args.libc_already_loaded is always assigned by dl_open_worker
+ (before any explicit/non-local returns). */
args.argc = argc;
args.argv = argv;
args.env = env;
@@ -856,6 +876,11 @@ no more namespaces available for dlmopen()"));
/* See if an error occurred during loading. */
if (__glibc_unlikely (exception.errstring != NULL))
{
+ /* Avoid keeping around a dangling reference to the libc.so link
+ map in case it has been cached in libc_map. */
+ if (!args.libc_already_loaded)
+ GL(dl_ns)[nsid].libc_map = NULL;
+
/* Remove the object from memory. It may be in an inconsistent
state if relocation failed, for example. */
if (args.map)
diff --git a/elf/libc-early-init.h b/elf/libc-early-init.h
new file mode 100644
index 0000000000000000..5185fa8895c0e11a
--- /dev/null
+++ b/elf/libc-early-init.h
@@ -0,0 +1,35 @@
+/* Early initialization of libc.so.
+ Copyright (C) 2020 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/>. */
+
+#ifndef _LIBC_EARLY_INIT_H
+#define _LIBC_EARLY_INIT_H
+
+struct link_map;
+
+/* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it
+ and call this function. */
+void _dl_call_libc_early_init (struct link_map *libc_map) attribute_hidden;
+
+/* In the shared case, this function is defined in libc.so and invoked
+ from ld.so (or on the fist static dlopen) after complete relocation
+ of a new loaded libc.so, but before user-defined ELF constructors
+ run. In the static case, this function is called directly from the
+ startup code. */
+void __libc_early_init (void);
+
+#endif /* _LIBC_EARLY_INIT_H */
diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c
new file mode 100644
index 0000000000000000..7f4ca332b805a22c
--- /dev/null
+++ b/elf/libc_early_init.c
@@ -0,0 +1,27 @@
+/* Early initialization of libc.so, libc.so side.
+ Copyright (C) 2020 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 <ctype.h>
+#include <libc-early-init.h>
+
+void
+__libc_early_init (void)
+{
+ /* Initialize ctype data. */
+ __ctype_init ();
+}
diff --git a/elf/rtld.c b/elf/rtld.c
index d44facf5343b3301..a40d5f17db0dac8b 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -44,6 +44,7 @@
#include <stackinfo.h>
#include <not-cancel.h>
#include <array_length.h>
+#include <libc-early-init.h>
#include <assert.h>
@@ -2365,6 +2366,9 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
rtld_timer_accum (&relocate_time, start);
}
+ /* Relocation is complete. Perform early libc initialization. */
+ _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map);
+
/* Do any necessary cleanups for the startup OS interface code.
We do these now so that no calls are made after rtld re-relocation
which might be resolved to different functions than we expect.
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index a8fb0d211426e4b1..ccec08929e4ad4e7 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -336,6 +336,10 @@ struct rtld_global
recursive dlopen calls from ELF constructors. */
unsigned int _ns_global_scope_pending_adds;
+ /* Once libc.so has been loaded into the namespace, this points to
+ its link map. */
+ struct link_map *libc_map;
+
/* Search table for unique objects. */
struct unique_sym_table
{
@@ -943,6 +947,19 @@ extern lookup_t _dl_lookup_symbol_x (const char *undef,
attribute_hidden;
+/* Restricted version of _dl_lookup_symbol_x. Searches MAP (and only
+ MAP) for the symbol UNDEF_NAME, with GNU hash NEW_HASH (computed
+ with dl_new_hash), symbol version VERSION, and symbol version hash
+ VERSION_HASH (computed with _dl_elf_hash). Returns a pointer to
+ the symbol table entry in MAP on success, or NULL on failure. MAP
+ must have symbol versioning information, or otherwise the result is
+ undefined. */
+const ElfW(Sym) *_dl_lookup_direct (struct link_map *map,
+ const char *undef_name,
+ uint32_t new_hash,
+ const char *version,
+ uint32_t version_hash) attribute_hidden;
+
/* Add the new link_map NEW to the end of the namespace list. */
extern void _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
attribute_hidden;
diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c
index f8ad2ceb8e324f92..1636a40ee5d78858 100644
--- a/sysdeps/mach/hurd/i386/init-first.c
+++ b/sysdeps/mach/hurd/i386/init-first.c
@@ -17,7 +17,6 @@
<http://www.gnu.org/licenses/>. */
#include <assert.h>
-#include <ctype.h>
#include <hurd.h>
#include <stdio.h>
#include <unistd.h>
@@ -84,9 +83,6 @@ posixland_init (int argc, char **argv, char **envp)
#endif
__init_misc (argc, argv, envp);
- /* Initialize ctype data. */
- __ctype_init ();
-
#if defined SHARED && !defined NO_CTORS_DTORS_SECTIONS
__libc_global_ctors ();
#endif

View File

@ -0,0 +1,688 @@
commit 92954ffa5a5662fbfde14febd7e5dcc358c85470
Author: Carlos O'Donell <carlos@redhat.com>
Date: Wed Jan 8 13:24:42 2020 -0500
localedef: Add verbose messages for failure paths.
During testing of localedef running in a minimal container
there were several error cases which were hard to diagnose
since they appeared as strerror (errno) values printed by the
higher level functions. This change adds three new verbose
messages for potential failure paths. The new messages give
the user the opportunity to use -v and display additional
information about why localedef might be failing. I found
these messages useful myself while writing a localedef
container test for --no-hard-links.
Since the changes cleanup the code that handle codeset
normalization we add tst-localedef-path-norm which contains
many sub-tests to verify the correct expected normalization of
codeset strings both when installing to default paths (the
only time normalization is enabled) and installing to absolute
paths. During the refactoring I created at least one
buffer-overflow which valgrind caught, but these tests did not
catch because the exec in the container had a very clean heap
with zero-initialized memory. However, between valgrind and
the tests the results are clean.
The new tst-localedef-path-norm passes without regression on
x86_64.
Change-Id: I28b9f680711ff00252a2cb15625b774cc58ecb9d
diff --git a/include/programs/xasprintf.h b/include/programs/xasprintf.h
new file mode 100644
index 0000000000000000..53193ba3837f7418
--- /dev/null
+++ b/include/programs/xasprintf.h
@@ -0,0 +1,24 @@
+/* asprintf with out of memory checking
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+#ifndef _XASPRINTF_H
+#define _XASPRINTF_H 1
+
+extern char *xasprintf (const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2), __warn_unused_result__));
+
+#endif /* xasprintf.h */
diff --git a/locale/Makefile b/locale/Makefile
index 23a71321b6646c49..4278350cdc7be28d 100644
--- a/locale/Makefile
+++ b/locale/Makefile
@@ -28,6 +28,7 @@ routines = setlocale findlocale loadlocale loadarchive \
localeconv nl_langinfo nl_langinfo_l mb_cur_max \
newlocale duplocale freelocale uselocale
tests = tst-C-locale tst-locname tst-duplocale
+tests-container = tst-localedef-path-norm
categories = ctype messages monetary numeric time paper name \
address telephone measurement identification collate
aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \
@@ -54,7 +55,7 @@ localedef-modules := localedef $(categories:%=ld-%) \
localedef-aux := md5
locale-modules := locale locale-spec
lib-modules := charmap-dir simple-hash xmalloc xstrdup \
- record-status
+ record-status xasprintf
GPERF = gperf
diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c
index d718d2e9f47382bc..9a57d2cb435b25ed 100644
--- a/locale/programs/localedef.c
+++ b/locale/programs/localedef.c
@@ -174,14 +174,14 @@ static struct argp argp =
/* Prototypes for local functions. */
static void error_print (void);
-static const char *construct_output_path (char *path);
-static const char *normalize_codeset (const char *codeset, size_t name_len);
+static char *construct_output_path (char *path);
+static char *normalize_codeset (const char *codeset, size_t name_len);
int
main (int argc, char *argv[])
{
- const char *output_path;
+ char *output_path;
int cannot_write_why;
struct charmap_t *charmap;
struct localedef_t global;
@@ -226,7 +226,8 @@ main (int argc, char *argv[])
}
/* The parameter describes the output path of the constructed files.
- If the described files cannot be written return a NULL pointer. */
+ If the described files cannot be written return a NULL pointer.
+ We don't free output_path because we will exit. */
output_path = construct_output_path (argv[remaining]);
if (output_path == NULL && ! no_archive)
error (4, errno, _("cannot create directory for output files"));
@@ -424,20 +425,16 @@ more_help (int key, const char *text, void *input)
{
case ARGP_KEY_HELP_EXTRA:
/* We print some extra information. */
- if (asprintf (&tp, gettext ("\
+ tp = xasprintf (gettext ("\
For bug reporting instructions, please see:\n\
-%s.\n"), REPORT_BUGS_TO) < 0)
- return NULL;
- if (asprintf (&cp, gettext ("\
+%s.\n"), REPORT_BUGS_TO);
+ cp = xasprintf (gettext ("\
System's directory for character maps : %s\n\
repertoire maps: %s\n\
locale path : %s\n\
%s"),
- CHARMAP_PATH, REPERTOIREMAP_PATH, LOCALE_PATH, tp) < 0)
- {
- free (tp);
- return NULL;
- }
+ CHARMAP_PATH, REPERTOIREMAP_PATH, LOCALE_PATH, tp);
+ free (tp);
return cp;
default:
break;
@@ -467,15 +464,13 @@ error_print (void)
}
-/* The parameter to localedef describes the output path. If it does
- contain a '/' character it is a relative path. Otherwise it names the
- locale this definition is for. */
-static const char *
+/* The parameter to localedef describes the output path. If it does contain a
+ '/' character it is a relative path. Otherwise it names the locale this
+ definition is for. The returned path must be freed by the caller. */
+static char *
construct_output_path (char *path)
{
- const char *normal = NULL;
char *result;
- char *endp;
if (strchr (path, '/') == NULL)
{
@@ -483,50 +478,44 @@ construct_output_path (char *path)
contains a reference to the codeset. This should be
normalized. */
char *startp;
+ char *endp = NULL;
+ char *normal = NULL;
startp = path;
- /* We must be prepared for finding a CEN name or a location of
- the introducing `.' where it is not possible anymore. */
+ /* Either we have a '@' which starts a CEN name or '.' which starts the
+ codeset specification. The CEN name starts with '@' and may also have
+ a codeset specification, but we do not normalize the string after '@'.
+ If we only find the codeset specification then we normalize only the codeset
+ specification (but not anything after a subsequent '@'). */
while (*startp != '\0' && *startp != '@' && *startp != '.')
++startp;
if (*startp == '.')
{
/* We found a codeset specification. Now find the end. */
endp = ++startp;
+
+ /* Stop at the first '@', and don't normalize anything past that. */
while (*endp != '\0' && *endp != '@')
++endp;
if (endp > startp)
normal = normalize_codeset (startp, endp - startp);
}
- else
- /* This is to keep gcc quiet. */
- endp = NULL;
- /* We put an additional '\0' at the end of the string because at
- the end of the function we need another byte for the trailing
- '/'. */
- ssize_t n;
if (normal == NULL)
- n = asprintf (&result, "%s%s/%s%c", output_prefix ?: "",
- COMPLOCALEDIR, path, '\0');
+ result = xasprintf ("%s%s/%s/", output_prefix ?: "",
+ COMPLOCALEDIR, path);
else
- n = asprintf (&result, "%s%s/%.*s%s%s%c",
- output_prefix ?: "", COMPLOCALEDIR,
- (int) (startp - path), path, normal, endp, '\0');
-
- if (n < 0)
- return NULL;
-
- endp = result + n - 1;
+ result = xasprintf ("%s%s/%.*s%s%s/",
+ output_prefix ?: "", COMPLOCALEDIR,
+ (int) (startp - path), path, normal, endp ?: "");
+ /* Free the allocated normalized codeset name. */
+ free (normal);
}
else
{
- /* This is a user path. Please note the additional byte in the
- memory allocation. */
- size_t len = strlen (path) + 1;
- result = xmalloc (len + 1);
- endp = mempcpy (result, path, len) - 1;
+ /* This is a user path. */
+ result = xasprintf ("%s/", path);
/* If the user specified an output path we cannot add the output
to the archive. */
@@ -536,25 +525,41 @@ construct_output_path (char *path)
errno = 0;
if (no_archive && euidaccess (result, W_OK) == -1)
- /* Perhaps the directory does not exist now. Try to create it. */
- if (errno == ENOENT)
- {
- errno = 0;
- if (mkdir (result, 0777) < 0)
- return NULL;
- }
-
- *endp++ = '/';
- *endp = '\0';
+ {
+ /* Perhaps the directory does not exist now. Try to create it. */
+ if (errno == ENOENT)
+ {
+ errno = 0;
+ if (mkdir (result, 0777) < 0)
+ {
+ record_verbose (stderr,
+ _("cannot create output path \'%s\': %s"),
+ result, strerror (errno));
+ free (result);
+ return NULL;
+ }
+ }
+ else
+ record_verbose (stderr,
+ _("no write permission to output path \'%s\': %s"),
+ result, strerror (errno));
+ }
return result;
}
-/* Normalize codeset name. There is no standard for the codeset
- names. Normalization allows the user to use any of the common
- names. */
-static const char *
+/* Normalize codeset name. There is no standard for the codeset names.
+ Normalization allows the user to use any of the common names e.g. UTF-8,
+ utf-8, utf8, UTF8 etc.
+
+ We normalize using the following rules:
+ - Remove all non-alpha-numeric characters
+ - Lowercase all characters.
+ - If there are only digits assume it's an ISO standard and prefix with 'iso'
+
+ We return the normalized string which needs to be freed by free. */
+static char *
normalize_codeset (const char *codeset, size_t name_len)
{
int len = 0;
@@ -563,6 +568,7 @@ normalize_codeset (const char *codeset, size_t name_len)
char *wp;
size_t cnt;
+ /* Compute the length of only the alpha-numeric characters. */
for (cnt = 0; cnt < name_len; ++cnt)
if (isalnum (codeset[cnt]))
{
@@ -572,25 +578,24 @@ normalize_codeset (const char *codeset, size_t name_len)
only_digit = 0;
}
- retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
+ /* If there were only digits we assume it's an ISO standard and we will
+ prefix with 'iso' so include space for that. We fill in the required
+ space from codeset up to the converted length. */
+ wp = retval = xasprintf ("%s%.*s", only_digit ? "iso" : "", len, codeset);
- if (retval != NULL)
- {
- if (only_digit)
- wp = stpcpy (retval, "iso");
- else
- wp = retval;
-
- for (cnt = 0; cnt < name_len; ++cnt)
- if (isalpha (codeset[cnt]))
- *wp++ = tolower (codeset[cnt]);
- else if (isdigit (codeset[cnt]))
- *wp++ = codeset[cnt];
+ /* Skip "iso". */
+ if (only_digit)
+ wp += 3;
- *wp = '\0';
- }
+ /* Lowercase all characters. */
+ for (cnt = 0; cnt < name_len; ++cnt)
+ if (isalpha (codeset[cnt]))
+ *wp++ = tolower (codeset[cnt]);
+ else if (isdigit (codeset[cnt]))
+ *wp++ = codeset[cnt];
- return (const char *) retval;
+ /* Return allocated and converted name for caller to free. */
+ return retval;
}
diff --git a/locale/programs/localedef.h b/locale/programs/localedef.h
index 0083faceabbf3dd9..c528dbb97854dbd1 100644
--- a/locale/programs/localedef.h
+++ b/locale/programs/localedef.h
@@ -122,6 +122,7 @@ extern const char *alias_file;
/* Prototypes for a few program-wide used functions. */
#include <programs/xmalloc.h>
+#include <programs/xasprintf.h>
/* Mark given locale as to be read. */
diff --git a/locale/programs/xasprintf.c b/locale/programs/xasprintf.c
new file mode 100644
index 0000000000000000..efc91a9c34074736
--- /dev/null
+++ b/locale/programs/xasprintf.c
@@ -0,0 +1,34 @@
+/* asprintf with out of memory checking
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <libintl.h>
+#include <error.h>
+
+char *
+xasprintf (const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ char *result;
+ if (vasprintf (&result, format, ap) < 0)
+ error (EXIT_FAILURE, 0, _("memory exhausted"));
+ va_end (ap);
+ return result;
+}
diff --git a/locale/tst-localedef-path-norm.c b/locale/tst-localedef-path-norm.c
new file mode 100644
index 0000000000000000..2ef1d26f07084c68
--- /dev/null
+++ b/locale/tst-localedef-path-norm.c
@@ -0,0 +1,242 @@
+/* Test for localedef path name handling and normalization.
+ Copyright (C) 2019 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/>. */
+
+/* The test runs localedef with various named paths to test for expected
+ behaviours dealing with codeset name normalization. That is to say that use
+ of UTF-8, and it's variations, are normalized to utf8. Likewise that values
+ after the @ are not normalized and left as-is. The test needs to run
+ localedef with known input values and then check that the generated path
+ matches the expected value after normalization. */
+
+/* Note: In some cases adding -v (verbose) to localedef changes the exit
+ status to a non-zero value because some warnings are only enabled in verbose
+ mode. This should probably be changed so warnings are either present or not
+ present, regardless of verbosity. POSIX requires that any warnings cause the
+ exit status to be non-zero. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+
+/* Full path to localedef. */
+char *prog;
+
+/* Execute localedef in a subprocess. */
+static void
+execv_wrapper (void *args)
+{
+ char **argv = args;
+
+ execv (prog, argv);
+ FAIL_EXIT1 ("execv: %m");
+}
+
+struct test_closure
+{
+ /* Arguments for running localedef. */
+ const char *const argv[16];
+ /* Expected directory name for compiled locale. */
+ const char *exp;
+ /* Expected path to compiled locale. */
+ const char *complocaledir;
+};
+
+/* Run localedef with DATA.ARGV arguments (NULL terminated), and expect path to
+ the compiled locale is "DATA.COMPLOCALEDIR/DATA.EXP". */
+static void
+run_test (struct test_closure data)
+{
+ const char * const *args = data.argv;
+ const char *exp = data.exp;
+ const char *complocaledir = data.complocaledir;
+ struct stat64 fs;
+
+ /* Expected output path. */
+ const char *path = xasprintf ("%s/%s", complocaledir, exp);
+
+ /* Run test. */
+ struct support_capture_subprocess result;
+ result = support_capture_subprocess (execv_wrapper, (void *)args);
+ support_capture_subprocess_check (&result, "execv", 0, sc_allow_none);
+ support_capture_subprocess_free (&result);
+
+ /* Verify path is present and is a directory. */
+ xstat (path, &fs);
+ TEST_VERIFY_EXIT (S_ISDIR (fs.st_mode));
+ printf ("info: Directory '%s' exists.\n", path);
+}
+
+static int
+do_test (void)
+{
+ /* We are running as root inside the container. */
+ prog = xasprintf ("%s/localedef", support_bindir_prefix);
+
+ /* Create the needed directories:
+ - We need the default compiled locale dir for default output.
+ - We need an arbitrary absolute path for localedef output.
+
+ Note: Writing to a non-default absolute path disables any kind
+ of path normalization since we expect the user wants the path
+ exactly as they specified it. */
+ xmkdirp (support_complocaledir_prefix, 0777);
+ xmkdirp ("/output", 0777);
+
+ /* It takes ~10 seconds to serially execute 9 localedef test. We
+ could run the compilations in parallel if we want to reduce test
+ time. We don't want to split this out into distinct tests because
+ it would require multiple chroots. Batching the same localedef
+ tests saves disk space during testing. */
+
+ /* Test 1: Expected normalization.
+ Run localedef and expect output in /usr/lib/locale/en_US1.utf8,
+ with normalization changing UTF-8 to utf8. */
+ run_test ((struct test_closure)
+ {
+ .argv = { prog,
+ "--no-archive",
+ "-i", "en_US",
+ "-f", "UTF-8",
+ "en_US1.UTF-8", NULL },
+ .exp = "en_US1.utf8",
+ .complocaledir = support_complocaledir_prefix
+ });
+
+ /* Test 2: No normalization past '@'.
+ Run localedef and expect output in /usr/lib/locale/en_US2.utf8@tEsT,
+ with normalization changing UTF-8@tEsT to utf8@tEsT (everything after
+ @ is untouched). */
+ run_test ((struct test_closure)
+ {
+ .argv = { prog,
+ "--no-archive",
+ "-i", "en_US",
+ "-f", "UTF-8",
+ "en_US2.UTF-8@tEsT", NULL },
+ .exp = "en_US2.utf8@tEsT",
+ .complocaledir = support_complocaledir_prefix
+ });
+
+ /* Test 3: No normalization past '@' despite period.
+ Run localedef and expect output in /usr/lib/locale/en_US3@tEsT.UTF-8,
+ with normalization changing nothing (everything after @ is untouched)
+ despite there being a period near the end. */
+ run_test ((struct test_closure)
+ {
+ .argv = { prog,
+ "--no-archive",
+ "-i", "en_US",
+ "-f", "UTF-8",
+ "en_US3@tEsT.UTF-8", NULL },
+ .exp = "en_US3@tEsT.UTF-8",
+ .complocaledir = support_complocaledir_prefix
+ });
+
+ /* Test 4: Normalize numeric codeset by adding 'iso' prefix.
+ Run localedef and expect output in /usr/lib/locale/en_US4.88591,
+ with normalization changing 88591 to iso88591. */
+ run_test ((struct test_closure)
+ {
+ .argv = { prog,
+ "--no-archive",
+ "-i", "en_US",
+ "-f", "UTF-8",
+ "en_US4.88591", NULL },
+ .exp = "en_US4.iso88591",
+ .complocaledir = support_complocaledir_prefix
+ });
+
+ /* Test 5: Don't add 'iso' prefix if first char is alpha.
+ Run localedef and expect output in /usr/lib/locale/en_US5.a88591,
+ with normalization changing nothing. */
+ run_test ((struct test_closure)
+ {
+ .argv = { prog,
+ "--no-archive",
+ "-i", "en_US",
+ "-f", "UTF-8",
+ "en_US5.a88591", NULL },
+ .exp = "en_US5.a88591",
+ .complocaledir = support_complocaledir_prefix
+ });
+
+ /* Test 6: Don't add 'iso' prefix if last char is alpha.
+ Run localedef and expect output in /usr/lib/locale/en_US6.88591a,
+ with normalization changing nothing. */
+ run_test ((struct test_closure)
+ {
+ .argv = { prog,
+ "--no-archive",
+ "-i", "en_US",
+ "-f", "UTF-8",
+ "en_US6.88591a", NULL },
+ .exp = "en_US6.88591a",
+ .complocaledir = support_complocaledir_prefix
+ });
+
+ /* Test 7: Don't normalize anything with an absolute path.
+ Run localedef and expect output in /output/en_US7.UTF-8,
+ with normalization changing nothing. */
+ run_test ((struct test_closure)
+ {
+ .argv = { prog,
+ "--no-archive",
+ "-i", "en_US",
+ "-f", "UTF-8",
+ "/output/en_US7.UTF-8", NULL },
+ .exp = "en_US7.UTF-8",
+ .complocaledir = "/output"
+ });
+
+ /* Test 8: Don't normalize anything with an absolute path.
+ Run localedef and expect output in /output/en_US8.UTF-8@tEsT,
+ with normalization changing nothing. */
+ run_test ((struct test_closure)
+ {
+ .argv = { prog,
+ "--no-archive",
+ "-i", "en_US",
+ "-f", "UTF-8",
+ "/output/en_US8.UTF-8@tEsT", NULL },
+ .exp = "en_US8.UTF-8@tEsT",
+ .complocaledir = "/output"
+ });
+
+ /* Test 9: Don't normalize anything with an absolute path.
+ Run localedef and expect output in /output/en_US9@tEsT.UTF-8,
+ with normalization changing nothing. */
+ run_test ((struct test_closure)
+ {
+ .argv = { prog,
+ "--no-archive",
+ "-i", "en_US",
+ "-f", "UTF-8",
+ "/output/en_US9@tEsT.UTF-8", NULL },
+ .exp = "en_US9@tEsT.UTF-8",
+ .complocaledir = "/output"
+ });
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/locale/tst-localedef-path-norm.root/postclean.req b/locale/tst-localedef-path-norm.root/postclean.req
new file mode 100644
index 0000000000000000..e69de29bb2d1d643
diff --git a/locale/tst-localedef-path-norm.root/tst-localedef-path-norm.script b/locale/tst-localedef-path-norm.root/tst-localedef-path-norm.script
new file mode 100644
index 0000000000000000..b0f016256a47f762
--- /dev/null
+++ b/locale/tst-localedef-path-norm.root/tst-localedef-path-norm.script
@@ -0,0 +1,2 @@
+# Must run localedef as root to write into default paths.
+su
diff --git a/support/Makefile b/support/Makefile
index 117cfdd4f22fc405..5808a42dce87151f 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -182,7 +182,8 @@ CFLAGS-support_paths.c = \
-DLIBDIR_PATH=\"$(libdir)\" \
-DBINDIR_PATH=\"$(bindir)\" \
-DSBINDIR_PATH=\"$(sbindir)\" \
- -DROOTSBINDIR_PATH=\"$(rootsbindir)\"
+ -DROOTSBINDIR_PATH=\"$(rootsbindir)\" \
+ -DCOMPLOCALEDIR_PATH=\"$(complocaledir)\"
ifeq (,$(CXX))
LINKS_DSO_PROGRAM = links-dso-program-c
diff --git a/support/support.h b/support/support.h
index 121cc9e9b7c98ca6..3af87f85fe1b762d 100644
--- a/support/support.h
+++ b/support/support.h
@@ -112,6 +112,8 @@ extern const char support_bindir_prefix[];
extern const char support_sbindir_prefix[];
/* Corresponds to the install's sbin/ directory (without prefix). */
extern const char support_install_rootsbindir[];
+/* Corresponds to the install's compiled locale directory. */
+extern const char support_complocaledir_prefix[];
extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *,
size_t, unsigned int);
diff --git a/support/support_paths.c b/support/support_paths.c
index eb2390227433aa70..6b15fae0f0173b1e 100644
--- a/support/support_paths.c
+++ b/support/support_paths.c
@@ -78,3 +78,10 @@ const char support_install_rootsbindir[] = ROOTSBINDIR_PATH;
#else
# error please -DROOTSBINDIR_PATH=something in the Makefile
#endif
+
+#ifdef COMPLOCALEDIR_PATH
+/* Corresponds to the install's compiled locale directory. */
+const char support_complocaledir_prefix[] = COMPLOCALEDIR_PATH;
+#else
+# error please -DCOMPLOCALEDIR_PATH=something in the Makefile
+#endif

View File

@ -0,0 +1,141 @@
commit 03e187a41d91069543cfcf33469a05912e555447
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Apr 29 15:44:03 2020 +0200
elf: Add initial flag argument to __libc_early_init
The rseq initialization should happen only for the libc in the base
namespace (in the dynamic case) or the statically linked libc. The
__libc_multiple_libcs flag does not quite cover this case at present,
so this commit introduces a flag argument to __libc_early_init,
indicating whether the libc being libc is the primary one (of the main
program).
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/csu/libc-start.c b/csu/libc-start.c
index d9c3248219d8f84f..fd0f8640eaeae34c 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -23,6 +23,7 @@
#include <exit-thread.h>
#include <libc-internal.h>
#include <elf/libc-early-init.h>
+#include <stdbool.h>
#include <elf/dl-tunables.h>
@@ -241,7 +242,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
#ifndef SHARED
/* Perform early initialization. In the shared case, this function
is called from the dynamic loader as early as possible. */
- __libc_early_init ();
+ __libc_early_init (true);
/* Call the initializer of the libc. This is only needed here if we
are compiling for the static library in which case we haven't
diff --git a/elf/dl-call-libc-early-init.c b/elf/dl-call-libc-early-init.c
index 41e9ad9aad8b5b46..9a84680a1ceafba2 100644
--- a/elf/dl-call-libc-early-init.c
+++ b/elf/dl-call-libc-early-init.c
@@ -23,7 +23,7 @@
#include <stddef.h>
void
-_dl_call_libc_early_init (struct link_map *libc_map)
+_dl_call_libc_early_init (struct link_map *libc_map, _Bool initial)
{
/* There is nothing to do if we did not actually load libc.so. */
if (libc_map == NULL)
@@ -37,5 +37,5 @@ _dl_call_libc_early_init (struct link_map *libc_map)
assert (sym != NULL);
__typeof (__libc_early_init) *early_init
= DL_SYMBOL_ADDRESS (libc_map, sym);
- early_init ();
+ early_init (initial);
}
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 1a77ec833cad6c55..3d49a84596e99bf6 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -748,9 +748,22 @@ dl_open_worker (void *a)
LIBC_PROBE (reloc_complete, 3, args->nsid, r, new);
/* If libc.so was not there before, attempt to call its early
- initialization routine. */
+ initialization routine. Indicate to the initialization routine
+ whether the libc being initialized is the one in the base
+ namespace. */
if (!args->libc_already_loaded)
- _dl_call_libc_early_init (GL(dl_ns)[args->nsid].libc_map);
+ {
+ struct link_map *libc_map = GL(dl_ns)[args->nsid].libc_map;
+#ifdef SHARED
+ bool initial = libc_map->l_ns == LM_ID_BASE;
+#else
+ /* In the static case, there is only one namespace, but it
+ contains a secondary libc (the primary libc is statically
+ linked). */
+ bool initial = false;
+#endif
+ _dl_call_libc_early_init (libc_map, initial);
+ }
#ifndef SHARED
DL_STATIC_INIT (new);
diff --git a/elf/libc-early-init.h b/elf/libc-early-init.h
index 5185fa8895c0e11a..8f7836dceaeecd5a 100644
--- a/elf/libc-early-init.h
+++ b/elf/libc-early-init.h
@@ -22,14 +22,17 @@
struct link_map;
/* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it
- and call this function. */
-void _dl_call_libc_early_init (struct link_map *libc_map) attribute_hidden;
+ and call this function, with INITIAL as the argument. */
+void _dl_call_libc_early_init (struct link_map *libc_map, _Bool initial)
+ attribute_hidden;
/* In the shared case, this function is defined in libc.so and invoked
from ld.so (or on the fist static dlopen) after complete relocation
of a new loaded libc.so, but before user-defined ELF constructors
run. In the static case, this function is called directly from the
- startup code. */
-void __libc_early_init (void);
+ startup code. If INITIAL is true, the libc being initialized is
+ the libc for the main program. INITIAL is false for libcs loaded
+ for audit modules, dlmopen, and static dlopen. */
+void __libc_early_init (_Bool initial);
#endif /* _LIBC_EARLY_INIT_H */
diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c
index 7f4ca332b805a22c..e6c64fb526600fae 100644
--- a/elf/libc_early_init.c
+++ b/elf/libc_early_init.c
@@ -20,7 +20,7 @@
#include <libc-early-init.h>
void
-__libc_early_init (void)
+__libc_early_init (_Bool initial)
{
/* Initialize ctype data. */
__ctype_init ();
diff --git a/elf/rtld.c b/elf/rtld.c
index a40d5f17db0dac8b..772aff5160359b7b 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2366,8 +2366,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
rtld_timer_accum (&relocate_time, start);
}
- /* Relocation is complete. Perform early libc initialization. */
- _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map);
+ /* Relocation is complete. Perform early libc initialization. This
+ is the initial libc, even if audit modules have been loaded with
+ other libcs. */
+ _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map, true);
/* Do any necessary cleanups for the startup OS interface code.
We do these now so that no calls are made after rtld re-relocation

View File

@ -0,0 +1,86 @@
commit 32ac0b988466785d6e3cc1dffc364bb26fc63193
Author: mayshao <mayshao-oc@zhaoxin.com>
Date: Fri Apr 24 12:55:38 2020 +0800
x86: Add CPU Vendor ID detection support for Zhaoxin processors
To recognize Zhaoxin CPU Vendor ID, add a new architecture type
arch_kind_zhaoxin for Vendor Zhaoxin detection.
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index ade37a9bb3de86cc..c432d646ce6806a6 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -464,6 +464,60 @@ init_cpu_features (struct cpu_features *cpu_features)
}
}
}
+ /* This spells out "CentaurHauls" or " Shanghai ". */
+ else if ((ebx == 0x746e6543 && ecx == 0x736c7561 && edx == 0x48727561)
+ || (ebx == 0x68532020 && ecx == 0x20206961 && edx == 0x68676e61))
+ {
+ unsigned int extended_model, stepping;
+
+ kind = arch_kind_zhaoxin;
+
+ get_common_indices (cpu_features, &family, &model, &extended_model,
+ &stepping);
+
+ get_extended_indices (cpu_features);
+
+ model += extended_model;
+ if (family == 0x6)
+ {
+ if (model == 0xf || model == 0x19)
+ {
+ cpu_features->feature[index_arch_AVX_Usable]
+ &= (~bit_arch_AVX_Usable
+ & ~bit_arch_AVX2_Usable);
+
+ cpu_features->feature[index_arch_Slow_SSE4_2]
+ |= (bit_arch_Slow_SSE4_2);
+
+ cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load]
+ &= ~bit_arch_AVX_Fast_Unaligned_Load;
+ }
+ }
+ else if (family == 0x7)
+ {
+ if (model == 0x1b)
+ {
+ cpu_features->feature[index_arch_AVX_Usable]
+ &= (~bit_arch_AVX_Usable
+ & ~bit_arch_AVX2_Usable);
+
+ cpu_features->feature[index_arch_Slow_SSE4_2]
+ |= bit_arch_Slow_SSE4_2;
+
+ cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load]
+ &= ~bit_arch_AVX_Fast_Unaligned_Load;
+ }
+ else if (model == 0x3b)
+ {
+ cpu_features->feature[index_arch_AVX_Usable]
+ &= (~bit_arch_AVX_Usable
+ & ~bit_arch_AVX2_Usable);
+
+ cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load]
+ &= ~bit_arch_AVX_Fast_Unaligned_Load;
+ }
+ }
+ }
else
{
kind = arch_kind_other;
diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h
index 4917182e99a8ee90..388172a1c07bf979 100644
--- a/sysdeps/x86/cpu-features.h
+++ b/sysdeps/x86/cpu-features.h
@@ -53,6 +53,7 @@ enum cpu_features_kind
arch_kind_unknown = 0,
arch_kind_intel,
arch_kind_amd,
+ arch_kind_zhaoxin,
arch_kind_other
};

View File

@ -0,0 +1,534 @@
commit a98dc92dd1e278df4c501deb07985018bc2b06de
Author: mayshao-oc <mayshao-oc@zhaoxin.com>
Date: Sun Apr 26 13:48:27 2020 +0800
x86: Add cache information support for Zhaoxin processors
To obtain Zhaoxin CPU cache information, add a new function
handle_zhaoxin().
Add a new function get_common_cache_info() that extracts the code
in init_cacheinfo() to get the value of the variable shared, threads.
Add Zhaoxin branch in init_cacheinfo() for initializing variables,
such as __x86_shared_cache_size.
diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c
index f1125f30223f5ca3..aa7cb705d546bcd0 100644
--- a/sysdeps/x86/cacheinfo.c
+++ b/sysdeps/x86/cacheinfo.c
@@ -436,6 +436,57 @@ handle_amd (int name)
}
+static long int __attribute__ ((noinline))
+handle_zhaoxin (int name)
+{
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+
+ int folded_rel_name = (M(name) / 3) * 3;
+
+ unsigned int round = 0;
+ while (1)
+ {
+ __cpuid_count (4, round, eax, ebx, ecx, edx);
+
+ enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
+ if (type == null)
+ break;
+
+ unsigned int level = (eax >> 5) & 0x7;
+
+ if ((level == 1 && type == data
+ && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE))
+ || (level == 1 && type == inst
+ && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE))
+ || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE))
+ || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)))
+ {
+ unsigned int offset = M(name) - folded_rel_name;
+
+ if (offset == 0)
+ /* Cache size. */
+ return (((ebx >> 22) + 1)
+ * (((ebx >> 12) & 0x3ff) + 1)
+ * ((ebx & 0xfff) + 1)
+ * (ecx + 1));
+ if (offset == 1)
+ return (ebx >> 22) + 1;
+
+ assert (offset == 2);
+ return (ebx & 0xfff) + 1;
+ }
+
+ ++round;
+ }
+
+ /* Nothing found. */
+ return 0;
+}
+
+
/* Get the value of the system variable NAME. */
long int
attribute_hidden
@@ -449,6 +500,9 @@ __cache_sysconf (int name)
if (cpu_features->basic.kind == arch_kind_amd)
return handle_amd (name);
+ if (cpu_features->basic.kind == arch_kind_zhaoxin)
+ return handle_zhaoxin (name);
+
// XXX Fill in more vendors.
/* CPU not known, we have no information. */
@@ -482,6 +536,224 @@ int __x86_prefetchw attribute_hidden;
#endif
+static void
+get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr,
+ long int core)
+{
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+
+ /* Number of logical processors sharing L2 cache. */
+ int threads_l2;
+
+ /* Number of logical processors sharing L3 cache. */
+ int threads_l3;
+
+ const struct cpu_features *cpu_features = __get_cpu_features ();
+ int max_cpuid = cpu_features->basic.max_cpuid;
+ unsigned int family = cpu_features->basic.family;
+ unsigned int model = cpu_features->basic.model;
+ long int shared = *shared_ptr;
+ unsigned int threads = *threads_ptr;
+ bool inclusive_cache = true;
+ bool support_count_mask = true;
+
+ /* Try L3 first. */
+ unsigned int level = 3;
+
+ if (cpu_features->basic.kind == arch_kind_zhaoxin && family == 6)
+ support_count_mask = false;
+
+ if (shared <= 0)
+ {
+ /* Try L2 otherwise. */
+ level = 2;
+ shared = core;
+ threads_l2 = 0;
+ threads_l3 = -1;
+ }
+ else
+ {
+ threads_l2 = 0;
+ threads_l3 = 0;
+ }
+
+ /* A value of 0 for the HTT bit indicates there is only a single
+ logical processor. */
+ if (HAS_CPU_FEATURE (HTT))
+ {
+ /* Figure out the number of logical threads that share the
+ highest cache level. */
+ if (max_cpuid >= 4)
+ {
+ int i = 0;
+
+ /* Query until cache level 2 and 3 are enumerated. */
+ int check = 0x1 | (threads_l3 == 0) << 1;
+ do
+ {
+ __cpuid_count (4, i++, eax, ebx, ecx, edx);
+
+ /* There seems to be a bug in at least some Pentium Ds
+ which sometimes fail to iterate all cache parameters.
+ Do not loop indefinitely here, stop in this case and
+ assume there is no such information. */
+ if (cpu_features->basic.kind == arch_kind_intel
+ && (eax & 0x1f) == 0 )
+ goto intel_bug_no_cache_info;
+
+ switch ((eax >> 5) & 0x7)
+ {
+ default:
+ break;
+ case 2:
+ if ((check & 0x1))
+ {
+ /* Get maximum number of logical processors
+ sharing L2 cache. */
+ threads_l2 = (eax >> 14) & 0x3ff;
+ check &= ~0x1;
+ }
+ break;
+ case 3:
+ if ((check & (0x1 << 1)))
+ {
+ /* Get maximum number of logical processors
+ sharing L3 cache. */
+ threads_l3 = (eax >> 14) & 0x3ff;
+
+ /* Check if L2 and L3 caches are inclusive. */
+ inclusive_cache = (edx & 0x2) != 0;
+ check &= ~(0x1 << 1);
+ }
+ break;
+ }
+ }
+ while (check);
+
+ /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum
+ numbers of addressable IDs for logical processors sharing
+ the cache, instead of the maximum number of threads
+ sharing the cache. */
+ if (max_cpuid >= 11 && support_count_mask)
+ {
+ /* Find the number of logical processors shipped in
+ one core and apply count mask. */
+ i = 0;
+
+ /* Count SMT only if there is L3 cache. Always count
+ core if there is no L3 cache. */
+ int count = ((threads_l2 > 0 && level == 3)
+ | ((threads_l3 > 0
+ || (threads_l2 > 0 && level == 2)) << 1));
+
+ while (count)
+ {
+ __cpuid_count (11, i++, eax, ebx, ecx, edx);
+
+ int shipped = ebx & 0xff;
+ int type = ecx & 0xff00;
+ if (shipped == 0 || type == 0)
+ break;
+ else if (type == 0x100)
+ {
+ /* Count SMT. */
+ if ((count & 0x1))
+ {
+ int count_mask;
+
+ /* Compute count mask. */
+ asm ("bsr %1, %0"
+ : "=r" (count_mask) : "g" (threads_l2));
+ count_mask = ~(-1 << (count_mask + 1));
+ threads_l2 = (shipped - 1) & count_mask;
+ count &= ~0x1;
+ }
+ }
+ else if (type == 0x200)
+ {
+ /* Count core. */
+ if ((count & (0x1 << 1)))
+ {
+ int count_mask;
+ int threads_core
+ = (level == 2 ? threads_l2 : threads_l3);
+
+ /* Compute count mask. */
+ asm ("bsr %1, %0"
+ : "=r" (count_mask) : "g" (threads_core));
+ count_mask = ~(-1 << (count_mask + 1));
+ threads_core = (shipped - 1) & count_mask;
+ if (level == 2)
+ threads_l2 = threads_core;
+ else
+ threads_l3 = threads_core;
+ count &= ~(0x1 << 1);
+ }
+ }
+ }
+ }
+ if (threads_l2 > 0)
+ threads_l2 += 1;
+ if (threads_l3 > 0)
+ threads_l3 += 1;
+ if (level == 2)
+ {
+ if (threads_l2)
+ {
+ threads = threads_l2;
+ if (cpu_features->basic.kind == arch_kind_intel
+ && threads > 2
+ && family == 6)
+ switch (model)
+ {
+ case 0x37:
+ case 0x4a:
+ case 0x4d:
+ case 0x5a:
+ case 0x5d:
+ /* Silvermont has L2 cache shared by 2 cores. */
+ threads = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else if (threads_l3)
+ threads = threads_l3;
+ }
+ else
+ {
+intel_bug_no_cache_info:
+ /* Assume that all logical threads share the highest cache
+ level. */
+ threads
+ = ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx
+ >> 16) & 0xff);
+ }
+
+ /* Cap usage of highest cache level to the number of supported
+ threads. */
+ if (shared > 0 && threads > 0)
+ shared /= threads;
+ }
+
+ /* Account for non-inclusive L2 and L3 caches. */
+ if (!inclusive_cache)
+ {
+ if (threads_l2 > 0)
+ core /= threads_l2;
+ shared += core;
+ }
+
+ *shared_ptr = shared;
+ *threads_ptr = threads;
+}
+
+
static void
__attribute__((constructor))
init_cacheinfo (void)
@@ -494,211 +766,25 @@ init_cacheinfo (void)
int max_cpuid_ex;
long int data = -1;
long int shared = -1;
- unsigned int level;
+ long int core;
unsigned int threads = 0;
const struct cpu_features *cpu_features = __get_cpu_features ();
- int max_cpuid = cpu_features->basic.max_cpuid;
if (cpu_features->basic.kind == arch_kind_intel)
{
data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features);
-
- long int core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features);
- bool inclusive_cache = true;
-
- /* Try L3 first. */
- level = 3;
+ core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features);
shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features);
- /* Number of logical processors sharing L2 cache. */
- int threads_l2;
-
- /* Number of logical processors sharing L3 cache. */
- int threads_l3;
-
- if (shared <= 0)
- {
- /* Try L2 otherwise. */
- level = 2;
- shared = core;
- threads_l2 = 0;
- threads_l3 = -1;
- }
- else
- {
- threads_l2 = 0;
- threads_l3 = 0;
- }
-
- /* A value of 0 for the HTT bit indicates there is only a single
- logical processor. */
- if (HAS_CPU_FEATURE (HTT))
- {
- /* Figure out the number of logical threads that share the
- highest cache level. */
- if (max_cpuid >= 4)
- {
- unsigned int family = cpu_features->basic.family;
- unsigned int model = cpu_features->basic.model;
-
- int i = 0;
-
- /* Query until cache level 2 and 3 are enumerated. */
- int check = 0x1 | (threads_l3 == 0) << 1;
- do
- {
- __cpuid_count (4, i++, eax, ebx, ecx, edx);
-
- /* There seems to be a bug in at least some Pentium Ds
- which sometimes fail to iterate all cache parameters.
- Do not loop indefinitely here, stop in this case and
- assume there is no such information. */
- if ((eax & 0x1f) == 0)
- goto intel_bug_no_cache_info;
-
- switch ((eax >> 5) & 0x7)
- {
- default:
- break;
- case 2:
- if ((check & 0x1))
- {
- /* Get maximum number of logical processors
- sharing L2 cache. */
- threads_l2 = (eax >> 14) & 0x3ff;
- check &= ~0x1;
- }
- break;
- case 3:
- if ((check & (0x1 << 1)))
- {
- /* Get maximum number of logical processors
- sharing L3 cache. */
- threads_l3 = (eax >> 14) & 0x3ff;
-
- /* Check if L2 and L3 caches are inclusive. */
- inclusive_cache = (edx & 0x2) != 0;
- check &= ~(0x1 << 1);
- }
- break;
- }
- }
- while (check);
-
- /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum
- numbers of addressable IDs for logical processors sharing
- the cache, instead of the maximum number of threads
- sharing the cache. */
- if (max_cpuid >= 11)
- {
- /* Find the number of logical processors shipped in
- one core and apply count mask. */
- i = 0;
-
- /* Count SMT only if there is L3 cache. Always count
- core if there is no L3 cache. */
- int count = ((threads_l2 > 0 && level == 3)
- | ((threads_l3 > 0
- || (threads_l2 > 0 && level == 2)) << 1));
-
- while (count)
- {
- __cpuid_count (11, i++, eax, ebx, ecx, edx);
-
- int shipped = ebx & 0xff;
- int type = ecx & 0xff00;
- if (shipped == 0 || type == 0)
- break;
- else if (type == 0x100)
- {
- /* Count SMT. */
- if ((count & 0x1))
- {
- int count_mask;
-
- /* Compute count mask. */
- asm ("bsr %1, %0"
- : "=r" (count_mask) : "g" (threads_l2));
- count_mask = ~(-1 << (count_mask + 1));
- threads_l2 = (shipped - 1) & count_mask;
- count &= ~0x1;
- }
- }
- else if (type == 0x200)
- {
- /* Count core. */
- if ((count & (0x1 << 1)))
- {
- int count_mask;
- int threads_core
- = (level == 2 ? threads_l2 : threads_l3);
-
- /* Compute count mask. */
- asm ("bsr %1, %0"
- : "=r" (count_mask) : "g" (threads_core));
- count_mask = ~(-1 << (count_mask + 1));
- threads_core = (shipped - 1) & count_mask;
- if (level == 2)
- threads_l2 = threads_core;
- else
- threads_l3 = threads_core;
- count &= ~(0x1 << 1);
- }
- }
- }
- }
- if (threads_l2 > 0)
- threads_l2 += 1;
- if (threads_l3 > 0)
- threads_l3 += 1;
- if (level == 2)
- {
- if (threads_l2)
- {
- threads = threads_l2;
- if (threads > 2 && family == 6)
- switch (model)
- {
- case 0x37:
- case 0x4a:
- case 0x4d:
- case 0x5a:
- case 0x5d:
- /* Silvermont has L2 cache shared by 2 cores. */
- threads = 2;
- break;
- default:
- break;
- }
- }
- }
- else if (threads_l3)
- threads = threads_l3;
- }
- else
- {
-intel_bug_no_cache_info:
- /* Assume that all logical threads share the highest cache
- level. */
-
- threads
- = ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx
- >> 16) & 0xff);
- }
-
- /* Cap usage of highest cache level to the number of supported
- threads. */
- if (shared > 0 && threads > 0)
- shared /= threads;
- }
+ get_common_cache_info (&shared, &threads, core);
+ }
+ else if (cpu_features->basic.kind == arch_kind_zhaoxin)
+ {
+ data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE);
+ core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE);
+ shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE);
- /* Account for non-inclusive L2 and L3 caches. */
- if (!inclusive_cache)
- {
- if (threads_l2 > 0)
- core /= threads_l2;
- shared += core;
- }
+ get_common_cache_info (&shared, &threads, core);
}
else if (cpu_features->basic.kind == arch_kind_amd)
{

View File

@ -0,0 +1,136 @@
commit 033362cfd7e0e1dccd6c9a2642710d6e3a7e7007
Author: Carlos O'Donell <carlos@redhat.com>
Date: Thu Jan 23 09:45:00 2020 -0500
test-container: Support $(complocaledir) and mkdirp.
Expand the support infrastructure:
- Create $(complocaledir) in the testroot.pristine to support localedef.
- Add the variable $complocaledir to script support.
- Add the script command 'mkdirp'.
All localedef tests which run with default paths need to have the
$(complocaledir) created in testroot.pristine. The localedef binary
will not by itself create the default path, but it will write into
the path. By adding this we can simplify the localedef tests.
The variable $complocaledir is the value of the configured
$(complocaledir) which is the location of the compiled locales that
will be searched by the runtime by default.
The command mkdirp will be available in script setup and will
be equivalent to running `mkdir -p`.
The variable and command can be used to write more complex tests.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/Makefile b/Makefile
index ae44b9cdd29fb0e3..3748d6f7cfb6223b 100644
--- a/Makefile
+++ b/Makefile
@@ -371,6 +371,9 @@ $(objpfx)testroot.pristine/install.stamp :
# We need a working /bin/sh for some of the tests.
test -d $(objpfx)testroot.pristine/bin || \
mkdir $(objpfx)testroot.pristine/bin
+ # We need the compiled locale dir for localedef tests.
+ test -d $(objpfx)testroot.pristine/$(complocaledir) || \
+ mkdir -p $(objpfx)testroot.pristine/$(complocaledir)
cp $(objpfx)support/shell-container $(objpfx)testroot.pristine/bin/sh
cp $(objpfx)support/echo-container $(objpfx)testroot.pristine/bin/echo
cp $(objpfx)support/true-container $(objpfx)testroot.pristine/bin/true
diff --git a/support/test-container.c b/support/test-container.c
index 9eff8baeef0e9d8a..9fcc91e478038232 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -72,6 +72,10 @@ int verbose = 0;
* mkdir $buildroot/testroot.pristine/
* install into it
+ * default glibc install
+ * create /bin for /bin/sh
+ * create $(complocaledir) so localedef tests work with default paths.
+ * install /bin/sh, /bin/echo, and /bin/true.
* rsync to $buildroot/testroot.root/
"Per-test" actions:
@@ -97,9 +101,23 @@ int verbose = 0;
rm FILE
cwd PATH
exec FILE
- FILE must start with $B/, $S/, $I/, $L/, or /
- (expands to build dir, source dir, install dir, library dir
- (in container), or container's root)
+ mkdirp MODE DIR
+
+ variables:
+ $B/ build dir, equivalent to $(common-objpfx)
+ $S/ source dir, equivalent to $(srcdir)
+ $I/ install dir, equivalent to $(prefix)
+ $L/ library dir (in container), equivalent to $(libdir)
+ $complocaledir/ compiled locale dir, equivalent to $(complocaledir)
+ / container's root
+
+ If FILE begins with any of these variables then they will be
+ substituted for the described value.
+
+ The goal is to expose as many of the runtime's configured paths
+ via variables so they can be used to setup the container environment
+ before execution reaches the test.
+
details:
- '#': A comment.
- 'su': Enables running test as root in the container.
@@ -108,6 +126,8 @@ int verbose = 0;
- 'rm': A minimal remove files command.
- 'cwd': set test working directory
- 'exec': change test binary location (may end in /)
+ - 'mkdirp': A minimal "mkdir -p FILE" command.
+
* mytest.root/postclean.req causes fresh rsync (with delete) after
test if present
@@ -859,6 +879,7 @@ main (int argc, char **argv)
int nt = tokenize (the_line, the_words, 3);
int i;
+ /* Expand variables. */
for (i = 1; i < nt; ++i)
{
if (memcmp (the_words[i], "$B/", 3) == 0)
@@ -875,6 +896,10 @@ main (int argc, char **argv)
the_words[i] = concat (new_root_path,
support_libdir_prefix,
the_words[i] + 2, NULL);
+ else if (memcmp (the_words[i], "$complocaledir/", 15) == 0)
+ the_words[i] = concat (new_root_path,
+ support_complocaledir_prefix,
+ the_words[i] + 14, NULL);
/* "exec" and "cwd" use inside-root paths. */
else if (strcmp (the_words[0], "exec") != 0
&& strcmp (the_words[0], "cwd") != 0
@@ -892,6 +917,9 @@ main (int argc, char **argv)
the_words[2] = concat (the_words[2], the_words[1], NULL);
}
+ /* Run the following commands in the_words[0] with NT number of
+ arguments (including the command). */
+
if (nt == 2 && strcmp (the_words[0], "so") == 0)
{
the_words[2] = concat (new_root_path, support_libdir_prefix,
@@ -961,6 +989,14 @@ main (int argc, char **argv)
{
be_su = 1;
}
+ else if (nt == 3 && strcmp (the_words[0], "mkdirp") == 0)
+ {
+ long int m;
+ errno = 0;
+ m = strtol (the_words[1], NULL, 0);
+ TEST_COMPARE (errno, 0);
+ xmkdirp (the_words[2], m);
+ }
else if (nt > 0 && the_words[0][0] != '#')
{
fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]);

View File

@ -0,0 +1,45 @@
commit 183083c35972611e7786c7ee0c96d7da571631ed
Author: Carlos O'Donell <carlos@redhat.com>
Date: Wed Apr 29 16:31:29 2020 -0400
support: Set errno before testing it.
In test-conainer we should set errno to 0 before calling strtol,
and check after with TEST_COMPARE.
In tst-support_capture_subprocess we should set errno to 0 before
checking it after the call to strtol.
Tested on x86_64.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/support/test-container.c b/support/test-container.c
index 9fcc91e478038232..d7ed073812305f71 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -940,7 +940,9 @@ main (int argc, char **argv)
else if (nt == 3 && strcmp (the_words[0], "chmod") == 0)
{
long int m;
+ errno = 0;
m = strtol (the_words[1], NULL, 0);
+ TEST_COMPARE (errno, 0);
if (chmod (the_words[2], m) < 0)
FAIL_EXIT1 ("chmod %s: %s\n",
the_words[2], strerror (errno));
diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
index 99570879eedd65b1..fe6649dda6032de2 100644
--- a/support/tst-support_capture_subprocess.c
+++ b/support/tst-support_capture_subprocess.c
@@ -133,7 +133,9 @@ static int
parse_int (const char *str)
{
char *endptr;
- long int ret = strtol (str, &endptr, 10);
+ long int ret;
+ errno = 0;
+ ret = strtol (str, &endptr, 10);
TEST_COMPARE (errno, 0);
TEST_VERIFY (ret >= 0 && ret <= INT_MAX);
return ret;

View File

@ -0,0 +1,30 @@
commit cad64f778aced84efdaa04ae64f8737b86f063ab
Author: Josh Triplett <josh@joshtriplett.org>
Date: Tue May 19 14:41:48 2020 +0200
ldconfig: Default to the new format for ld.so.cache
glibc has supported this format for close to 20 years.
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 5e6516688a1c192a..f31e10817dd5d665 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -97,7 +97,7 @@ int opt_verbose;
/* Format to support. */
/* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */
-int opt_format = 1;
+int opt_format = 2;
/* Build cache. */
static int opt_build_cache = 1;
@@ -150,7 +150,7 @@ static const struct argp_option options[] =
{ NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0},
{ NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
{ NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
- { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new, old or compat (default)"), 0},
+ { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new (default), old, or compat"), 0},
{ "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
{ NULL, 0, NULL, 0, NULL, 0 }
};

View File

@ -0,0 +1,59 @@
commit 76d5b2f002a1243ddba06bd646249553353f4322
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu May 21 13:36:54 2020 -0700
x86: Update Intel Atom processor family optimization
Enable Intel Silvermont optimization for Intel Goldmont Plus. Detect more
Intel Airmont processors. Optimize Intel Tremont like Intel Silvermont
with rep string instructions.
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index c432d646ce6806a6..2a801e1856cfe1b3 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -347,18 +347,23 @@ init_cpu_features (struct cpu_features *cpu_features)
case 0x57:
/* Knights Landing. Enable Silvermont optimizations. */
+ case 0x7a:
+ /* Unaligned load versions are faster than SSSE3
+ on Goldmont Plus. */
+
case 0x5c:
case 0x5f:
/* Unaligned load versions are faster than SSSE3
on Goldmont. */
case 0x4c:
+ case 0x5a:
+ case 0x75:
/* Airmont is a die shrink of Silvermont. */
case 0x37:
case 0x4a:
case 0x4d:
- case 0x5a:
case 0x5d:
/* Unaligned load versions are faster than SSSE3
on Silvermont. */
@@ -369,6 +374,19 @@ init_cpu_features (struct cpu_features *cpu_features)
| bit_arch_Slow_SSE4_2);
break;
+ case 0x86:
+ case 0x96:
+ case 0x9c:
+ /* Enable rep string instructions, unaligned load, unaligned
+ copy, pminub and avoid SSE 4.2 on Tremont. */
+ cpu_features->feature[index_arch_Fast_Rep_String]
+ |= (bit_arch_Fast_Rep_String
+ | bit_arch_Fast_Unaligned_Load
+ | bit_arch_Fast_Unaligned_Copy
+ | bit_arch_Prefer_PMINUB_for_stringop
+ | bit_arch_Slow_SSE4_2);
+ break;
+
default:
/* Unknown family 0x06 processors. Assuming this is one
of Core i3/i5/i7 processors if AVX is available. */

View File

@ -0,0 +1,148 @@
commit dcbc6b83eff5b9238170bdfed834ba934150895f
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu May 28 10:20:56 2020 +0200
elf: Do not read hwcaps from the vDSO in ld.so
This was only ever used for the "nosegneg" flag. This approach for
passing hardware capability information creates a subtle dependency
between the kernel and userspace, and ld.so.cache contents. It seems
inappropriate for toady, where people expect to be able to run
system images which very different kernel versions.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
index ecf00b457760e517..ae2e4ca7fe91d407 100644
--- a/elf/dl-hwcaps.c
+++ b/elf/dl-hwcaps.c
@@ -26,12 +26,6 @@
#include <dl-procinfo.h>
#include <dl-hwcaps.h>
-#ifdef _DL_FIRST_PLATFORM
-# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
-#else
-# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
-#endif
-
/* Return an array of useful/necessary hardware capability names. */
const struct r_strlenpair *
_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
@@ -52,116 +46,12 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
if ((masked & (1ULL << n)) != 0)
++cnt;
-#ifdef NEED_DL_SYSINFO_DSO
- /* 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);
- /* NB: Some PT_NOTE segment may have alignment value of 0
- or 1. gABI specifies that PT_NOTE segments should be
- aligned to 4 bytes in 32-bit objects and to 8 bytes in
- 64-bit objects. As a Linux extension, we also support
- 4 byte alignment in 64-bit objects. If p_align is less
- than 4, we treate alignment as 4 bytes since some note
- segments have 0 or 1 byte alignment. */
- ElfW(Addr) align = phdr[i].p_align;
- if (align < 4)
- align = 4;
- else if (align != 4 && align != 8)
- continue;
- /* The standard ELF note layout is exactly as the anonymous struct.
- The next element is a variable length vendor name of length
- VENDORLEN (with a real length rounded to ElfW(Word)), followed
- by the data of length DATALEN (with a real length rounded to
- ElfW(Word)). */
- 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)
- {
- /* The layout of the type 2, vendor "GNU" note is as follows:
- .long <Number of capabilities enabled by this note>
- .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA).
- .byte <The bit number for the next capability>
- .asciz <The name of the capability>. */
- if (note->type == NT_GNU_HWCAP
- && note->vendorlen == sizeof "GNU"
- && !memcmp ((note + 1), "GNU", sizeof "GNU")
- && note->datalen > 2 * sizeof (ElfW(Word)) + 2)
- {
- const ElfW(Word) *p
- = ((const void *) note
- + ELF_NOTE_DESC_OFFSET (sizeof "GNU", align));
- cnt += *p++;
- ++p; /* Skip mask word. */
- dsocaps = (const char *) p; /* Pseudo-string "<b>name" */
- dsocapslen = note->datalen - sizeof *p * 2;
- break;
- }
- note = ((const void *) note
- + ELF_NOTE_NEXT_OFFSET (note->vendorlen,
- note->datalen, align));
- }
- if (dsocaps != NULL)
- break;
- }
- }
-#endif
-
/* For TLS enabled builds always add 'tls'. */
++cnt;
/* Create temporary data structure to generate result table. */
struct r_strlenpair temp[cnt];
m = 0;
-#ifdef NEED_DL_SYSINFO_DSO
- if (dsocaps != NULL)
- {
- /* dsocaps points to the .asciz string, and -1 points to the mask
- .long just before the string. */
- const ElfW(Word) mask = ((const ElfW(Word) *) dsocaps)[-1];
- GLRO(dl_hwcap) |= (uint64_t) mask << _DL_FIRST_EXTRA;
- /* Note that we add the dsocaps to the set already chosen by the
- LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT).
- So there is no way to request ignoring an OS-supplied dsocap
- string and bit like you can ignore an OS-supplied HWCAP bit. */
- hwcap_mask |= (uint64_t) mask << _DL_FIRST_EXTRA;
-#if HAVE_TUNABLES
- TUNABLE_SET (glibc, cpu, hwcap_mask, uint64_t, hwcap_mask);
-#else
- GLRO(dl_hwcap_mask) = hwcap_mask;
-#endif
- size_t len;
- for (const char *p = dsocaps; p < dsocaps + dsocapslen; p += len + 1)
- {
- uint_fast8_t bit = *p++;
- len = strlen (p);
-
- /* Skip entries that are not enabled in the mask word. */
- if (__glibc_likely (mask & ((ElfW(Word)) 1 << bit)))
- {
- temp[m].str = p;
- temp[m].len = len;
- ++m;
- }
- else
- --cnt;
- }
- }
-#endif
for (n = 0; masked != 0; ++n)
if ((masked & (1ULL << n)) != 0)
{

View File

@ -0,0 +1,53 @@
commit d330f31af68f96dde82840d1e9343b479a8c179e
Author: Carlos O'Donell <carlos@redhat.com>
Date: Thu Aug 30 11:01:33 2018 -0400
Fix test failure with -DNDEBUG.
The elf/tst-dlopen-aout.c test uses asserts to verify properties of the
test execution. Instead of using assert it should use xpthread_create
and xpthread_join to catch errors starting the threads and fail the
test. This shows up in Fedora 28 when building for i686-pc-linux-gnu
and using gcc 8.1.1.
Tested on i686, and fixes a check failure with -DNDEBUG.
Signed-off-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/tst-dlopen-aout.c b/elf/tst-dlopen-aout.c
index 9038e2096add8798..b0264515cfe62276 100644
--- a/elf/tst-dlopen-aout.c
+++ b/elf/tst-dlopen-aout.c
@@ -27,6 +27,7 @@
#include <dlfcn.h>
#include <stdio.h>
#include <pthread.h>
+#include <support/xthread.h>
__thread int x;
@@ -45,7 +46,6 @@ do_test (int argc, char *argv[])
{
pthread_t thr;
void *p;
- int rc;
p = dlopen (argv[0], RTLD_LAZY);
if (p != NULL)
@@ -53,11 +53,11 @@ do_test (int argc, char *argv[])
fprintf (stderr, "dlopen unexpectedly succeeded\n");
return 1;
}
- rc = pthread_create (&thr, NULL, fn, NULL);
- assert (rc == 0);
-
- rc = pthread_join (thr, NULL);
- assert (rc == 0);
+ /* We create threads to force TLS allocation, which triggers
+ the original bug i.e. running out of surplus slotinfo entries
+ for TLS. */
+ thr = xpthread_create (NULL, fn, NULL);
+ xpthread_join (thr);
}
return 0;

View File

@ -0,0 +1,151 @@
commit 31563b68410ff8e9490c5aafca31ec71b38f87a5
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu May 28 10:21:17 2020 +0200
elf: Remove extra hwcap mechanism from ldconfig
Historically, this mechanism was used to process "nosegneg"
subdirectories, and it is still used to include the "tls"
subdirectories. With nosegneg support gone from ld.so, this is part
no longer useful.
The entire mechanism is not well-designed because it causes the
meaning of hwcap bits in ld.so.cache to depend on the kernel version
that was used to generate the cache, which makes it difficult to use
this mechanism for anything else in the future.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index f31e10817dd5d665..7c8fd29387463a8a 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -44,11 +44,15 @@
#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
+/* This subpath in search path entries is always supported and
+ included in the cache for backwards compatibility. */
+#define TLS_SUBPATH "tls"
+
+/* The MSB of the hwcap field is set for objects in TLS_SUBPATH
+ directories. There is always TLS support in glibc, so the dynamic
+ loader does not check the bit directly. But more hwcap bits make a
+ an object more preferred, so the bit still has meaning. */
+#define TLS_HWCAP_BIT 63
#ifndef LD_SO_CONF
# define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
@@ -127,9 +131,6 @@ static const char *config_file;
/* Mask to use for important hardware capabilities. */
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. */
static void print_version (FILE *stream, struct argp_state *state);
void (*argp_program_version_hook) (FILE *, struct argp_state *)
@@ -186,12 +187,9 @@ is_hwcap_platform (const char *name)
if (hwcap_idx != -1)
return 1;
- /* Is this one of the extra pseudo-hwcaps that we map beyond
- _DL_FIRST_EXTRA like "tls", or "nosegneg?" */
- for (hwcap_idx = _DL_FIRST_EXTRA; hwcap_idx < 64; ++hwcap_idx)
- if (hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA] != NULL
- && !strcmp (name, hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA]))
- return 1;
+ /* Backwards-compatibility for the "tls" subdirectory. */
+ if (strcmp (name, TLS_SUBPATH) == 0)
+ return 1;
return 0;
}
@@ -226,11 +224,9 @@ path_hwcap (const char *path)
h = _dl_string_platform (ptr + 1);
if (h == (uint64_t) -1)
{
- for (h = _DL_FIRST_EXTRA; h < 64; ++h)
- if (hwcap_extra[h - _DL_FIRST_EXTRA] != NULL
- && !strcmp (ptr + 1, hwcap_extra[h - _DL_FIRST_EXTRA]))
- break;
- if (h == 64)
+ if (strcmp (ptr + 1, TLS_SUBPATH) == 0)
+ h = TLS_HWCAP_BIT;
+ else
break;
}
}
@@ -1145,52 +1141,7 @@ Warning: ignoring configuration file that cannot be opened: %s"),
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);
- }
- }
+ error (0, 0, _("%s:%u: hwcap directive ignored"), filename, lineno);
else
add_dir_1 (cp, filename, lineno);
}
@@ -1303,12 +1254,6 @@ main (int argc, char **argv)
add_dir_1 (argv[i], "<cmdline>", 0);
}
- /* The last entry in hwcap_extra is reserved for the "tls" pseudo-hwcap which
- indicates support for TLS. This pseudo-hwcap is only used by old versions
- under which TLS support was optional. The entry is no longer needed, but
- must remain for compatibility. */
- hwcap_extra[63 - _DL_FIRST_EXTRA] = "tls";
-
set_hwcap ();
if (opt_chroot)

View File

@ -0,0 +1,21 @@
commit 9e2dc874e62b0950891b319c000b009ea12ac8c2
Author: Girish Joshi <girish946@gmail.com>
Date: Fri May 29 10:11:24 2020 -0300
build: Use FAIL_EXIT1 () on failure to exec child [BZ #23990]
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/support/test-container.c b/support/test-container.c
index d7ed073812305f71..9975c8cb7bc9a955 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -392,7 +392,7 @@ recursive_remove (char *path)
/* "rm" would have already printed a suitable error message. */
if (! WIFEXITED (status)
|| WEXITSTATUS (status) != 0)
- exit (1);
+ FAIL_EXIT1 ("exec child returned status: %d", status);
break;
}

View File

@ -0,0 +1,67 @@
commit 533dd2acf7eefa969fb770fa782b20519bd4bc0f
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Tue Jun 9 12:15:01 2020 -0700
Add "%d" support to _dl_debug_vdprintf
"%d" will be used to print out signed value.
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index 2eb81eeb0231368d..3f28de3ee9d68368 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -167,6 +167,7 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
switch (*fmt)
{
/* Integer formatting. */
+ case 'd':
case 'u':
case 'x':
{
@@ -179,11 +180,34 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
#else
unsigned long int num = va_arg (arg, unsigned int);
#endif
+ bool negative = false;
+ if (*fmt == 'd')
+ {
+#if LONG_MAX != INT_MAX
+ if (long_mod)
+ {
+ if ((long int) num < 0)
+ negative = true;
+ }
+ else
+ {
+ if ((int) num < 0)
+ {
+ num = (unsigned int) num;
+ negative = true;
+ }
+ }
+#else
+ if ((int) num < 0)
+ negative = true;
+#endif
+ }
+
/* We use alloca() to allocate the buffer with the most
pessimistic guess for the size. Using alloca() allows
having more than one integer formatting in a call. */
- char *buf = (char *) alloca (3 * sizeof (unsigned long int));
- char *endp = &buf[3 * sizeof (unsigned long int)];
+ char *buf = (char *) alloca (1 + 3 * sizeof (unsigned long int));
+ char *endp = &buf[1 + 3 * sizeof (unsigned long int)];
char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
/* Pad to the width the user specified. */
@@ -191,6 +215,9 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
while (endp - cp < width)
*--cp = fill;
+ if (negative)
+ *--cp = '-';
+
iov[niov].iov_base = cp;
iov[niov].iov_len = endp - cp;
++niov;

View File

@ -0,0 +1,62 @@
commit e221c512c74ec42fd47b71de2981a475b38110a4
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jun 15 09:50:14 2020 +0200
ld.so: Check for new cache format first and enhance corruption check
Now that ldconfig defaults to the new format (only), check for it
first. Also apply the corruption check added in commit 2954daf00bb4d
("Add more checks for valid ld.so.cache file (bug 18093)") to the
new-format-only case.
Suggested-by: Josh Triplett <josh@joshtriplett.org>
diff --git a/elf/dl-cache.c b/elf/dl-cache.c
index 6dd99a35b9f97cfb..ef37ca18fa9fb6e0 100644
--- a/elf/dl-cache.c
+++ b/elf/dl-cache.c
@@ -199,15 +199,25 @@ _dl_load_cache_lookup (const char *name)
PROT_READ);
/* We can handle three different cache file formats here:
+ - only the new format
- the old libc5/glibc2.0/2.1 format
- the old format with the new format in it
- - only the new format
The following checks if the cache contains any of these formats. */
- if (file != MAP_FAILED && cachesize > sizeof *cache
- && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0
+ if (file != MAP_FAILED && cachesize > sizeof *cache_new
+ && memcmp (file, CACHEMAGIC_VERSION_NEW,
+ sizeof CACHEMAGIC_VERSION_NEW - 1) == 0
/* Check for corruption, avoiding overflow. */
- && ((cachesize - sizeof *cache) / sizeof (struct file_entry)
- >= ((struct cache_file *) file)->nlibs))
+ && ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new)
+ >= ((struct cache_file_new *) file)->nlibs))
+ {
+ cache_new = file;
+ cache = file;
+ }
+ else if (file != MAP_FAILED && cachesize > sizeof *cache
+ && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0
+ /* Check for corruption, avoiding overflow. */
+ && ((cachesize - sizeof *cache) / sizeof (struct file_entry)
+ >= ((struct cache_file *) file)->nlibs))
{
size_t offset;
/* Looks ok. */
@@ -223,13 +233,6 @@ _dl_load_cache_lookup (const char *name)
sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
cache_new = (void *) -1;
}
- else if (file != MAP_FAILED && cachesize > sizeof *cache_new
- && memcmp (file, CACHEMAGIC_VERSION_NEW,
- sizeof CACHEMAGIC_VERSION_NEW - 1) == 0)
- {
- cache_new = file;
- cache = file;
- }
else
{
if (file != MAP_FAILED)

Some files were not shown because too many files have changed in this diff Show More