summaryrefslogtreecommitdiff
path: root/sysdeps/generic
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2020-12-04 09:13:43 +0100
committerFlorian Weimer <fweimer@redhat.com>2020-12-04 09:16:41 +0100
commitb44ac4f4c7a8bbe5eaa2701aa9452eaf2c96e1dd (patch)
tree39c5fa6ec9ab24d282c75bb31e15fca0f584e27d /sysdeps/generic
parent73b6e50a22dea9ae6144beaaa675d2ac62c281ca (diff)
downloadglibc-b44ac4f4c7a8bbe5eaa2701aa9452eaf2c96e1dd.tar.gz
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>
Diffstat (limited to 'sysdeps/generic')
-rw-r--r--sysdeps/generic/dl-cache.h50
-rw-r--r--sysdeps/generic/ldconfig.h18
2 files changed, 66 insertions, 2 deletions
diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h
index 393cdc5754..72a66b45ee 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 cfec9d4668..1ad1528890 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);