12a6b7db3Sskrll // elfcpp_swap.h -- Handle swapping for elfcpp -*- C++ -*-
22a6b7db3Sskrll
3*cb63e24eSchristos // Copyright (C) 2006-2024 Free Software Foundation, Inc.
42a6b7db3Sskrll // Written by Ian Lance Taylor <iant@google.com>.
52a6b7db3Sskrll
62a6b7db3Sskrll // This file is part of elfcpp.
72a6b7db3Sskrll
82a6b7db3Sskrll // This program is free software; you can redistribute it and/or
92a6b7db3Sskrll // modify it under the terms of the GNU Library General Public License
102a6b7db3Sskrll // as published by the Free Software Foundation; either version 2, or
112a6b7db3Sskrll // (at your option) any later version.
122a6b7db3Sskrll
132a6b7db3Sskrll // In addition to the permissions in the GNU Library General Public
142a6b7db3Sskrll // License, the Free Software Foundation gives you unlimited
152a6b7db3Sskrll // permission to link the compiled version of this file into
162a6b7db3Sskrll // combinations with other programs, and to distribute those
172a6b7db3Sskrll // combinations without any restriction coming from the use of this
182a6b7db3Sskrll // file. (The Library Public License restrictions do apply in other
192a6b7db3Sskrll // respects; for example, they cover modification of the file, and
202a6b7db3Sskrll /// distribution when not linked into a combined executable.)
212a6b7db3Sskrll
222a6b7db3Sskrll // This program is distributed in the hope that it will be useful, but
232a6b7db3Sskrll // WITHOUT ANY WARRANTY; without even the implied warranty of
242a6b7db3Sskrll // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
252a6b7db3Sskrll // Library General Public License for more details.
262a6b7db3Sskrll
272a6b7db3Sskrll // You should have received a copy of the GNU Library General Public
282a6b7db3Sskrll // License along with this program; if not, write to the Free Software
292a6b7db3Sskrll // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
302a6b7db3Sskrll // 02110-1301, USA.
312a6b7db3Sskrll
322a6b7db3Sskrll // This header file defines basic template classes to efficiently swap
332a6b7db3Sskrll // numbers between host form and target form. When the host and
342a6b7db3Sskrll // target have the same endianness, these turn into no-ops.
352a6b7db3Sskrll
362a6b7db3Sskrll #ifndef ELFCPP_SWAP_H
372a6b7db3Sskrll #define ELFCPP_SWAP_H
382a6b7db3Sskrll
392a6b7db3Sskrll #include <stdint.h>
40be12b8bcSchristos
41be12b8bcSchristos // We need an autoconf-generated config.h file for endianness and
42be12b8bcSchristos // swapping. We check two macros: WORDS_BIGENDIAN and
43be12b8bcSchristos // HAVE_BYTESWAP_H.
44be12b8bcSchristos
45be12b8bcSchristos #include "config.h"
46be12b8bcSchristos
47be12b8bcSchristos #ifdef HAVE_BYTESWAP_H
482a6b7db3Sskrll #include <byteswap.h>
494f645668Schristos #endif // defined(HAVE_BYTESWAP_H)
504f645668Schristos
51be12b8bcSchristos // Provide our own versions of the byteswap functions.
524f645668Schristos #if !HAVE_DECL_BSWAP_16
534f645668Schristos static inline uint16_t
bswap_16(uint16_t v)54be12b8bcSchristos bswap_16(uint16_t v)
55be12b8bcSchristos {
56be12b8bcSchristos return ((v >> 8) & 0xff) | ((v & 0xff) << 8);
57be12b8bcSchristos }
584f645668Schristos #endif // !HAVE_DECL_BSWAP16
59be12b8bcSchristos
604f645668Schristos #if !HAVE_DECL_BSWAP_32
614f645668Schristos static inline uint32_t
bswap_32(uint32_t v)62be12b8bcSchristos bswap_32(uint32_t v)
63be12b8bcSchristos {
64be12b8bcSchristos return ( ((v & 0xff000000) >> 24)
65be12b8bcSchristos | ((v & 0x00ff0000) >> 8)
66be12b8bcSchristos | ((v & 0x0000ff00) << 8)
67be12b8bcSchristos | ((v & 0x000000ff) << 24));
68be12b8bcSchristos }
694f645668Schristos #endif // !HAVE_DECL_BSWAP32
70be12b8bcSchristos
714f645668Schristos #if !HAVE_DECL_BSWAP_64
724f645668Schristos static inline uint64_t
bswap_64(uint64_t v)73be12b8bcSchristos bswap_64(uint64_t v)
74be12b8bcSchristos {
75be12b8bcSchristos return ( ((v & 0xff00000000000000ULL) >> 56)
76be12b8bcSchristos | ((v & 0x00ff000000000000ULL) >> 40)
77be12b8bcSchristos | ((v & 0x0000ff0000000000ULL) >> 24)
78be12b8bcSchristos | ((v & 0x000000ff00000000ULL) >> 8)
79be12b8bcSchristos | ((v & 0x00000000ff000000ULL) << 8)
80be12b8bcSchristos | ((v & 0x0000000000ff0000ULL) << 24)
81be12b8bcSchristos | ((v & 0x000000000000ff00ULL) << 40)
82be12b8bcSchristos | ((v & 0x00000000000000ffULL) << 56));
83be12b8bcSchristos }
844f645668Schristos #endif // !HAVE_DECL_BSWAP64
85be12b8bcSchristos
86be12b8bcSchristos // gcc 4.3 and later provides __builtin_bswap32 and __builtin_bswap64.
87be12b8bcSchristos
88be12b8bcSchristos #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
89be12b8bcSchristos #undef bswap_32
90be12b8bcSchristos #define bswap_32 __builtin_bswap32
91be12b8bcSchristos #undef bswap_64
92be12b8bcSchristos #define bswap_64 __builtin_bswap64
93be12b8bcSchristos #endif
942a6b7db3Sskrll
952a6b7db3Sskrll namespace elfcpp
962a6b7db3Sskrll {
972a6b7db3Sskrll
982a6b7db3Sskrll // Endian simply indicates whether the host is big endian or not.
992a6b7db3Sskrll
1002a6b7db3Sskrll struct Endian
1012a6b7db3Sskrll {
1022a6b7db3Sskrll public:
1032a6b7db3Sskrll // Used for template specializations.
104be12b8bcSchristos static const bool host_big_endian =
105be12b8bcSchristos #ifdef WORDS_BIGENDIAN
106be12b8bcSchristos true
107be12b8bcSchristos #else
108be12b8bcSchristos false
109be12b8bcSchristos #endif
110be12b8bcSchristos ;
1112a6b7db3Sskrll };
1122a6b7db3Sskrll
1132a6b7db3Sskrll // Valtype_base is a template based on size (8, 16, 32, 64) which
1142a6b7db3Sskrll // defines the type Valtype as the unsigned integer, and
1152a6b7db3Sskrll // Signed_valtype as the signed integer, of the specified size.
1162a6b7db3Sskrll
1172a6b7db3Sskrll template<int size>
1182a6b7db3Sskrll struct Valtype_base;
1192a6b7db3Sskrll
1202a6b7db3Sskrll template<>
1212a6b7db3Sskrll struct Valtype_base<8>
1222a6b7db3Sskrll {
1232a6b7db3Sskrll typedef uint8_t Valtype;
1242a6b7db3Sskrll typedef int8_t Signed_valtype;
1252a6b7db3Sskrll };
1262a6b7db3Sskrll
1272a6b7db3Sskrll template<>
1282a6b7db3Sskrll struct Valtype_base<16>
1292a6b7db3Sskrll {
1302a6b7db3Sskrll typedef uint16_t Valtype;
1312a6b7db3Sskrll typedef int16_t Signed_valtype;
1322a6b7db3Sskrll };
1332a6b7db3Sskrll
1342a6b7db3Sskrll template<>
1352a6b7db3Sskrll struct Valtype_base<32>
1362a6b7db3Sskrll {
1372a6b7db3Sskrll typedef uint32_t Valtype;
1382a6b7db3Sskrll typedef int32_t Signed_valtype;
1392a6b7db3Sskrll };
1402a6b7db3Sskrll
1412a6b7db3Sskrll template<>
1422a6b7db3Sskrll struct Valtype_base<64>
1432a6b7db3Sskrll {
1442a6b7db3Sskrll typedef uint64_t Valtype;
1452a6b7db3Sskrll typedef int64_t Signed_valtype;
1462a6b7db3Sskrll };
1472a6b7db3Sskrll
1482a6b7db3Sskrll // Convert_endian is a template based on size and on whether the host
1492a6b7db3Sskrll // and target have the same endianness. It defines the type Valtype
1502a6b7db3Sskrll // as Valtype_base does, and also defines a function convert_host
1512a6b7db3Sskrll // which takes an argument of type Valtype and returns the same value,
1522a6b7db3Sskrll // but swapped if the host and target have different endianness.
1532a6b7db3Sskrll
1542a6b7db3Sskrll template<int size, bool same_endian>
1552a6b7db3Sskrll struct Convert_endian;
1562a6b7db3Sskrll
1572a6b7db3Sskrll template<int size>
1582a6b7db3Sskrll struct Convert_endian<size, true>
1592a6b7db3Sskrll {
1602a6b7db3Sskrll typedef typename Valtype_base<size>::Valtype Valtype;
1612a6b7db3Sskrll
1622a6b7db3Sskrll static inline Valtype
1632a6b7db3Sskrll convert_host(Valtype v)
1642a6b7db3Sskrll { return v; }
1652a6b7db3Sskrll };
1662a6b7db3Sskrll
1672a6b7db3Sskrll template<>
1682a6b7db3Sskrll struct Convert_endian<8, false>
1692a6b7db3Sskrll {
1702a6b7db3Sskrll typedef Valtype_base<8>::Valtype Valtype;
1712a6b7db3Sskrll
1722a6b7db3Sskrll static inline Valtype
1732a6b7db3Sskrll convert_host(Valtype v)
1742a6b7db3Sskrll { return v; }
1752a6b7db3Sskrll };
1762a6b7db3Sskrll
1772a6b7db3Sskrll template<>
1782a6b7db3Sskrll struct Convert_endian<16, false>
1792a6b7db3Sskrll {
1802a6b7db3Sskrll typedef Valtype_base<16>::Valtype Valtype;
1812a6b7db3Sskrll
1822a6b7db3Sskrll static inline Valtype
1832a6b7db3Sskrll convert_host(Valtype v)
1842a6b7db3Sskrll { return bswap_16(v); }
1852a6b7db3Sskrll };
1862a6b7db3Sskrll
1872a6b7db3Sskrll template<>
1882a6b7db3Sskrll struct Convert_endian<32, false>
1892a6b7db3Sskrll {
1902a6b7db3Sskrll typedef Valtype_base<32>::Valtype Valtype;
1912a6b7db3Sskrll
1922a6b7db3Sskrll static inline Valtype
1932a6b7db3Sskrll convert_host(Valtype v)
1942a6b7db3Sskrll { return bswap_32(v); }
1952a6b7db3Sskrll };
1962a6b7db3Sskrll
1972a6b7db3Sskrll template<>
1982a6b7db3Sskrll struct Convert_endian<64, false>
1992a6b7db3Sskrll {
2002a6b7db3Sskrll typedef Valtype_base<64>::Valtype Valtype;
2012a6b7db3Sskrll
2022a6b7db3Sskrll static inline Valtype
2032a6b7db3Sskrll convert_host(Valtype v)
2042a6b7db3Sskrll { return bswap_64(v); }
2052a6b7db3Sskrll };
2062a6b7db3Sskrll
2072a6b7db3Sskrll // Convert is a template based on size and on whether the target is
2082a6b7db3Sskrll // big endian. It defines Valtype and convert_host like
2092a6b7db3Sskrll // Convert_endian. That is, it is just like Convert_endian except in
2102a6b7db3Sskrll // the meaning of the second template parameter.
2112a6b7db3Sskrll
2122a6b7db3Sskrll template<int size, bool big_endian>
2132a6b7db3Sskrll struct Convert
2142a6b7db3Sskrll {
2152a6b7db3Sskrll typedef typename Valtype_base<size>::Valtype Valtype;
2162a6b7db3Sskrll
2172a6b7db3Sskrll static inline Valtype
2182a6b7db3Sskrll convert_host(Valtype v)
2192a6b7db3Sskrll {
2202a6b7db3Sskrll return Convert_endian<size, big_endian == Endian::host_big_endian>
2212a6b7db3Sskrll ::convert_host(v);
2222a6b7db3Sskrll }
2232a6b7db3Sskrll };
2242a6b7db3Sskrll
2252a6b7db3Sskrll // Swap is a template based on size and on whether the target is big
2262a6b7db3Sskrll // endian. It defines the type Valtype and the functions readval and
2272a6b7db3Sskrll // writeval. The functions read and write values of the appropriate
2282a6b7db3Sskrll // size out of buffers, swapping them if necessary. readval and
2292a6b7db3Sskrll // writeval are overloaded to take pointers to the appropriate type or
2302a6b7db3Sskrll // pointers to unsigned char.
2312a6b7db3Sskrll
2322a6b7db3Sskrll template<int size, bool big_endian>
2332a6b7db3Sskrll struct Swap
2342a6b7db3Sskrll {
2352a6b7db3Sskrll typedef typename Valtype_base<size>::Valtype Valtype;
2362a6b7db3Sskrll
2372a6b7db3Sskrll static inline Valtype
2382a6b7db3Sskrll readval(const Valtype* wv)
2392a6b7db3Sskrll { return Convert<size, big_endian>::convert_host(*wv); }
2402a6b7db3Sskrll
2412a6b7db3Sskrll static inline void
2422a6b7db3Sskrll writeval(Valtype* wv, Valtype v)
2432a6b7db3Sskrll { *wv = Convert<size, big_endian>::convert_host(v); }
2442a6b7db3Sskrll
2452a6b7db3Sskrll static inline Valtype
2462a6b7db3Sskrll readval(const unsigned char* wv)
2472a6b7db3Sskrll { return readval(reinterpret_cast<const Valtype*>(wv)); }
2482a6b7db3Sskrll
2492a6b7db3Sskrll static inline void
2502a6b7db3Sskrll writeval(unsigned char* wv, Valtype v)
2512a6b7db3Sskrll { writeval(reinterpret_cast<Valtype*>(wv), v); }
2522a6b7db3Sskrll };
2532a6b7db3Sskrll
2542a6b7db3Sskrll // We need to specialize the 8-bit version of Swap to avoid
2552a6b7db3Sskrll // conflicting overloads, since both versions of readval and writeval
2562a6b7db3Sskrll // will have the same type parameters.
2572a6b7db3Sskrll
2582a6b7db3Sskrll template<bool big_endian>
2592a6b7db3Sskrll struct Swap<8, big_endian>
2602a6b7db3Sskrll {
2612a6b7db3Sskrll typedef typename Valtype_base<8>::Valtype Valtype;
2622a6b7db3Sskrll
2632a6b7db3Sskrll static inline Valtype
2642a6b7db3Sskrll readval(const Valtype* wv)
2652a6b7db3Sskrll { return *wv; }
2662a6b7db3Sskrll
2672a6b7db3Sskrll static inline void
2682a6b7db3Sskrll writeval(Valtype* wv, Valtype v)
2692a6b7db3Sskrll { *wv = v; }
2702a6b7db3Sskrll };
2712a6b7db3Sskrll
2722a6b7db3Sskrll // Swap_unaligned is a template based on size and on whether the
2732a6b7db3Sskrll // target is big endian. It defines the type Valtype and the
2742a6b7db3Sskrll // functions readval and writeval. The functions read and write
2752a6b7db3Sskrll // values of the appropriate size out of buffers which may be
2762a6b7db3Sskrll // misaligned.
2772a6b7db3Sskrll
2782a6b7db3Sskrll template<int size, bool big_endian>
2792a6b7db3Sskrll struct Swap_unaligned;
2802a6b7db3Sskrll
2812a6b7db3Sskrll template<bool big_endian>
2822a6b7db3Sskrll struct Swap_unaligned<8, big_endian>
2832a6b7db3Sskrll {
2842a6b7db3Sskrll typedef typename Valtype_base<8>::Valtype Valtype;
2852a6b7db3Sskrll
2862a6b7db3Sskrll static inline Valtype
2872a6b7db3Sskrll readval(const unsigned char* wv)
2882a6b7db3Sskrll { return *wv; }
2892a6b7db3Sskrll
2902a6b7db3Sskrll static inline void
2912a6b7db3Sskrll writeval(unsigned char* wv, Valtype v)
2922a6b7db3Sskrll { *wv = v; }
2932a6b7db3Sskrll };
2942a6b7db3Sskrll
2952a6b7db3Sskrll template<>
2962a6b7db3Sskrll struct Swap_unaligned<16, false>
2972a6b7db3Sskrll {
2982a6b7db3Sskrll typedef Valtype_base<16>::Valtype Valtype;
2992a6b7db3Sskrll
3002a6b7db3Sskrll static inline Valtype
3012a6b7db3Sskrll readval(const unsigned char* wv)
3022a6b7db3Sskrll {
3032a6b7db3Sskrll return (wv[1] << 8) | wv[0];
3042a6b7db3Sskrll }
3052a6b7db3Sskrll
3062a6b7db3Sskrll static inline void
3072a6b7db3Sskrll writeval(unsigned char* wv, Valtype v)
3082a6b7db3Sskrll {
3092a6b7db3Sskrll wv[1] = v >> 8;
3102a6b7db3Sskrll wv[0] = v;
3112a6b7db3Sskrll }
3122a6b7db3Sskrll };
3132a6b7db3Sskrll
3142a6b7db3Sskrll template<>
3152a6b7db3Sskrll struct Swap_unaligned<16, true>
3162a6b7db3Sskrll {
3172a6b7db3Sskrll typedef Valtype_base<16>::Valtype Valtype;
3182a6b7db3Sskrll
3192a6b7db3Sskrll static inline Valtype
3202a6b7db3Sskrll readval(const unsigned char* wv)
3212a6b7db3Sskrll {
3222a6b7db3Sskrll return (wv[0] << 8) | wv[1];
3232a6b7db3Sskrll }
3242a6b7db3Sskrll
3252a6b7db3Sskrll static inline void
3262a6b7db3Sskrll writeval(unsigned char* wv, Valtype v)
3272a6b7db3Sskrll {
3282a6b7db3Sskrll wv[0] = v >> 8;
3292a6b7db3Sskrll wv[1] = v;
3302a6b7db3Sskrll }
3312a6b7db3Sskrll };
3322a6b7db3Sskrll
3332a6b7db3Sskrll template<>
3342a6b7db3Sskrll struct Swap_unaligned<32, false>
3352a6b7db3Sskrll {
3362a6b7db3Sskrll typedef Valtype_base<32>::Valtype Valtype;
3372a6b7db3Sskrll
3382a6b7db3Sskrll static inline Valtype
3392a6b7db3Sskrll readval(const unsigned char* wv)
3402a6b7db3Sskrll {
3412a6b7db3Sskrll return (wv[3] << 24) | (wv[2] << 16) | (wv[1] << 8) | wv[0];
3422a6b7db3Sskrll }
3432a6b7db3Sskrll
3442a6b7db3Sskrll static inline void
3452a6b7db3Sskrll writeval(unsigned char* wv, Valtype v)
3462a6b7db3Sskrll {
3472a6b7db3Sskrll wv[3] = v >> 24;
3482a6b7db3Sskrll wv[2] = v >> 16;
3492a6b7db3Sskrll wv[1] = v >> 8;
3502a6b7db3Sskrll wv[0] = v;
3512a6b7db3Sskrll }
3522a6b7db3Sskrll };
3532a6b7db3Sskrll
3542a6b7db3Sskrll template<>
3552a6b7db3Sskrll struct Swap_unaligned<32, true>
3562a6b7db3Sskrll {
3572a6b7db3Sskrll typedef Valtype_base<32>::Valtype Valtype;
3582a6b7db3Sskrll
3592a6b7db3Sskrll static inline Valtype
3602a6b7db3Sskrll readval(const unsigned char* wv)
3612a6b7db3Sskrll {
3622a6b7db3Sskrll return (wv[0] << 24) | (wv[1] << 16) | (wv[2] << 8) | wv[3];
3632a6b7db3Sskrll }
3642a6b7db3Sskrll
3652a6b7db3Sskrll static inline void
3662a6b7db3Sskrll writeval(unsigned char* wv, Valtype v)
3672a6b7db3Sskrll {
3682a6b7db3Sskrll wv[0] = v >> 24;
3692a6b7db3Sskrll wv[1] = v >> 16;
3702a6b7db3Sskrll wv[2] = v >> 8;
3712a6b7db3Sskrll wv[3] = v;
3722a6b7db3Sskrll }
3732a6b7db3Sskrll };
3742a6b7db3Sskrll
3752a6b7db3Sskrll template<>
3762a6b7db3Sskrll struct Swap_unaligned<64, false>
3772a6b7db3Sskrll {
3782a6b7db3Sskrll typedef Valtype_base<64>::Valtype Valtype;
3792a6b7db3Sskrll
3802a6b7db3Sskrll static inline Valtype
3812a6b7db3Sskrll readval(const unsigned char* wv)
3822a6b7db3Sskrll {
3832a6b7db3Sskrll return ((static_cast<Valtype>(wv[7]) << 56)
3842a6b7db3Sskrll | (static_cast<Valtype>(wv[6]) << 48)
3852a6b7db3Sskrll | (static_cast<Valtype>(wv[5]) << 40)
3862a6b7db3Sskrll | (static_cast<Valtype>(wv[4]) << 32)
3872a6b7db3Sskrll | (static_cast<Valtype>(wv[3]) << 24)
3882a6b7db3Sskrll | (static_cast<Valtype>(wv[2]) << 16)
3892a6b7db3Sskrll | (static_cast<Valtype>(wv[1]) << 8)
3902a6b7db3Sskrll | static_cast<Valtype>(wv[0]));
3912a6b7db3Sskrll }
3922a6b7db3Sskrll
3932a6b7db3Sskrll static inline void
3942a6b7db3Sskrll writeval(unsigned char* wv, Valtype v)
3952a6b7db3Sskrll {
3962a6b7db3Sskrll wv[7] = v >> 56;
3972a6b7db3Sskrll wv[6] = v >> 48;
3982a6b7db3Sskrll wv[5] = v >> 40;
3992a6b7db3Sskrll wv[4] = v >> 32;
4002a6b7db3Sskrll wv[3] = v >> 24;
4012a6b7db3Sskrll wv[2] = v >> 16;
4022a6b7db3Sskrll wv[1] = v >> 8;
4032a6b7db3Sskrll wv[0] = v;
4042a6b7db3Sskrll }
4052a6b7db3Sskrll };
4062a6b7db3Sskrll
4072a6b7db3Sskrll template<>
4082a6b7db3Sskrll struct Swap_unaligned<64, true>
4092a6b7db3Sskrll {
4102a6b7db3Sskrll typedef Valtype_base<64>::Valtype Valtype;
4112a6b7db3Sskrll
4122a6b7db3Sskrll static inline Valtype
4132a6b7db3Sskrll readval(const unsigned char* wv)
4142a6b7db3Sskrll {
4152a6b7db3Sskrll return ((static_cast<Valtype>(wv[0]) << 56)
4162a6b7db3Sskrll | (static_cast<Valtype>(wv[1]) << 48)
4172a6b7db3Sskrll | (static_cast<Valtype>(wv[2]) << 40)
4182a6b7db3Sskrll | (static_cast<Valtype>(wv[3]) << 32)
4192a6b7db3Sskrll | (static_cast<Valtype>(wv[4]) << 24)
4202a6b7db3Sskrll | (static_cast<Valtype>(wv[5]) << 16)
4212a6b7db3Sskrll | (static_cast<Valtype>(wv[6]) << 8)
4222a6b7db3Sskrll | static_cast<Valtype>(wv[7]));
4232a6b7db3Sskrll }
4242a6b7db3Sskrll
4252a6b7db3Sskrll static inline void
4262a6b7db3Sskrll writeval(unsigned char* wv, Valtype v)
4272a6b7db3Sskrll {
4282a6b7db3Sskrll wv[0] = v >> 56;
4292a6b7db3Sskrll wv[1] = v >> 48;
4302a6b7db3Sskrll wv[2] = v >> 40;
4312a6b7db3Sskrll wv[3] = v >> 32;
4322a6b7db3Sskrll wv[4] = v >> 24;
4332a6b7db3Sskrll wv[5] = v >> 16;
4342a6b7db3Sskrll wv[6] = v >> 8;
4352a6b7db3Sskrll wv[7] = v;
4362a6b7db3Sskrll }
4372a6b7db3Sskrll };
4382a6b7db3Sskrll
439883529b6Schristos // Swap_aligned32 is a template based on size and on whether the
440883529b6Schristos // target is big endian. It defines the type Valtype and the
441883529b6Schristos // functions readval and writeval. The functions read and write
442883529b6Schristos // values of the appropriate size out of buffers which may not be
443883529b6Schristos // 64-bit aligned, but are 32-bit aligned.
444883529b6Schristos
445883529b6Schristos template<int size, bool big_endian>
446883529b6Schristos struct Swap_aligned32
447883529b6Schristos {
448883529b6Schristos typedef typename Valtype_base<size>::Valtype Valtype;
449883529b6Schristos
450883529b6Schristos static inline Valtype
451883529b6Schristos readval(const unsigned char* wv)
452883529b6Schristos { return Swap<size, big_endian>::readval(
453883529b6Schristos reinterpret_cast<const Valtype*>(wv)); }
454883529b6Schristos
455883529b6Schristos static inline void
456883529b6Schristos writeval(unsigned char* wv, Valtype v)
457883529b6Schristos { Swap<size, big_endian>::writeval(reinterpret_cast<Valtype*>(wv), v); }
458883529b6Schristos };
459883529b6Schristos
460883529b6Schristos template<>
461883529b6Schristos struct Swap_aligned32<64, true>
462883529b6Schristos {
463883529b6Schristos typedef Valtype_base<64>::Valtype Valtype;
464883529b6Schristos
465883529b6Schristos static inline Valtype
466883529b6Schristos readval(const unsigned char* wv)
467883529b6Schristos {
468883529b6Schristos return ((static_cast<Valtype>(Swap<32, true>::readval(wv)) << 32)
469883529b6Schristos | static_cast<Valtype>(Swap<32, true>::readval(wv + 4)));
470883529b6Schristos }
471883529b6Schristos
472883529b6Schristos static inline void
473883529b6Schristos writeval(unsigned char* wv, Valtype v)
474883529b6Schristos {
475883529b6Schristos typedef Valtype_base<32>::Valtype Valtype32;
476883529b6Schristos
477883529b6Schristos Swap<32, true>::writeval(wv, static_cast<Valtype32>(v >> 32));
478883529b6Schristos Swap<32, true>::writeval(wv + 4, static_cast<Valtype32>(v));
479883529b6Schristos }
480883529b6Schristos };
481883529b6Schristos
482883529b6Schristos template<>
483883529b6Schristos struct Swap_aligned32<64, false>
484883529b6Schristos {
485883529b6Schristos typedef Valtype_base<64>::Valtype Valtype;
486883529b6Schristos
487883529b6Schristos static inline Valtype
488883529b6Schristos readval(const unsigned char* wv)
489883529b6Schristos {
490883529b6Schristos return ((static_cast<Valtype>(Swap<32, false>::readval(wv + 4)) << 32)
491883529b6Schristos | static_cast<Valtype>(Swap<32, false>::readval(wv)));
492883529b6Schristos }
493883529b6Schristos
494883529b6Schristos static inline void
495883529b6Schristos writeval(unsigned char* wv, Valtype v)
496883529b6Schristos {
497883529b6Schristos typedef Valtype_base<32>::Valtype Valtype32;
498883529b6Schristos
499883529b6Schristos Swap<32, false>::writeval(wv + 4, static_cast<Valtype32>(v >> 32));
500883529b6Schristos Swap<32, false>::writeval(wv, static_cast<Valtype32>(v));
501883529b6Schristos }
502883529b6Schristos };
503883529b6Schristos
5042a6b7db3Sskrll } // End namespace elfcpp.
5052a6b7db3Sskrll
5062a6b7db3Sskrll #endif // !defined(ELFCPP_SWAP_H)
507