Supporting byte ordering in Linux user space

2019-05-07 16:32发布

I'm writing a program on Linux in C to analyze core files produced from an embedded system. The core files might be little endian (ARM) or big endian (MIPS), and the program to analyze them might be running on a little endian host (x86) or big endian (PowerPC).

By looking at the headers I know whether the core is LE or BE. I'd rather my program not need to know whether the host it runs on is little or big endian, I'd like to use an API to handle it for me. If there is no better option, I guess I'll start relying on #ifdef __BIG_ENDIAN__.

In the Linux kernel we have cpu_to_le32 et al to convert from native byte ordering to little endian, etc. In user space there is htonl et al, which convert from native to big endian but no equivalent for native to little endian that I can find.

Can anyone suggest a suitable API for user space?

Edit: Just to be clear, I'm looking for an API which already knows whether my CPU is big or little endian and swaps byes accordingly. I don't want to have to litter my code with #ifdefs for this. I'm not just looking for code snippets to swap bytes; thank you for those, but that wasn't the point.

9条回答
老娘就宠你
2楼-- · 2019-05-07 17:24

You could just write your own (these are based on Apple's routines):

static inline uint16_t Swap16(uint16_t x)
{
    return ( (x << 8) | (x >> 8) );
}

static inline uint32_t Swap32(uint32_t x)
{
    return ( (((x ^ (x >> 16 | (x << 16))) & 0xff00ffff) >> 8) ^ (x >> 8 | data << 24) );
}

Then you can define conditional macros:

#ifdef __BIG_ENDIAN__
# define htols(x) Swap16(x)
# define htoll(x) Swap32(x)
#else
# define htols(x) (x)
# define htoll(x) (x)
#endif

If you're happy with Intel assembler code, you can even do this:

// Swap16 is unchanged

static inline uint32_t Swap32(uint32_t x)
{
    __asm__ ("bswap %0" : "+r" (x));
    return ( x );
}
#ifdef __i386__
static inline uint64_t Swap64(uint64_t x)
{
    __asm__ ("bswap  %%eax\n\t"
             "bswap  %%edx\n\t"
             "xchgl  %%eax, %%edx"
             : "+A" (x));
    return ( x );
}
#elif defined(__x86_64__)
static inline uint64_t Swap64( uint64_t x )
{
    __asm__ ("bswap  %0" : "+r" (x));
    return ( x );
}
#endif
查看更多
看我几分像从前
3楼-- · 2019-05-07 17:26

If you treat the file as a byte array, then you control which order you pick the bytes out, and the endian-ness of your CPU actually ends up not mattering.

This is also highly useful in terms of dealing with alignment problems. Your core dump might concievably have unaligned references in it. I know that's highly unlikely, but it could be due to corruption as well. This is another problem that is avoided by treating the file as a byte array.

I used this approach in implementing jhead.

查看更多
Summer. ? 凉城
4楼-- · 2019-05-07 17:29

You can use the standard network bytswapping functions in apa/inet.h:

#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); // Host to network
uint16_t htons(uint16_t hostshort); // Host to network
uint32_t ntohl(uint32_t netlong); // Network to host
uint16_t ntohs(uint16_t netshort); // Network to host

Network byte order is big-endian. So, these functions mean:

hton*: Host endian to big endian
ntoh*: Big endian to host endian

Hope this helps.

查看更多
登录 后发表回答