Commit | Line | Data |
---|---|---|
8d9455b4 ILT |
1 | // elfcpp_swap.h -- Handle swapping for elfcpp -*- C++ -*- |
2 | ||
b3adc24a | 3 | // Copyright (C) 2006-2020 Free Software Foundation, Inc. |
6cb15b7f ILT |
4 | // Written by Ian Lance Taylor <iant@google.com>. |
5 | ||
6 | // This file is part of elfcpp. | |
7 | ||
8 | // This program is free software; you can redistribute it and/or | |
9 | // modify it under the terms of the GNU Library General Public License | |
10 | // as published by the Free Software Foundation; either version 2, or | |
11 | // (at your option) any later version. | |
12 | ||
13 | // In addition to the permissions in the GNU Library General Public | |
14 | // License, the Free Software Foundation gives you unlimited | |
15 | // permission to link the compiled version of this file into | |
16 | // combinations with other programs, and to distribute those | |
17 | // combinations without any restriction coming from the use of this | |
18 | // file. (The Library Public License restrictions do apply in other | |
19 | // respects; for example, they cover modification of the file, and | |
20 | /// distribution when not linked into a combined executable.) | |
21 | ||
22 | // This program is distributed in the hope that it will be useful, but | |
23 | // WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
25 | // Library General Public License for more details. | |
26 | ||
27 | // You should have received a copy of the GNU Library General Public | |
28 | // License along with this program; if not, write to the Free Software | |
29 | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA | |
30 | // 02110-1301, USA. | |
31 | ||
8d9455b4 ILT |
32 | // This header file defines basic template classes to efficiently swap |
33 | // numbers between host form and target form. When the host and | |
34 | // target have the same endianness, these turn into no-ops. | |
35 | ||
36 | #ifndef ELFCPP_SWAP_H | |
37 | #define ELFCPP_SWAP_H | |
38 | ||
39 | #include <stdint.h> | |
15d5fa16 ILT |
40 | |
41 | // We need an autoconf-generated config.h file for endianness and | |
42 | // swapping. We check two macros: WORDS_BIGENDIAN and | |
43 | // HAVE_BYTESWAP_H. | |
44 | ||
45 | #include "config.h" | |
46 | ||
47 | #ifdef HAVE_BYTESWAP_H | |
8d9455b4 | 48 | #include <byteswap.h> |
e755667f NA |
49 | #endif // defined(HAVE_BYTESWAP_H) |
50 | ||
15d5fa16 | 51 | // Provide our own versions of the byteswap functions. |
e755667f NA |
52 | #if !HAVE_DECL_BSWAP_16 |
53 | static inline uint16_t | |
15d5fa16 ILT |
54 | bswap_16(uint16_t v) |
55 | { | |
56 | return ((v >> 8) & 0xff) | ((v & 0xff) << 8); | |
57 | } | |
e755667f | 58 | #endif // !HAVE_DECL_BSWAP16 |
15d5fa16 | 59 | |
e755667f NA |
60 | #if !HAVE_DECL_BSWAP_32 |
61 | static inline uint32_t | |
15d5fa16 ILT |
62 | bswap_32(uint32_t v) |
63 | { | |
64 | return ( ((v & 0xff000000) >> 24) | |
65 | | ((v & 0x00ff0000) >> 8) | |
66 | | ((v & 0x0000ff00) << 8) | |
67 | | ((v & 0x000000ff) << 24)); | |
68 | } | |
e755667f | 69 | #endif // !HAVE_DECL_BSWAP32 |
15d5fa16 | 70 | |
e755667f NA |
71 | #if !HAVE_DECL_BSWAP_64 |
72 | static inline uint64_t | |
15d5fa16 ILT |
73 | bswap_64(uint64_t v) |
74 | { | |
75 | return ( ((v & 0xff00000000000000ULL) >> 56) | |
76 | | ((v & 0x00ff000000000000ULL) >> 40) | |
77 | | ((v & 0x0000ff0000000000ULL) >> 24) | |
78 | | ((v & 0x000000ff00000000ULL) >> 8) | |
79 | | ((v & 0x00000000ff000000ULL) << 8) | |
80 | | ((v & 0x0000000000ff0000ULL) << 24) | |
81 | | ((v & 0x000000000000ff00ULL) << 40) | |
82 | | ((v & 0x00000000000000ffULL) << 56)); | |
83 | } | |
e755667f | 84 | #endif // !HAVE_DECL_BSWAP64 |
15d5fa16 ILT |
85 | |
86 | // gcc 4.3 and later provides __builtin_bswap32 and __builtin_bswap64. | |
87 | ||
88 | #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) | |
89 | #undef bswap_32 | |
90 | #define bswap_32 __builtin_bswap32 | |
91 | #undef bswap_64 | |
92 | #define bswap_64 __builtin_bswap64 | |
93 | #endif | |
8d9455b4 ILT |
94 | |
95 | namespace elfcpp | |
96 | { | |
97 | ||
98 | // Endian simply indicates whether the host is big endian or not. | |
99 | ||
100 | struct Endian | |
101 | { | |
102 | public: | |
103 | // Used for template specializations. | |
15d5fa16 ILT |
104 | static const bool host_big_endian = |
105 | #ifdef WORDS_BIGENDIAN | |
106 | true | |
107 | #else | |
108 | false | |
109 | #endif | |
110 | ; | |
8d9455b4 ILT |
111 | }; |
112 | ||
113 | // Valtype_base is a template based on size (8, 16, 32, 64) which | |
5b3463d9 ILT |
114 | // defines the type Valtype as the unsigned integer, and |
115 | // Signed_valtype as the signed integer, of the specified size. | |
8d9455b4 ILT |
116 | |
117 | template<int size> | |
118 | struct Valtype_base; | |
119 | ||
120 | template<> | |
121 | struct Valtype_base<8> | |
122 | { | |
5b3463d9 ILT |
123 | typedef uint8_t Valtype; |
124 | typedef int8_t Signed_valtype; | |
8d9455b4 ILT |
125 | }; |
126 | ||
127 | template<> | |
128 | struct Valtype_base<16> | |
129 | { | |
130 | typedef uint16_t Valtype; | |
5b3463d9 | 131 | typedef int16_t Signed_valtype; |
8d9455b4 ILT |
132 | }; |
133 | ||
134 | template<> | |
135 | struct Valtype_base<32> | |
136 | { | |
137 | typedef uint32_t Valtype; | |
5b3463d9 | 138 | typedef int32_t Signed_valtype; |
8d9455b4 ILT |
139 | }; |
140 | ||
141 | template<> | |
142 | struct Valtype_base<64> | |
143 | { | |
144 | typedef uint64_t Valtype; | |
5b3463d9 | 145 | typedef int64_t Signed_valtype; |
8d9455b4 ILT |
146 | }; |
147 | ||
148 | // Convert_endian is a template based on size and on whether the host | |
149 | // and target have the same endianness. It defines the type Valtype | |
150 | // as Valtype_base does, and also defines a function convert_host | |
151 | // which takes an argument of type Valtype and returns the same value, | |
152 | // but swapped if the host and target have different endianness. | |
153 | ||
154 | template<int size, bool same_endian> | |
155 | struct Convert_endian; | |
156 | ||
157 | template<int size> | |
158 | struct Convert_endian<size, true> | |
159 | { | |
160 | typedef typename Valtype_base<size>::Valtype Valtype; | |
161 | ||
162 | static inline Valtype | |
163 | convert_host(Valtype v) | |
164 | { return v; } | |
165 | }; | |
166 | ||
167 | template<> | |
168 | struct Convert_endian<8, false> | |
169 | { | |
170 | typedef Valtype_base<8>::Valtype Valtype; | |
171 | ||
172 | static inline Valtype | |
173 | convert_host(Valtype v) | |
174 | { return v; } | |
175 | }; | |
176 | ||
177 | template<> | |
178 | struct Convert_endian<16, false> | |
179 | { | |
180 | typedef Valtype_base<16>::Valtype Valtype; | |
181 | ||
182 | static inline Valtype | |
183 | convert_host(Valtype v) | |
184 | { return bswap_16(v); } | |
185 | }; | |
186 | ||
187 | template<> | |
188 | struct Convert_endian<32, false> | |
189 | { | |
190 | typedef Valtype_base<32>::Valtype Valtype; | |
191 | ||
192 | static inline Valtype | |
193 | convert_host(Valtype v) | |
194 | { return bswap_32(v); } | |
195 | }; | |
196 | ||
197 | template<> | |
198 | struct Convert_endian<64, false> | |
199 | { | |
200 | typedef Valtype_base<64>::Valtype Valtype; | |
201 | ||
202 | static inline Valtype | |
203 | convert_host(Valtype v) | |
204 | { return bswap_64(v); } | |
205 | }; | |
206 | ||
207 | // Convert is a template based on size and on whether the target is | |
208 | // big endian. It defines Valtype and convert_host like | |
209 | // Convert_endian. That is, it is just like Convert_endian except in | |
210 | // the meaning of the second template parameter. | |
211 | ||
212 | template<int size, bool big_endian> | |
213 | struct Convert | |
214 | { | |
215 | typedef typename Valtype_base<size>::Valtype Valtype; | |
216 | ||
217 | static inline Valtype | |
218 | convert_host(Valtype v) | |
219 | { | |
220 | return Convert_endian<size, big_endian == Endian::host_big_endian> | |
221 | ::convert_host(v); | |
222 | } | |
223 | }; | |
224 | ||
225 | // Swap is a template based on size and on whether the target is big | |
226 | // endian. It defines the type Valtype and the functions readval and | |
227 | // writeval. The functions read and write values of the appropriate | |
228 | // size out of buffers, swapping them if necessary. readval and | |
229 | // writeval are overloaded to take pointers to the appropriate type or | |
230 | // pointers to unsigned char. | |
231 | ||
232 | template<int size, bool big_endian> | |
233 | struct Swap | |
234 | { | |
235 | typedef typename Valtype_base<size>::Valtype Valtype; | |
236 | ||
237 | static inline Valtype | |
238 | readval(const Valtype* wv) | |
239 | { return Convert<size, big_endian>::convert_host(*wv); } | |
240 | ||
241 | static inline void | |
242 | writeval(Valtype* wv, Valtype v) | |
243 | { *wv = Convert<size, big_endian>::convert_host(v); } | |
244 | ||
245 | static inline Valtype | |
246 | readval(const unsigned char* wv) | |
247 | { return readval(reinterpret_cast<const Valtype*>(wv)); } | |
248 | ||
249 | static inline void | |
250 | writeval(unsigned char* wv, Valtype v) | |
251 | { writeval(reinterpret_cast<Valtype*>(wv), v); } | |
252 | }; | |
253 | ||
254 | // We need to specialize the 8-bit version of Swap to avoid | |
255 | // conflicting overloads, since both versions of readval and writeval | |
256 | // will have the same type parameters. | |
257 | ||
258 | template<bool big_endian> | |
259 | struct Swap<8, big_endian> | |
260 | { | |
261 | typedef typename Valtype_base<8>::Valtype Valtype; | |
262 | ||
263 | static inline Valtype | |
264 | readval(const Valtype* wv) | |
265 | { return *wv; } | |
266 | ||
267 | static inline void | |
268 | writeval(Valtype* wv, Valtype v) | |
269 | { *wv = v; } | |
270 | }; | |
271 | ||
272 | // Swap_unaligned is a template based on size and on whether the | |
273 | // target is big endian. It defines the type Valtype and the | |
a3ad94ed ILT |
274 | // functions readval and writeval. The functions read and write |
275 | // values of the appropriate size out of buffers which may be | |
276 | // misaligned. | |
8d9455b4 ILT |
277 | |
278 | template<int size, bool big_endian> | |
279 | struct Swap_unaligned; | |
280 | ||
281 | template<bool big_endian> | |
282 | struct Swap_unaligned<8, big_endian> | |
283 | { | |
284 | typedef typename Valtype_base<8>::Valtype Valtype; | |
285 | ||
286 | static inline Valtype | |
a3ad94ed | 287 | readval(const unsigned char* wv) |
8d9455b4 ILT |
288 | { return *wv; } |
289 | ||
290 | static inline void | |
a3ad94ed | 291 | writeval(unsigned char* wv, Valtype v) |
8d9455b4 ILT |
292 | { *wv = v; } |
293 | }; | |
294 | ||
295 | template<> | |
296 | struct Swap_unaligned<16, false> | |
297 | { | |
298 | typedef Valtype_base<16>::Valtype Valtype; | |
299 | ||
300 | static inline Valtype | |
a3ad94ed | 301 | readval(const unsigned char* wv) |
8d9455b4 ILT |
302 | { |
303 | return (wv[1] << 8) | wv[0]; | |
304 | } | |
305 | ||
306 | static inline void | |
a3ad94ed | 307 | writeval(unsigned char* wv, Valtype v) |
8d9455b4 ILT |
308 | { |
309 | wv[1] = v >> 8; | |
310 | wv[0] = v; | |
311 | } | |
312 | }; | |
313 | ||
314 | template<> | |
315 | struct Swap_unaligned<16, true> | |
316 | { | |
317 | typedef Valtype_base<16>::Valtype Valtype; | |
318 | ||
319 | static inline Valtype | |
a3ad94ed | 320 | readval(const unsigned char* wv) |
8d9455b4 ILT |
321 | { |
322 | return (wv[0] << 8) | wv[1]; | |
323 | } | |
324 | ||
325 | static inline void | |
a3ad94ed | 326 | writeval(unsigned char* wv, Valtype v) |
8d9455b4 ILT |
327 | { |
328 | wv[0] = v >> 8; | |
329 | wv[1] = v; | |
330 | } | |
331 | }; | |
332 | ||
333 | template<> | |
334 | struct Swap_unaligned<32, false> | |
335 | { | |
336 | typedef Valtype_base<32>::Valtype Valtype; | |
337 | ||
338 | static inline Valtype | |
a3ad94ed | 339 | readval(const unsigned char* wv) |
8d9455b4 ILT |
340 | { |
341 | return (wv[3] << 24) | (wv[2] << 16) | (wv[1] << 8) | wv[0]; | |
342 | } | |
343 | ||
344 | static inline void | |
a3ad94ed | 345 | writeval(unsigned char* wv, Valtype v) |
8d9455b4 ILT |
346 | { |
347 | wv[3] = v >> 24; | |
348 | wv[2] = v >> 16; | |
349 | wv[1] = v >> 8; | |
350 | wv[0] = v; | |
351 | } | |
352 | }; | |
353 | ||
354 | template<> | |
355 | struct Swap_unaligned<32, true> | |
356 | { | |
357 | typedef Valtype_base<32>::Valtype Valtype; | |
358 | ||
359 | static inline Valtype | |
a3ad94ed | 360 | readval(const unsigned char* wv) |
8d9455b4 ILT |
361 | { |
362 | return (wv[0] << 24) | (wv[1] << 16) | (wv[2] << 8) | wv[3]; | |
363 | } | |
364 | ||
365 | static inline void | |
a3ad94ed | 366 | writeval(unsigned char* wv, Valtype v) |
8d9455b4 ILT |
367 | { |
368 | wv[0] = v >> 24; | |
369 | wv[1] = v >> 16; | |
370 | wv[2] = v >> 8; | |
371 | wv[3] = v; | |
372 | } | |
373 | }; | |
374 | ||
375 | template<> | |
376 | struct Swap_unaligned<64, false> | |
377 | { | |
378 | typedef Valtype_base<64>::Valtype Valtype; | |
379 | ||
380 | static inline Valtype | |
a3ad94ed | 381 | readval(const unsigned char* wv) |
8d9455b4 ILT |
382 | { |
383 | return ((static_cast<Valtype>(wv[7]) << 56) | |
384 | | (static_cast<Valtype>(wv[6]) << 48) | |
385 | | (static_cast<Valtype>(wv[5]) << 40) | |
386 | | (static_cast<Valtype>(wv[4]) << 32) | |
387 | | (static_cast<Valtype>(wv[3]) << 24) | |
388 | | (static_cast<Valtype>(wv[2]) << 16) | |
389 | | (static_cast<Valtype>(wv[1]) << 8) | |
390 | | static_cast<Valtype>(wv[0])); | |
391 | } | |
392 | ||
393 | static inline void | |
a3ad94ed | 394 | writeval(unsigned char* wv, Valtype v) |
8d9455b4 ILT |
395 | { |
396 | wv[7] = v >> 56; | |
397 | wv[6] = v >> 48; | |
398 | wv[5] = v >> 40; | |
399 | wv[4] = v >> 32; | |
400 | wv[3] = v >> 24; | |
401 | wv[2] = v >> 16; | |
402 | wv[1] = v >> 8; | |
403 | wv[0] = v; | |
404 | } | |
405 | }; | |
406 | ||
407 | template<> | |
408 | struct Swap_unaligned<64, true> | |
409 | { | |
410 | typedef Valtype_base<64>::Valtype Valtype; | |
411 | ||
412 | static inline Valtype | |
a3ad94ed | 413 | readval(const unsigned char* wv) |
8d9455b4 ILT |
414 | { |
415 | return ((static_cast<Valtype>(wv[0]) << 56) | |
416 | | (static_cast<Valtype>(wv[1]) << 48) | |
417 | | (static_cast<Valtype>(wv[2]) << 40) | |
418 | | (static_cast<Valtype>(wv[3]) << 32) | |
419 | | (static_cast<Valtype>(wv[4]) << 24) | |
420 | | (static_cast<Valtype>(wv[5]) << 16) | |
421 | | (static_cast<Valtype>(wv[6]) << 8) | |
422 | | static_cast<Valtype>(wv[7])); | |
423 | } | |
424 | ||
425 | static inline void | |
a3ad94ed | 426 | writeval(unsigned char* wv, Valtype v) |
8d9455b4 | 427 | { |
15fb9978 ILT |
428 | wv[0] = v >> 56; |
429 | wv[1] = v >> 48; | |
430 | wv[2] = v >> 40; | |
431 | wv[3] = v >> 32; | |
432 | wv[4] = v >> 24; | |
433 | wv[5] = v >> 16; | |
434 | wv[6] = v >> 8; | |
435 | wv[7] = v; | |
8d9455b4 ILT |
436 | } |
437 | }; | |
438 | ||
1d509098 CC |
439 | // Swap_aligned32 is a template based on size and on whether the |
440 | // target is big endian. It defines the type Valtype and the | |
441 | // functions readval and writeval. The functions read and write | |
442 | // values of the appropriate size out of buffers which may not be | |
443 | // 64-bit aligned, but are 32-bit aligned. | |
444 | ||
445 | template<int size, bool big_endian> | |
446 | struct Swap_aligned32 | |
447 | { | |
448 | typedef typename Valtype_base<size>::Valtype Valtype; | |
449 | ||
450 | static inline Valtype | |
451 | readval(const unsigned char* wv) | |
452 | { return Swap<size, big_endian>::readval( | |
453 | reinterpret_cast<const Valtype*>(wv)); } | |
454 | ||
455 | static inline void | |
456 | writeval(unsigned char* wv, Valtype v) | |
457 | { Swap<size, big_endian>::writeval(reinterpret_cast<Valtype*>(wv), v); } | |
458 | }; | |
459 | ||
460 | template<> | |
461 | struct Swap_aligned32<64, true> | |
462 | { | |
463 | typedef Valtype_base<64>::Valtype Valtype; | |
464 | ||
465 | static inline Valtype | |
466 | readval(const unsigned char* wv) | |
467 | { | |
468 | return ((static_cast<Valtype>(Swap<32, true>::readval(wv)) << 32) | |
469 | | static_cast<Valtype>(Swap<32, true>::readval(wv + 4))); | |
470 | } | |
471 | ||
472 | static inline void | |
473 | writeval(unsigned char* wv, Valtype v) | |
474 | { | |
475 | typedef Valtype_base<32>::Valtype Valtype32; | |
476 | ||
477 | Swap<32, true>::writeval(wv, static_cast<Valtype32>(v >> 32)); | |
478 | Swap<32, true>::writeval(wv + 4, static_cast<Valtype32>(v)); | |
479 | } | |
480 | }; | |
481 | ||
482 | template<> | |
483 | struct Swap_aligned32<64, false> | |
484 | { | |
485 | typedef Valtype_base<64>::Valtype Valtype; | |
486 | ||
487 | static inline Valtype | |
488 | readval(const unsigned char* wv) | |
489 | { | |
490 | return ((static_cast<Valtype>(Swap<32, false>::readval(wv + 4)) << 32) | |
491 | | static_cast<Valtype>(Swap<32, false>::readval(wv))); | |
492 | } | |
493 | ||
494 | static inline void | |
495 | writeval(unsigned char* wv, Valtype v) | |
496 | { | |
497 | typedef Valtype_base<32>::Valtype Valtype32; | |
498 | ||
499 | Swap<32, false>::writeval(wv + 4, static_cast<Valtype32>(v >> 32)); | |
500 | Swap<32, false>::writeval(wv, static_cast<Valtype32>(v)); | |
501 | } | |
502 | }; | |
503 | ||
8d9455b4 ILT |
504 | } // End namespace elfcpp. |
505 | ||
506 | #endif // !defined(ELFCPP_SWAP_H) |