1  /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
       2     Licensed under the Apache 2.0 License. */
       3  
       4  #ifndef __LOWSTAR_ENDIANNESS_H
       5  #define __LOWSTAR_ENDIANNESS_H
       6  
       7  #include <string.h>
       8  #include <inttypes.h>
       9  
      10  /******************************************************************************/
      11  /* Implementing C.fst (part 2: endian-ness macros)                            */
      12  /******************************************************************************/
      13  
      14  /* ... for Linux */
      15  #if defined(__linux__) || defined(__CYGWIN__) || defined (__USE_SYSTEM_ENDIAN_H__) || defined(__GLIBC__)
      16  #  include <endian.h>
      17  
      18  /* ... for OSX */
      19  #elif defined(__APPLE__)
      20  #  include <libkern/OSByteOrder.h>
      21  #  define htole64(x) OSSwapHostToLittleInt64(x)
      22  #  define le64toh(x) OSSwapLittleToHostInt64(x)
      23  #  define htobe64(x) OSSwapHostToBigInt64(x)
      24  #  define be64toh(x) OSSwapBigToHostInt64(x)
      25  
      26  #  define htole16(x) OSSwapHostToLittleInt16(x)
      27  #  define le16toh(x) OSSwapLittleToHostInt16(x)
      28  #  define htobe16(x) OSSwapHostToBigInt16(x)
      29  #  define be16toh(x) OSSwapBigToHostInt16(x)
      30  
      31  #  define htole32(x) OSSwapHostToLittleInt32(x)
      32  #  define le32toh(x) OSSwapLittleToHostInt32(x)
      33  #  define htobe32(x) OSSwapHostToBigInt32(x)
      34  #  define be32toh(x) OSSwapBigToHostInt32(x)
      35  
      36  /* ... for Solaris */
      37  #elif defined(__sun__)
      38  #  include <sys/byteorder.h>
      39  #  define htole64(x) LE_64(x)
      40  #  define le64toh(x) LE_64(x)
      41  #  define htobe64(x) BE_64(x)
      42  #  define be64toh(x) BE_64(x)
      43  
      44  #  define htole16(x) LE_16(x)
      45  #  define le16toh(x) LE_16(x)
      46  #  define htobe16(x) BE_16(x)
      47  #  define be16toh(x) BE_16(x)
      48  
      49  #  define htole32(x) LE_32(x)
      50  #  define le32toh(x) LE_32(x)
      51  #  define htobe32(x) BE_32(x)
      52  #  define be32toh(x) BE_32(x)
      53  
      54  /* ... for the BSDs */
      55  #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
      56  #  include <sys/endian.h>
      57  #elif defined(__OpenBSD__)
      58  #  include <endian.h>
      59  
      60  /* ... for Windows (MSVC)... not targeting XBOX 360! */
      61  #elif defined(_MSC_VER)
      62  
      63  #  include <stdlib.h>
      64  #  define htobe16(x) _byteswap_ushort(x)
      65  #  define htole16(x) (x)
      66  #  define be16toh(x) _byteswap_ushort(x)
      67  #  define le16toh(x) (x)
      68  
      69  #  define htobe32(x) _byteswap_ulong(x)
      70  #  define htole32(x) (x)
      71  #  define be32toh(x) _byteswap_ulong(x)
      72  #  define le32toh(x) (x)
      73  
      74  #  define htobe64(x) _byteswap_uint64(x)
      75  #  define htole64(x) (x)
      76  #  define be64toh(x) _byteswap_uint64(x)
      77  #  define le64toh(x) (x)
      78  
      79  /* ... for Windows (GCC-like, e.g. mingw or clang) */
      80  #elif (defined(_WIN32) || defined(_WIN64) || defined(__EMSCRIPTEN__)) &&       \
      81      (defined(__GNUC__) || defined(__clang__))
      82  
      83  #  define htobe16(x) __builtin_bswap16(x)
      84  #  define htole16(x) (x)
      85  #  define be16toh(x) __builtin_bswap16(x)
      86  #  define le16toh(x) (x)
      87  
      88  #  define htobe32(x) __builtin_bswap32(x)
      89  #  define htole32(x) (x)
      90  #  define be32toh(x) __builtin_bswap32(x)
      91  #  define le32toh(x) (x)
      92  
      93  #  define htobe64(x) __builtin_bswap64(x)
      94  #  define htole64(x) (x)
      95  #  define be64toh(x) __builtin_bswap64(x)
      96  #  define le64toh(x) (x)
      97  
      98  /* ... generic big-endian fallback code */
      99  /* ... AIX doesn't have __BYTE_ORDER__ (with XLC compiler) & is always big-endian */
     100  #elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || defined(_AIX)
     101  
     102  /* byte swapping code inspired by:
     103   * https://github.com/rweather/arduinolibs/blob/master/libraries/Crypto/utility/EndianUtil.h
     104   * */
     105  
     106  #  define htobe32(x) (x)
     107  #  define be32toh(x) (x)
     108  #  define htole32(x)                                                           \
     109      (__extension__({                                                           \
     110        uint32_t _temp = (x);                                                    \
     111        ((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) |             \
     112            ((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000);          \
     113      }))
     114  #  define le32toh(x) (htole32((x)))
     115  
     116  #  define htobe64(x) (x)
     117  #  define be64toh(x) (x)
     118  #  define htole64(x)                                                           \
     119      (__extension__({                                                           \
     120        uint64_t __temp = (x);                                                   \
     121        uint32_t __low = htobe32((uint32_t)__temp);                              \
     122        uint32_t __high = htobe32((uint32_t)(__temp >> 32));                     \
     123        (((uint64_t)__low) << 32) | __high;                                      \
     124      }))
     125  #  define le64toh(x) (htole64((x)))
     126  
     127  /* ... generic little-endian fallback code */
     128  #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
     129  
     130  #  define htole32(x) (x)
     131  #  define le32toh(x) (x)
     132  #  define htobe32(x)                                                           \
     133      (__extension__({                                                           \
     134        uint32_t _temp = (x);                                                    \
     135        ((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) |             \
     136            ((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000);          \
     137      }))
     138  #  define be32toh(x) (htobe32((x)))
     139  
     140  #  define htole64(x) (x)
     141  #  define le64toh(x) (x)
     142  #  define htobe64(x)                                                           \
     143      (__extension__({                                                           \
     144        uint64_t __temp = (x);                                                   \
     145        uint32_t __low = htobe32((uint32_t)__temp);                              \
     146        uint32_t __high = htobe32((uint32_t)(__temp >> 32));                     \
     147        (((uint64_t)__low) << 32) | __high;                                      \
     148      }))
     149  #  define be64toh(x) (htobe64((x)))
     150  
     151  /* ... couldn't determine endian-ness of the target platform */
     152  #else
     153  #  error "Please define __BYTE_ORDER__!"
     154  
     155  #endif /* defined(__linux__) || ... */
     156  
     157  /* Loads and stores. These avoid undefined behavior due to unaligned memory
     158   * accesses, via memcpy. */
     159  
     160  inline static uint16_t load16(uint8_t *b) {
     161    uint16_t x;
     162    memcpy(&x, b, 2);
     163    return x;
     164  }
     165  
     166  inline static uint32_t load32(uint8_t *b) {
     167    uint32_t x;
     168    memcpy(&x, b, 4);
     169    return x;
     170  }
     171  
     172  inline static uint64_t load64(uint8_t *b) {
     173    uint64_t x;
     174    memcpy(&x, b, 8);
     175    return x;
     176  }
     177  
     178  inline static void store16(uint8_t *b, uint16_t i) {
     179    memcpy(b, &i, 2);
     180  }
     181  
     182  inline static void store32(uint8_t *b, uint32_t i) {
     183    memcpy(b, &i, 4);
     184  }
     185  
     186  inline static void store64(uint8_t *b, uint64_t i) {
     187    memcpy(b, &i, 8);
     188  }
     189  
     190  /* Legacy accessors so that this header can serve as an implementation of
     191   * C.Endianness */
     192  #define load16_le(b) (le16toh(load16(b)))
     193  #define store16_le(b, i) (store16(b, htole16(i)))
     194  #define load16_be(b) (be16toh(load16(b)))
     195  #define store16_be(b, i) (store16(b, htobe16(i)))
     196  
     197  #define load32_le(b) (le32toh(load32(b)))
     198  #define store32_le(b, i) (store32(b, htole32(i)))
     199  #define load32_be(b) (be32toh(load32(b)))
     200  #define store32_be(b, i) (store32(b, htobe32(i)))
     201  
     202  #define load64_le(b) (le64toh(load64(b)))
     203  #define store64_le(b, i) (store64(b, htole64(i)))
     204  #define load64_be(b) (be64toh(load64(b)))
     205  #define store64_be(b, i) (store64(b, htobe64(i)))
     206  
     207  /* Co-existence of LowStar.Endianness and FStar.Endianness generates name
     208   * conflicts, because of course both insist on having no prefixes. Until a
     209   * prefix is added, or until we truly retire FStar.Endianness, solve this issue
     210   * in an elegant way. */
     211  #define load16_le0 load16_le
     212  #define store16_le0 store16_le
     213  #define load16_be0 load16_be
     214  #define store16_be0 store16_be
     215  
     216  #define load32_le0 load32_le
     217  #define store32_le0 store32_le
     218  #define load32_be0 load32_be
     219  #define store32_be0 store32_be
     220  
     221  #define load64_le0 load64_le
     222  #define store64_le0 store64_le
     223  #define load64_be0 load64_be
     224  #define store64_be0 store64_be
     225  
     226  #define load128_le0 load128_le
     227  #define store128_le0 store128_le
     228  #define load128_be0 load128_be
     229  #define store128_be0 store128_be
     230  
     231  #endif