1 /* Hardware capability support for run-time dynamic loader.
2 Copyright (C) 2012-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
26 #include <dl-procinfo.h>
27 #include <dl-hwcaps.h>
29 #ifdef _DL_FIRST_PLATFORM
30 # define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
32 # define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
35 /* Return an array of useful/necessary hardware capability names. */
36 const struct r_strlenpair
*
37 _dl_important_hwcaps (const char *platform
, size_t platform_len
, size_t *sz
,
38 size_t *max_capstrlen
)
40 uint64_t hwcap_mask
= GET_HWCAP_MASK();
41 /* Determine how many important bits are set. */
42 uint64_t masked
= GLRO(dl_hwcap
) & hwcap_mask
;
43 size_t cnt
= platform
!= NULL
;
46 struct r_strlenpair
*result
;
47 struct r_strlenpair
*rp
;
50 /* Count the number of bits set in the masked value. */
51 for (n
= 0; (~((1ULL << n
) - 1) & masked
) != 0; ++n
)
52 if ((masked
& (1ULL << n
)) != 0)
55 #ifdef NEED_DL_SYSINFO_DSO
56 /* The system-supplied DSO can contain a note of type 2, vendor "GNU".
57 This gives us a list of names to treat as fake hwcap bits. */
59 const char *dsocaps
= NULL
;
60 size_t dsocapslen
= 0;
61 if (GLRO(dl_sysinfo_map
) != NULL
)
63 const ElfW(Phdr
) *const phdr
= GLRO(dl_sysinfo_map
)->l_phdr
;
64 const ElfW(Word
) phnum
= GLRO(dl_sysinfo_map
)->l_phnum
;
65 for (uint_fast16_t i
= 0; i
< phnum
; ++i
)
66 if (phdr
[i
].p_type
== PT_NOTE
)
68 const ElfW(Addr
) start
= (phdr
[i
].p_vaddr
69 + GLRO(dl_sysinfo_map
)->l_addr
);
70 /* NB: Some PT_NOTE segment may have alignment value of 0
71 or 1. gABI specifies that PT_NOTE segments should be
72 aligned to 4 bytes in 32-bit objects and to 8 bytes in
73 64-bit objects. As a Linux extension, we also support
74 4 byte alignment in 64-bit objects. If p_align is less
75 than 4, we treate alignment as 4 bytes since some note
76 segments have 0 or 1 byte alignment. */
77 ElfW(Addr
) align
= phdr
[i
].p_align
;
80 else if (align
!= 4 && align
!= 8)
82 /* The standard ELF note layout is exactly as the anonymous struct.
83 The next element is a variable length vendor name of length
84 VENDORLEN (with a real length rounded to ElfW(Word)), followed
85 by the data of length DATALEN (with a real length rounded to
92 } *note
= (const void *) start
;
93 while ((ElfW(Addr
)) (note
+ 1) - start
< phdr
[i
].p_memsz
)
95 /* The layout of the type 2, vendor "GNU" note is as follows:
96 .long <Number of capabilities enabled by this note>
97 .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA).
98 .byte <The bit number for the next capability>
99 .asciz <The name of the capability>. */
100 if (note
->type
== NT_GNU_HWCAP
101 && note
->vendorlen
== sizeof "GNU"
102 && !memcmp ((note
+ 1), "GNU", sizeof "GNU")
103 && note
->datalen
> 2 * sizeof (ElfW(Word
)) + 2)
106 = ((const void *) note
107 + ELF_NOTE_DESC_OFFSET (sizeof "GNU", align
));
109 ++p
; /* Skip mask word. */
110 dsocaps
= (const char *) p
; /* Pseudo-string "<b>name" */
111 dsocapslen
= note
->datalen
- sizeof *p
* 2;
114 note
= ((const void *) note
115 + ELF_NOTE_NEXT_OFFSET (note
->vendorlen
,
116 note
->datalen
, align
));
124 /* For TLS enabled builds always add 'tls'. */
127 /* Create temporary data structure to generate result table. */
128 struct r_strlenpair temp
[cnt
];
130 #ifdef NEED_DL_SYSINFO_DSO
133 /* dsocaps points to the .asciz string, and -1 points to the mask
134 .long just before the string. */
135 const ElfW(Word
) mask
= ((const ElfW(Word
) *) dsocaps
)[-1];
136 GLRO(dl_hwcap
) |= (uint64_t) mask
<< _DL_FIRST_EXTRA
;
137 /* Note that we add the dsocaps to the set already chosen by the
138 LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT).
139 So there is no way to request ignoring an OS-supplied dsocap
140 string and bit like you can ignore an OS-supplied HWCAP bit. */
141 hwcap_mask
|= (uint64_t) mask
<< _DL_FIRST_EXTRA
;
143 TUNABLE_SET (glibc
, tune
, hwcap_mask
, uint64_t, hwcap_mask
);
145 GLRO(dl_hwcap_mask
) = hwcap_mask
;
148 for (const char *p
= dsocaps
; p
< dsocaps
+ dsocapslen
; p
+= len
+ 1)
150 uint_fast8_t bit
= *p
++;
153 /* Skip entries that are not enabled in the mask word. */
154 if (__glibc_likely (mask
& ((ElfW(Word
)) 1 << bit
)))
165 for (n
= 0; masked
!= 0; ++n
)
166 if ((masked
& (1ULL << n
)) != 0)
168 temp
[m
].str
= _dl_hwcap_string (n
);
169 temp
[m
].len
= strlen (temp
[m
].str
);
173 if (platform
!= NULL
)
175 temp
[m
].str
= platform
;
176 temp
[m
].len
= platform_len
;
186 /* Determine the total size of all strings together. */
188 total
= temp
[0].len
+ 1;
191 total
= temp
[0].len
+ temp
[cnt
- 1].len
+ 2;
195 for (n
= 1; n
+ 1 < cnt
; ++n
)
196 total
+= temp
[n
].len
+ 1;
198 && (cnt
>= sizeof (size_t) * 8
199 || total
+ (sizeof (*result
) << 3)
200 >= (1UL << (sizeof (size_t) * 8 - cnt
+ 3))))
201 _dl_signal_error (ENOMEM
, NULL
, NULL
,
202 N_("cannot create capability list"));
208 /* The result structure: we use a very compressed way to store the
209 various combinations of capability names. */
211 result
= (struct r_strlenpair
*) malloc (*sz
* sizeof (*result
) + total
);
213 _dl_signal_error (ENOMEM
, NULL
, NULL
,
214 N_("cannot create capability list"));
218 result
[0].str
= (char *) (result
+ *sz
);
219 result
[0].len
= temp
[0].len
+ 1;
220 result
[1].str
= (char *) (result
+ *sz
);
222 cp
= __mempcpy ((char *) (result
+ *sz
), temp
[0].str
, temp
[0].len
);
225 *max_capstrlen
= result
[0].len
;
230 /* Fill in the information. This follows the following scheme
231 (indices from TEMP for four strings):
232 entry #0: 0, 1, 2, 3 binary: 1111
236 This allows the representation of all possible combinations of
237 capability names in the string. First generate the strings. */
238 result
[1].str
= result
[0].str
= cp
= (char *) (result
+ *sz
);
240 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
253 /* We always add the last string. */
256 /* Add the strings which have the bit set in N. */
257 for (m
= cnt
- 2; m
> 0; --m
)
258 if ((n
& (1 << m
)) != 0)
261 /* Always add the first string. */
268 /* Now we are ready to install the string pointers and length. */
269 for (n
= 0; n
< (1UL << cnt
); ++n
)
274 size_t mask
= 1 << --n
;
277 for (m
= 1 << cnt
; m
> 0; ++rp
)
278 if ((--m
& mask
) != 0)
279 rp
->len
+= temp
[n
].len
+ 1;
283 /* The first half of the strings all include the first string. */
286 while (n
!= (1UL << (cnt
- 1)))
289 rp
[0].str
= rp
[-2].str
+ rp
[-2].len
;
291 rp
[0].str
= rp
[-1].str
;
295 /* The second half starts right after the first part of the string of
296 the corresponding entry in the first half. */
299 rp
[0].str
= rp
[-(1 << (cnt
- 1))].str
+ temp
[cnt
- 1].len
+ 1;
304 /* The maximum string length. */
305 *max_capstrlen
= result
[0].len
;