/* 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 */