elfcpp_swap.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. // elfcpp_swap.h -- Handle swapping for elfcpp -*- C++ -*-
  2. // Copyright (C) 2006-2017 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. #else
  38. // Provide our own versions of the byteswap functions.
  39. inline uint16_t
  40. bswap_16(uint16_t v)
  41. {
  42. return ((v >> 8) & 0xff) | ((v & 0xff) << 8);
  43. }
  44. inline uint32_t
  45. bswap_32(uint32_t v)
  46. {
  47. return ( ((v & 0xff000000) >> 24)
  48. | ((v & 0x00ff0000) >> 8)
  49. | ((v & 0x0000ff00) << 8)
  50. | ((v & 0x000000ff) << 24));
  51. }
  52. inline uint64_t
  53. bswap_64(uint64_t v)
  54. {
  55. return ( ((v & 0xff00000000000000ULL) >> 56)
  56. | ((v & 0x00ff000000000000ULL) >> 40)
  57. | ((v & 0x0000ff0000000000ULL) >> 24)
  58. | ((v & 0x000000ff00000000ULL) >> 8)
  59. | ((v & 0x00000000ff000000ULL) << 8)
  60. | ((v & 0x0000000000ff0000ULL) << 24)
  61. | ((v & 0x000000000000ff00ULL) << 40)
  62. | ((v & 0x00000000000000ffULL) << 56));
  63. }
  64. #endif // !defined(HAVE_BYTESWAP_H)
  65. // gcc 4.3 and later provides __builtin_bswap32 and __builtin_bswap64.
  66. #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
  67. #undef bswap_32
  68. #define bswap_32 __builtin_bswap32
  69. #undef bswap_64
  70. #define bswap_64 __builtin_bswap64
  71. #endif
  72. namespace elfcpp
  73. {
  74. // Endian simply indicates whether the host is big endian or not.
  75. struct Endian
  76. {
  77. public:
  78. // Used for template specializations.
  79. static const bool host_big_endian =
  80. #ifdef WORDS_BIGENDIAN
  81. true
  82. #else
  83. false
  84. #endif
  85. ;
  86. };
  87. // Valtype_base is a template based on size (8, 16, 32, 64) which
  88. // defines the type Valtype as the unsigned integer, and
  89. // Signed_valtype as the signed integer, of the specified size.
  90. template<int size>
  91. struct Valtype_base;
  92. template<>
  93. struct Valtype_base<8>
  94. {
  95. typedef uint8_t Valtype;
  96. typedef int8_t Signed_valtype;
  97. };
  98. template<>
  99. struct Valtype_base<16>
  100. {
  101. typedef uint16_t Valtype;
  102. typedef int16_t Signed_valtype;
  103. };
  104. template<>
  105. struct Valtype_base<32>
  106. {
  107. typedef uint32_t Valtype;
  108. typedef int32_t Signed_valtype;
  109. };
  110. template<>
  111. struct Valtype_base<64>
  112. {
  113. typedef uint64_t Valtype;
  114. typedef int64_t Signed_valtype;
  115. };
  116. // Convert_endian is a template based on size and on whether the host
  117. // and target have the same endianness. It defines the type Valtype
  118. // as Valtype_base does, and also defines a function convert_host
  119. // which takes an argument of type Valtype and returns the same value,
  120. // but swapped if the host and target have different endianness.
  121. template<int size, bool same_endian>
  122. struct Convert_endian;
  123. template<int size>
  124. struct Convert_endian<size, true>
  125. {
  126. typedef typename Valtype_base<size>::Valtype Valtype;
  127. static inline Valtype
  128. convert_host(Valtype v)
  129. { return v; }
  130. };
  131. template<>
  132. struct Convert_endian<8, false>
  133. {
  134. typedef Valtype_base<8>::Valtype Valtype;
  135. static inline Valtype
  136. convert_host(Valtype v)
  137. { return v; }
  138. };
  139. template<>
  140. struct Convert_endian<16, false>
  141. {
  142. typedef Valtype_base<16>::Valtype Valtype;
  143. static inline Valtype
  144. convert_host(Valtype v)
  145. { return bswap_16(v); }
  146. };
  147. template<>
  148. struct Convert_endian<32, false>
  149. {
  150. typedef Valtype_base<32>::Valtype Valtype;
  151. static inline Valtype
  152. convert_host(Valtype v)
  153. { return bswap_32(v); }
  154. };
  155. template<>
  156. struct Convert_endian<64, false>
  157. {
  158. typedef Valtype_base<64>::Valtype Valtype;
  159. static inline Valtype
  160. convert_host(Valtype v)
  161. { return bswap_64(v); }
  162. };
  163. // Convert is a template based on size and on whether the target is
  164. // big endian. It defines Valtype and convert_host like
  165. // Convert_endian. That is, it is just like Convert_endian except in
  166. // the meaning of the second template parameter.
  167. template<int size, bool big_endian>
  168. struct Convert
  169. {
  170. typedef typename Valtype_base<size>::Valtype Valtype;
  171. static inline Valtype
  172. convert_host(Valtype v)
  173. {
  174. return Convert_endian<size, big_endian == Endian::host_big_endian>
  175. ::convert_host(v);
  176. }
  177. };
  178. // Swap is a template based on size and on whether the target is big
  179. // endian. It defines the type Valtype and the functions readval and
  180. // writeval. The functions read and write values of the appropriate
  181. // size out of buffers, swapping them if necessary. readval and
  182. // writeval are overloaded to take pointers to the appropriate type or
  183. // pointers to unsigned char.
  184. template<int size, bool big_endian>
  185. struct Swap
  186. {
  187. typedef typename Valtype_base<size>::Valtype Valtype;
  188. static inline Valtype
  189. readval(const Valtype* wv)
  190. { return Convert<size, big_endian>::convert_host(*wv); }
  191. static inline void
  192. writeval(Valtype* wv, Valtype v)
  193. { *wv = Convert<size, big_endian>::convert_host(v); }
  194. static inline Valtype
  195. readval(const unsigned char* wv)
  196. { return readval(reinterpret_cast<const Valtype*>(wv)); }
  197. static inline void
  198. writeval(unsigned char* wv, Valtype v)
  199. { writeval(reinterpret_cast<Valtype*>(wv), v); }
  200. };
  201. // We need to specialize the 8-bit version of Swap to avoid
  202. // conflicting overloads, since both versions of readval and writeval
  203. // will have the same type parameters.
  204. template<bool big_endian>
  205. struct Swap<8, big_endian>
  206. {
  207. typedef typename Valtype_base<8>::Valtype Valtype;
  208. static inline Valtype
  209. readval(const Valtype* wv)
  210. { return *wv; }
  211. static inline void
  212. writeval(Valtype* wv, Valtype v)
  213. { *wv = v; }
  214. };
  215. // Swap_unaligned is a template based on size and on whether the
  216. // target is big endian. It defines the type Valtype and the
  217. // functions readval and writeval. The functions read and write
  218. // values of the appropriate size out of buffers which may be
  219. // misaligned.
  220. template<int size, bool big_endian>
  221. struct Swap_unaligned;
  222. template<bool big_endian>
  223. struct Swap_unaligned<8, big_endian>
  224. {
  225. typedef typename Valtype_base<8>::Valtype Valtype;
  226. static inline Valtype
  227. readval(const unsigned char* wv)
  228. { return *wv; }
  229. static inline void
  230. writeval(unsigned char* wv, Valtype v)
  231. { *wv = v; }
  232. };
  233. template<>
  234. struct Swap_unaligned<16, false>
  235. {
  236. typedef Valtype_base<16>::Valtype Valtype;
  237. static inline Valtype
  238. readval(const unsigned char* wv)
  239. {
  240. return (wv[1] << 8) | wv[0];
  241. }
  242. static inline void
  243. writeval(unsigned char* wv, Valtype v)
  244. {
  245. wv[1] = v >> 8;
  246. wv[0] = v;
  247. }
  248. };
  249. template<>
  250. struct Swap_unaligned<16, true>
  251. {
  252. typedef Valtype_base<16>::Valtype Valtype;
  253. static inline Valtype
  254. readval(const unsigned char* wv)
  255. {
  256. return (wv[0] << 8) | wv[1];
  257. }
  258. static inline void
  259. writeval(unsigned char* wv, Valtype v)
  260. {
  261. wv[0] = v >> 8;
  262. wv[1] = v;
  263. }
  264. };
  265. template<>
  266. struct Swap_unaligned<32, false>
  267. {
  268. typedef Valtype_base<32>::Valtype Valtype;
  269. static inline Valtype
  270. readval(const unsigned char* wv)
  271. {
  272. return (wv[3] << 24) | (wv[2] << 16) | (wv[1] << 8) | wv[0];
  273. }
  274. static inline void
  275. writeval(unsigned char* wv, Valtype v)
  276. {
  277. wv[3] = v >> 24;
  278. wv[2] = v >> 16;
  279. wv[1] = v >> 8;
  280. wv[0] = v;
  281. }
  282. };
  283. template<>
  284. struct Swap_unaligned<32, true>
  285. {
  286. typedef Valtype_base<32>::Valtype Valtype;
  287. static inline Valtype
  288. readval(const unsigned char* wv)
  289. {
  290. return (wv[0] << 24) | (wv[1] << 16) | (wv[2] << 8) | wv[3];
  291. }
  292. static inline void
  293. writeval(unsigned char* wv, Valtype v)
  294. {
  295. wv[0] = v >> 24;
  296. wv[1] = v >> 16;
  297. wv[2] = v >> 8;
  298. wv[3] = v;
  299. }
  300. };
  301. template<>
  302. struct Swap_unaligned<64, false>
  303. {
  304. typedef Valtype_base<64>::Valtype Valtype;
  305. static inline Valtype
  306. readval(const unsigned char* wv)
  307. {
  308. return ((static_cast<Valtype>(wv[7]) << 56)
  309. | (static_cast<Valtype>(wv[6]) << 48)
  310. | (static_cast<Valtype>(wv[5]) << 40)
  311. | (static_cast<Valtype>(wv[4]) << 32)
  312. | (static_cast<Valtype>(wv[3]) << 24)
  313. | (static_cast<Valtype>(wv[2]) << 16)
  314. | (static_cast<Valtype>(wv[1]) << 8)
  315. | static_cast<Valtype>(wv[0]));
  316. }
  317. static inline void
  318. writeval(unsigned char* wv, Valtype v)
  319. {
  320. wv[7] = v >> 56;
  321. wv[6] = v >> 48;
  322. wv[5] = v >> 40;
  323. wv[4] = v >> 32;
  324. wv[3] = v >> 24;
  325. wv[2] = v >> 16;
  326. wv[1] = v >> 8;
  327. wv[0] = v;
  328. }
  329. };
  330. template<>
  331. struct Swap_unaligned<64, true>
  332. {
  333. typedef Valtype_base<64>::Valtype Valtype;
  334. static inline Valtype
  335. readval(const unsigned char* wv)
  336. {
  337. return ((static_cast<Valtype>(wv[0]) << 56)
  338. | (static_cast<Valtype>(wv[1]) << 48)
  339. | (static_cast<Valtype>(wv[2]) << 40)
  340. | (static_cast<Valtype>(wv[3]) << 32)
  341. | (static_cast<Valtype>(wv[4]) << 24)
  342. | (static_cast<Valtype>(wv[5]) << 16)
  343. | (static_cast<Valtype>(wv[6]) << 8)
  344. | static_cast<Valtype>(wv[7]));
  345. }
  346. static inline void
  347. writeval(unsigned char* wv, Valtype v)
  348. {
  349. wv[0] = v >> 56;
  350. wv[1] = v >> 48;
  351. wv[2] = v >> 40;
  352. wv[3] = v >> 32;
  353. wv[4] = v >> 24;
  354. wv[5] = v >> 16;
  355. wv[6] = v >> 8;
  356. wv[7] = v;
  357. }
  358. };
  359. // Swap_aligned32 is a template based on size and on whether the
  360. // target is big endian. It defines the type Valtype and the
  361. // functions readval and writeval. The functions read and write
  362. // values of the appropriate size out of buffers which may not be
  363. // 64-bit aligned, but are 32-bit aligned.
  364. template<int size, bool big_endian>
  365. struct Swap_aligned32
  366. {
  367. typedef typename Valtype_base<size>::Valtype Valtype;
  368. static inline Valtype
  369. readval(const unsigned char* wv)
  370. { return Swap<size, big_endian>::readval(
  371. reinterpret_cast<const Valtype*>(wv)); }
  372. static inline void
  373. writeval(unsigned char* wv, Valtype v)
  374. { Swap<size, big_endian>::writeval(reinterpret_cast<Valtype*>(wv), v); }
  375. };
  376. template<>
  377. struct Swap_aligned32<64, true>
  378. {
  379. typedef Valtype_base<64>::Valtype Valtype;
  380. static inline Valtype
  381. readval(const unsigned char* wv)
  382. {
  383. return ((static_cast<Valtype>(Swap<32, true>::readval(wv)) << 32)
  384. | static_cast<Valtype>(Swap<32, true>::readval(wv + 4)));
  385. }
  386. static inline void
  387. writeval(unsigned char* wv, Valtype v)
  388. {
  389. typedef Valtype_base<32>::Valtype Valtype32;
  390. Swap<32, true>::writeval(wv, static_cast<Valtype32>(v >> 32));
  391. Swap<32, true>::writeval(wv + 4, static_cast<Valtype32>(v));
  392. }
  393. };
  394. template<>
  395. struct Swap_aligned32<64, false>
  396. {
  397. typedef Valtype_base<64>::Valtype Valtype;
  398. static inline Valtype
  399. readval(const unsigned char* wv)
  400. {
  401. return ((static_cast<Valtype>(Swap<32, false>::readval(wv + 4)) << 32)
  402. | static_cast<Valtype>(Swap<32, false>::readval(wv)));
  403. }
  404. static inline void
  405. writeval(unsigned char* wv, Valtype v)
  406. {
  407. typedef Valtype_base<32>::Valtype Valtype32;
  408. Swap<32, false>::writeval(wv + 4, static_cast<Valtype32>(v >> 32));
  409. Swap<32, false>::writeval(wv, static_cast<Valtype32>(v));
  410. }
  411. };
  412. } // End namespace elfcpp.
  413. #endif // !defined(ELFCPP_SWAP_H)