/* $NetBSD$ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_UNALIGNED_H_ #define _SYS_UNALIGNED_H_ #include #ifdef __clang__ //#define NO_SANITIZE_ALIGNMENT __attribute__((no_sanitize("alignment"))) #define NO_SANITIZE_ALIGNMENT __attribute__((no_sanitize_undefined)) #elif __GNUC__ #define NO_SANITIZE_ALIGNMENT __attribute__((no_sanitize_undefined)) #else #define NO_SANITIZE_ALIGNMENT #endif #ifdef __NO_STRICT_ALIGNMENT #define ___GET_UNALIGNED_TYPE(type, suffix) \ NO_SANITIZE_ALIGNMENT static inline type \ __get_unaligned_##suffix(const type *val) \ { \ return *val; \ } #else #if BYTE_ORDER == LITTLE_ENDIAN #define __GET_UNALIGNED_FORLOOP for (i = size; i-- > 0;) #else /* BYTE_ORDER == BIG_ENDIAN */ #define __GET_UNALIGNED_FORLOOP for (i = 0; i < size; i++) #endif #define ___GET_UNALIGNED_TYPE(type, suffix) \ static inline type \ __get_unaligned_##suffix(const type *val) \ { \ size_t i, size; \ type res = 0; \ size = sizeof(type); \ __GET_UNALIGNED_FORLOOP \ res |= (uintmax_t)(((char *)val)[i]) << (CHAR_BIT * i); \ return res; \ } #endif #define __GET_UNALIGNED_TYPE(type, suffix) ___GET_UNALIGNED_TYPE(type, suffix) /* * The char, signed and unsigned char types have the weekest alignment * and the operation on them should be always correctly aligned. */ __GET_UNALIGNED_TYPE(signed char, c) __GET_UNALIGNED_TYPE(unsigned char, b) __GET_UNALIGNED_TYPE(short, h) __GET_UNALIGNED_TYPE(int, i) __GET_UNALIGNED_TYPE(long, l) __GET_UNALIGNED_TYPE(long long, q) __GET_UNALIGNED_TYPE(unsigned short, H) __GET_UNALIGNED_TYPE(unsigned int, I) __GET_UNALIGNED_TYPE(unsigned long, L) __GET_UNALIGNED_TYPE(unsigned long long, Q) /* * This macro is GCC and Clang compatible, other incompatible * compilers could use a C11 variation using _Generic(). */ #define get_unaligned(_val) \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), signed char), \ __get_unaligned_c((const signed char *)_val), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), short), \ __get_unaligned_h((const short *)_val), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), int), \ __get_unaligned_i((const int *)_val), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), long), \ __get_unaligned_l((const long *)_val), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), long long), \ __get_unaligned_q((const long long *)_val), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), unsigned char), \ __get_unaligned_b((const unsigned char *)_val), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), unsigned short), \ __get_unaligned_H((const unsigned short *)_val), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), unsigned int), \ __get_unaligned_I((const unsigned int *)_val), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), unsigned long), \ __get_unaligned_L((const unsigned long *)_val), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(*_val), unsigned long long),\ __get_unaligned_Q((const unsigned long long *)_val), \ (void)0)))))))))) #endif /* _SYS_UNALIGNED_H_ */