(追記 2020/1/10)続編もご覧ください→ Go 1.10にMIPS32 softfloat対応が来たよー - Qiita
Go 1.8から32bit MIPS Linux環境がサポートされました(参考:https://tip.golang.org/doc/go1.8#ports )。32bit MIPSは組み込み系開発ボードなどに多く採用されているCPUで、身近なところでは家庭用ブロードバンドルータの半分以上1でMIPS32が採用されています。つまりブロードバンドルータ上でGoプログラムが動くというわけです。これはアツいですね!
本稿ではまず簡単なGoプログラムをMIPSベースのブロードバンドルータ上で動かします。次に、GoのMIPS32サポートの現状と今後について紹介します。
動かしてみた
では、さっそくGoでMIPS32バイナリを生成してみましょう。まずはGo 1.8RC1をインストールします。
$ go get golang.org/x/build/version/go1.8rc1
$ go1.8rc1 download
次に、下記のGoプログラムを用意します。
package main
import "fmt"
func main() {
fmt.Printf("Hello, world!\n")
}
次のようにコンパイルすれば32-bit MIPS用のhello
バイナリが得られます。
$ GOOS=linux GOARCH=mips go1.8rc1 build hello.go
$ file hello
hello: ELF 32-bit MSB executable, MIPS, MIPS32 version 1 (SYSV), statically linked, not stripped
さて、実際に動かしてみましょう。筆者はBuffalo社の有線ブロードバンドルータBHR-4GRV上にOpenWrtというLinuxディストリビューションをインストールしています。
このブロードバンドルータにscpでバイナリを送り込むと、バイナリが動作しました。
$ scp hello openwrt01:/tmp
$ ssh openwrt01
BusyBox v1.23.2 (2017-01-19 17:27:24 UTC) built-in shell (ash)
_______ ________ __
| |.-----.-----.-----.| | | |.----.| |_
| - || _ | -__| || | | || _|| _|
|_______|| __|_____|__|__||________||__| |____|
|__| W I R E L E S S F R E E D O M
-----------------------------------------------------
CHAOS CALMER (Chaos Calmer, unknown)
-----------------------------------------------------
* 1 1/2 oz Gin Shake with a glassful
* 1/4 oz Triple Sec of broken ice and pour
* 3/4 oz Lime Juice unstrained into a goblet.
* 1 1/2 oz Orange Juice
* 1 tsp. Grenadine Syrup
-----------------------------------------------------
# /tmp/hello
Hello, world!
こう書くと簡単に動くように見えますが、実はこのバイナリは多くの環境で動作しません。上記の環境ではこのバイナリを動かすため自前のカーネルに入れ替えています。
現時点のGoのMIPS32サポート状況
Go 1.8のリリースノートには、次のような記述があります。
Go now supports 32-bit MIPS on Linux for both big-endian (linux/mips) and little-endian machines (linux/mipsle) that implement the MIPS32r1 instruction set with FPU or kernel FPU emulation. Note that many common MIPS-based routers lack an FPU and have firmware that doesn't enable kernel FPU emulation; Go won't run on such machines.
Go 1.8の32-bit MIPSサポートはFPU(浮動小数点演算ユニット)またはカーネルによるFPUエミュレーションが必須だと書いてあります。これを満たす32-bit MIPS環境はごく少数であるため、かなり厳しい制約だと言えるでしょう。
実際、私の持っているブロードバンドルータにはFPUはありませんし、OpenWrtでもカーネルFPUエミュレーションはデフォルトで無効になっています。FPUエミュエーション有効にしてカーネルビルドしなおしたのが上の環境というわけです。
カーネルFPUエミュレーションとsoft-float
ところで、FPUが無い環境というのは組み込み系では珍しくありません。そうした環境でもC言語でfloat
やdouble
などの型が使えるのはなぜでしょうか。
実は、整数演算命令のみで浮動小数点数演算を実現する機構が大半のCコンパイラで提供されています。これはsoftware floating pointとかsoft-floatなどと呼ばれます。この仕組みにより、FPUの無い環境でも浮動小数点数演算が実現できているわけです。逆に、Go 1.8でFPU必須という制約がついているのはsoft-floatが未実装であるという意味でもあります。
一方で、今回の実験で使ったようにカーネル側でFPU命令のエミュレーションを行うアプローチも考えられます。これはARM LinuxとMIPS Linuxで提供されている機構のようです(私が知らないだけで、他の環境でも珍しくないのかもしれません)。これを使えばコンパイラ側の実装コストは減りますが、FPU命令が発効されるたびにカーネル割り込みが走るため速度面ではかなり不利です。カーネルFPUエミュレーションとsoft-floatの好きな方が選べるのであれば、当然後者を選ぶべきです。
もちろんGoの中の人も同じ認識のようで、既にMIPS32のsoft-floatサポートについて議論されています(参考:「runtime: mips32 soft float point support · Issue #18162 · golang/go」)。ただ、Go 1.8のタイミングでは時間切れだったということのようです。Go 1.9以降に期待したいですね。
まとめ
- Go 1.8でMIPS32バイナリが出力できるようになった
- ただし、このバイナリが動く環境は少ないと思われる。大抵の環境ではカーネルリコンパイルが必要。
- Go 1.9以降MIPS32のsoft-floatサポートが入るはず、そのタイミングが本命
-
組み込み系素人の感覚値です ↩