Possible bug in Go assembler/linker

202 views
Skip to first unread message

Jan Mercl

unread,
Jul 6, 2025, 1:05:22 PMJul 6
to golang-dev
It might be the case that some invalid amd64 opcodes make it into an
executable for

XORPD mem,X0

A workaround replacing it with two instructions

MOVSD mem,X1
XORPD X1,X0

fixes the crash. Possibly useful details near the end of the debug
session conversation here: https://g.co/gemini/share/3a5cd27f8166

Steps to reproduce are something like:

$ git clone modernc.org/qbecc
$ cd qbecc/lib
$ git checkout v0.0.5
$ go test -v -run Exec -dump-ssa -extended-errors -keep -trc
-trco -re '^gofast.c$' |& tee log

The Go prototypes and the assembler file can be found in ./tmp/main0000.c.dir/

-j

Keith Randall

unread,
Jul 7, 2025, 2:29:58 PMJul 7
to Jan Mercl, golang-dev
I cannot reproduce this problem.

cd qbecc/lib
git checkout v0.0.5
go test -v -run Exec -dump-ssa -extended-errors -keep -trc -trco -re '^gofast.c$' |& tee log

The test passes.
There is no assembler file in  ./tmp/main0000.c.dir/ (that dir does not exist. The only file in ./tmp is main0000.c)

I tried assembling various XORPD mem, X0 instructions for different mem values ( 16(SP), 32(SP)(AX*8), main·global(SB), ..) and nothing looked wrong. I disassembled with the native objdump and they all looked correct.


--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/golang-dev/CAA40n-V8%3Dt6XExDLVf2FoScXO2pn58dHoKB0vzNM5WZuE0DMbg%40mail.gmail.com.

Jan Mercl

unread,
Jul 7, 2025, 2:56:46 PMJul 7
to kei...@alum.mit.edu, golang-dev
On Mon, Jul 7, 2025 at 8:29 PM Keith Randall <keith....@gmail.com> wrote:

> I cannot reproduce this problem.

That's most probably my fault as I forgot to add that to reproduce it
must be run on linux/amd64:
https://gitlab.com/cznic/qbecc/-/blob/71e2deb45106854513dd96705046f3d1074658ef/lib/all_test.go#L44

My apologies. If it still doesn't work please let me know. It may be
the case that it depends on something on my machine that I am not
aware of. Wait, I am. The qbecc linker also needs to find
modernc.org/libc in $GOPATH/src:
https://gitlab.com/cznic/qbecc/-/blob/71e2deb45106854513dd96705046f3d1074658ef/lib/link.go#L407

If everything else fails, please find attached the archived files that
should reproduce per se. The log file was created using Go 1.24.4 on
linux/amd64 via `$ go run .`

I am sorry for not having enough patience yesterday to make the
initial report better.

-j

----

Archive content:

jnml@3900x:~/tmp/xorpd$ ls -l
total 52
-rw-r--r-- 1 jnml jnml 540 Jul 7 20:46 go.mod
-rw-r--r-- 1 jnml jnml 3703 Jul 7 20:46 go.sum
-rw-r--r-- 1 jnml jnml 4840 Jul 7 20:47 log-go-run-dot
-rw-r----- 1 jnml jnml 1764 Jul 7 20:45 main0000.c.go
-rw-r--r-- 1 jnml jnml 32330 Jul 7 20:45 main0000.c.s
jnml@3900x:~/tmp/xorpd$
xorpd.tar.gz

Keith Randall

unread,
Jul 7, 2025, 3:55:55 PMJul 7
to Jan Mercl, golang-dev
On Mon, Jul 7, 2025 at 11:56 AM Jan Mercl <0xj...@gmail.com> wrote:
On Mon, Jul 7, 2025 at 8:29 PM Keith Randall <keith....@gmail.com> wrote:

> I cannot reproduce this problem.

That's most probably my fault as I forgot to add that to reproduce it
must be run on linux/amd64:
https://gitlab.com/cznic/qbecc/-/blob/71e2deb45106854513dd96705046f3d1074658ef/lib/all_test.go#L44


That is the platform I was on.
 
My apologies. If it still doesn't work please let me know. It may be
the case that it depends on something on my machine that I am not
aware of. Wait, I am. The qbecc linker also needs to find
modernc.org/libc in $GOPATH/src:
https://gitlab.com/cznic/qbecc/-/blob/71e2deb45106854513dd96705046f3d1074658ef/lib/link.go#L407


modernc.org/libc is in the go.mod file (as an indirect dependency). Shouldn't that be enough?

Could you be running into alignment issues?
The one difference between MOVSD mem,reg + XORPD reg,reg and XORPD mem,reg is the latter requires alignment.
 
If everything else fails, please find attached the archived files that
should reproduce per se. The log file was created using Go 1.24.4 on
linux/amd64 via `$ go run .`

I don't think your attachments made it through to golang-dev.

Probably best to run the host objdump on the functions in question, in both the good and bad states, and post the results here.
 

I am sorry for not having enough patience yesterday to make the
initial report better.

-j

----

Archive content:

        jnml@3900x:~/tmp/xorpd$ ls -l
        total 52
        -rw-r--r-- 1 jnml jnml   540 Jul  7 20:46 go.mod
        -rw-r--r-- 1 jnml jnml  3703 Jul  7 20:46 go.sum
        -rw-r--r-- 1 jnml jnml  4840 Jul  7 20:47 log-go-run-dot
        -rw-r----- 1 jnml jnml  1764 Jul  7 20:45 main0000.c.go
        -rw-r--r-- 1 jnml jnml 32330 Jul  7 20:45 main0000.c.s
        jnml@3900x:~/tmp/xorpd$

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

Keith Randall

unread,
Jul 7, 2025, 4:02:33 PMJul 7
to Jan Mercl, golang-dev
Never mind, there was an attachment.

I think my alignment issue theory is correct. XORPD requires 16-byte alignment, and your program builds with that address at 8 mod 16.
Not sure why it segfaults at address 0. I would have expected it to SIGBUS.

Jan Mercl

unread,
Jul 7, 2025, 4:09:24 PMJul 7
to kei...@alum.mit.edu, golang-dev
On Mon, Jul 7, 2025 at 10:02 PM Keith Randall <keith....@gmail.com> wrote:
>
> Never mind, there was an attachment.
>
> I think my alignment issue theory is correct. XORPD requires 16-byte alignment, and your program builds with that address at 8 mod 16.
> Not sure why it segfaults at address 0. I would have expected it to SIGBUS.

Nice catch! Thank you. That would also explain why the behaviour was
so unstable. As I added debug prints, the data probably got different
(mod 8) addresses.

I am not aware of a way to enforce 16 byte alignment for DATA items. I
will try to change

DATA ··fc·1<>(SB)/8, $0x8000000000000000
GLOBL ··fc·1<>(SB), RODATA, $8

to

DATA ··fc·1<>(SB)/8, $0x8000000000000000
GLOBL ··fc·1<>(SB), RODATA, $16

Is there a better way?

Thanks again for your help.

-j

Keith Randall

unread,
Jul 7, 2025, 4:12:51 PMJul 7
to Jan Mercl, golang-dev
Make your symbol 16 bytes big. It should get 16 byte alignment.
You probably want it 16 bytes big anyway. That instruction is reading 16 bytes into your register, if your global is only 8 bytes big the top 8 bytes in your register would be from an unrelated global variable.

I can still beat Gemini at debugging...

Jan Mercl

unread,
Jul 7, 2025, 4:43:27 PMJul 7
to kei...@alum.mit.edu, golang-dev
On Mon, Jul 7, 2025 at 10:12 PM Keith Randall <keith....@gmail.com> wrote:

> Make your symbol 16 bytes big. It should get 16 byte alignment.
> You probably want it 16 bytes big anyway. That instruction is reading 16 bytes into your register, if your global is only 8 bytes big the top 8 bytes in your register would be from an unrelated global variable.

Thanks, it works:
https://gitlab.com/cznic/libqbe/-/commit/537c7fef567766201de8f9a1a2b9a558e1a060c1

> I can still beat Gemini at debugging...

I started my professional career coding in assembler. Well, it was the
front panel at that time. But that was decades and 52 bits of register
width ago ;-)

Thanks again,

-j

Jorropo

unread,
Jul 7, 2025, 4:46:53 PMJul 7
to Jan Mercl, kei...@alum.mit.edu, golang-dev
52%8 = 4; 52%10 = 2; What was the byte size ?

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

Jan Mercl

unread,
Jul 7, 2025, 5:01:42 PMJul 7
to Jorropo, kei...@alum.mit.edu, golang-dev
On Mon, Jul 7, 2025 at 10:46 PM Jorropo <jorro...@gmail.com> wrote:

> 52%8 = 4; 52%10 = 2; What was the byte size ?

I am not sure if the word 'byte' was really used in the context of
this machine (actually its clone):
https://www.computerhistory.org/collections/catalog/102776323/

Maybe 3 bytes were packed into two words? OTOH, the connected TTY used
5 bit encoding, so two code points per word plus a nice high bit
indicator for end of string in the sixth bit?. Not that I can remember
it actually, but that would have probably been my style in that era.

-j

PS: Apologies for drifting way off-topic. I'll stop now.
Reply all
Reply to author
Forward
0 new messages