diff --git a/configure.ac b/configure.ac index c97da0c..9eadec9 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,19 @@ AC_C_CONST AC_C_RESTRICT AC_C_VOLATILE AC_C_BIGENDIAN +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_INT8_T +AC_TYPE_INTMAX_T +AC_TYPE_INTPTR_T +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT8_T +AC_TYPE_UINTMAX_T +AC_TYPE_UINTPTR_T # libtool LT_PREREQ([2.2.6]) @@ -34,10 +47,18 @@ AC_PROG_INSTALL # AC_CHECK_HEADERS([endian.h sys/endian.h]) +AX_GCC_BUILTIN([__builtin_bswap16]) +AX_GCC_BUILTIN([__builtin_bswap32]) +AX_GCC_BUILTIN([__builtin_bswap64]) AC_CHECK_DECLS([ + bswap16, bswap32, bswap64, be16enc, be16dec, le16enc, le16dec, be32enc, be32dec, le32enc, le32dec, - be64enc, be64dec, le64enc, le64dec + be64enc, be64dec, le64enc, le64dec, + htobe16, be16toh, htole16, le16toh, + htobe32, be32toh, htole32, le32toh, + htobe64, be64toh, htole64, le64toh, + nothing ], [], [], [[ #if HAVE_SYS_ENDIAN_H #include diff --git a/include/cryb/endian.h b/include/cryb/endian.h index eab1c32..53b40a8 100644 --- a/include/cryb/endian.h +++ b/include/cryb/endian.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2014 Dag-Erling Smørgrav + * Copyright (c) 2016 Universitetet i Oslo * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,6 +43,15 @@ #include #endif +#if !HAVE_DECL_BSWAP16 +#define bswap16 cryb_bswap16 +#endif +#if !HAVE_DECL_BSWAP32 +#define bswap32 cryb_bswap32 +#endif +#if !HAVE_DECL_BSWAP64 +#define bswap64 cryb_bswap64 +#endif #if !HAVE_DECL_BE16ENC #define be16enc cryb_be16enc #endif @@ -78,6 +88,83 @@ #if !HAVE_DECL_LE64DEC #define le64dec cryb_le64dec #endif +#if !HAVE_DECL_HTOBE16 +#define htobe16 cryb_htobe16 +#endif +#if !HAVE_DECL_BE16TOH +#define be16toh cryb_be16toh +#endif +#if !HAVE_DECL_HTOLE16 +#define htole16 cryb_htole16 +#endif +#if !HAVE_DECL_LE16TOH +#define le16toh cryb_le16toh +#endif +#if !HAVE_DECL_HTOBE32 +#define htobe32 cryb_htobe32 +#endif +#if !HAVE_DECL_BE32TOH +#define be32toh cryb_be32toh +#endif +#if !HAVE_DECL_HTOLE32 +#define htole32 cryb_htole32 +#endif +#if !HAVE_DECL_LE32TOH +#define le32toh cryb_le32toh +#endif +#if !HAVE_DECL_HTOBE64 +#define htobe64 cryb_htobe64 +#endif +#if !HAVE_DECL_BE64TOH +#define be64toh cryb_be64toh +#endif +#if !HAVE_DECL_HTOLE64 +#define htole64 cryb_htole64 +#endif +#if !HAVE_DECL_LE64TOH +#define le64toh cryb_le64toh +#endif + +static inline uint16_t +cryb_bswap16(uint16_t u16) +{ +#if HAVE___BUILTIN_BSWAP16 + return (__builtin_bswap16(u16)); +#else + return (((u16 & 0x00ffU) >> 0) << 8 | + ((u16 & 0xff00U) >> 8) << 0); +#endif +} + +static inline uint32_t +cryb_bswap32(uint32_t u32) +{ +#if HAVE___BUILTIN_BSWAP32 + return (__builtin_bswap32(u32)); +#else + return (((u32 & 0x000000ffLU) >> 0) << 24 | + ((u32 & 0x0000ff00LU) >> 8) << 16 | + ((u32 & 0x00ff0000LU) >> 16) << 8 | + ((u32 & 0xff000000LU) >> 24) << 0); +#endif +} + +static inline uint64_t +cryb_bswap64(uint64_t u64) +{ +#if HAVE___BUILTIN_BSWAP64 + return (__builtin_bswap64(u64)); +#else + return (((u64 & 0x00000000000000ffLLU) >> 0) << 56 | + ((u64 & 0x000000000000ff00LLU) >> 8) << 48 | + ((u64 & 0x0000000000ff0000LLU) >> 16) << 40 | + ((u64 & 0x00000000ff000000LLU) >> 24) << 32 | + ((u64 & 0x000000ff00000000LLU) >> 32) << 24 | + ((u64 & 0x0000ff0000000000LLU) >> 40) << 16 | + ((u64 & 0x00ff000000000000LLU) >> 48) << 8 | + ((u64 & 0xff00000000000000LLU) >> 56) << 0); +#endif +} static inline void cryb_be16enc(void *p, uint16_t u16) @@ -195,4 +282,112 @@ cryb_le64dec(const void *p) (uint64_t)((const uint8_t *)p)[7] << 56); } +static inline uint16_t +cryb_htobe16(uint16_t u16) +{ +#if !WORDS_BIGENDIAN + u16 = cryb_bswap16(u16); +#endif + return (u16); +} + +static inline uint16_t +cryb_be16toh(uint16_t u16) +{ +#if !WORDS_BIGENDIAN + u16 = cryb_bswap16(u16); +#endif + return (u16); +} + +static inline uint16_t +cryb_htole16(uint16_t u16) +{ +#if WORDS_BIGENDIAN + u16 = cryb_bswap16(u16); +#endif + return (u16); +} + +static inline uint16_t +cryb_le16toh(uint16_t u16) +{ +#if WORDS_BIGENDIAN + u16 = cryb_bswap16(u16); +#endif + return (u16); +} + +static inline uint32_t +cryb_htobe32(uint32_t u32) +{ +#if !WORDS_BIGENDIAN + u32 = cryb_bswap32(u32); +#endif + return (u32); +} + +static inline uint32_t +cryb_be32toh(uint32_t u32) +{ +#if !WORDS_BIGENDIAN + u32 = cryb_bswap32(u32); +#endif + return (u32); +} + +static inline uint32_t +cryb_htole32(uint32_t u32) +{ +#if WORDS_BIGENDIAN + u32 = cryb_bswap32(u32); +#endif + return (u32); +} + +static inline uint32_t +cryb_le32toh(uint32_t u32) +{ +#if WORDS_BIGENDIAN + u32 = cryb_bswap32(u32); +#endif + return (u32); +} + +static inline uint64_t +cryb_htobe64(uint64_t u64) +{ +#if !WORDS_BIGENDIAN + u64 = cryb_bswap64(u64); +#endif + return (u64); +} + +static inline uint64_t +cryb_be64toh(uint64_t u64) +{ +#if !WORDS_BIGENDIAN + u64 = cryb_bswap64(u64); +#endif + return (u64); +} + +static inline uint64_t +cryb_htole64(uint64_t u64) +{ +#if WORDS_BIGENDIAN + u64 = cryb_bswap64(u64); +#endif + return (u64); +} + +static inline uint64_t +cryb_le64toh(uint64_t u64) +{ +#if WORDS_BIGENDIAN + u64 = cryb_bswap64(u64); +#endif + return (u64); +} + #endif diff --git a/t/t_endian.c b/t/t_endian.c index 61f9082..17913df 100644 --- a/t/t_endian.c +++ b/t/t_endian.c @@ -35,6 +35,11 @@ #include #include +/* test our own code, not the compiler's */ +#undef HAVE___BUILTIN_BSWAP16 +#undef HAVE___BUILTIN_BSWAP32 +#undef HAVE___BUILTIN_BSWAP64 + #include #include @@ -45,10 +50,27 @@ static uint64_t be64 = 0xdeadbeefcafef001ULL; static uint16_t le16 = 0x01f0U; static uint32_t le32 = 0xefbeaddeUL; static uint64_t le64 = 0x01f0fecaefbeaddeULL; +static uint16_t h16; +static uint32_t h32; +static uint64_t h64; static const void *s16 = "\xf0\x01"; static const void *s32 = "\xde\xad\xbe\xef"; static const void *s64 = "\xde\xad\xbe\xef\xca\xfe\xf0\x01"; +#define T_BSWAP(w) \ + static int \ + t_bswap##w(char **desc CRYB_UNUSED, void *arg CRYB_UNUSED) \ + { \ + uint##w##_t swap; \ + \ + swap = cryb_bswap##w(be##w); \ + return (t_compare_x##w(le##w, swap)); \ + } + +T_BSWAP(16); +T_BSWAP(32); +T_BSWAP(64); + #define T_DEC(e, w) \ static int \ t_##e##w##dec(char **desc CRYB_UNUSED, void *arg CRYB_UNUSED) \ @@ -83,15 +105,55 @@ T_ENC(le, 16) T_ENC(le, 32) T_ENC(le, 64) +#define T_HTO(e, w) \ + static int \ + t_hto##e##w(char **desc CRYB_UNUSED, void *arg CRYB_UNUSED) \ + { \ + uint##w##_t e; \ + \ + e = cryb_hto##e##w(h##w); \ + return (t_compare_x##w(e##w, e)); \ + } + +T_HTO(be, 16); +T_HTO(be, 32); +T_HTO(be, 64); +T_HTO(le, 16); +T_HTO(le, 32); +T_HTO(le, 64); + +#define T_TOH(e, w) \ + static int \ + t_##e##w##toh(char **desc CRYB_UNUSED, void *arg CRYB_UNUSED) \ + { \ + uint##w##_t h; \ + \ + h = cryb_##e##w##toh(e##w); \ + return (t_compare_x##w(h##w, h)); \ + } + +T_TOH(be, 16); +T_TOH(be, 32); +T_TOH(be, 64); +T_TOH(le, 16); +T_TOH(le, 32); +T_TOH(le, 64); + /*************************************************************************** * Boilerplate */ +#define T_BSWAP_ADD(w) \ + t_add_test(t_bswap##w, 0, "bswap" #w); #define T_DEC_ADD(e, w) \ t_add_test(t_##e##w##dec, 0, #e #w "dec"); #define T_ENC_ADD(e, w) \ t_add_test(t_##e##w##enc, 0, #e #w "enc"); +#define T_HTO_ADD(e, w) \ + t_add_test(t_hto##e##w, 0, "hto" #e #w); +#define T_TOH_ADD(e, w) \ + t_add_test(t_##e##w##toh, 0, #e #w "toh"); static int t_prepare(int argc, char *argv[]) @@ -99,6 +161,20 @@ t_prepare(int argc, char *argv[]) (void)argc; (void)argv; + +#if WORD_BIGENDIAN + h16 = be16; + h32 = be32; + h64 = be64; +#else + h16 = le16; + h32 = le32; + h64 = le64; +#endif + + T_BSWAP_ADD(16); + T_BSWAP_ADD(32); + T_BSWAP_ADD(64); T_DEC_ADD(be, 16); T_DEC_ADD(be, 32); T_DEC_ADD(be, 64); @@ -111,6 +187,18 @@ t_prepare(int argc, char *argv[]) T_ENC_ADD(le, 16); T_ENC_ADD(le, 32); T_ENC_ADD(le, 64); + T_HTO_ADD(be, 16); + T_HTO_ADD(be, 32); + T_HTO_ADD(be, 64); + T_HTO_ADD(le, 16); + T_HTO_ADD(le, 32); + T_HTO_ADD(le, 64); + T_TOH_ADD(be, 16); + T_TOH_ADD(be, 32); + T_TOH_ADD(be, 64); + T_TOH_ADD(le, 16); + T_TOH_ADD(le, 32); + T_TOH_ADD(le, 64); return (0); }