Edited at

Go 1.8のMIPS32バイナリをルータ上で動かしてみた(成功編)

More than 1 year has passed since last update.

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プログラムを用意します。


hello.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言語でfloatdoubleなどの型が使えるのはなぜでしょうか。

実は、整数演算命令のみで浮動小数点数演算を実現する機構が大半の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サポートが入るはず、そのタイミングが本命





  1. 組み込み系素人の感覚値です