4

組み込みシステムから生成されたコアファイルを分析するために、LinuxでCのプログラムを書いています。コアファイルはリトルエンディアン(ARM)またはビッグエンディアン(MIPS)であり、それらを分析するプログラムはリトルエンディアンホスト(x86)またはビッグエンディアン(PowerPC)で実行されている可能性があります。

ヘッダーを見ると、コアがLEかBEかがわかります。プログラムが実行されているホストがリトルエンディアンかビッグエンディアンかを知る必要はなく APIを使用して処理したいと思います。これ以上の選択肢がない場合は、#ifdef__BIG_ENDIAN__に依存し始めると思います。

Linuxカーネルには、ネイティブバイト順序からリトルエンディアンなどに変換するcpu_to_le32 et alがあります。ユーザースペースには、ネイティブからビッグエンディアンに変換するhtonl et alがありますが、ネイティブからリトルエンディアンに相当するものはありません。

誰かがユーザースペースに適したAPIを提案できますか?

編集:明確にするために、CPUがビッグエンディアンかリトルエンディアンかをすでに認識しており、それに応じてバイを交換するAPIを探しています。このためにコードに#ifdefsを散らかす必要はありません。バイトを交換するためのコードスニペットを探しているだけではありません。それらに感謝します、しかしそれはポイントではありませんでした。

4

9 に答える 9

19

#include <arpa/inet.h>素晴らしくポータブルですが、保証するだけ{ntoh,hton}{s,l}です。64 ビット値での変換、またはビッグ エンディアンでのエンディアン フリッピング (wherentohhton何もしない) が必要な場合は、十分ではありません。

Linux (glibc) では#include <endian.h>、現在のマシンに適したものとして定義された以下を提供します。

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

*BSD では、#include <sys/endian.h>これらと同じマクロを提供します。

于 2009-05-18T20:37:40.217 に答える
5

ネオン コプロセッサにアクセスでき、メモリが連続している場合 (ビデオ フレームなど)、この方法で 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"
        );
}
于 2012-11-05T14:42:41.433 に答える
3

ファイルをバイト配列として扱う場合、バイトを取り出す順序を制御することになり、CPU のエンディアンは実際には問題になりません。

これは、アライメントの問題を処理するという点でも非常に役立ちます。コア ダンプには、アライメントされていない参照が含まれている可能性があります。その可能性は非常に低いことはわかっていますが、腐敗が原因である可能性もあります。これは、ファイルをバイト配列として扱うことで回避できるもう 1 つの問題です。

私は jhead を実装する際にこのアプローチを使用しました。

于 2009-05-18T20:54:23.397 に答える
3

あなたが実際にやろうとしていること (エンディアンの問題を気にせずに ELF コア ダンプ ファイルを読むこと) に基づいて、libelf を使用するのが良い選択だと思います。

このライブラリは、ビッグ エンディアンとリトルエンディアンの ELF ファイルで透過的に動作し、FreeBSD の起源にもかかわらず、Linux で問題なく動作します (通常の "./configure" と "make" シーケンスだけでビルドできます)。grinsについては、x86コアファイルとMIPSビッグエンディアンコアファイルで「プログラムヘッダーテーブルの読み取り」の例(ビルドするために少し変更を加えたもの)を試しましたが、「うまくいく」ようです。

于 2009-05-18T19:11:09.407 に答える
2

apa/inet.h で標準のネットワーク bytswapping 関数を使用できます。

#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

ネットワーク バイト オーダーはビッグ エンディアンです。したがって、これらの関数は次のことを意味します。

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

お役に立てれば。

于 2009-05-18T19:49:29.767 に答える
1

なぜそれを行うためにAPIが必要なのですか?呼び出す独自の関数htonl()(またはBEを生成するもの)を記述してから、バイトを逆にするだけです。それはそれほど難しいことではありません。

何かのようなもの:

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;
于 2009-05-17T13:40:14.117 に答える
1

__cpu_to_be32()や__be32_to_cpu()など、/ usr / include / linux /byteorder/にあるカーネル提供のヘッダーを見てください。

/usr/include/linux/types.hファイルも参照してください。このファイルでは、型を明示的なビッグ/リトルエンディアンのプレーン整数として定義できます。これは、コンパイル時に不一致が検出されるため、非常に役立ちます。

于 2009-05-17T13:44:49.330 に答える
1

エンディアンの切り替えは簡単なので、私は常にそのようなカスタムコードを使用し、コードで使用する表現について厳密なルールを守り、エンドポイント(入力と出力)でエンディアンを処理することになりました。

于 2009-05-17T13:46:04.680 に答える
1

あなたはあなた自身を書くことができます(これらはAppleのルーチンに基づいています):

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) );
}

次に、条件付きマクロを定義できます。

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

Intelアセンブラコードに満足している場合は、次のこともできます。

// 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
于 2009-05-17T13:52:30.047 に答える