123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- // elfcpp_swap.h -- Handle swapping for elfcpp -*- C++ -*-
- // Copyright (C) 2006-2017 Free Software Foundation, Inc.
- // Written by Ian Lance Taylor <iant@google.com>.
- // This file is part of elfcpp.
-
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU Library General Public License
- // as published by the Free Software Foundation; either version 2, or
- // (at your option) any later version.
- // In addition to the permissions in the GNU Library General Public
- // License, the Free Software Foundation gives you unlimited
- // permission to link the compiled version of this file into
- // combinations with other programs, and to distribute those
- // combinations without any restriction coming from the use of this
- // file. (The Library Public License restrictions do apply in other
- // respects; for example, they cover modification of the file, and
- /// distribution when not linked into a combined executable.)
- // This program is distributed in the hope that it will be useful, but
- // WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // Library General Public License for more details.
- // You should have received a copy of the GNU Library General Public
- // License along with this program; if not, write to the Free Software
- // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
- // 02110-1301, USA.
- // This header file defines basic template classes to efficiently swap
- // numbers between host form and target form. When the host and
- // target have the same endianness, these turn into no-ops.
- #ifndef ELFCPP_SWAP_H
- #define ELFCPP_SWAP_H
- #include <stdint.h>
- // We need an autoconf-generated config.h file for endianness and
- // swapping. We check two macros: WORDS_BIGENDIAN and
- // HAVE_BYTESWAP_H.
- #include "config.h"
- #ifdef HAVE_BYTESWAP_H
- #include <byteswap.h>
- #else
- // Provide our own versions of the byteswap functions.
- inline uint16_t
- bswap_16(uint16_t v)
- {
- return ((v >> 8) & 0xff) | ((v & 0xff) << 8);
- }
- inline uint32_t
- bswap_32(uint32_t v)
- {
- return ( ((v & 0xff000000) >> 24)
- | ((v & 0x00ff0000) >> 8)
- | ((v & 0x0000ff00) << 8)
- | ((v & 0x000000ff) << 24));
- }
- inline uint64_t
- bswap_64(uint64_t v)
- {
- return ( ((v & 0xff00000000000000ULL) >> 56)
- | ((v & 0x00ff000000000000ULL) >> 40)
- | ((v & 0x0000ff0000000000ULL) >> 24)
- | ((v & 0x000000ff00000000ULL) >> 8)
- | ((v & 0x00000000ff000000ULL) << 8)
- | ((v & 0x0000000000ff0000ULL) << 24)
- | ((v & 0x000000000000ff00ULL) << 40)
- | ((v & 0x00000000000000ffULL) << 56));
- }
- #endif // !defined(HAVE_BYTESWAP_H)
- // gcc 4.3 and later provides __builtin_bswap32 and __builtin_bswap64.
- #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
- #undef bswap_32
- #define bswap_32 __builtin_bswap32
- #undef bswap_64
- #define bswap_64 __builtin_bswap64
- #endif
- namespace elfcpp
- {
- // Endian simply indicates whether the host is big endian or not.
- struct Endian
- {
- public:
- // Used for template specializations.
- static const bool host_big_endian =
- #ifdef WORDS_BIGENDIAN
- true
- #else
- false
- #endif
- ;
- };
- // Valtype_base is a template based on size (8, 16, 32, 64) which
- // defines the type Valtype as the unsigned integer, and
- // Signed_valtype as the signed integer, of the specified size.
- template<int size>
- struct Valtype_base;
- template<>
- struct Valtype_base<8>
- {
- typedef uint8_t Valtype;
- typedef int8_t Signed_valtype;
- };
- template<>
- struct Valtype_base<16>
- {
- typedef uint16_t Valtype;
- typedef int16_t Signed_valtype;
- };
- template<>
- struct Valtype_base<32>
- {
- typedef uint32_t Valtype;
- typedef int32_t Signed_valtype;
- };
- template<>
- struct Valtype_base<64>
- {
- typedef uint64_t Valtype;
- typedef int64_t Signed_valtype;
- };
- // Convert_endian is a template based on size and on whether the host
- // and target have the same endianness. It defines the type Valtype
- // as Valtype_base does, and also defines a function convert_host
- // which takes an argument of type Valtype and returns the same value,
- // but swapped if the host and target have different endianness.
- template<int size, bool same_endian>
- struct Convert_endian;
- template<int size>
- struct Convert_endian<size, true>
- {
- typedef typename Valtype_base<size>::Valtype Valtype;
- static inline Valtype
- convert_host(Valtype v)
- { return v; }
- };
- template<>
- struct Convert_endian<8, false>
- {
- typedef Valtype_base<8>::Valtype Valtype;
- static inline Valtype
- convert_host(Valtype v)
- { return v; }
- };
- template<>
- struct Convert_endian<16, false>
- {
- typedef Valtype_base<16>::Valtype Valtype;
- static inline Valtype
- convert_host(Valtype v)
- { return bswap_16(v); }
- };
- template<>
- struct Convert_endian<32, false>
- {
- typedef Valtype_base<32>::Valtype Valtype;
- static inline Valtype
- convert_host(Valtype v)
- { return bswap_32(v); }
- };
- template<>
- struct Convert_endian<64, false>
- {
- typedef Valtype_base<64>::Valtype Valtype;
- static inline Valtype
- convert_host(Valtype v)
- { return bswap_64(v); }
- };
- // Convert is a template based on size and on whether the target is
- // big endian. It defines Valtype and convert_host like
- // Convert_endian. That is, it is just like Convert_endian except in
- // the meaning of the second template parameter.
- template<int size, bool big_endian>
- struct Convert
- {
- typedef typename Valtype_base<size>::Valtype Valtype;
- static inline Valtype
- convert_host(Valtype v)
- {
- return Convert_endian<size, big_endian == Endian::host_big_endian>
- ::convert_host(v);
- }
- };
- // Swap is a template based on size and on whether the target is big
- // endian. It defines the type Valtype and the functions readval and
- // writeval. The functions read and write values of the appropriate
- // size out of buffers, swapping them if necessary. readval and
- // writeval are overloaded to take pointers to the appropriate type or
- // pointers to unsigned char.
- template<int size, bool big_endian>
- struct Swap
- {
- typedef typename Valtype_base<size>::Valtype Valtype;
- static inline Valtype
- readval(const Valtype* wv)
- { return Convert<size, big_endian>::convert_host(*wv); }
- static inline void
- writeval(Valtype* wv, Valtype v)
- { *wv = Convert<size, big_endian>::convert_host(v); }
- static inline Valtype
- readval(const unsigned char* wv)
- { return readval(reinterpret_cast<const Valtype*>(wv)); }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- { writeval(reinterpret_cast<Valtype*>(wv), v); }
- };
- // We need to specialize the 8-bit version of Swap to avoid
- // conflicting overloads, since both versions of readval and writeval
- // will have the same type parameters.
- template<bool big_endian>
- struct Swap<8, big_endian>
- {
- typedef typename Valtype_base<8>::Valtype Valtype;
- static inline Valtype
- readval(const Valtype* wv)
- { return *wv; }
- static inline void
- writeval(Valtype* wv, Valtype v)
- { *wv = v; }
- };
- // Swap_unaligned is a template based on size and on whether the
- // target is big endian. It defines the type Valtype and the
- // functions readval and writeval. The functions read and write
- // values of the appropriate size out of buffers which may be
- // misaligned.
- template<int size, bool big_endian>
- struct Swap_unaligned;
- template<bool big_endian>
- struct Swap_unaligned<8, big_endian>
- {
- typedef typename Valtype_base<8>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- { return *wv; }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- { *wv = v; }
- };
- template<>
- struct Swap_unaligned<16, false>
- {
- typedef Valtype_base<16>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- {
- return (wv[1] << 8) | wv[0];
- }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- {
- wv[1] = v >> 8;
- wv[0] = v;
- }
- };
- template<>
- struct Swap_unaligned<16, true>
- {
- typedef Valtype_base<16>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- {
- return (wv[0] << 8) | wv[1];
- }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- {
- wv[0] = v >> 8;
- wv[1] = v;
- }
- };
- template<>
- struct Swap_unaligned<32, false>
- {
- typedef Valtype_base<32>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- {
- return (wv[3] << 24) | (wv[2] << 16) | (wv[1] << 8) | wv[0];
- }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- {
- wv[3] = v >> 24;
- wv[2] = v >> 16;
- wv[1] = v >> 8;
- wv[0] = v;
- }
- };
- template<>
- struct Swap_unaligned<32, true>
- {
- typedef Valtype_base<32>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- {
- return (wv[0] << 24) | (wv[1] << 16) | (wv[2] << 8) | wv[3];
- }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- {
- wv[0] = v >> 24;
- wv[1] = v >> 16;
- wv[2] = v >> 8;
- wv[3] = v;
- }
- };
- template<>
- struct Swap_unaligned<64, false>
- {
- typedef Valtype_base<64>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- {
- return ((static_cast<Valtype>(wv[7]) << 56)
- | (static_cast<Valtype>(wv[6]) << 48)
- | (static_cast<Valtype>(wv[5]) << 40)
- | (static_cast<Valtype>(wv[4]) << 32)
- | (static_cast<Valtype>(wv[3]) << 24)
- | (static_cast<Valtype>(wv[2]) << 16)
- | (static_cast<Valtype>(wv[1]) << 8)
- | static_cast<Valtype>(wv[0]));
- }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- {
- wv[7] = v >> 56;
- wv[6] = v >> 48;
- wv[5] = v >> 40;
- wv[4] = v >> 32;
- wv[3] = v >> 24;
- wv[2] = v >> 16;
- wv[1] = v >> 8;
- wv[0] = v;
- }
- };
- template<>
- struct Swap_unaligned<64, true>
- {
- typedef Valtype_base<64>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- {
- return ((static_cast<Valtype>(wv[0]) << 56)
- | (static_cast<Valtype>(wv[1]) << 48)
- | (static_cast<Valtype>(wv[2]) << 40)
- | (static_cast<Valtype>(wv[3]) << 32)
- | (static_cast<Valtype>(wv[4]) << 24)
- | (static_cast<Valtype>(wv[5]) << 16)
- | (static_cast<Valtype>(wv[6]) << 8)
- | static_cast<Valtype>(wv[7]));
- }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- {
- wv[0] = v >> 56;
- wv[1] = v >> 48;
- wv[2] = v >> 40;
- wv[3] = v >> 32;
- wv[4] = v >> 24;
- wv[5] = v >> 16;
- wv[6] = v >> 8;
- wv[7] = v;
- }
- };
- // Swap_aligned32 is a template based on size and on whether the
- // target is big endian. It defines the type Valtype and the
- // functions readval and writeval. The functions read and write
- // values of the appropriate size out of buffers which may not be
- // 64-bit aligned, but are 32-bit aligned.
- template<int size, bool big_endian>
- struct Swap_aligned32
- {
- typedef typename Valtype_base<size>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- { return Swap<size, big_endian>::readval(
- reinterpret_cast<const Valtype*>(wv)); }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- { Swap<size, big_endian>::writeval(reinterpret_cast<Valtype*>(wv), v); }
- };
- template<>
- struct Swap_aligned32<64, true>
- {
- typedef Valtype_base<64>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- {
- return ((static_cast<Valtype>(Swap<32, true>::readval(wv)) << 32)
- | static_cast<Valtype>(Swap<32, true>::readval(wv + 4)));
- }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- {
- typedef Valtype_base<32>::Valtype Valtype32;
- Swap<32, true>::writeval(wv, static_cast<Valtype32>(v >> 32));
- Swap<32, true>::writeval(wv + 4, static_cast<Valtype32>(v));
- }
- };
- template<>
- struct Swap_aligned32<64, false>
- {
- typedef Valtype_base<64>::Valtype Valtype;
- static inline Valtype
- readval(const unsigned char* wv)
- {
- return ((static_cast<Valtype>(Swap<32, false>::readval(wv + 4)) << 32)
- | static_cast<Valtype>(Swap<32, false>::readval(wv)));
- }
- static inline void
- writeval(unsigned char* wv, Valtype v)
- {
- typedef Valtype_base<32>::Valtype Valtype32;
- Swap<32, false>::writeval(wv + 4, static_cast<Valtype32>(v >> 32));
- Swap<32, false>::writeval(wv, static_cast<Valtype32>(v));
- }
- };
- } // End namespace elfcpp.
- #endif // !defined(ELFCPP_SWAP_H)
|