12

ELF アナライザーを作成していますが、エンディアンを適切に変換するのに問題があります。アナライザーのエンディアンとオブジェクト ファイルのエンディアンを判断する関数があります。

基本的に、考えられるシナリオは次の 4 つです。

  1. ビッグ エンディアン オブジェクト ファイルで実行されるビッグ エンディアン コンパイル済みアナライザー
    • 何も変換する必要はありません
  2. リトル エンディアン オブジェクト ファイルで実行されるビッグ エンディアン コンパイル済みアナライザー
    • バイト オーダーを交換する必要がありますが、ビッグ エンディアン マシンでは ntohs/l() と htons/l() は両方ともヌル マクロであるため、バイト オーダーを交換しません。これが問題です
  3. ビッグ エンディアン オブジェクト ファイルで実行されるリトル エンディアン コンパイル済みアナライザー
    • バイト オーダーを入れ替える必要があるため、htons() を使用してバイト オーダーを入れ替えます。
  4. リトル エンディアン オブジェクト ファイルで実行されるリトル エンディアン コンパイル済みアナライザー。
    • 何も変換する必要はありません

ntohs/l() と htons/l() はホストのエンディアンを考慮し、変換しない場合があるため、バイト オーダーを明示的にスワップ/エンディアンを変更するために使用できる関数はありますか? または、独自のスワップ バイト オーダー関数を検索/作成する必要がありますか?

4

5 に答える 5

12

I think it's worth raising The Byte Order Fallacy article here, by Rob Pyke (one of Go's author).

If you do things right -- ie you do not assume anything about your platforms byte order -- then it will just work. All you need to care about is whether ELF format files are in Little Endian or Big Endian mode.

From the article:

Let's say your data stream has a little-endian-encoded 32-bit integer. Here's how to extract it (assuming unsigned bytes):

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

If it's big-endian, here's how to extract it:

i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);

And just let the compiler worry about optimizing the heck out of it.

于 2012-04-27T06:49:15.470 に答える
8

Linuxには、任意のエンディアン間の変換を可能にする変換関数がいくつかあります。endian.h

uint16_t htobe16(uint16_t host_16bits);
uint16_t htole16(uint16_t host_16bits);
uint16_t be16toh(uint16_t big_endian_16bits);
uint16_t le16toh(uint16_t little_endian_16bits);

uint32_t htobe32(uint32_t host_32bits);
uint32_t htole32(uint32_t host_32bits);
uint32_t be32toh(uint32_t big_endian_32bits);
uint32_t le32toh(uint32_t little_endian_32bits);

uint64_t htobe64(uint64_t host_64bits);
uint64_t htole64(uint64_t host_64bits);
uint64_t be64toh(uint64_t big_endian_64bits);
uint64_t le64toh(uint64_t little_endian_64bits);

編集された、信頼性の低いソリューション。ユニオンを使用して、任意の順序でバイトにアクセスできます。とても便利です:

union {
    short number;
    char bytes[sizeof(number)];
};
于 2012-04-26T21:12:02.340 に答える
4

独自のスワップ バイト オーダー関数を検索/作成する必要がありますか?

そうです。しかし、簡単にするために、次の質問を参照してください: C++ でビッグ エンディアンとリトルエンディアンの値を変換するにはどうすればよいですか? これは、コンパイラ固有のバイト順スワップ関数のリストと、バイト順スワップ関数のいくつかの実装を提供します。

于 2012-04-26T21:12:39.970 に答える
1

ntoh 関数は、ビッグ エンディアンとリトル エンディアンの間だけでなく、スワップすることもできます。一部のシステムは、バイトが単に順序付けられるのではなく、スクランブルされる「ミドル エンディアン」でもあります。

とにかく、ビッグ エンディアンとリトル エンディアンだけを気にするのであれば、ホストとオブジェクト ファイルのエンディアンが異なるかどうかを知る必要があるだけです。無条件にバイトオーダーを交換する独自の関数があり、それを呼び出すかどうかに基づいて呼び出しますhost_endianess()==objectfile_endianess()

于 2012-04-26T21:17:57.173 に答える
0

Windows または Linux で動作するクロスプラットフォーム ソリューションについて考えるとしたら、次のように記述します。

#include <algorithm>

// dataSize is the number of bytes to convert.
char le[dataSize];// little-endian
char be[dataSize];// big-endian

// Fill contents in le here...
std::reverse_copy(le, le + dataSize, be);
于 2012-04-27T02:27:29.987 に答える