1 /* Hardware capability support for run-time dynamic loader.
2 Copyright (C) 2012-2017 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>
28 #ifdef _DL_FIRST_PLATFORM
29 # define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
31 # define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
34 /* Return an array of useful/necessary hardware capability names. */
35 const struct r_strlenpair
*
37 _dl_important_hwcaps (const char *platform
, size_t platform_len
, size_t *sz
,
38 size_t *max_capstrlen
)
40 /* Determine how many important bits are set. */
41 uint64_t masked
= GLRO(dl_hwcap
) & GLRO(dl_hwcap_mask
);
42 size_t cnt
= platform
!= NULL
;
45 struct r_strlenpair
*result
;
46 struct r_strlenpair
*rp
;
49 /* Count the number of bits set in the masked value. */
50 for (n
= 0; (~((1ULL << n
) - 1) & masked
) != 0; ++n
)
51 if ((masked
& (1ULL << n
)) != 0)
54 #ifdef NEED_DL_SYSINFO_DSO
55 /* The system-supplied DSO can contain a note of type 2, vendor "GNU".
56 This gives us a list of names to treat as fake hwcap bits. */
58 const char *dsocaps
= NULL
;
59 size_t dsocapslen
= 0;
60 if (GLRO(dl_sysinfo_map
) != NULL
)
62 const ElfW(Phdr
) *const phdr
= GLRO(dl_sysinfo_map
)->l_phdr
;
63 const ElfW(Word
) phnum
= GLRO(dl_sysinfo_map
)->l_phnum
;
64 for (uint_fast16_t i
= 0; i
< phnum
; ++i
)
65 if (phdr
[i
].p_type
== PT_NOTE
)
67 const ElfW(Addr
) start
= (phdr
[i
].p_vaddr
68 + GLRO(dl_sysinfo_map
)->l_addr
);
69 /* The standard ELF note layout is exactly as the anonymous struct.
70 The next element is a variable length vendor name of length
71 VENDORLEN (with a real length rounded to ElfW(Word)), followed
72 by the data of length DATALEN (with a real length rounded to
79 } *note
= (const void *) start
;
80 while ((ElfW(Addr
)) (note
+ 1) - start
< phdr
[i
].p_memsz
)
82 #define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
83 /* The layout of the type 2, vendor "GNU" note is as follows:
84 .long <Number of capabilities enabled by this note>
85 .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA).
86 .byte <The bit number for the next capability>
87 .asciz <The name of the capability>. */
88 if (note
->type
== NT_GNU_HWCAP
89 && note
->vendorlen
== sizeof "GNU"
90 && !memcmp ((note
+ 1), "GNU", sizeof "GNU")
91 && note
->datalen
> 2 * sizeof (ElfW(Word
)) + 2)
93 const ElfW(Word
) *p
= ((const void *) (note
+ 1)
94 + ROUND (sizeof "GNU"));
96 ++p
; /* Skip mask word. */
97 dsocaps
= (const char *) p
; /* Pseudo-string "<b>name" */
98 dsocapslen
= note
->datalen
- sizeof *p
* 2;
101 note
= ((const void *) (note
+ 1)
102 + ROUND (note
->vendorlen
) + ROUND (note
->datalen
));
111 /* For TLS enabled builds always add 'tls'. */
114 /* Create temporary data structure to generate result table. */
115 struct r_strlenpair temp
[cnt
];
117 #ifdef NEED_DL_SYSINFO_DSO
120 /* dsocaps points to the .asciz string, and -1 points to the mask
121 .long just before the string. */
122 const ElfW(Word
) mask
= ((const ElfW(Word
) *) dsocaps
)[-1];
123 GLRO(dl_hwcap
) |= (uint64_t) mask
<< _DL_FIRST_EXTRA
;
124 /* Note that we add the dsocaps to the set already chosen by the
125 LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT).
126 So there is no way to request ignoring an OS-supplied dsocap
127 string and bit like you can ignore an OS-supplied HWCAP bit. */
128 GLRO(dl_hwcap_mask
) |= (uint64_t) mask
<< _DL_FIRST_EXTRA
;
130 for (const char *p
= dsocaps
; p
< dsocaps
+ dsocapslen
; p
+= len
+ 1)
132 uint_fast8_t bit
= *p
++;
135 /* Skip entries that are not enabled in the mask word. */
136 if (__glibc_likely (mask
& ((ElfW(Word
)) 1 << bit
)))
147 for (n
= 0; masked
!= 0; ++n
)
148 if ((masked
& (1ULL << n
)) != 0)
150 temp
[m
].str
= _dl_hwcap_string (n
);
151 temp
[m
].len
= strlen (temp
[m
].str
);
155 if (platform
!= NULL
)
157 temp
[m
].str
= platform
;
158 temp
[m
].len
= platform_len
;
168 /* Determine the total size of all strings together. */
170 total
= temp
[0].len
+ 1;
173 total
= temp
[0].len
+ temp
[cnt
- 1].len
+ 2;
177 for (n
= 1; n
+ 1 < cnt
; ++n
)
178 total
+= temp
[n
].len
+ 1;
180 && (cnt
>= sizeof (size_t) * 8
181 || total
+ (sizeof (*result
) << 3)
182 >= (1UL << (sizeof (size_t) * 8 - cnt
+ 3))))
183 _dl_signal_error (ENOMEM
, NULL
, NULL
,
184 N_("cannot create capability list"));
190 /* The result structure: we use a very compressed way to store the
191 various combinations of capability names. */
193 result
= (struct r_strlenpair
*) malloc (*sz
* sizeof (*result
) + total
);
195 _dl_signal_error (ENOMEM
, NULL
, NULL
,
196 N_("cannot create capability list"));
200 result
[0].str
= (char *) (result
+ *sz
);
201 result
[0].len
= temp
[0].len
+ 1;
202 result
[1].str
= (char *) (result
+ *sz
);
204 cp
= __mempcpy ((char *) (result
+ *sz
), temp
[0].str
, temp
[0].len
);
207 *max_capstrlen
= result
[0].len
;
212 /* Fill in the information. This follows the following scheme
213 (indices from TEMP for four strings):
214 entry #0: 0, 1, 2, 3 binary: 1111
218 This allows the representation of all possible combinations of
219 capability names in the string. First generate the strings. */
220 result
[1].str
= result
[0].str
= cp
= (char *) (result
+ *sz
);
222 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
235 /* We always add the last string. */
238 /* Add the strings which have the bit set in N. */
239 for (m
= cnt
- 2; m
> 0; --m
)
240 if ((n
& (1 << m
)) != 0)
243 /* Always add the first string. */
250 /* Now we are ready to install the string pointers and length. */
251 for (n
= 0; n
< (1UL << cnt
); ++n
)
256 size_t mask
= 1 << --n
;
259 for (m
= 1 << cnt
; m
> 0; ++rp
)
260 if ((--m
& mask
) != 0)
261 rp
->len
+= temp
[n
].len
+ 1;
265 /* The first half of the strings all include the first string. */
268 while (n
!= (1UL << (cnt
- 1)))
271 rp
[0].str
= rp
[-2].str
+ rp
[-2].len
;
273 rp
[0].str
= rp
[-1].str
;
277 /* The second half starts right after the first part of the string of
278 the corresponding entry in the first half. */
281 rp
[0].str
= rp
[-(1 << (cnt
- 1))].str
+ temp
[cnt
- 1].len
+ 1;
286 /* The maximum string length. */
287 *max_capstrlen
= result
[0].len
;