Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

バイトオーダーの検出 #3

Closed
kawasin73 opened this issue Nov 7, 2018 · 1 comment
Closed

バイトオーダーの検出 #3

kawasin73 opened this issue Nov 7, 2018 · 1 comment
Assignees

Comments

@kawasin73
Copy link
Owner

動いているマシンのバイトオーダーを Go 言語で検出する方法を調査する。

@kawasin73 kawasin73 self-assigned this Nov 7, 2018
@kawasin73 kawasin73 mentioned this issue Nov 7, 2018
15 tasks
@kawasin73
Copy link
Owner Author

kawasin73 commented Nov 8, 2018

マシンのバイトオーダーを検出する方法は以下の2通りある。

  • マシンアーキテクチャによってコンパイルするファイルを変更するビルドフラグを利用する
  • uint64 の値の 1 バイト目の値を読み取る

ビルドフラグを利用する方法 では、2種類のバイトオーダーそれぞれについてソースファイルを作成し、ビルドアーキテクチャによってコンパイルするファイルを変更するビルドフラグをファイルの先頭に記載することでバイトオーダーをコード内で判別できるようにする。

Little Endian の場合

// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le mips64p32le

const endian = LittleEndian

https://github.com/tsuna/endian/blob/master/little.go#L6

Big Endian の場合

// +build armbe arm64be ppc64 mips mips64 mips64p32 ppc s390 s390x sparc sparc64

const endian = BigEndian

https://github.com/tsuna/endian/blob/master/big.go#L6

この手法ではマシンアーキテクチャを指定するためコンパイル時にホストのバイトオーダーがわかるためその結果を定数に保存可能であるが、以下のデメリットがあるため採用を見送る

  • Go言語が対応するアーキテクチャが増えたときに追記するメンテナンスコストが発生する
  • それぞれのアーキテクチャのバイトオーダーの調査コスト
  • ビルドフラグの記載ミスが発生する可能性がある

uint64 の1バイト目の値を読み取る方法 では、uint64 に値を設定しその 0 バイト目の値を unsafe パッケージを利用して読み取りホストマシンのバイトオーダーを検出する。この処理を init() 関数内で行い起動時にバイトオーダーを判別する。

// Get native endianness for the system
func NativeEndian() binary.ByteOrder {
	if nativeEndian == nil {
		var x uint32 = 0x01020304
		if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
			nativeEndian = binary.BigEndian
		} else {
			nativeEndian = binary.LittleEndian
		}
	}
	return nativeEndian
}

https://github.com/vishvananda/netlink/blob/aa5b058fc07b88462111aaf4f7c89f1caee9c990/nl/nl_linux.go#L50-L60

この手法は unsafe パッケージを使うため実装には注意が必要となるが、直接的にホストマシンのバイトオーダーを検出する手法であり、Go 言語の対応するアーキテクチャが増えてもメンテナンスをする必要がない。
また、副次的なメリットとして、ごく少数のアーキテクチャで採用される ミドルエンディアン を検出することができる。ミドルエンディアンは PDP-11 などで採用されているバイトオーダーであるが、起動時にこのエンディアンが検出された場合はプロセスを終了させるなどの対応が可能になる。

参考記事

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant