Calling a Go function from asm ("fatal error: missing stackmap")

335 views
Skip to first unread message

Caleb Spare

unread,
Sep 19, 2016, 6:56:55 PM9/19/16
to golang-nuts
I'm trying to call a Go function from asm and I'm having trouble figuring out the details.

(In the past I've always endeavored to avoid this situation and make all my asm functions be leaf functions, but in my current use case it would be most helpful to be able to call a Go helper.)

See the demo code at https://github.com/cespare/misc/tree/master/asm/stackmap or go get github.com/cespare/misc/asm/stackmap.

For
​the​
 demo, I have a small function with an append-style API:

func X(b []byte) []byte


This calls a Go helper growSlice.

This code sometimes works, but if I run `go test -count 1000` I'll quickly see

runtime: frame github.com/cespare/misc/asm/stackmap.X untyped locals 0xc420042bf8+0x30
fatal error: missing stackmap
...


I've read through the Runtime Coordination section of the
​asm
 walkthrough (https://golang.org/doc/asm#runtime) several times, but I don't see the problem.

Here is my understanding of a few relevant bits of that section (which might be incorrect):

If the results will hold live pointers during a call instruction, the function should start by zeroing the results and then executing the pseudo-instruction GO_RESULTS_INITIALIZED.

This doesn't seem to apply to my code because the results aren't populated until after the CALL.

If a function has no local stack frame, the pointer information can be omitted. This is indicated by a local frame size annotation of $0-n on the TEXT instruction. The pointer information can also be omitted if the function contains no call instructions. Otherwise, the local stack frame must not contain pointers, and the assembly must confirm this fact by executing the pseudo-instruction NO_LOCAL_POINTERS.

​My function makes a CALL with arguments. But it has to ​have a pointer (the slice) on the local stack frame in order to pass to that helper. I don't really understand what this section means.

`go vet` doesn't say anything about my code.

Any ideas?

Thanks!
Caleb

Ian Lance Taylor

unread,
Sep 19, 2016, 7:17:22 PM9/19/16
to Caleb Spare, golang-nuts
You've run into a really hairy area of asm code.

My first suggestion is not try to call from assembler into Go.

Otherwise, the problem is that when you call into Go the garbage
collector may run. The garbage collector will walk up the stack and
mark all pointers on the stack as live. That means that it needs to
know which values on the stack are live pointers and which are not.
For Go code the compiler generates this information automatically.
For assembler code you need to generate this information yourself.

Also, calling into Go code may cause the stack to be copied so, again,
the stack copier needs to know which stack pointers are live.

In your case you do apparently have a pointer on the stack while
calling the Go function. That means that you need to write PCDATA
$PCDATA_StackMapIndex pseudo-ops that specifies the stack map. But
frankly I don't know what the value should be. If you run "go tool
compile -S" on some similar Go code you will see the PCDATA
statements, probably one per function call. But the details are so
complex that they are undocumented. To get further on this you will
need to read through cmd/compile/internal/gc/plive.go.

Ian

Peng Gao

unread,
Sep 19, 2016, 11:00:34 PM9/19/16
to golang-nuts
BTW in your test file, you can directly append your bytes slice.
b1 = append(b1, vs...)
and slicesEqual is redundant, bytes.Equal does test the length of two arguments.

Peng Gao

unread,
Sep 19, 2016, 11:04:09 PM9/19/16
to golang-nuts


On Tuesday, September 20, 2016 at 11:00:34 AM UTC+8, Peng Gao wrote:
BTW in your test file, you can directly append your bytes slice.
b1 = append(b1, vs...)
and slicesEqual is redundant, bytes.Equal does test the length of two arguments
I mix up cap and len, just ignore it. 

Caleb Spare

unread,
Sep 20, 2016, 7:08:47 PM9/20/16
to Ian Lance Taylor, golang-nuts
Thanks very much for your reply, Ian. I had hoped this would not be
the answer, though :)

I think I can arrange to avoid calling from asm to Go at a minor cost.
That sounds like the best solution here.

Creating the stack map manually might be interesting exercise for
learning about this corner of the compiler/runtime integration.

-Caleb
Reply all
Reply to author
Forward
0 new messages