/* bele.h -- access memory in BigEndian and LittleEndian byte order This file is part of the UPX executable compressor. Copyright (C) 1996-2024 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996-2024 Laszlo Molnar All Rights Reserved. UPX and the UCL library are free software; you can redistribute them and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Markus F.X.J. Oberhumer Laszlo Molnar */ #pragma once // BE - Big Endian // LE - Little Endian // NE - Native Endianness (aka Host Endianness aka CPU Endianness) // TE - Target Endianness (not used here, see various packers) static_assert(std::is_same_v); static_assert(std::is_same_v); #if defined(upx_is_constant_evaluated) #define bele_constexpr constexpr #else #define bele_constexpr /*empty*/ #endif // forward declarations struct BE16; struct BE32; struct BE64; struct LE16; struct LE32; struct LE64; /************************************************************************* // XE - eXtended Endian compatibility // try to detect XX16 vs XX32 vs XX64 size mismatches **************************************************************************/ #if !defined(upx_is_constant_evaluated) && !(DEBUG) // permissive version using "void *" #define REQUIRE_XE16 /*empty*/ #define REQUIRE_XE24 /*empty*/ #define REQUIRE_XE32 /*empty*/ #define REQUIRE_XE64 /*empty*/ typedef void XE16; typedef void XE24; typedef void XE32; typedef void XE64; #else // permissive version namespace bele_detail { // Note: // void is explicitly allowed (but there is no automatic pointer conversion because of template!) // char is explicitly allowed // byte is explicitly allowed template inline constexpr bool is_xe16_type = upx::is_same_any_v; template inline constexpr bool is_xe24_type = upx::is_same_any_v; template inline constexpr bool is_xe32_type = upx::is_same_any_v; template inline constexpr bool is_xe64_type = upx::is_same_any_v; template using enable_if_xe16 = std::enable_if_t, T>; template using enable_if_xe24 = std::enable_if_t, T>; template using enable_if_xe32 = std::enable_if_t, T>; template using enable_if_xe64 = std::enable_if_t, T>; } // namespace bele_detail #define REQUIRE_XE16 template > #define REQUIRE_XE24 template > #define REQUIRE_XE32 template > #define REQUIRE_XE64 template > #endif // permissive version /************************************************************************* // core - NE **************************************************************************/ forceinline bele_constexpr unsigned get_ne16(const byte *p) noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::get_ne16(p); else #endif { upx_uint16_t v = 0; upx_memcpy_inline(&v, p, sizeof(v)); return v; } } forceinline bele_constexpr unsigned get_ne32(const byte *p) noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::get_ne32(p); else #endif { upx_uint32_t v = 0; upx_memcpy_inline(&v, p, sizeof(v)); return v; } } forceinline bele_constexpr upx_uint64_t get_ne64(const byte *p) noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::get_ne64(p); else #endif { upx_uint64_t v = 0; upx_memcpy_inline(&v, p, sizeof(v)); return v; } } forceinline bele_constexpr void set_ne16(byte *p, unsigned v) noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) upx::compile_time::set_ne16(p, upx_uint16_t(v & 0xffff)); else #endif { upx_uint16_t vv = upx_uint16_t(v & 0xffff); upx_memcpy_inline(p, &vv, sizeof(vv)); } } forceinline bele_constexpr void set_ne32(byte *p, unsigned v) noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) upx::compile_time::set_ne32(p, v); else #endif { upx_uint32_t vv = v; upx_memcpy_inline(p, &vv, sizeof(vv)); } } forceinline bele_constexpr void set_ne64(byte *p, upx_uint64_t v) noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) upx::compile_time::set_ne64(p, v); else #endif { upx_uint64_t vv = v; upx_memcpy_inline(p, &vv, sizeof(vv)); } } /************************************************************************* // core - NE **************************************************************************/ REQUIRE_XE16 forceinline bele_constexpr unsigned get_ne16(const XE16 *p) noexcept { return get_ne16(upx::ptr_static_cast(p)); } REQUIRE_XE32 forceinline bele_constexpr unsigned get_ne32(const XE32 *p) noexcept { return get_ne32(upx::ptr_static_cast(p)); } REQUIRE_XE64 forceinline bele_constexpr upx_uint64_t get_ne64(const XE64 *p) noexcept { return get_ne64(upx::ptr_static_cast(p)); } REQUIRE_XE16 forceinline bele_constexpr void set_ne16(XE16 *p, unsigned v) noexcept { set_ne16(upx::ptr_static_cast(p), v); } REQUIRE_XE32 forceinline bele_constexpr void set_ne32(XE32 *p, unsigned v) noexcept { set_ne32(upx::ptr_static_cast(p), v); } REQUIRE_XE64 forceinline bele_constexpr void set_ne64(XE64 *p, upx_uint64_t v) noexcept { set_ne64(upx::ptr_static_cast(p), v); } /************************************************************************* // core - bswap **************************************************************************/ #if __cpp_lib_byteswap >= 202110L forceinline constexpr unsigned bswap16(unsigned v) noexcept { return std::byteswap(upx_uint16_t(v & 0xffff)); } forceinline constexpr unsigned bswap32(unsigned v) noexcept { return std::byteswap(v); } forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) noexcept { return std::byteswap(v); } #elif (ACC_CC_MSC) static_assert(sizeof(long) == 4); // _byteswap_XXX is unfortunately *not* constexpr with current MSVC forceinline bele_constexpr unsigned bswap16(unsigned v) noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::bswap16(upx_uint16_t(v & 0xffff)); else #endif return (unsigned) _byteswap_ulong(v << 16); } forceinline bele_constexpr unsigned bswap32(unsigned v) noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::bswap32(v); else #endif return (unsigned) _byteswap_ulong(v); } forceinline bele_constexpr upx_uint64_t bswap64(upx_uint64_t v) noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::bswap64(v); else #endif return _byteswap_uint64(v); } #else forceinline constexpr unsigned bswap16(unsigned v) noexcept { #if defined(__riscv) && __riscv_xlen == 64 return (unsigned) __builtin_bswap64(upx_uint64_t(v) << 48); #else // return __builtin_bswap16(upx_uint16_t(v & 0xffff)); return __builtin_bswap32(v << 16); #endif } forceinline constexpr unsigned bswap32(unsigned v) noexcept { #if defined(__riscv) && __riscv_xlen == 64 return (unsigned) __builtin_bswap64(upx_uint64_t(v) << 32); #else return __builtin_bswap32(v); #endif } forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) noexcept { return __builtin_bswap64(v); } #endif forceinline constexpr unsigned no_bswap16(unsigned v) noexcept { // mask is needed so that for all v: bswap16(bswap16(v)) == no_bswap16(v) return v & 0xffff; } forceinline constexpr unsigned no_bswap32(unsigned v) noexcept { return v; } forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) noexcept { return v; } #if (ACC_ABI_BIG_ENDIAN) #define ne16_to_be16(v) no_bswap16(v) #define ne32_to_be32(v) no_bswap32(v) #define ne64_to_be64(v) no_bswap64(v) #define ne16_to_le16(v) bswap16(v) #define ne32_to_le32(v) bswap32(v) #define ne64_to_le64(v) bswap64(v) #else #define ne16_to_be16(v) bswap16(v) #define ne32_to_be32(v) bswap32(v) #define ne64_to_be64(v) bswap64(v) #define ne16_to_le16(v) no_bswap16(v) #define ne32_to_le32(v) no_bswap32(v) #define ne64_to_le64(v) no_bswap64(v) #endif /************************************************************************* // get/set 16/32/64 **************************************************************************/ REQUIRE_XE16 inline bele_constexpr unsigned get_be16(const XE16 *p) noexcept { return ne16_to_be16(get_ne16(p)); } REQUIRE_XE32 inline bele_constexpr unsigned get_be32(const XE32 *p) noexcept { return ne32_to_be32(get_ne32(p)); } REQUIRE_XE64 inline bele_constexpr upx_uint64_t get_be64(const XE64 *p) noexcept { return ne64_to_be64(get_ne64(p)); } REQUIRE_XE16 inline bele_constexpr unsigned get_le16(const XE16 *p) noexcept { return ne16_to_le16(get_ne16(p)); } REQUIRE_XE32 inline bele_constexpr unsigned get_le32(const XE32 *p) noexcept { return ne32_to_le32(get_ne32(p)); } REQUIRE_XE64 inline bele_constexpr upx_uint64_t get_le64(const XE64 *p) noexcept { return ne64_to_le64(get_ne64(p)); } REQUIRE_XE16 inline bele_constexpr void set_be16(XE16 *p, unsigned v) noexcept { set_ne16(p, ne16_to_be16(v)); } REQUIRE_XE32 inline bele_constexpr void set_be32(XE32 *p, unsigned v) noexcept { set_ne32(p, ne32_to_be32(v)); } REQUIRE_XE64 inline bele_constexpr void set_be64(XE64 *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_be64(v)); } REQUIRE_XE16 inline bele_constexpr void set_le16(XE16 *p, unsigned v) noexcept { set_ne16(p, ne16_to_le16(v)); } REQUIRE_XE32 inline bele_constexpr void set_le32(XE32 *p, unsigned v) noexcept { set_ne32(p, ne32_to_le32(v)); } REQUIRE_XE64 inline bele_constexpr void set_le64(XE64 *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_le64(v)); } /************************************************************************* // get/set 24/26 **************************************************************************/ inline constexpr unsigned get_be24(const byte *p) noexcept { return upx::compile_time::get_be24(p); } inline constexpr unsigned get_le24(const byte *p) noexcept { return upx::compile_time::get_le24(p); } inline constexpr void set_be24(byte *p, unsigned v) noexcept { upx::compile_time::set_be24(p, v); } inline constexpr void set_le24(byte *p, unsigned v) noexcept { upx::compile_time::set_le24(p, v); } REQUIRE_XE24 forceinline bele_constexpr unsigned get_be24(const XE24 *p) noexcept { return get_be24(upx::ptr_static_cast(p)); } REQUIRE_XE24 forceinline bele_constexpr unsigned get_le24(const XE24 *p) noexcept { return get_le24(upx::ptr_static_cast(p)); } REQUIRE_XE24 forceinline bele_constexpr void set_be24(XE24 *p, unsigned v) noexcept { set_be24(upx::ptr_static_cast(p), v); } REQUIRE_XE24 forceinline bele_constexpr void set_le24(XE24 *p, unsigned v) noexcept { set_le24(upx::ptr_static_cast(p), v); } REQUIRE_XE32 inline bele_constexpr unsigned get_le26(const XE32 *p) noexcept { return get_le32(p) & 0x03ffffff; } REQUIRE_XE32 inline bele_constexpr unsigned get_le19_5(const XE32 *p) noexcept { return (get_le32(p) >> 5) & 0x0007ffff; } REQUIRE_XE32 inline bele_constexpr unsigned get_le14_5(const XE32 *p) noexcept { return (get_le32(p) >> 5) & 0x00003fff; } REQUIRE_XE32 inline bele_constexpr void set_le26(XE32 *p, unsigned v) noexcept { // preserve the top 6 bits // set_le32(p, (get_le32(p) & 0xfc000000) | (v & 0x03ffffff)); // optimized version, saving a runtime bswap32 set_ne32(p, (get_ne32(p) & ne32_to_le32(0xfc000000)) | (ne32_to_le32(v) & ne32_to_le32(0x03ffffff))); } REQUIRE_XE32 inline bele_constexpr void set_le19_5(XE32 *p, unsigned v) noexcept { set_le32(p, (get_le32(p) & 0xff00001f) | ((v & 0x0007ffff) << 5)); } REQUIRE_XE32 inline bele_constexpr void set_le14_5(XE32 *p, unsigned v) noexcept { set_le32(p, (get_le32(p) & 0xfff8001f) | ((v & 0x00003fff) << 5)); } /************************************************************************* // get signed values **************************************************************************/ forceinline constexpr int sign_extend(unsigned v, unsigned bits) noexcept { #if (ACC_ARCH_M68K) // no barrel shifter const unsigned sign_bit = 1u << (bits - 1); return ACC_ICAST(int, (v & (sign_bit - 1)) - (v & sign_bit)); #else return ACC_ICAST(int, v << (32 - bits)) >> (32 - bits); #endif } forceinline constexpr upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) noexcept { #if (ACC_ARCH_M68K) // no barrel shifter const upx_uint64_t sign_bit = upx_uint64_t(1) << (bits - 1); return ACC_ICAST(upx_int64_t, (v & (sign_bit - 1)) - (v & sign_bit)); #else return ACC_ICAST(upx_int64_t, v << (64 - bits)) >> (64 - bits); #endif } REQUIRE_XE16 inline bele_constexpr int get_be16_signed(const XE16 *p) noexcept { unsigned v = get_be16(p); return sign_extend(v, 16); } REQUIRE_XE24 inline bele_constexpr int get_be24_signed(const XE24 *p) noexcept { unsigned v = get_be24(p); return sign_extend(v, 24); } REQUIRE_XE32 inline bele_constexpr int get_be32_signed(const XE32 *p) noexcept { unsigned v = get_be32(p); return sign_extend(v, 32); } REQUIRE_XE64 inline bele_constexpr upx_int64_t get_be64_signed(const XE64 *p) noexcept { upx_uint64_t v = get_be64(p); return sign_extend(v, 64); } REQUIRE_XE16 inline bele_constexpr int get_le16_signed(const XE16 *p) noexcept { unsigned v = get_le16(p); return sign_extend(v, 16); } REQUIRE_XE24 inline bele_constexpr int get_le24_signed(const XE24 *p) noexcept { unsigned v = get_le24(p); return sign_extend(v, 24); } REQUIRE_XE32 inline bele_constexpr int get_le32_signed(const XE32 *p) noexcept { unsigned v = get_le32(p); return sign_extend(v, 32); } REQUIRE_XE64 inline bele_constexpr upx_int64_t get_le64_signed(const XE64 *p) noexcept { upx_uint64_t v = get_le64(p); return sign_extend(v, 64); } /************************************************************************* // classes for portable unaligned access // // Note: these classes must be PODs (Plain Old Data), i.e. no // constructor, no destructor, no virtual functions and no default // assignment operator, and all fields must be public **************************************************************************/ struct alignas(1) BE16 final { typedef unsigned integral_conversion_type; // automatic conversion to unsigned byte d[2]; static forceinline constexpr BE16 make(const BE16 &x) noexcept { return x; } static forceinline bele_constexpr BE16 make(unsigned v) noexcept { BE16 x = {}; set_be16(x.d, v); return x; } forceinline bele_constexpr operator unsigned() const noexcept { return get_be16(d); } forceinline bele_constexpr BE16 &operator=(unsigned v) noexcept { set_be16(d, v); return *this; } BE16 &operator+=(unsigned v) noexcept { set_be16(d, get_be16(d) + v); return *this; } BE16 &operator-=(unsigned v) noexcept { set_be16(d, get_be16(d) - v); return *this; } BE16 &operator*=(unsigned v) noexcept { set_be16(d, get_be16(d) * v); return *this; } BE16 &operator/=(unsigned v) noexcept { set_be16(d, get_be16(d) / v); return *this; } BE16 &operator&=(unsigned v) noexcept { set_be16(d, get_be16(d) & v); return *this; } BE16 &operator|=(unsigned v) noexcept { set_be16(d, get_be16(d) | v); return *this; } BE16 &operator^=(unsigned v) noexcept { set_be16(d, get_be16(d) ^ v); return *this; } BE16 &operator<<=(unsigned v) noexcept { set_be16(d, get_be16(d) << v); return *this; } BE16 &operator>>=(unsigned v) noexcept { set_be16(d, get_be16(d) >> v); return *this; } bele_constexpr bool operator==(const BE16 &x) const noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::mem_eq(d, x.d, sizeof(d)); else #endif return upx_memcmp_inline(d, x.d, sizeof(d)) == 0; } bele_constexpr bool operator<(const BE16 &x) const noexcept { return unsigned(*this) < unsigned(x); } }; struct alignas(1) BE32 final { typedef unsigned integral_conversion_type; // automatic conversion to unsigned byte d[4]; static forceinline constexpr BE32 make(const BE32 &x) noexcept { return x; } static forceinline bele_constexpr BE32 make(unsigned v) noexcept { BE32 x = {}; set_be32(x.d, v); return x; } forceinline bele_constexpr operator unsigned() const noexcept { return get_be32(d); } forceinline bele_constexpr BE32 &operator=(unsigned v) noexcept { set_be32(d, v); return *this; } BE32 &operator+=(unsigned v) noexcept { set_be32(d, get_be32(d) + v); return *this; } BE32 &operator-=(unsigned v) noexcept { set_be32(d, get_be32(d) - v); return *this; } BE32 &operator*=(unsigned v) noexcept { set_be32(d, get_be32(d) * v); return *this; } BE32 &operator/=(unsigned v) noexcept { set_be32(d, get_be32(d) / v); return *this; } BE32 &operator&=(unsigned v) noexcept { set_be32(d, get_be32(d) & v); return *this; } BE32 &operator|=(unsigned v) noexcept { set_be32(d, get_be32(d) | v); return *this; } BE32 &operator^=(unsigned v) noexcept { set_be32(d, get_be32(d) ^ v); return *this; } BE32 &operator<<=(unsigned v) noexcept { set_be32(d, get_be32(d) << v); return *this; } BE32 &operator>>=(unsigned v) noexcept { set_be32(d, get_be32(d) >> v); return *this; } bele_constexpr bool operator==(const BE32 &x) const noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::mem_eq(d, x.d, sizeof(d)); else #endif return upx_memcmp_inline(d, x.d, sizeof(d)) == 0; } bele_constexpr bool operator<(const BE32 &x) const noexcept { return unsigned(*this) < unsigned(x); } }; struct alignas(1) BE64 final { typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t byte d[8]; static forceinline constexpr BE64 make(const BE64 &x) noexcept { return x; } static forceinline bele_constexpr BE64 make(upx_uint64_t v) noexcept { BE64 x = {}; set_be64(x.d, v); return x; } forceinline bele_constexpr operator upx_uint64_t() const noexcept { return get_be64(d); } forceinline bele_constexpr BE64 &operator=(upx_uint64_t v) noexcept { set_be64(d, v); return *this; } BE64 &operator+=(upx_uint64_t v) noexcept { set_be64(d, get_be64(d) + v); return *this; } BE64 &operator-=(upx_uint64_t v) noexcept { set_be64(d, get_be64(d) - v); return *this; } BE64 &operator*=(upx_uint64_t v) noexcept { set_be64(d, get_be64(d) * v); return *this; } BE64 &operator/=(upx_uint64_t v) noexcept { set_be64(d, get_be64(d) / v); return *this; } BE64 &operator&=(upx_uint64_t v) noexcept { set_be64(d, get_be64(d) & v); return *this; } BE64 &operator|=(upx_uint64_t v) noexcept { set_be64(d, get_be64(d) | v); return *this; } BE64 &operator^=(upx_uint64_t v) noexcept { set_be64(d, get_be64(d) ^ v); return *this; } BE64 &operator<<=(unsigned v) noexcept { set_be64(d, get_be64(d) << v); return *this; } BE64 &operator>>=(unsigned v) noexcept { set_be64(d, get_be64(d) >> v); return *this; } bele_constexpr bool operator==(const BE64 &x) const noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::mem_eq(d, x.d, sizeof(d)); else #endif return upx_memcmp_inline(d, x.d, sizeof(d)) == 0; } bele_constexpr bool operator<(const BE64 &x) const noexcept { return upx_uint64_t(*this) < upx_uint64_t(x); } }; struct alignas(1) LE16 final { typedef unsigned integral_conversion_type; // automatic conversion to unsigned byte d[2]; static forceinline constexpr LE16 make(const LE16 &x) noexcept { return x; } static forceinline bele_constexpr LE16 make(unsigned v) noexcept { LE16 x = {}; set_le16(x.d, v); return x; } forceinline bele_constexpr operator unsigned() const noexcept { return get_le16(d); } forceinline bele_constexpr LE16 &operator=(unsigned v) noexcept { set_le16(d, v); return *this; } LE16 &operator+=(unsigned v) noexcept { set_le16(d, get_le16(d) + v); return *this; } LE16 &operator-=(unsigned v) noexcept { set_le16(d, get_le16(d) - v); return *this; } LE16 &operator*=(unsigned v) noexcept { set_le16(d, get_le16(d) * v); return *this; } LE16 &operator/=(unsigned v) noexcept { set_le16(d, get_le16(d) / v); return *this; } LE16 &operator&=(unsigned v) noexcept { set_le16(d, get_le16(d) & v); return *this; } LE16 &operator|=(unsigned v) noexcept { set_le16(d, get_le16(d) | v); return *this; } LE16 &operator^=(unsigned v) noexcept { set_le16(d, get_le16(d) ^ v); return *this; } LE16 &operator<<=(unsigned v) noexcept { set_le16(d, get_le16(d) << v); return *this; } LE16 &operator>>=(unsigned v) noexcept { set_le16(d, get_le16(d) >> v); return *this; } bele_constexpr bool operator==(const LE16 &x) const noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::mem_eq(d, x.d, sizeof(d)); else #endif return upx_memcmp_inline(d, x.d, sizeof(d)) == 0; } bele_constexpr bool operator<(const LE16 &x) const noexcept { return unsigned(*this) < unsigned(x); } }; struct alignas(1) LE32 final { typedef unsigned integral_conversion_type; // automatic conversion to unsigned byte d[4]; static forceinline constexpr LE32 make(const LE32 &x) noexcept { return x; } static forceinline bele_constexpr LE32 make(unsigned v) noexcept { LE32 x = {}; set_le32(x.d, v); return x; } forceinline bele_constexpr operator unsigned() const noexcept { return get_le32(d); } forceinline bele_constexpr LE32 &operator=(unsigned v) noexcept { set_le32(d, v); return *this; } LE32 &operator+=(unsigned v) noexcept { set_le32(d, get_le32(d) + v); return *this; } LE32 &operator-=(unsigned v) noexcept { set_le32(d, get_le32(d) - v); return *this; } LE32 &operator*=(unsigned v) noexcept { set_le32(d, get_le32(d) * v); return *this; } LE32 &operator/=(unsigned v) noexcept { set_le32(d, get_le32(d) / v); return *this; } LE32 &operator&=(unsigned v) noexcept { set_le32(d, get_le32(d) & v); return *this; } LE32 &operator|=(unsigned v) noexcept { set_le32(d, get_le32(d) | v); return *this; } LE32 &operator^=(unsigned v) noexcept { set_le32(d, get_le32(d) ^ v); return *this; } LE32 &operator<<=(unsigned v) noexcept { set_le32(d, get_le32(d) << v); return *this; } LE32 &operator>>=(unsigned v) noexcept { set_le32(d, get_le32(d) >> v); return *this; } bele_constexpr bool operator==(const LE32 &x) const noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::mem_eq(d, x.d, sizeof(d)); else #endif return upx_memcmp_inline(d, x.d, sizeof(d)) == 0; } bele_constexpr bool operator<(const LE32 &x) const noexcept { return unsigned(*this) < unsigned(x); } }; struct alignas(1) LE64 final { typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t byte d[8]; static forceinline constexpr LE64 make(const LE64 &x) noexcept { return x; } static forceinline bele_constexpr LE64 make(upx_uint64_t v) noexcept { LE64 x = {}; set_le64(x.d, v); return x; } forceinline bele_constexpr operator upx_uint64_t() const noexcept { return get_le64(d); } forceinline bele_constexpr LE64 &operator=(upx_uint64_t v) noexcept { set_le64(d, v); return *this; } LE64 &operator+=(upx_uint64_t v) noexcept { set_le64(d, get_le64(d) + v); return *this; } LE64 &operator-=(upx_uint64_t v) noexcept { set_le64(d, get_le64(d) - v); return *this; } LE64 &operator*=(upx_uint64_t v) noexcept { set_le64(d, get_le64(d) * v); return *this; } LE64 &operator/=(upx_uint64_t v) noexcept { set_le64(d, get_le64(d) / v); return *this; } LE64 &operator&=(upx_uint64_t v) noexcept { set_le64(d, get_le64(d) & v); return *this; } LE64 &operator|=(upx_uint64_t v) noexcept { set_le64(d, get_le64(d) | v); return *this; } LE64 &operator^=(upx_uint64_t v) noexcept { set_le64(d, get_le64(d) ^ v); return *this; } LE64 &operator<<=(unsigned v) noexcept { set_le64(d, get_le64(d) << v); return *this; } LE64 &operator>>=(unsigned v) noexcept { set_le64(d, get_le64(d) >> v); return *this; } bele_constexpr bool operator==(const LE64 &x) const noexcept { #if defined(upx_is_constant_evaluated) if (upx_is_constant_evaluated()) return upx::compile_time::mem_eq(d, x.d, sizeof(d)); else #endif return upx_memcmp_inline(d, x.d, sizeof(d)) == 0; } bele_constexpr bool operator<(const LE64 &x) const noexcept { return upx_uint64_t(*this) < upx_uint64_t(x); } }; /************************************************************************* // global operators (pointer addition/subtraction) **************************************************************************/ template inline bele_constexpr T *operator+(T *ptr, const BE16 &v) noexcept { return ptr + unsigned(v); } template inline bele_constexpr T *operator-(T *ptr, const BE16 &v) noexcept { return ptr - unsigned(v); } template inline bele_constexpr T *operator+(T *ptr, const BE32 &v) noexcept { return ptr + unsigned(v); } template inline bele_constexpr T *operator-(T *ptr, const BE32 &v) noexcept { return ptr - unsigned(v); } template inline bele_constexpr T *operator+(T *ptr, const LE16 &v) noexcept { return ptr + unsigned(v); } template inline bele_constexpr T *operator-(T *ptr, const LE16 &v) noexcept { return ptr - unsigned(v); } template inline bele_constexpr T *operator+(T *ptr, const LE32 &v) noexcept { return ptr + unsigned(v); } template inline bele_constexpr T *operator-(T *ptr, const LE32 &v) noexcept { return ptr - unsigned(v); } // these are not implemented on purpose and will cause errors template T *operator+(T *ptr, const BE64 &v) noexcept DELETED_FUNCTION; template T *operator-(T *ptr, const BE64 &v) noexcept DELETED_FUNCTION; template T *operator+(T *ptr, const LE64 &v) noexcept DELETED_FUNCTION; template T *operator-(T *ptr, const LE64 &v) noexcept DELETED_FUNCTION; #if !ALLOW_INT_PLUS_MEMBUFFER template T *operator+(const BE16 &v, T *ptr) noexcept DELETED_FUNCTION; template T *operator+(const BE32 &v, T *ptr) noexcept DELETED_FUNCTION; template T *operator+(const LE16 &v, T *ptr) noexcept DELETED_FUNCTION; template T *operator+(const LE32 &v, T *ptr) noexcept DELETED_FUNCTION; #endif // ALLOW_INT_PLUS_MEMBUFFER template T *operator+(const BE64 &v, T *ptr) noexcept DELETED_FUNCTION; template T *operator+(const LE64 &v, T *ptr) noexcept DELETED_FUNCTION; /************************************************************************* // some global overloads **************************************************************************/ namespace upx { #define REQUIRE_UINT32 \ template , T> > #define REQUIRE_UINT64 \ template , T> > REQUIRE_UINT32 inline bele_constexpr T align_down(const T &a, const BE32 &b) noexcept { return align_down(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T align_down(const BE32 &a, const T &b) noexcept { return align_down(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T align_down(const T &a, const LE32 &b) noexcept { return align_down(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T align_down(const LE32 &a, const T &b) noexcept { return align_down(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T align_up(const T &a, const LE32 &b) noexcept { return align_up(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T align_up(const LE32 &a, const T &b) noexcept { return align_up(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T align_up(const T &a, const BE32 &b) noexcept { return align_up(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T align_up(const BE32 &a, const T &b) noexcept { return align_up(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T min(const T &a, const BE16 &b) noexcept { return min(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T min(const BE16 &a, const T &b) noexcept { return min(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T min(const T &a, const BE32 &b) noexcept { return min(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T min(const BE32 &a, const T &b) noexcept { return min(T(a), b); } REQUIRE_UINT64 inline bele_constexpr T min(const T &a, const BE64 &b) noexcept { return min(a, T(b)); } REQUIRE_UINT64 inline bele_constexpr T min(const BE64 &a, const T &b) noexcept { return min(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T min(const T &a, const LE16 &b) noexcept { return min(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T min(const LE16 &a, const T &b) noexcept { return min(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T min(const T &a, const LE32 &b) noexcept { return min(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T min(const LE32 &a, const T &b) noexcept { return min(T(a), b); } REQUIRE_UINT64 inline bele_constexpr T min(const T &a, const LE64 &b) noexcept { return min(a, T(b)); } REQUIRE_UINT64 inline bele_constexpr T min(const LE64 &a, const T &b) noexcept { return min(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T max(const T &a, const BE16 &b) noexcept { return max(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T max(const BE16 &a, const T &b) noexcept { return max(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T max(const T &a, const BE32 &b) noexcept { return max(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T max(const BE32 &a, const T &b) noexcept { return max(T(a), b); } REQUIRE_UINT64 inline bele_constexpr T max(const T &a, const BE64 &b) noexcept { return max(a, T(b)); } REQUIRE_UINT64 inline bele_constexpr T max(const BE64 &a, const T &b) noexcept { return max(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T max(const T &a, const LE16 &b) noexcept { return max(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T max(const LE16 &a, const T &b) noexcept { return max(T(a), b); } REQUIRE_UINT32 inline bele_constexpr T max(const T &a, const LE32 &b) noexcept { return max(a, T(b)); } REQUIRE_UINT32 inline bele_constexpr T max(const LE32 &a, const T &b) noexcept { return max(T(a), b); } REQUIRE_UINT64 inline bele_constexpr T max(const T &a, const LE64 &b) noexcept { return max(a, T(b)); } REQUIRE_UINT64 inline bele_constexpr T max(const LE64 &a, const T &b) noexcept { return max(T(a), b); } #undef REQUIRE_UINT32 #undef REQUIRE_UINT64 } // namespace upx /************************************************************************* // misc support **************************************************************************/ // for use with qsort() extern "C" { int __acc_cdecl_qsort be16_compare(const void *, const void *); int __acc_cdecl_qsort be24_compare(const void *, const void *); int __acc_cdecl_qsort be32_compare(const void *, const void *); int __acc_cdecl_qsort be64_compare(const void *, const void *); int __acc_cdecl_qsort le16_compare(const void *, const void *); int __acc_cdecl_qsort le24_compare(const void *, const void *); int __acc_cdecl_qsort le32_compare(const void *, const void *); int __acc_cdecl_qsort le64_compare(const void *, const void *); int __acc_cdecl_qsort be16_compare_signed(const void *, const void *); int __acc_cdecl_qsort be24_compare_signed(const void *, const void *); int __acc_cdecl_qsort be32_compare_signed(const void *, const void *); int __acc_cdecl_qsort be64_compare_signed(const void *, const void *); int __acc_cdecl_qsort le16_compare_signed(const void *, const void *); int __acc_cdecl_qsort le24_compare_signed(const void *, const void *); int __acc_cdecl_qsort le32_compare_signed(const void *, const void *); int __acc_cdecl_qsort le64_compare_signed(const void *, const void *); } // extern "C" // upx_is_integral; see conf.h #define TT_UPX_IS_INTEGRAL(T) \ template <> \ struct upx_is_integral : public std::true_type {}; \ template <> \ struct upx_is_integral : public std::true_type {}; \ template <> \ struct upx_is_integral : public std::true_type {}; \ template <> \ struct upx_is_integral : public std::true_type {} TT_UPX_IS_INTEGRAL(BE16); TT_UPX_IS_INTEGRAL(BE32); TT_UPX_IS_INTEGRAL(BE64); TT_UPX_IS_INTEGRAL(LE16); TT_UPX_IS_INTEGRAL(LE32); TT_UPX_IS_INTEGRAL(LE64); #undef TT_UPX_IS_INTEGRAL // native types #if (ACC_ABI_BIG_ENDIAN) typedef BE16 NE16; typedef BE32 NE32; typedef BE64 NE64; #define ne16_compare be16_compare #define ne32_compare be32_compare #define ne64_compare be64_compare #define ne16_compare_signed be16_compare_signed #define ne32_compare_signed be32_compare_signed #define ne64_compare_signed be64_compare_signed #else typedef LE16 NE16; typedef LE32 NE32; typedef LE64 NE64; #define ne16_compare le16_compare #define ne32_compare le32_compare #define ne64_compare le64_compare #define ne16_compare_signed le16_compare_signed #define ne32_compare_signed le32_compare_signed #define ne64_compare_signed le64_compare_signed #endif /************************************************************************* // Provide namespaces and classes to abstract endianness policies. // // CTP - Compile-Time Polymorphism (templates) // RTP - Run-Time Polymorphism (virtual functions) **************************************************************************/ // forward declarations namespace N_BELE_CTP { struct BEPolicy; struct LEPolicy; extern const BEPolicy be_policy; extern const LEPolicy le_policy; } // namespace N_BELE_CTP namespace N_BELE_RTP { struct AbstractPolicy; struct BEPolicy; struct LEPolicy; extern const BEPolicy be_policy; extern const LEPolicy le_policy; } // namespace N_BELE_RTP // implementation namespace N_BELE_CTP { #define BELE_CTP 1 #include "bele_policy.h" #undef BELE_CTP } // namespace N_BELE_CTP namespace N_BELE_RTP { #define BELE_RTP 1 #include "bele_policy.h" #undef BELE_RTP } // namespace N_BELE_RTP // util namespace N_BELE_CTP { inline const N_BELE_RTP::AbstractPolicy *getRTP(const BEPolicy * /*dummy*/) noexcept { return &N_BELE_RTP::be_policy; } inline const N_BELE_RTP::AbstractPolicy *getRTP(const LEPolicy * /*dummy*/) noexcept { return &N_BELE_RTP::le_policy; } } // namespace N_BELE_CTP /* vim:set ts=4 sw=4 et: */