X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=elfcpp%2Felfcpp_swap.h;h=e1f527aec419ecf61b3ea1e68fad7fb5e1456b0c;hb=036003a671233c43e35b3004f91e4cbd61255cf3;hp=71b02eb8d3680cbccd2d124f8e8c56b5857f54b9;hpb=a3ad94edd406b9abc26493761764d4034dda69fa;p=deliverable%2Fbinutils-gdb.git diff --git a/elfcpp/elfcpp_swap.h b/elfcpp/elfcpp_swap.h index 71b02eb8d3..e1f527aec4 100644 --- a/elfcpp/elfcpp_swap.h +++ b/elfcpp/elfcpp_swap.h @@ -1,5 +1,34 @@ // elfcpp_swap.h -- Handle swapping for elfcpp -*- C++ -*- +// Copyright (C) 2006-2019 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. @@ -8,8 +37,54 @@ #define ELFCPP_SWAP_H #include -#include + +// 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 +#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 { @@ -20,12 +95,18 @@ struct Endian { public: // Used for template specializations. - static const bool host_big_endian = __BYTE_ORDER == __BIG_ENDIAN; + 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 of the specified -// size. +// defines the type Valtype as the unsigned integer, and +// Signed_valtype as the signed integer, of the specified size. template struct Valtype_base; @@ -33,25 +114,29 @@ struct Valtype_base; template<> struct Valtype_base<8> { - typedef unsigned char Valtype; + 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 @@ -334,14 +419,79 @@ struct Swap_unaligned<64, true> 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; + 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 +struct Swap_aligned32 +{ + typedef typename Valtype_base::Valtype Valtype; + + static inline Valtype + readval(const unsigned char* wv) + { return Swap::readval( + reinterpret_cast(wv)); } + + static inline void + writeval(unsigned char* wv, Valtype v) + { Swap::writeval(reinterpret_cast(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(Swap<32, true>::readval(wv)) << 32) + | static_cast(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(v >> 32)); + Swap<32, true>::writeval(wv + 4, static_cast(v)); + } +}; + +template<> +struct Swap_aligned32<64, false> +{ + typedef Valtype_base<64>::Valtype Valtype; + + static inline Valtype + readval(const unsigned char* wv) + { + return ((static_cast(Swap<32, false>::readval(wv + 4)) << 32) + | static_cast(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(v >> 32)); + Swap<32, false>::writeval(wv, static_cast(v)); } };