ARMv7なLinuxマシン上で、GoでビルドしたARMバイナリを実行してみたら「Illegal instruction」エラーで死にました。
# uname -m
armv7l
# ./hello
Illegal instruction
このARMバイナリは下記コマンドで生成しました。GOARM
環境変数が指定されていない場合はデフォルトでARMv6バイナリを生成します。
$ GOOS=linux GOARCH=arm go build
ARMv7の方がバージョンが上なのだから、ARMv6バイナリは動きそうなものです。ちなみに、ARMv7バイナリを生成してみても同じエラーで死にます。
FPUの有無を確認する方法
結論から言うと、今回作ったARMバイナリはFPU命令を含んでいるのですが、このCPUにはFPUがないためエラーで終了しています。
対象のCPUにFPUが存在するかどうかは次のように確認できます。
# cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 0 (v7l)
BogoMIPS : 1594.16
Features : half thumb fastmult edsp tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x3
CPU part : 0xc09
CPU revision : 0
Hardware : BCM5301X
Revision : 0000
Serial : 0000000000000000
Features
の行にvfp
という文字列が見当たらなかったらFPU無しということになります。つまり、このCPUはARMv7命令は理解するけどFPU命令は理解できないということになります。
GoでARMのsoft-floatバイナリを生成する方法
この問題への対策ですが、Goプロジェクトのビルド時にGOARM=5
でARMv5バイナリを指定すればFPU無しの機種でも動くバイナリがコンパイルできます。
$ GOOS=linux GOARCH=arm GOARM=5 go build
現状のGoコンパイラではv5用はsoft-floatバイナリしか作ることはできない一方で、v6用やv7用は必ずhard-floatバイナリになってしまうようです。