1 // elfcpp_swap.h -- Handle swapping for elfcpp -*- C++ -*- 2 3 // Copyright (C) 2006-2022 Free Software Foundation, Inc. 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 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> 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 48 #include <byteswap.h> 49 #endif // defined(HAVE_BYTESWAP_H) 50 51 // Provide our own versions of the byteswap functions. 52 #if !HAVE_DECL_BSWAP_16 53 static inline uint16_t 54 bswap_16(uint16_t v) 55 { 56 return ((v >> 8) & 0xff) | ((v & 0xff) << 8); 57 } 58 #endif // !HAVE_DECL_BSWAP16 59 60 #if !HAVE_DECL_BSWAP_32 61 static inline uint32_t 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 } 69 #endif // !HAVE_DECL_BSWAP32 70 71 #if !HAVE_DECL_BSWAP_64 72 static inline uint64_t 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 } 84 #endif // !HAVE_DECL_BSWAP64 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 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. 104 static const bool host_big_endian = 105 #ifdef WORDS_BIGENDIAN 106 true 107 #else 108 false 109 #endif 110 ; 111 }; 112 113 // Valtype_base is a template based on size (8, 16, 32, 64) which 114 // defines the type Valtype as the unsigned integer, and 115 // Signed_valtype as the signed integer, of the specified size. 116 117 template<int size> 118 struct Valtype_base; 119 120 template<> 121 struct Valtype_base<8> 122 { 123 typedef uint8_t Valtype; 124 typedef int8_t Signed_valtype; 125 }; 126 127 template<> 128 struct Valtype_base<16> 129 { 130 typedef uint16_t Valtype; 131 typedef int16_t Signed_valtype; 132 }; 133 134 template<> 135 struct Valtype_base<32> 136 { 137 typedef uint32_t Valtype; 138 typedef int32_t Signed_valtype; 139 }; 140 141 template<> 142 struct Valtype_base<64> 143 { 144 typedef uint64_t Valtype; 145 typedef int64_t Signed_valtype; 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 274 // functions readval and writeval. The functions read and write 275 // values of the appropriate size out of buffers which may be 276 // misaligned. 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 287 readval(const unsigned char* wv) 288 { return *wv; } 289 290 static inline void 291 writeval(unsigned char* wv, Valtype v) 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 301 readval(const unsigned char* wv) 302 { 303 return (wv[1] << 8) | wv[0]; 304 } 305 306 static inline void 307 writeval(unsigned char* wv, Valtype v) 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 320 readval(const unsigned char* wv) 321 { 322 return (wv[0] << 8) | wv[1]; 323 } 324 325 static inline void 326 writeval(unsigned char* wv, Valtype v) 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 339 readval(const unsigned char* wv) 340 { 341 return (wv[3] << 24) | (wv[2] << 16) | (wv[1] << 8) | wv[0]; 342 } 343 344 static inline void 345 writeval(unsigned char* wv, Valtype v) 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 360 readval(const unsigned char* wv) 361 { 362 return (wv[0] << 24) | (wv[1] << 16) | (wv[2] << 8) | wv[3]; 363 } 364 365 static inline void 366 writeval(unsigned char* wv, Valtype v) 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 381 readval(const unsigned char* wv) 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 394 writeval(unsigned char* wv, Valtype v) 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 413 readval(const unsigned char* wv) 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 426 writeval(unsigned char* wv, Valtype v) 427 { 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; 436 } 437 }; 438 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 504 } // End namespace elfcpp. 505 506 #endif // !defined(ELFCPP_SWAP_H) 507