#ifndef ASM_UNALIGNED_H #define ASM_UNALIGNED_H #include #include #ifndef __LITTLE_ENDIAN # if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN__) # define __LITTLE_ENDIAN 1 # endif #endif #ifdef __LITTLE_ENDIAN # define _IS_LITTLE_ENDIAN 1 #else # define _IS_LITTLE_ENDIAN 0 #endif static unsigned _isLittleEndian(void) { const union { uint32_t u; uint8_t c[4]; } one = { 1 }; assert(_IS_LITTLE_ENDIAN == one.c[0]); (void)one; return _IS_LITTLE_ENDIAN; } static uint16_t _swap16(uint16_t in) { return ((in & 0xF) << 8) + ((in & 0xF0) >> 8); } static uint32_t _swap32(uint32_t in) { return __builtin_bswap32(in); } static uint64_t _swap64(uint64_t in) { return __builtin_bswap64(in); } /* Little endian */ static uint16_t get_unaligned_le16(const void* memPtr) { uint16_t val; __builtin_memcpy(&val, memPtr, sizeof(val)); if (!_isLittleEndian()) _swap16(val); return val; } static uint32_t get_unaligned_le32(const void* memPtr) { uint32_t val; __builtin_memcpy(&val, memPtr, sizeof(val)); if (!_isLittleEndian()) _swap32(val); return val; } static uint64_t get_unaligned_le64(const void* memPtr) { uint64_t val; __builtin_memcpy(&val, memPtr, sizeof(val)); if (!_isLittleEndian()) _swap64(val); return val; } static void put_unaligned_le16(uint16_t value, void* memPtr) { if (!_isLittleEndian()) value = _swap16(value); __builtin_memcpy(memPtr, &value, sizeof(value)); } static void put_unaligned_le32(uint32_t value, void* memPtr) { if (!_isLittleEndian()) value = _swap32(value); __builtin_memcpy(memPtr, &value, sizeof(value)); } static void put_unaligned_le64(uint64_t value, void* memPtr) { if (!_isLittleEndian()) value = _swap64(value); __builtin_memcpy(memPtr, &value, sizeof(value)); } /* big endian */ static uint32_t get_unaligned_be32(const void* memPtr) { uint32_t val; __builtin_memcpy(&val, memPtr, sizeof(val)); if (_isLittleEndian()) _swap32(val); return val; } static uint64_t get_unaligned_be64(const void* memPtr) { uint64_t val; __builtin_memcpy(&val, memPtr, sizeof(val)); if (_isLittleEndian()) _swap64(val); return val; } static void put_unaligned_be32(uint32_t value, void* memPtr) { if (_isLittleEndian()) value = _swap32(value); __builtin_memcpy(memPtr, &value, sizeof(value)); } static void put_unaligned_be64(uint64_t value, void* memPtr) { if (_isLittleEndian()) value = _swap64(value); __builtin_memcpy(memPtr, &value, sizeof(value)); } /* generic */ extern void __bad_unaligned_access_size(void); #define __get_unaligned_le(ptr) ((typeof(*(ptr)))({ \ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \ __bad_unaligned_access_size())))); \ })) #define __get_unaligned_be(ptr) ((typeof(*(ptr)))({ \ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \ __bad_unaligned_access_size())))); \ })) #define __put_unaligned_le(val, ptr) \ ({ \ void *__gu_p = (ptr); \ switch (sizeof(*(ptr))) { \ case 1: \ *(uint8_t *)__gu_p = (uint8_t)(val); \ break; \ case 2: \ put_unaligned_le16((uint16_t)(val), __gu_p); \ break; \ case 4: \ put_unaligned_le32((uint32_t)(val), __gu_p); \ break; \ case 8: \ put_unaligned_le64((uint64_t)(val), __gu_p); \ break; \ default: \ __bad_unaligned_access_size(); \ break; \ } \ (void)0; \ }) #define __put_unaligned_be(val, ptr) \ ({ \ void *__gu_p = (ptr); \ switch (sizeof(*(ptr))) { \ case 1: \ *(uint8_t *)__gu_p = (uint8_t)(val); \ break; \ case 2: \ put_unaligned_be16((uint16_t)(val), __gu_p); \ break; \ case 4: \ put_unaligned_be32((uint32_t)(val), __gu_p); \ break; \ case 8: \ put_unaligned_be64((uint64_t)(val), __gu_p); \ break; \ default: \ __bad_unaligned_access_size(); \ break; \ } \ (void)0; \ }) #if _IS_LITTLE_ENDIAN # define get_unaligned __get_unaligned_le # define put_unaligned __put_unaligned_le #else # define get_unaligned __get_unaligned_be # define put_unaligned __put_unaligned_be #endif #endif // ASM_UNALIGNED_H