123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- #ifndef ASM_UNALIGNED_H
- #define ASM_UNALIGNED_H
- #include <assert.h>
- #include <linux/types.h>
- #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
|