diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/dl-hwcaps.c | 14 | ||||
-rw-r--r-- | elf/ldconfig.c | 6 |
2 files changed, 19 insertions, 1 deletions
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c index 8d49383d76..1b7fe52a6a 100644 --- a/elf/dl-hwcaps.c +++ b/elf/dl-hwcaps.c @@ -66,6 +66,11 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, { const ElfW(Addr) start = (phdr[i].p_vaddr + GLRO(dl_sysinfo_map)->l_addr); + /* 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(Addr)), followed + by the data of length DATALEN (with a real length rounded to + ElfW(Addr)). */ const struct { ElfW(Word) vendorlen; @@ -75,6 +80,11 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz) { #define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word))) + /* 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") @@ -84,7 +94,7 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + ROUND (sizeof "GNU")); cnt += *p++; ++p; /* Skip mask word. */ - dsocaps = (const char *) p; + dsocaps = (const char *) p; /* Pseudo-string "<b>name" */ dsocapslen = note->datalen - sizeof *p * 2; break; } @@ -107,6 +117,8 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, #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 diff --git a/elf/ldconfig.c b/elf/ldconfig.c index 57c6a6f04d..340c132a83 100644 --- a/elf/ldconfig.c +++ b/elf/ldconfig.c @@ -173,13 +173,17 @@ is_hwcap_platform (const char *name) { int hwcap_idx = _dl_string_hwcap (name); + /* Is this a normal hwcap for the machine e.g. fpu? */ if (hwcap_idx != -1 && ((1 << hwcap_idx) & hwcap_mask)) return 1; + /* ... Or is it a platform pseudo-hwcap e.g. i686? */ hwcap_idx = _dl_string_platform (name); if (hwcap_idx != -1) return 1; + /* ... Or is this one of the extra pseudo-hwcaps that we map beyond + _DL_FIRST_EXTRA e.g. 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])) @@ -1265,6 +1269,8 @@ main (int argc, char **argv) add_dir (argv[i]); } + /* The last entry in hwcap_extra is reserved for the "tls" + pseudo-hwcap which indicates support for TLS. */ hwcap_extra[63 - _DL_FIRST_EXTRA] = "tls"; set_hwcap (); |