OpenBSD/sgi on octane2 - __cpu_simple_lock_tryのバグ
__cpu_simple_lock_try()でoldとnewが両方ともv0にコンパイルされちまってるよ、"=r"を"=&r"に書き換えると直るよ、とエラい人に教えてもらった。
まじかよ。
って事で早速ダンプを取ってみた。
__cpu_simple_lock_try()はinline関数だから、展開先を作ってあげると読みやすい。なので
#include <machine/lock.h> __cpu_simple_lock_t lock; static void locktest(void) { __cpu_simple_lock_try(&lock); }
という関数を定義して、これをobjdumpで覗いてみる。
a80000002013dbc0 <locktest>: a80000002013dbc0: 67bdfff0 daddiu sp,sp,-16 a80000002013dbc4: 24020001 li v0,1 a80000002013dbc8: afa20004 sw v0,4(sp) a80000002013dbcc: 3c03a800 lui v1,0xa800 a80000002013dbd0: 3c01205c lui at,0x205c a80000002013dbd4: 64630000 daddiu v1,v1,0 a80000002013dbd8: 6421e5d0 daddiu at,at,-6704 a80000002013dbdc: 0003183c dsll32 v1,v1,0x0 a80000002013dbe0: 0061182d daddu v1,v1,at a80000002013dbe4: 8fa20004 lw v0,4(sp) a80000002013dbe8: c0620000 ll v0,0(v1) a80000002013dbec: e0620000 sc v0,0(v1) a80000002013dbf0: 1040fffd beqz v0,a80000002013dbe8 <locktest+0x28> a80000002013dbf4: 00000000 nop a80000002013dbf8: 00000000 nop a80000002013dbfc: afa20000 sw v0,0(sp) a80000002013dc00: 8fa30000 lw v1,0(sp) a80000002013dc04: 8fa20000 lw v0,0(sp) a80000002013dc08: 03e00008 jr ra a80000002013dc0c: 67bd0010 daddiu sp,sp,16
llとscに注目。
インラインアセンブリでは
__asm__ __volatile__ ("1:\tll\t%0, %1\n" "\tsc\t%2, %1\n" "\tbeqz\t%2, 1b\n" "\t nop" : "=r" (old) : "m" (*l), "r" (new));
と定義されているので、llの一個目のオペランドとscの一個目のオペランドは異ならなければならない。
が、両方ともv0。
何のマジック?これ( Д ) ゚ ゚
で、"=r"を=&r"と書き換えると、きちんと別々のレジスタを使うようになる。
a80000002013dbc0 <locktest>: a80000002013dbc0: 67bdfff0 daddiu sp,sp,-16 a80000002013dbc4: 24020001 li v0,1 a80000002013dbc8: afa20004 sw v0,4(sp) a80000002013dbcc: 3c04a800 lui a0,0xa800 a80000002013dbd0: 3c01205c lui at,0x205c a80000002013dbd4: 64840000 daddiu a0,a0,0 a80000002013dbd8: 6421e5d0 daddiu at,at,-6704 a80000002013dbdc: 0004203c dsll32 a0,a0,0x0 a80000002013dbe0: 0081202d daddu a0,a0,at a80000002013dbe4: 8fa20004 lw v0,4(sp) a80000002013dbe8: c0830000 ll v1,0(a0) a80000002013dbec: e0820000 sc v0,0(a0) a80000002013dbf0: 1040fffd beqz v0,a80000002013dbe8 <locktest+0x28> a80000002013dbf4: 00000000 nop a80000002013dbf8: 00000000 nop a80000002013dbfc: afa30000 sw v1,0(sp) a80000002013dc00: 8fa20000 lw v0,0(sp) a80000002013dc04: 8fa30000 lw v1,0(sp) a80000002013dc08: 03e00008 jr ra a80000002013dc0c: 67bd0010 daddiu sp,sp,16
うまくいっているようだが、なんだこれ。