xref: /netbsd-src/external/gpl3/binutils/dist/elfcpp/elfcpp_swap.h (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
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