1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

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>
This commit is contained in:
Florian Weimer
2020-12-04 09:13:43 +01:00
parent 73b6e50a22
commit b44ac4f4c7
4 changed files with 427 additions and 53 deletions

View File

@ -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;
}