elfcpp_swap.h 12 KB

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