Make tunsafe_endian.h better

This commit is contained in:
Ludvig Strigeus 2018-12-10 23:04:05 +01:00
parent aa22daeeb2
commit b1ffd5738e

View file

@ -10,43 +10,14 @@
#endif
#include <stdint.h>
#define ByteSwap32Fallback(x) ( \
(((uint32)(x) & (uint32)0x000000fful) << 24) | \
(((uint32)(x) & (uint32)0x0000ff00ul) << 8) | \
(((uint32)(x) & (uint32)0x00ff0000ul) >> 8) | \
(((uint32)(x) & (uint32)0xff000000ul) >> 24))
#define ByteSwap16Fallback(x) ((uint16)( \
(((uint16)(x) & (uint16)0x00ffu) << 8) | \
(((uint16)(x) & (uint16)0xff00u) >> 8)))
#define ByteSwap64Fallback(x) ((uint64)ByteSwap32Fallback(x)<<32 | ByteSwap32Fallback(x>>32))
#define ReadBE32AlignedFallback(pt) (((uint32)((pt)[0] & 0xFF) << 24) ^ \
((uint32)((pt)[1] & 0xFF) << 16) ^ \
((uint32)((pt)[2] & 0xFF) << 8) ^ \
((uint32)((pt)[3] & 0xFF)))
#define WriteBE32AlignedFallback(ct, st) { \
(ct)[0] = (char)((st) >> 24); \
(ct)[1] = (char)((st) >> 16); \
(ct)[2] = (char)((st) >> 8); \
(ct)[3] = (char)(st); }
#if defined(OS_WIN) && defined(COMPILER_MSVC)
#define ByteSwap16(x) _byteswap_ushort((uint16)x)
#define ByteSwap32(x) _byteswap_ulong((uint32)x)
#define ByteSwap64(x) _byteswap_uint64((uint64)x)
#elif defined(COMPILER_GCC)
#else
#define ByteSwap16(x) __builtin_bswap16((uint16)x)
#define ByteSwap32(x) __builtin_bswap32((uint32)x)
#define ByteSwap64(x) __builtin_bswap64((uint64)x)
#else
#define ByteSwap16 ByteSwap16Fallback
#define ByteSwap32 ByteSwap32Fallback
#define ByteSwap64 ByteSwap64Fallback
#endif
#if defined(ARCH_CPU_LITTLE_ENDIAN)
@ -56,41 +27,78 @@
#define ToLE64(x) (x)
#define ToLE32(x) (x)
#define ToLE16(x) (x)
#else
#elif defined(ARCH_CPU_BIG_ENDIAN)
#define ToBE64(x) (x)
#define ToBE32(x) (x)
#define ToBE16(x) (x)
#define ToLE64(x) ByteSwap64(x)
#define ToLE32(x) ByteSwap32(x)
#define ToLE16(x) ByteSwap16(x)
#else
#error The CPU is neither big / little endian
#endif
#define ReadBE16Aligned(pt) ToBE16(*(uint16*)(pt))
#define WriteBE16Aligned(ct, st) (*(uint16*)(ct) = ToBE16(st))
#define ReadBE32Aligned(pt) ToBE32(*(uint32*)(pt))
#define WriteBE32Aligned(ct, st) (*(uint32*)(ct) = ToBE32(st))
#if !(defined(COMPILER_GCC) || defined(COMPILER_CLANG) || defined(ARCH_CPU_ALLOW_UNALIGNED))
#error The CPU does not support unaligned memory accesses
#endif // defined(ARCH_CPU_ALLOW_UNALIGNED)
// todo: these need to support unaligned pointers
#define ReadBE16(pt) ToBE16(*(uint16*)(pt))
#define WriteBE16(ct, st) (*(uint16*)(ct) = ToBE16(st))
#define ReadBE32(pt) ToBE32(*(uint32*)(pt))
#define WriteBE32(ct, st) (*(uint32*)(ct) = ToBE32(st))
#define ReadBE64(pt) ToBE64(*(uint64*)(pt))
#define WriteBE64(ct, st) (*(uint64*)(ct) = ToBE64(st))
#if defined(COMPILER_GCC) || defined(COMPILER_CLANG)
// The WriteBE/WriteLE functions below write a uint to a char pointer which
// is not valid per the C spec because of aliasing, so work around it.
typedef uint16 __attribute__((__may_alias__)) uint16_unaligned __attribute__((aligned(1)));
typedef uint32 __attribute__((__may_alias__)) uint32_unaligned __attribute__((aligned(1)));
typedef uint64 __attribute__((__may_alias__)) uint64_unaligned __attribute__((aligned(1)));
typedef uint16 __attribute__((__may_alias__)) uint16_aligned;
typedef uint32 __attribute__((__may_alias__)) uint32_aligned;
typedef uint64 __attribute__((__may_alias__)) uint64_aligned;
#else
typedef uint16 uint16_unaligned;
typedef uint32 uint32_unaligned;
typedef uint64 uint64_unaligned;
typedef uint16 uint16_aligned;
typedef uint32 uint32_aligned;
typedef uint64 uint64_aligned;
#endif
#define ReadLE16(pt) ToLE16(*(uint16*)(pt))
#define WriteLE16(ct, st) (*(uint16*)(ct) = ToLE16(st))
#define ReadLE32(pt) ToLE32(*(uint32*)(pt))
#define WriteLE32(ct, st) (*(uint32*)(ct) = ToLE32(st))
#define ReadLE64(pt) ToLE64(*(uint64*)(pt))
#define WriteLE64(ct, st) (*(uint64*)(ct) = ToLE64(st))
#define Read16(pt) (*(uint16*)(pt))
#define Write16(ct, st) (*(uint16*)(ct) = (st))
#define Read32(pt) (*(uint32*)(pt))
#define Write32(ct, st) (*(uint32*)(ct) = (st))
#define Read64(pt) (*(uint64*)(pt))
#define Write64(ct, st) (*(uint64*)(ct) = (st))
// Use the _Aligned variants when you are sure that the pointers are aligned
#define Read16Aligned(pt) *(uint16_aligned*)(pt)
#define Read32Aligned(pt) *(uint32_aligned*)(pt)
#define Read64Aligned(pt) *(uint64_aligned*)(pt)
#define Write16Aligned(ct, st) (*(uint16_aligned*)(ct) = (st))
#define Write32Aligned(ct, st) (*(uint32_aligned*)(ct) = (st))
#define Write64Aligned(ct, st) (*(uint64_aligned*)(ct) = (st))
#define ReadBE16Aligned(pt) ToBE16(Read16Aligned(pt))
#define ReadBE32Aligned(pt) ToBE32(Read32Aligned(pt))
#define ReadBE64Aligned(pt) ToBE64(Read64Aligned(pt))
#define WriteBE16Aligned(ct, st) Write16Aligned(ct, ToBE16(st))
#define WriteBE32Aligned(ct, st) Write32Aligned(ct, ToBE32(st))
#define WriteBE64Aligned(ct, st) Write64Aligned(ct, ToBE64(st))
#define ReadLE16Aligned(pt) ToLE16(Read16Aligned(pt))
#define ReadLE32Aligned(pt) ToLE32(Read32Aligned(pt))
#define ReadLE64Aligned(pt) ToLE64(Read64Aligned(pt))
#define WriteLE16Aligned(ct, st) Write16Aligned(ct, ToLE16(st))
#define WriteLE32Aligned(ct, st) Write32Aligned(ct, ToLE32(st))
#define WriteLE64Aligned(ct, st) Write64Aligned(ct, ToLE64(st))
// Use the below this when pointers may be unaligned
#define Read16(pt) *(uint16_unaligned*)(pt)
#define Read32(pt) *(uint32_unaligned*)(pt)
#define Read64(pt) *(uint64_unaligned*)(pt)
#define Write16(ct, st) (*(uint16_unaligned*)(ct) = (st))
#define Write32(ct, st) (*(uint32_unaligned*)(ct) = (st))
#define Write64(ct, st) (*(uint64_unaligned*)(ct) = (st))
#define ReadBE16(pt) ToBE16(Read16(pt))
#define ReadBE32(pt) ToBE32(Read32(pt))
#define ReadBE64(pt) ToBE64(Read64(pt))
#define WriteBE16(ct, st) Write16(ct, ToBE16(st))
#define WriteBE32(ct, st) Write32(ct, ToBE32(st))
#define WriteBE64(ct, st) Write64(ct, ToBE64(st))
#define ReadLE16(pt) ToLE16(Read16(pt))
#define ReadLE32(pt) ToLE32(Read32(pt))
#define ReadLE64(pt) ToLE64(Read64(pt))
#define WriteLE16(ct, st) Write16(ct, ToLE16(st))
#define WriteLE32(ct, st) Write32(ct, ToLE32(st))
#define WriteLE64(ct, st) Write64(ct, ToLE64(st))
#endif // TINYVPN_ENDIAN_H_