Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在Linux用户空间中支持字节排序_C_Linux_Endianness - Fatal编程技术网

C 在Linux用户空间中支持字节排序

C 在Linux用户空间中支持字节排序,c,linux,endianness,C,Linux,Endianness,我正在用C语言在Linux上编写一个程序来分析由嵌入式系统生成的核心文件。核心文件可能是little-endian(ARM)或big-endian(MIPS),用于分析它们的程序可能运行在little-endian主机(x86)或big-endian(PowerPC)上 通过查看标题,我知道核心是LE还是BE。我希望我的程序不需要知道它运行的主机是little endian还是big endian,我希望使用API为我处理它。如果没有更好的选择,我想我会开始依赖于#ifdef uu BIG u

我正在用C语言在Linux上编写一个程序来分析由嵌入式系统生成的核心文件。核心文件可能是little-endian(ARM)或big-endian(MIPS),用于分析它们的程序可能运行在little-endian主机(x86)或big-endian(PowerPC)上

通过查看标题,我知道核心是LE还是BE。我希望我的程序不需要知道它运行的主机是little endian还是big endian,我希望使用API为我处理它。如果没有更好的选择,我想我会开始依赖于#ifdef uu BIG u ENDIAN u

在Linux内核中,我们有cpu_to_le32等从本机字节顺序转换为小端,等等。在用户空间中有htonl等,它从本机转换为大端,但我找不到与本机转换为小端的等价物

有人能为用户空间推荐合适的API吗


编辑:我只是想说清楚,我正在寻找一个API,它已经知道我的CPU是大的还是小的endian,并相应地交换是。我不想在我的代码中乱丢ifdef。我不仅仅是寻找代码片段来交换字节;谢谢你的支持,但这不是重点。

为什么你需要一个API来做这件事?只需编写自己的函数来调用
htonl()
(或任何生成的函数),然后简单地反转字节。听起来没那么难

比如:

union {
    struct {
        unsigned char c0;
        unsigned char c1;
        unsigned char c2;
        unsigned char c3;
    } ch;
    uint32_t ui;
} u;
unsigned char t;

u.ui = htonl (hostlong);
t = u.ch.c0; u.ch.c0 = u.ch.c3 ; u.ch.c3 = t;
t = u.ch.c1; u.ch.c1 = u.ch.c2 ; u.ch.c2 = t;

请看一下/usr/include/linux/byteorder/中内核提供的头文件,例如uu cpu_to_be32()和u be32_to_cpu()


还可以查看/usr/include/linux/types.h文件,在该文件中,您可以将类型定义为显式的大/小endian纯整数,这非常有用,因为任何不匹配都会在编译时检测到。

鉴于切换endian ess,我总是使用这样的自定义代码,对我在代码中使用的表示形式保持严格的规则,并在端点(输入和输出)处理endianity。

您可以自己编写(这些基于Apple的例程):

如果您对英特尔汇编程序代码感到满意,您甚至可以执行以下操作:

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

基于您实际要做的工作(读取ELF核心转储文件而不必担心endian问题),我相信使用libelf是一个不错的选择,它提供了一个很好的教程


该库可以透明地处理大小endian ELF文件,并且在Linux下运行良好,尽管它源于FreeBSD(通常的“/configure”和“make”序列是构建它所需要的全部)。对于grins,我在x86核心文件和MIPS big-endian核心文件上尝试了“读取程序头表”示例(进行了一些小的修改以使其得以构建),它似乎“正常工作”。

您可以使用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
希望这有帮助。

#include提供了以下内容,这些内容根据当前机器的情况定义

htobe16  be16toh    htole16  le16toh
htobe32  be32toh    htole32  le32toh
htobe64  be64toh    htole64  le64toh

在*BSD上,提供了这些相同的宏。

如果将文件视为字节数组,则可以控制从中提取字节的顺序,CPU的尾端实际上并不重要

这在处理对齐问题方面也非常有用。您的核心转储中可能有未对齐的引用。我知道这不太可能,但也可能是因为腐败。这是另一个可以通过将文件视为字节数组来避免的问题


我在实现jhead时使用了这种方法。

如果您可以访问neon协处理器,并且内存是连续的(例如视频帧),您可以通过这种方式使用q寄存器(128字节)在帧上执行swap16;当然,您必须注意对齐问题

void swap16(void *__restrict src16)
{
    const void *start = src16;
    const void *end = src16 + FRAME_SIZE;
    asm volatile (
        "1: pld     [%0, #0x100]\n"
        "vld2.8         {q0,q1}, [%0]\n"
        "vmov           q2,q0\n"
        "vst2.8         {q1,q2}, [%0]!\n"
        "cmp            %1,%0\n"
        "bne            1b\n"
        : /* empty output operands */
        : "r" (start), "r" (end)
        : "cc", "memory"
        );
}

很好的发现。但是,快速查看一下,您似乎仍然需要类似“#ifdef BIG_ENDIAN”的东西来有条件地包括linux/byteorder/little_ENDIAN.h或linux/byteorder/BIG_ENDIAN.h。没什么大不了的,但还是…没错,但最好的方法是不使用
#ifdef BIG_ENDIAN
进行编写,请看,但通过这些代码片段,您可以轻松编写一个宏来实现这一点,从而创建您自己的“API”,不是吗?它是哪种嵌入式系统?你不能简单地使用一些跨gdb来查看核心文件吗?我可以编写自己的API吗?当然我只是想避免使用“ifdef BIG#ENDIAN”,如果有一种更干净、更易于维护的方法,可以通过一个已经知道我的CPU是BIG还是little ENDIAN的现有API来实现它。至于它是什么样的嵌入式系统:它是一个非常普通、乏味的PowerPC。我已经有了一个交叉编译的gdb。gdb在很多方面都很好,但不是所有方面都很好。例如,它在搜索特定模式的所有内存时表现得非常糟糕;您编写了一个gdb宏,它需要花费一天的时间来完成中等大小的核心文件的搜索。这里介绍了一种避免使用
#ifdef BIG_ENDIAN
的方法:我一直在使用libbfd来打开核心并定位每个部分,但对于内容,它只传递了一个大的无符号字符数组(让我来处理其中任何内容的结尾)。我将研究libelf,也许它在这方面更有用。为此,elf32xlatetom()和elf32xlatetof()函数可能很有趣,API在
hton*: Host endian to big endian
ntoh*: Big endian to host endian
htobe16  be16toh    htole16  le16toh
htobe32  be32toh    htole32  le32toh
htobe64  be64toh    htole64  le64toh
void swap16(void *__restrict src16)
{
    const void *start = src16;
    const void *end = src16 + FRAME_SIZE;
    asm volatile (
        "1: pld     [%0, #0x100]\n"
        "vld2.8         {q0,q1}, [%0]\n"
        "vmov           q2,q0\n"
        "vst2.8         {q1,q2}, [%0]!\n"
        "cmp            %1,%0\n"
        "bne            1b\n"
        : /* empty output operands */
        : "r" (start), "r" (end)
        : "cc", "memory"
        );
}