Hi,
I encountered a minor trouble: panic
called from a golang’s assembly function doesn’t work completely.
The motivation is as follows:
I want the highly-optimized code for vector inner product code, hence, its code should check the length of the two vectors equal, and reports the error with panic
.
When I wrap the assembly code with golang’s function for panic
, the overhead at the entry and exit process (runtime.morestack_noctxt
, etc) makes the calculation slow down (profiler reports that they took more than a second …).
In order to show my problem, I wrote a PoC code.
At first, I wrote the following assembly code:
#include "funcdata.h"
#include "textflag.h"
// func panicPanic()
TEXT ·panicPanic(SB), NOSPLIT, $0-0
SUBQ $8, SP
MOVQ BP, 0(SP)
LEAQ 0(SP), BP
MOVQ ·panicMessage(SB), AX
MOVQ ·panicMessage+8(SB), CX
TESTQ AX, AX
JEQ panic1
MOVQ 8(AX), AX
panic1:
MOVQ AX, (SP)
MOVQ CX, 8(SP)
CALL runtime·gopanic(SB)
Then, I build and run the following golang’s code on golang 1.10.3 and macOS 10.13.5:
package main
import "fmt"
var panicMessage = fmt.Errorf("Panic panic")
func panicPanic()
func tryPanic() {
defer func() {
fmt.Printf("recovered: %s\n", recover())
}()
panicPanic()
}
func main() {
tryPanic()
panicPanic()
}
I found that recover
works expectedly, however, the backtrace triggered by runtime.gopanic
called at panicPanic
didn’t work expectedly:
recovered: Panic panic
panic: Panic panic
goroutine 1 [running]:
runtime: unexpected return pc for runtime.gopanic called from 0x108f261
stack: frame={sp:0xc420045ec8, fp:0xc420045f68} stack=[0xc420044000,0xc420046000)
000000c420045dc8: 00000000010489a2 <runtime.writeErr+66> 0000000000000002
000000c420045dd8: 00000000010c0147 0000000000000001
000000c420045de8: 000000c400000001 000000c420045e28
000000c420045df8: 0000000001026b08 <runtime.gwrite+280> 00000000010c0147
000000c420045e08: 0000000000000001 0000000000000001
000000c420045e18: 0000000001026b08 <runtime.gwrite+280> 00000000010c0748
000000c420045e28: 000000c420045e78 00000000010272bd <runtime.printstring+125>
000000c420045e38: 00000000010c0147 0000000000000001
000000c420045e48: 0000000000000001 00000000010c0147
000000c420045e58: 0000000000000001 00000000010c0147
000000c420045e68: 0000000000000001 0000000000000001
000000c420045e78: 000000c420045e98 000000c420045e98
000000c420045e88: 0000000001025f7a <runtime.dopanic+74> 000000c420045e98
000000c420045e98: 000000000104a330 <runtime.dopanic.func1+0> 000000c420000180
000000c420045ea8: 0000000001025bb1 <runtime.gopanic+961> 000000c420045ec8
000000c420045eb8: 000000c420045f58 0000000001025bb1 <runtime.gopanic+961>
000000c420045ec8: <0000000000000000 00000000010c70a8
000000c420045ed8: 000000c420056030 0000000800000008
000000c420045ee8: 00000000010277b1 <runtime.main+257> 000000c42007e1a0
000000c420045ef8: 000000c420045f88 000000c420000180
000000c420045f08: 000000c4200001a0 000000c420056020
000000c420045f18: 000000c420056000 000000c4200001a8
000000c420045f28: 000000c4200001a0 0000000000000000
000000c420045f38: 000000000109f220 000000c42007a1d0
000000c420045f48: 0000000000000000 0000000000000000
000000c420045f58: 000000c420045f68 !000000000108f261
000000c420045f68: >00000000010a5c40 000000c42007a1c0
000000c420045f78: 00007fffffe00000 00000000010278c2 <runtime.main+530>
000000c420045f88: 000000c420078000 0000000000000000
000000c420045f98: 000000c420078000 0000000000000000
000000c420045fa8: 0000000000000000 0000000000000000
000000c420045fb8: 0000000000000000 0000000000000000
000000c420045fc8: 000000c420000180 0000000000000000
000000c420045fd8: 000000000104d981 <runtime.goexit+1> 0000000000000000
000000c420045fe8: 0000000000000000 0000000000000000
000000c420045ff8: 0000000000000000
runtime: unexpected return pc for runtime.gopanic called from 0x108f261
stack: frame={sp:0xc420045ec8, fp:0xc420045f68} stack=[0xc420044000,0xc420046000)
000000c420045dc8: 00000000010489a2 <runtime.writeErr+66> 0000000000000002
000000c420045dd8: 00000000010c0147 0000000000000001
000000c420045de8: 000000c400000001 000000c420045e28
000000c420045df8: 0000000001026b08 <runtime.gwrite+280> 00000000010c0147
000000c420045e08: 0000000000000001 0000000000000001
000000c420045e18: 0000000001026b08 <runtime.gwrite+280> 00000000010c0748
000000c420045e28: 000000c420045e78 00000000010272bd <runtime.printstring+125>
000000c420045e38: 00000000010c0147 0000000000000001
000000c420045e48: 0000000000000001 00000000010c0147
000000c420045e58: 0000000000000001 00000000010c0147
000000c420045e68: 0000000000000001 0000000000000001
000000c420045e78: 000000c420045e98 000000c420045e98
000000c420045e88: 0000000001025f7a <runtime.dopanic+74> 000000c420045e98
000000c420045e98: 000000000104a330 <runtime.dopanic.func1+0> 000000c420000180
000000c420045ea8: 0000000001025bb1 <runtime.gopanic+961> 000000c420045ec8
000000c420045eb8: 000000c420045f58 0000000001025bb1 <runtime.gopanic+961>
000000c420045ec8: <0000000000000000 00000000010c70a8
000000c420045ed8: 000000c420056030 0000000800000008
000000c420045ee8: 00000000010277b1 <runtime.main+257> 000000c42007e1a0
000000c420045ef8: 000000c420045f88 000000c420000180
000000c420045f08: 000000c4200001a0 000000c420056020
000000c420045f18: 000000c420056000 000000c4200001a8
000000c420045f28: 000000c4200001a0 0000000000000000
000000c420045f38: 000000000109f220 000000c42007a1d0
000000c420045f48: 0000000000000000 0000000000000000
000000c420045f58: 000000c420045f68 !000000000108f261
000000c420045f68: >00000000010a5c40 000000c42007a1c0
000000c420045f78: 00007fffffe00000 00000000010278c2 <runtime.main+530>
000000c420045f88: 000000c420078000 0000000000000000
000000c420045f98: 000000c420078000 0000000000000000
000000c420045fa8: 0000000000000000 0000000000000000
000000c420045fb8: 0000000000000000 0000000000000000
000000c420045fc8: 000000c420000180 0000000000000000
000000c420045fd8: 000000000104d981 <runtime.goexit+1> 0000000000000000
000000c420045fe8: 0000000000000000 0000000000000000
000000c420045ff8: 0000000000000000
panic(0x10a5c40, 0xc42007a1c0)
/usr/local/go/src/runtime/panic.go:551 +0x3c1
I doubt that this is because the runtime.gopanic
call from a assembly function is not registered (see https://github.com/golang/go/blob/0e0cd70ecf6b5f0d9c8271f68b8fcc9f85cd6598/src/runtime/traceback.go#L257).
I think the backtrace implementation detected that the call stack was broken.
I tried some options funcdata.h
or textflag.h
as referring to the assembly code generated by golang’s compiler, but I didn’t find a solution.
I searched this problem on web also, but, I didn’t find any solution…
If you have any idea, please tell me your solution!