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