1
Tricky implementation
Of Go ARM soft float
Tetsuyuki Kobayashi
2015.2.14 Kernel/VM 探検隊
2015.2.22 YAPF
2
 The latest version of this slide will
be available from here
 http://www.slideshare.net/tetsu.koba/presentati
ons
3
Who am I?
 20+ years involved in embedded systems
 10 years in real time OS, such as iTRON
 10 years in embedded Java Virtual Machine
 Now GCC, Linux, QEMU, Android, …
 Blogs
 http://d.hatena.ne.jp/embedded/
 http://kobablog.wordpress.com/(English)
 Twitter
 @tetsu_koba
4
Golang for ARM Linux
 ツールチェインのビルド
 ソースコードを入手して
$ cd go/src
$ GOOS=linux GOARCH=arm GOARM=5 ./make.bash
 実行型のビルド
 Go コマンドに PATH を通して
$ GOOS=linux GOARCH=arm GOARM=5 go build hello.go
5
GOARM
 GOARM=5
 For armv5, no FPU, soft float
 GOARM=6
 (Default)
 For armv6, VFPv1
 GOARM=7
 For armv7, VFPv3
6
以上。
7
間違えなければ
どうということはない。
8
しかし、
9
間違いから理解が
深まることもある。
10
ツールチェインのビルドミス
$ GOOS=linux GOARCH=arm GOARM=5 ./make.bash
 GOARM を指定しないときは GOARM=6
これを忘れた!
11
ARM$ ./hello
Illegal Instruction
 できた実行ファイルを実機 (armv5, no
FPU) に持って行って実行すると
$ GOOS=linux GOARCH=arm GOARM=5 go build hello.go
12
FPU 命令が混じってた
vldr d2, [r3]
 gdb で illegal instruction を起こした命令を
調べると
ランタイムライブラリが GOARM=6 で
ビルドされているからか!
13
やり直し
$ GOOS=linux GOARCH=arm GOARM=5 ./make.bash
$ GOOS=linux GOARCH=arm GOARM=5 go build hello.go
14
念のために逆アセンブル
$ arm-linux-gnueabi-objdump -d hello
...
bl <_sfloat>
vldr d2, [r3]
fcpyd d4, d2
...
  FPU 命令がまだある?!
15
Go1.4 は armv5 サポート
無くなった?
 git で go1.3, go1.2, go1.1 のそれぞれ
のタグをチェックアウトして調べた
 全て同じだった
16
Soft float emulation
 ARM の Linux kernel には soft float
emulation があった
 kernel を再ビルド
CONFIG_OABI_COMAT=y
CONFIG_FPE_NWFPE=y
 これで動いた!
ARM$ ./hello
Hello, Go
17
しかし
 Go ARM がカーネルコンフィグに依
存するとはどこにも書いてない?
 しかも
 ARM の soft float emulation は
Deprecated
 最近のカーネルではすでに削除されて
いる
18
実は
 soft float emulation を有効にしていな
いカーネルでも hello は動いた
 カーネルのコンフィグは無関係

 ( 本当はツールチェインのビルドを間
違っただけ )
19
謎の関数 _sfloat
...
bl <_sfloat>
vldr d2, [r3]
fcpyd d4, d2
...
フロート演算のコードに共通するパターンを発見。
...
bl <_sfloat>
vldr d2, [r0]
fcmped d3, d2
fmstat
bvs 117fc
...
  FPU 命令の前に必ず
_sfloat を呼び出す
20
_sfloat のソースコードを追跡
 _sfloat in go/src/runtime/vlop_arm.s
 → runtime ・ _sfloat2
 _sfloat2 in go/src/runtime/softfloat_arm.c
 → sfloat2
21
static void sfloat2(void)
{
…
while (skip = stepflt(pc, (uint32*)&regs->r0)){
:
:
pc += skip
}
g->m->ptarg[0] = pc;
}
Soft float emulation inside golang
Comment is source code:
stepflt returns number of words that the fp instruction is occupying,
0 if next instruction isn't float
FPU 命令のインタープリタ
22
// returns number of words that the fp instruction
// is occupying, 0 if next instruction isn't float.
static uint32
stepflt(uint32 *pc, uint32 *regs)
{
...
switch(i & 0xffff0ff0) {
default:
goto done;
case 0xeeb00a40: // F[regd] = F[regm] (MOVF)
m->freglo[regd] = m->freglo[regm];
if(trace)
runtime·printf("*** F[%d] = F[%d] %xn",
regd, regm, m->freglo[regd]);
break;
case 0xeeb00b40: // D[regd] = D[regm] (MOVD)
stepflt は FPU 命令のインタープリタ
23
FPU 命令は CPU で実行されていない
FPU 命令が混じっていても
illegal instruction にならない
...
bl <_sfloat>
vldr d2, [r0]
fcmped d3, d2
fmstat
bvs 117fc
...
_sfloat から戻ってきた後に
この命令から実行再開
24
GOARM=5 と 6 の生成コードの違い
 どちらも FPU 命令を生成する
 GOARM=5 の場合は FPU 命令の塊の前に
_sfloat への呼び出しが挿入される。
( リンカーがこれを行っている )
 生成された FPU 命令は同じ。
 コンパイラは soft float のための命令を生成し
ないので実装がラク。
25
結論
 Golang は自前で soft float emulation する
仕組みを持っている。
 カーネルの soft float emulation は不要。
 正しくビルドすれば普通に動く。
 ついでにわかったこと
 ARM Linux の soft float emulation は
deprecated
26
Q & A
@tetsu_koba
Thank you for listening!

Tricky implementation of Go ARM soft float

  • 1.
    1 Tricky implementation Of GoARM soft float Tetsuyuki Kobayashi 2015.2.14 Kernel/VM 探検隊 2015.2.22 YAPF
  • 2.
    2  The latestversion of this slide will be available from here  http://www.slideshare.net/tetsu.koba/presentati ons
  • 3.
    3 Who am I? 20+ years involved in embedded systems  10 years in real time OS, such as iTRON  10 years in embedded Java Virtual Machine  Now GCC, Linux, QEMU, Android, …  Blogs  http://d.hatena.ne.jp/embedded/  http://kobablog.wordpress.com/(English)  Twitter  @tetsu_koba
  • 4.
    4 Golang for ARMLinux  ツールチェインのビルド  ソースコードを入手して $ cd go/src $ GOOS=linux GOARCH=arm GOARM=5 ./make.bash  実行型のビルド  Go コマンドに PATH を通して $ GOOS=linux GOARCH=arm GOARM=5 go build hello.go
  • 5.
    5 GOARM  GOARM=5  Forarmv5, no FPU, soft float  GOARM=6  (Default)  For armv6, VFPv1  GOARM=7  For armv7, VFPv3
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
    10 ツールチェインのビルドミス $ GOOS=linux GOARCH=armGOARM=5 ./make.bash  GOARM を指定しないときは GOARM=6 これを忘れた!
  • 11.
    11 ARM$ ./hello Illegal Instruction できた実行ファイルを実機 (armv5, no FPU) に持って行って実行すると $ GOOS=linux GOARCH=arm GOARM=5 go build hello.go
  • 12.
    12 FPU 命令が混じってた vldr d2,[r3]  gdb で illegal instruction を起こした命令を 調べると ランタイムライブラリが GOARM=6 で ビルドされているからか!
  • 13.
    13 やり直し $ GOOS=linux GOARCH=armGOARM=5 ./make.bash $ GOOS=linux GOARCH=arm GOARM=5 go build hello.go
  • 14.
    14 念のために逆アセンブル $ arm-linux-gnueabi-objdump -dhello ... bl <_sfloat> vldr d2, [r3] fcpyd d4, d2 ...   FPU 命令がまだある?!
  • 15.
    15 Go1.4 は armv5サポート 無くなった?  git で go1.3, go1.2, go1.1 のそれぞれ のタグをチェックアウトして調べた  全て同じだった
  • 16.
    16 Soft float emulation ARM の Linux kernel には soft float emulation があった  kernel を再ビルド CONFIG_OABI_COMAT=y CONFIG_FPE_NWFPE=y  これで動いた! ARM$ ./hello Hello, Go
  • 17.
    17 しかし  Go ARMがカーネルコンフィグに依 存するとはどこにも書いてない?  しかも  ARM の soft float emulation は Deprecated  最近のカーネルではすでに削除されて いる
  • 18.
    18 実は  soft floatemulation を有効にしていな いカーネルでも hello は動いた  カーネルのコンフィグは無関係   ( 本当はツールチェインのビルドを間 違っただけ )
  • 19.
    19 謎の関数 _sfloat ... bl <_sfloat> vldrd2, [r3] fcpyd d4, d2 ... フロート演算のコードに共通するパターンを発見。 ... bl <_sfloat> vldr d2, [r0] fcmped d3, d2 fmstat bvs 117fc ...   FPU 命令の前に必ず _sfloat を呼び出す
  • 20.
    20 _sfloat のソースコードを追跡  _sfloatin go/src/runtime/vlop_arm.s  → runtime ・ _sfloat2  _sfloat2 in go/src/runtime/softfloat_arm.c  → sfloat2
  • 21.
    21 static void sfloat2(void) { … while(skip = stepflt(pc, (uint32*)&regs->r0)){ : : pc += skip } g->m->ptarg[0] = pc; } Soft float emulation inside golang Comment is source code: stepflt returns number of words that the fp instruction is occupying, 0 if next instruction isn't float FPU 命令のインタープリタ
  • 22.
    22 // returns numberof words that the fp instruction // is occupying, 0 if next instruction isn't float. static uint32 stepflt(uint32 *pc, uint32 *regs) { ... switch(i & 0xffff0ff0) { default: goto done; case 0xeeb00a40: // F[regd] = F[regm] (MOVF) m->freglo[regd] = m->freglo[regm]; if(trace) runtime·printf("*** F[%d] = F[%d] %xn", regd, regm, m->freglo[regd]); break; case 0xeeb00b40: // D[regd] = D[regm] (MOVD) stepflt は FPU 命令のインタープリタ
  • 23.
    23 FPU 命令は CPUで実行されていない FPU 命令が混じっていても illegal instruction にならない ... bl <_sfloat> vldr d2, [r0] fcmped d3, d2 fmstat bvs 117fc ... _sfloat から戻ってきた後に この命令から実行再開
  • 24.
    24 GOARM=5 と 6の生成コードの違い  どちらも FPU 命令を生成する  GOARM=5 の場合は FPU 命令の塊の前に _sfloat への呼び出しが挿入される。 ( リンカーがこれを行っている )  生成された FPU 命令は同じ。  コンパイラは soft float のための命令を生成し ないので実装がラク。
  • 25.
    25 結論  Golang は自前でsoft float emulation する 仕組みを持っている。  カーネルの soft float emulation は不要。  正しくビルドすれば普通に動く。  ついでにわかったこと  ARM Linux の soft float emulation は deprecated
  • 26.
    26 Q & A @tetsu_koba Thankyou for listening!