| /* Unaligned memory access functionality. |
| Copyright (C) 2000, 2001, 2002, 2003, 2008 Red Hat, Inc. |
| This file is part of elfutils. |
| Written by Ulrich Drepper <drepper@redhat.com>, 2001. |
| |
| This file is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| elfutils is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef _UNALIGNED_H |
| #define _UNALIGNED_H 1 |
| |
| #include <byteswap.h> |
| #include <endian.h> |
| |
| |
| #ifndef UNALIGNED_ACCESS_CLASS |
| # error "UNALIGNED_ACCESS_CLASS must be defined" |
| #endif |
| |
| |
| /* Macros to convert from the host byte order to that of the object file. */ |
| #if UNALIGNED_ACCESS_CLASS == BYTE_ORDER |
| # define target_bswap_16(n) (n) |
| # define target_bswap_32(n) (n) |
| # define target_bswap_64(n) (n) |
| #else |
| # define target_bswap_16(n) bswap_16 (n) |
| # define target_bswap_32(n) bswap_32 (n) |
| # define target_bswap_64(n) bswap_64 (n) |
| #endif |
| |
| |
| union u_2ubyte_unaligned |
| { |
| uint16_t u; |
| char c[2]; |
| } __attribute__((packed)); |
| |
| union u_4ubyte_unaligned |
| { |
| uint32_t u; |
| char c[4]; |
| } __attribute__((packed)); |
| |
| union u_8ubyte_unaligned |
| { |
| uint64_t u; |
| char c[8]; |
| } __attribute__((packed)); |
| |
| |
| /* Macros to store value at unaligned address. */ |
| #define store_2ubyte_unaligned(ptr, value) \ |
| (void) (((union u_2ubyte_unaligned *) (ptr))->u = target_bswap_16 (value)) |
| #define store_4ubyte_unaligned(ptr, value) \ |
| (void) (((union u_4ubyte_unaligned *) (ptr))->u = target_bswap_32 (value)) |
| #define store_8ubyte_unaligned(ptr, value) \ |
| (void) (((union u_8ubyte_unaligned *) (ptr))->u = target_bswap_64 (value)) |
| |
| |
| /* Macros to add value to unaligned address. This is a bit more |
| complicated since the value must be read from memory and eventually |
| converted twice. */ |
| #if UNALIGNED_ACCESS_CLASS == BYTE_ORDER |
| # define add_2ubyte_unaligned(ptr, value) \ |
| (void) (((union u_2ubyte_unaligned *) (ptr))->u += value) |
| # define add_4ubyte_unaligned(ptr, value) \ |
| (void) (((union u_4ubyte_unaligned *) (ptr))->u += value) |
| # define add_8ubyte_unaligned(ptr, value) \ |
| (void) (((union u_8ubyte_unaligned *) (ptr))->u += value) |
| #else |
| # define add_2ubyte_unaligned(ptr, value) \ |
| do { \ |
| union u_2ubyte_unaligned *_ptr = (void *) (ptr); \ |
| uint16_t _val = bswap_16 (_ptr->u) + (value); \ |
| _ptr->u = bswap_16 (_val); \ |
| } while (0) |
| # define add_4ubyte_unaligned(ptr, value) \ |
| do { \ |
| union u_4ubyte_unaligned *_ptr = (void *) (ptr); \ |
| uint32_t _val = bswap_32 (_ptr->u) + (value); \ |
| _ptr->u = bswap_32 (_val); \ |
| } while (0) |
| # define add_8ubyte_unaligned(ptr, value) \ |
| do { \ |
| union u_8ubyte_unaligned *_ptr = (void *) (ptr); \ |
| uint64_t _val = bswap_64 (_ptr->u) + (value); \ |
| _ptr->u = bswap_64 (_val); \ |
| } while (0) |
| #endif |
| |
| #endif /* unaligned.h */ |