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