1/* Unaligned memory access functionality.
2   Copyright (C) 2000, 2001, 2002, 2003, 2008 Red Hat, Inc.
3   This file is part of elfutils.
4   Written by Ulrich Drepper <drepper@redhat.com>, 2001.
5
6   This file is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   elfutils is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19#ifndef _UNALIGNED_H
20#define _UNALIGNED_H	1
21
22#include <byteswap.h>
23#include <endian.h>
24
25
26#ifndef UNALIGNED_ACCESS_CLASS
27# error "UNALIGNED_ACCESS_CLASS must be defined"
28#endif
29
30
31/* Macros to convert from the host byte order to that of the object file.  */
32#if UNALIGNED_ACCESS_CLASS == BYTE_ORDER
33# define target_bswap_16(n) (n)
34# define target_bswap_32(n) (n)
35# define target_bswap_64(n) (n)
36#else
37# define target_bswap_16(n) bswap_16 (n)
38# define target_bswap_32(n) bswap_32 (n)
39# define target_bswap_64(n) bswap_64 (n)
40#endif
41
42
43union u_2ubyte_unaligned
44{
45  uint16_t u;
46  char c[2];
47} __attribute__((packed));
48
49union u_4ubyte_unaligned
50{
51  uint32_t u;
52  char c[4];
53} __attribute__((packed));
54
55union u_8ubyte_unaligned
56{
57  uint64_t u;
58  char c[8];
59} __attribute__((packed));
60
61
62/* Macros to store value at unaligned address.  */
63#define store_2ubyte_unaligned(ptr, value) \
64  (void) (((union u_2ubyte_unaligned *) (ptr))->u = target_bswap_16 (value))
65#define store_4ubyte_unaligned(ptr, value) \
66  (void) (((union u_4ubyte_unaligned *) (ptr))->u = target_bswap_32 (value))
67#define store_8ubyte_unaligned(ptr, value) \
68  (void) (((union u_8ubyte_unaligned *) (ptr))->u = target_bswap_64 (value))
69
70
71/* Macros to add value to unaligned address.  This is a bit more
72   complicated since the value must be read from memory and eventually
73   converted twice.  */
74#if UNALIGNED_ACCESS_CLASS == BYTE_ORDER
75# define add_2ubyte_unaligned(ptr, value) \
76  (void) (((union u_2ubyte_unaligned *) (ptr))->u += value)
77# define add_4ubyte_unaligned(ptr, value) \
78  (void) (((union u_4ubyte_unaligned *) (ptr))->u += value)
79# define add_8ubyte_unaligned(ptr, value) \
80  (void) (((union u_8ubyte_unaligned *) (ptr))->u += value)
81#else
82# define add_2ubyte_unaligned(ptr, value) \
83  do {									      \
84    union u_2ubyte_unaligned *_ptr = (void *) (ptr);			      \
85    uint16_t _val = bswap_16 (_ptr->u) + (value);			      \
86    _ptr->u = bswap_16 (_val);						      \
87  } while (0)
88# define add_4ubyte_unaligned(ptr, value) \
89  do {									      \
90    union u_4ubyte_unaligned *_ptr = (void *) (ptr);			      \
91    uint32_t _val = bswap_32 (_ptr->u) + (value);			      \
92    _ptr->u = bswap_32 (_val);						      \
93  } while (0)
94# define add_8ubyte_unaligned(ptr, value) \
95  do {									      \
96    union u_8ubyte_unaligned *_ptr = (void *) (ptr);			      \
97    uint64_t _val = bswap_64 (_ptr->u) + (value);			      \
98    _ptr->u = bswap_64 (_val);						      \
99  } while (0)
100#endif
101
102#endif /* unaligned.h */
103