1 /* Hardware capability support for run-time dynamic loader.
2 Copyright (C) 2012-2020 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 <https://www.gnu.org/licenses/>. */
26 #include <dl-procinfo.h>
27 #include <dl-hwcaps.h>
29 /* Return an array of useful/necessary hardware capability names. */
30 const struct r_strlenpair
*
31 _dl_important_hwcaps (const char *platform
, size_t platform_len
, size_t *sz
,
32 size_t *max_capstrlen
)
34 uint64_t hwcap_mask
= GET_HWCAP_MASK();
35 /* Determine how many important bits are set. */
36 uint64_t masked
= GLRO(dl_hwcap
) & hwcap_mask
;
37 size_t cnt
= platform
!= NULL
;
40 struct r_strlenpair
*result
;
41 struct r_strlenpair
*rp
;
44 /* Count the number of bits set in the masked value. */
45 for (n
= 0; (~((1ULL << n
) - 1) & masked
) != 0; ++n
)
46 if ((masked
& (1ULL << n
)) != 0)
49 /* For TLS enabled builds always add 'tls'. */
52 /* Create temporary data structure to generate result table. */
53 struct r_strlenpair temp
[cnt
];
55 for (n
= 0; masked
!= 0; ++n
)
56 if ((masked
& (1ULL << n
)) != 0)
58 temp
[m
].str
= _dl_hwcap_string (n
);
59 temp
[m
].len
= strlen (temp
[m
].str
);
65 temp
[m
].str
= platform
;
66 temp
[m
].len
= platform_len
;
76 /* Determine the total size of all strings together. */
78 total
= temp
[0].len
+ 1;
81 total
= temp
[0].len
+ temp
[cnt
- 1].len
+ 2;
85 for (n
= 1; n
+ 1 < cnt
; ++n
)
86 total
+= temp
[n
].len
+ 1;
88 && (cnt
>= sizeof (size_t) * 8
89 || total
+ (sizeof (*result
) << 3)
90 >= (1UL << (sizeof (size_t) * 8 - cnt
+ 3))))
91 _dl_signal_error (ENOMEM
, NULL
, NULL
,
92 N_("cannot create capability list"));
98 /* The result structure: we use a very compressed way to store the
99 various combinations of capability names. */
101 result
= (struct r_strlenpair
*) malloc (*sz
* sizeof (*result
) + total
);
103 _dl_signal_error (ENOMEM
, NULL
, NULL
,
104 N_("cannot create capability list"));
108 result
[0].str
= (char *) (result
+ *sz
);
109 result
[0].len
= temp
[0].len
+ 1;
110 result
[1].str
= (char *) (result
+ *sz
);
112 cp
= __mempcpy ((char *) (result
+ *sz
), temp
[0].str
, temp
[0].len
);
115 *max_capstrlen
= result
[0].len
;
120 /* Fill in the information. This follows the following scheme
121 (indices from TEMP for four strings):
122 entry #0: 0, 1, 2, 3 binary: 1111
126 This allows the representation of all possible combinations of
127 capability names in the string. First generate the strings. */
128 result
[1].str
= result
[0].str
= cp
= (char *) (result
+ *sz
);
130 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
143 /* We always add the last string. */
146 /* Add the strings which have the bit set in N. */
147 for (m
= cnt
- 2; m
> 0; --m
)
148 if ((n
& (1 << m
)) != 0)
151 /* Always add the first string. */
158 /* Now we are ready to install the string pointers and length. */
159 for (n
= 0; n
< (1UL << cnt
); ++n
)
164 size_t mask
= 1 << --n
;
167 for (m
= 1 << cnt
; m
> 0; ++rp
)
168 if ((--m
& mask
) != 0)
169 rp
->len
+= temp
[n
].len
+ 1;
173 /* The first half of the strings all include the first string. */
176 while (n
!= (1UL << (cnt
- 1)))
179 rp
[0].str
= rp
[-2].str
+ rp
[-2].len
;
181 rp
[0].str
= rp
[-1].str
;
185 /* The second half starts right after the first part of the string of
186 the corresponding entry in the first half. */
189 rp
[0].str
= rp
[-(1 << (cnt
- 1))].str
+ temp
[cnt
- 1].len
+ 1;
194 /* The maximum string length. */
195 *max_capstrlen
= result
[0].len
;