C 在Linux用户空间中支持字节排序
我正在用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吗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
编辑:我只是想说清楚,我正在寻找一个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"
);
}