/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ // Written in 2014 by Nils Maier #ifndef CRYPTO_ENDIAN_H #define CRYPTO_ENDIAN_H #include #include "config.h" namespace crypto { #if defined(__GNUG__) #define forceinline __attribute__((always_inline)) inline #elif defined(_MSC_VER) #define forceinline __forceinline #else // ! _MSC_VER #define forceinline inline #endif // ! _MSC_VER /* In order for this implementation to work your system (or you yourself) must * define after including * - LITTLE_ENDIAN * - BIG_ENDIAN * - BYTE_ORDER * - where BYTE_ORDER == LITTLE_ENDIAN or BYTE_ORDER == BIG_ENDIAN * Failing to conform will render this implementation utterly incorrect. */ #if defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER) // Itanium is dead! #define LITTLE_ENDIAN 1234 #define BIG_ENDIAN 4321 #define BYTE_ORDER LITTLE_ENDIAN #else // ! defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER) #ifdef HAVE_SYS_PARAM_H #include #endif // HAVE_SYS_PARAM_H #endif // ! defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER) #if !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) || !defined(BYTE_ORDER) || (LITTLE_ENDIAN != BYTE_ORDER && BIG_ENDIAN != BYTE_ORDER) #error Unsupported byte order/endianess #endif // Lets spend some quality time mucking around with byte swap and endian-ness. // First bswap32: #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUG__) #define __crypto_bswap32(p) \ ({ \ uint32_t t = p; \ __asm__ __volatile__("bswap %0" : "=r"(t) : "0"(t)); \ t; \ }) #elif defined(__GNUG__) #define __crypto_bswap32 __builtin_bswap32 #else // defined(__GNUG__) forceinline uint32_t __crypto_bswap32(uint32_t n) { n = ((n << 8) & 0xff00ff00) | ((n >> 8) & 0xff00ff); return (n << 16) | (n >> 16); } #endif // defined(__GNUG__) // Next up: bswap64 #if defined(__x86_64__) && defined(__GNUG__) #define __crypto_bswap64(p) \ ({ \ uint64_t t = p; \ __asm__ __volatile__("bswapq %q0" : "=r"(t) : "0"(t)); \ t; \ }) #elif defined(__GNUG__) #define __crypto_bswap64 __builtin_bswap64 #else // defined(__GNUG__) forceinline uint64_t __crypto_bswap64(uint64_t n) { n = ((n << 8) & 0xff00ff00ff00ff00) | ((n >> 8) & 0x00ff00ff00ff00ff); n = ((n << 16) & 0xffff0000ffff0000) | ((n >> 16) & 0x0000ffff0000ffff); return (n << 32) | (n >> 32); } #endif // defined(__GNUG__) // Time for an implementation that makes reuse easier. namespace { template inline T __crypto_bswap(T n) { static_assert(sizeof(T) != sizeof(T), "Not implemented"); } template<> inline uint32_t __crypto_bswap(uint32_t n) { return __crypto_bswap32(n); } template<> inline uint64_t __crypto_bswap(uint64_t n) { return __crypto_bswap64(n); } } // namespace // __crypto_le and __crypto_be depending on byte order #if LITTLE_ENDIAN == BYTE_ORDER #define __crypto_be(n) __crypto_bswap(n) #define __crypto_le(n) (n) #else // LITTLE_ENDIAN != WORD_ORDER #define __crypto_be(n) (n) #define __crypto_le(n) __crypto_bswap(n) #endif } // namespace crypto #endif // CRYPTO_ENDIAN_H