Cross-compilation of golang assembly via 'go tool asm'

479 views
Skip to first unread message

pcj...@gmail.com

unread,
Sep 12, 2016, 11:17:19 PM9/12/16
to golang-nuts
I'm implementing cross-compilation support in rules_go.  This takes a low-level approach to building golang targets that involves use of the individual toolchain components such as 'go tool asm', 'go tool compile', 'go tool link', etc...

Cross-compilation of pure-go inputs is working swimmingly.  However, I'm wondering how to cross-compile assembly inputs correctly.  Consider the following assembly file that defines an 'add' method.

#include "textflag.h"

TEXT ·add(SB),NOSPLIT,$0
MOVQ x+0(FP), BX
MOVQ y+8(FP), BP
ADDQ BP, BX
MOVQ BX, ret+16(FP)
RET

For example, this works:

$ go tool asm -I $(go env GOROOT)/pkg/include -o add.o add.s

$ hexdump add.o

0000000 67 6f 20 6f 62 6a 65 63 74 20 64 61 72 77 69 6e

0000010 20 61 6d 64 36 34 20 67 6f 31 2e 36 2e 32 0a 21

0000020 0a 00 00 67 6f 31 33 6c 64 01 00 fe 02 0c 22 22

0000030 2e 61 64 64 00 00 40 00 00 40 48 8b 5c 24 08 48

0000040 8b 6c 24 10 48 01 eb 48 89 5c 24 18 c3 cc cc cc

0000050 cc cc cc cc cc cc cc cc cc cc 00 ff ff ff ff 0f

0000060 00 02 00 00 06 02 20 00 06 02 20 00 16 0a 05 02

0000070 05 02 03 02 05 02 0e 00 00 02 28 22 22 2e 61 64

0000080 64 2e 61 72 67 73 5f 73 74 61 63 6b 6d 61 70 00

0000090 00 02 52 2f 55 73 65 72 73 2f 70 63 6a 2f 67 69

00000a0 74 68 75 62 2f 67 72 70 63 2d 67 72 65 65 74 65

00000b0 72 74 69 6d 65 72 2f 61 64 64 2e 73 02 ff ff 67

00000c0 6f 31 33 6c 64                                 

00000c5


Given the magic of "goose" and "garch" (and it is magical), I expected this to work:

$ env GOOS=linux GOARCH=arm go tool asm -I $(go env GOROOT)/pkg/include -o add.o add.s

add.s:4: unrecognized instruction "MOVQ"

add.s:5: unrecognized instruction "MOVQ"

add.s:6: unrecognized instruction "ADDQ"

add.s:7: unrecognized instruction "MOVQ"

asm: asm: assembly of add.s failed


This was the initial issue for this post.  However, I figured that part out (the std library needs to be compiled first).  So this works:

$ env GOOS=linux GOARCH=arm go install std && go tool asm -I $(go env GOROOT)/pkg/include -o add.o add.s

However, now I'm curious why whatever platform GOOS_GOARCH I choose, the file is exactly the same (see hexdump above).

So i'm wondering why that is.  Am I doing something wrong?  If not, why are GOOS and GOARCH needed at all at this stage?  

Thanks for helping me clear this up, and thanks for golang!
Paul

Michael Hudson-Doyle

unread,
Sep 12, 2016, 11:58:58 PM9/12/16
to pcj...@gmail.com, golang-nuts
The problem here is that MOVQ is not a valid instruction for arm.
 
This was the initial issue for this post.  However, I figured that part out (the std library needs to be compiled first).  So this works:

$ env GOOS=linux GOARCH=arm go install std && go tool asm -I $(go env GOROOT)/pkg/include -o add.o add.s

And here, the GOOS/GOARCH settings only apply to the first command that is run, not the asm invocation.

Cheers,
mwh
 
However, now I'm curious why whatever platform GOOS_GOARCH I choose, the file is exactly the same (see hexdump above).

So i'm wondering why that is.  Am I doing something wrong?  If not, why are GOOS and GOARCH needed at all at this stage?  

Thanks for helping me clear this up, and thanks for golang!
Paul

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

pcj...@gmail.com

unread,
Sep 13, 2016, 12:19:53 AM9/13/16
to golang-nuts, pcj...@gmail.com
I see (apologies for limited knowledge of assembly).  

My interpretation of golang's assembly is that it represents an intermediate pseudo-language that is transformed via "instruction selection" to a concrete form.  Therefore, is it possible to re-write the above to a cross-compilable form?  If so, is this generalizable?
 
 
This was the initial issue for this post.  However, I figured that part out (the std library needs to be compiled first).  So this works:

$ env GOOS=linux GOARCH=arm go install std && go tool asm -I $(go env GOROOT)/pkg/include -o add.o add.s

And here, the GOOS/GOARCH settings only apply to the first command that is run, not the asm invocation.


That makes sense...  I should get up and walk around more often.  No wonder the file is always the same!
 
Cheers,
mwh
 
However, now I'm curious why whatever platform GOOS_GOARCH I choose, the file is exactly the same (see hexdump above).

So i'm wondering why that is.  Am I doing something wrong?  If not, why are GOOS and GOARCH needed at all at this stage?  

Thanks for helping me clear this up, and thanks for golang!
Paul

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Aram Hăvărneanu

unread,
Sep 13, 2016, 11:32:25 AM9/13/16
to pcj...@gmail.com, golang-nuts
On Tue, Sep 13, 2016 at 6:19 AM, <pcj...@gmail.com> wrote:
> My interpretation of golang's assembly is that it represents an intermediate
> pseudo-language that is transformed via "instruction selection" to a
> concrete form.

Correct, but this pseudo-language is not portable between architectures.

> Therefore, is it possible to re-write the above to a cross-compilable form?

The assembly in the Go distribution is already cross-compilable, but
looking at your example you are not concerned whether the assembly is
cross-compilable or not (that depends on the toolchain, and not on the
assembly code), but you want the assembly to be portable between
architectures.

Apart from the most trivial of cases, this is not possible. Different
targets use different instructions and different registers.

The Go assembler uses the same *syntax* on every architecture, so it
can be parsed and processed by a single program, however the assembly
code required for each target is very different.

--
Aram Hăvărneanu

pcj...@gmail.com

unread,
Sep 13, 2016, 12:08:18 PM9/13/16
to golang-nuts, pcj...@gmail.com
Thanks Aram and Michael, that helps a lot.  

I've studied https://github.com/golang/go/tree/master/src/crypto/sha1 which looks like a good example of having a pure-go fallback with architecture-specific assembly.  

My next question is which tool is responsible for selecting the correct sha1block_GOARCH.s? Is the the compiler, linker, or where?

ironi...@gmail.com

unread,
Sep 13, 2016, 1:04:44 PM9/13/16
to golang-nuts, pcj...@gmail.com


On Tuesday, September 13, 2016 at 11:08:18 AM UTC-5, pcj...@gmail.com wrote:
My next question is which tool is responsible for selecting the correct sha1block_GOARCH.s? Is the the compiler, linker, or where?
 
See https://golang.org/pkg/go/build/ (under Build Constraints)
And (as of Go 1.7.1) https://golang.org/src/go/build/build.go#L1449 goodOSArchFile()


pcj...@gmail.com

unread,
Sep 13, 2016, 7:08:47 PM9/13/16
to golang-nuts, pcj...@gmail.com, ironi...@gmail.com
Thanks, great reference to gooOsArchFile()
Reply all
Reply to author
Forward
0 new messages