nasm/include/bytesex.h

262 lines
8.6 KiB
C
Raw Normal View History

/* ----------------------------------------------------------------------- *
*
* Copyright 1996-2017 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*
* ----------------------------------------------------------------------- */
/*
* bytesex.h - byte order helper functions
*
* In this function, be careful about getting X86_MEMORY versus
* LITTLE_ENDIAN correct: X86_MEMORY also means we are allowed to
* do unaligned memory references, and is probabilistic.
*/
#ifndef NASM_BYTEORD_H
#define NASM_BYTEORD_H
#include "compiler.h"
/*
* Some handy macros that will probably be of use in more than one
* output format: convert integers into little-endian byte packed
* format in memory.
*/
#define WRITECHAR(p,v) \
do { \
uint8_t *_wc_p = (uint8_t *)(p); \
*_wc_p++ = (v); \
(p) = (void *)_wc_p; \
} while (0)
#if X86_MEMORY
#define WRITESHORT(p,v) \
do { \
uint16_t *_ws_p = (uint16_t *)(p); \
*_ws_p++ = (v); \
(p) = (void *)_ws_p; \
} while (0)
#define WRITELONG(p,v) \
do { \
uint32_t *_wl_p = (uint32_t *)(p); \
*_wl_p++ = (v); \
(p) = (void *)_wl_p; \
} while (0)
#define WRITEDLONG(p,v) \
do { \
uint64_t *_wq_p = (uint64_t *)(p); \
*_wq_p++ = (v); \
(p) = (void *)_wq_p; \
} while (0)
#else /* !X86_MEMORY */
#define WRITESHORT(p,v) \
do { \
uint8_t *_ws_p = (uint8_t *)(p); \
const uint16_t _ws_v = (v); \
WRITECHAR(_ws_p, _ws_v); \
WRITECHAR(_ws_p, _ws_v >> 8); \
(p) = (void *)_ws_p; \
} while (0)
#define WRITELONG(p,v) \
do { \
uint8_t *_wl_p = (uint8_t *)(p); \
const uint32_t _wl_v = (v); \
WRITESHORT(_wl_p, _wl_v); \
WRITESHORT(_wl_p, _wl_v >> 16); \
(p) = (void *)_wl_p; \
} while (0)
#define WRITEDLONG(p,v) \
do { \
uint8_t *_wq_p = (uint8_t *)(p); \
const uint64_t _wq_v = (v); \
WRITELONG(_wq_p, _wq_v); \
WRITELONG(_wq_p, _wq_v >> 32); \
(p) = (void *)_wq_p; \
} while (0)
#endif /* X86_MEMORY */
/*
* Endian control functions which work on a single integer
*/
#ifdef WORDS_LITTLEENDIAN
#ifndef HAVE_CPU_TO_LE16
# define cpu_to_le16(v) ((uint16_t)(v))
#endif
#ifndef HAVE_CPU_TO_LE32
# define cpu_to_le32(v) ((uint32_t)(v))
#endif
#ifndef HAVE_CPU_TO_LE64
# define cpu_to_le64(v) ((uint64_t)(v))
#endif
#elif defined(WORDS_BIGENDIAN)
#ifndef HAVE_CPU_TO_LE16
static inline uint16_t cpu_to_le16(uint16_t v)
{
# ifdef HAVE___CPU_TO_LE16
return __cpu_to_le16(v);
# elif defined(HAVE_HTOLE16)
return htole16(v);
# elif defined(HAVE___BSWAP_16)
return __bswap_16(v);
# elif defined(HAVE___BUILTIN_BSWAP16)
return __builtin_bswap16(v);
# elif defined(HAVE__BYTESWAP_USHORT) && (USHRT_MAX == 0xffffU)
return _byteswap_ushort(v);
# else
return (v << 8) | (v >> 8);
# endif
}
#endif
#ifndef HAVE_CPU_TO_LE32
static inline uint32_t cpu_to_le32(uint32_t v)
{
# ifdef HAVE___CPU_TO_LE32
return __cpu_to_le32(v);
# elif defined(HAVE_HTOLE32)
return htole32(v);
# elif defined(HAVE___BSWAP_32)
return __bswap_32(v);
# elif defined(HAVE___BUILTIN_BSWAP32)
return __builtin_bswap32(v);
# elif defined(HAVE__BYTESWAP_ULONG) && (ULONG_MAX == 0xffffffffUL)
return _byteswap_ulong(v);
# else
v = ((v << 8) & 0xff00ff00 ) |
((v >> 8) & 0x00ff00ff);
return (v << 16) | (v >> 16);
# endif
}
#endif
#ifndef HAVE_CPU_TO_LE64
static inline uint64_t cpu_to_le64(uint64_t v)
{
# ifdef HAVE___CPU_TO_LE64
return __cpu_to_le64(v);
# elif defined(HAVE_HTOLE64)
return htole64(v);
# elif defined(HAVE___BSWAP_64)
return __bswap_64(v);
# elif defined(HAVE___BUILTIN_BSWAP64)
return __builtin_bswap64(v);
# elif defined(HAVE__BYTESWAP_UINT64)
return _byteswap_uint64(v);
# else
v = ((v << 8) & 0xff00ff00ff00ff00ull) |
((v >> 8) & 0x00ff00ff00ff00ffull);
v = ((v << 16) & 0xffff0000ffff0000ull) |
((v >> 16) & 0x0000ffff0000ffffull);
return (v << 32) | (v >> 32);
# endif
}
#endif
#else /* not WORDS_LITTLEENDIAN or WORDS_BIGENDIAN */
static inline uint16_t cpu_to_le16(uint16_t v)
{
union u16 {
uint16_t v;
uint8_t c[2];
} x;
uint8_t *cp = &x.c;
WRITESHORT(cp, v);
return x.v;
}
static inline uint32_t cpu_to_le32(uint32_t v)
{
union u32 {
uint32_t v;
uint8_t c[4];
} x;
uint8_t *cp = &x.c;
WRITELONG(cp, v);
return x.v;
}
static inline uint64_t cpu_to_le64(uint64_t v)
{
union u64 {
uint64_t v;
uint8_t c[8];
} x;
uint8_t *cp = &x.c;
WRITEDLONG(cp, v);
return x.v;
}
#endif
#define WRITEADDR(p,v,s) \
do { \
switch (is_constant(s) ? (s) : 0) { \
case 1: \
WRITECHAR(p,v); \
break; \
case 2: \
WRITESHORT(p,v); \
break; \
case 4: \
WRITELONG(p,v); \
break; \
case 8: \
WRITEDLONG(p,v); \
break; \
default: \
{ \
const uint64_t _wa_v = cpu_to_le64(v); \
const size_t _wa_s = (s); \
uint8_t * const _wa_p = (uint8_t *)(p); \
memcpy(_wa_p, &_wa_v, _wa_s); \
(p) = (void *)(_wa_p + _wa_s); \
} \
break; \
} \
} while (0)
#endif /* NASM_BYTESEX_H */