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>
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 /* The standard ELF note layout is exactly as the anonymous struct.
71 The next element is a variable length vendor name of length
72 VENDORLEN (with a real length rounded to ElfW(Word)), followed
73 by the data of length DATALEN (with a real length rounded to
80 } *note
= (const void *) start
;
81 while ((ElfW(Addr
)) (note
+ 1) - start
< phdr
[i
].p_memsz
)
83 #define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
84 /* The layout of the type 2, vendor "GNU" note is as follows:
85 .long <Number of capabilities enabled by this note>
86 .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA).
87 .byte <The bit number for the next capability>
88 .asciz <The name of the capability>. */
89 if (note
->type
== NT_GNU_HWCAP
90 && note
->vendorlen
== sizeof "GNU"
91 && !memcmp ((note
+ 1), "GNU", sizeof "GNU")
92 && note
->datalen
> 2 * sizeof (ElfW(Word
)) + 2)
94 const ElfW(Word
) *p
= ((const void *) (note
+ 1)
95 + ROUND (sizeof "GNU"));
97 ++p
; /* Skip mask word. */
98 dsocaps
= (const char *) p
; /* Pseudo-string "<b>name" */
99 dsocapslen
= note
->datalen
- sizeof *p
* 2;
102 note
= ((const void *) (note
+ 1)
103 + ROUND (note
->vendorlen
) + ROUND (note
->datalen
));
112 /* For TLS enabled builds always add 'tls'. */
115 /* Create temporary data structure to generate result table. */
116 struct r_strlenpair temp
[cnt
];
118 #ifdef NEED_DL_SYSINFO_DSO
121 /* dsocaps points to the .asciz string, and -1 points to the mask
122 .long just before the string. */
123 const ElfW(Word
) mask
= ((const ElfW(Word
) *) dsocaps
)[-1];
124 GLRO(dl_hwcap
) |= (uint64_t) mask
<< _DL_FIRST_EXTRA
;
125 /* Note that we add the dsocaps to the set already chosen by the
126 LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT).
127 So there is no way to request ignoring an OS-supplied dsocap
128 string and bit like you can ignore an OS-supplied HWCAP bit. */
129 hwcap_mask
|= (uint64_t) mask
<< _DL_FIRST_EXTRA
;
131 TUNABLE_SET (glibc
, tune
, hwcap_mask
, uint64_t, hwcap_mask
);
133 GLRO(dl_hwcap_mask
) = hwcap_mask
;
136 for (const char *p
= dsocaps
; p
< dsocaps
+ dsocapslen
; p
+= len
+ 1)
138 uint_fast8_t bit
= *p
++;
141 /* Skip entries that are not enabled in the mask word. */
142 if (__glibc_likely (mask
& ((ElfW(Word
)) 1 << bit
)))
153 for (n
= 0; masked
!= 0; ++n
)
154 if ((masked
& (1ULL << n
)) != 0)
156 temp
[m
].str
= _dl_hwcap_string (n
);
157 temp
[m
].len
= strlen (temp
[m
].str
);
161 if (platform
!= NULL
)
163 temp
[m
].str
= platform
;
164 temp
[m
].len
= platform_len
;
174 /* Determine the total size of all strings together. */
176 total
= temp
[0].len
+ 1;
179 total
= temp
[0].len
+ temp
[cnt
- 1].len
+ 2;
183 for (n
= 1; n
+ 1 < cnt
; ++n
)
184 total
+= temp
[n
].len
+ 1;
186 && (cnt
>= sizeof (size_t) * 8
187 || total
+ (sizeof (*result
) << 3)
188 >= (1UL << (sizeof (size_t) * 8 - cnt
+ 3))))
189 _dl_signal_error (ENOMEM
, NULL
, NULL
,
190 N_("cannot create capability list"));
196 /* The result structure: we use a very compressed way to store the
197 various combinations of capability names. */
199 result
= (struct r_strlenpair
*) malloc (*sz
* sizeof (*result
) + total
);
201 _dl_signal_error (ENOMEM
, NULL
, NULL
,
202 N_("cannot create capability list"));
206 result
[0].str
= (char *) (result
+ *sz
);
207 result
[0].len
= temp
[0].len
+ 1;
208 result
[1].str
= (char *) (result
+ *sz
);
210 cp
= __mempcpy ((char *) (result
+ *sz
), temp
[0].str
, temp
[0].len
);
213 *max_capstrlen
= result
[0].len
;
218 /* Fill in the information. This follows the following scheme
219 (indices from TEMP for four strings):
220 entry #0: 0, 1, 2, 3 binary: 1111
224 This allows the representation of all possible combinations of
225 capability names in the string. First generate the strings. */
226 result
[1].str
= result
[0].str
= cp
= (char *) (result
+ *sz
);
228 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
241 /* We always add the last string. */
244 /* Add the strings which have the bit set in N. */
245 for (m
= cnt
- 2; m
> 0; --m
)
246 if ((n
& (1 << m
)) != 0)
249 /* Always add the first string. */
256 /* Now we are ready to install the string pointers and length. */
257 for (n
= 0; n
< (1UL << cnt
); ++n
)
262 size_t mask
= 1 << --n
;
265 for (m
= 1 << cnt
; m
> 0; ++rp
)
266 if ((--m
& mask
) != 0)
267 rp
->len
+= temp
[n
].len
+ 1;
271 /* The first half of the strings all include the first string. */
274 while (n
!= (1UL << (cnt
- 1)))
277 rp
[0].str
= rp
[-2].str
+ rp
[-2].len
;
279 rp
[0].str
= rp
[-1].str
;
283 /* The second half starts right after the first part of the string of
284 the corresponding entry in the first half. */
287 rp
[0].str
= rp
[-(1 << (cnt
- 1))].str
+ temp
[cnt
- 1].len
+ 1;
292 /* The maximum string length. */
293 *max_capstrlen
= result
[0].len
;