From 5d663434881b0117f68f99c8706671453a01e678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Balv=C3=ADn?= Date: Thu, 20 Aug 2026 15:35:39 +0200 Subject: [PATCH] fix(goobj): make R_DWTXTADDR_U4 relocation type Go-version-aware The relocation type number shifted between Go 1.26 (103) and Go 1.27 (106) because new LoongArch relocations were inserted. Detect the Go version at runtime and use the correct value. --- asm/goobj.go | 45 ++++++++++++++++++++++++++++++++++++++--- asm/goobj_dwarf.go | 2 +- asm/goobj_dwarf_test.go | 2 +- asm/goobj_test.go | 2 +- asm/l64_goobj_test.go | 2 +- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/asm/goobj.go b/asm/goobj.go index 66855a6..3f1087b 100644 --- a/asm/goobj.go +++ b/asm/goobj.go @@ -10,6 +10,7 @@ import ( "os" "os/exec" "path/filepath" + "strings" "sync" ) @@ -90,12 +91,50 @@ const ( ) // Relocation types (cmd/internal/objabi). +// R_PCREL and R_ADDR are stable across Go versions. const ( - relocPCRel = 14 // R_PCREL - relocAddr = 1 // R_ADDR - relocDWTXTADDRU4 = 106 // R_DWTXTADDR_U4 + relocPCRel = 14 // R_PCREL + relocAddr = 1 // R_ADDR ) +// relocDWTXTADDRU4 returns the R_DWTXTADDR_U4 relocation type for the +// installed Go toolchain. The value shifted between Go 1.26 (103) and +// Go 1.27 (106) because new LoongArch relocations were inserted before it. +func relocDWTXTADDRU4() uint16 { + if isGo127OrLater() { + return 106 + } + return 103 +} + +var ( + goVersionOnce sync.Once + goVersionGT26 bool +) + +// isGo127OrLater reports whether the installed Go toolchain is 1.27 or later. +func isGo127OrLater() bool { + goVersionOnce.Do(func() { + goBin, err := exec.LookPath("go") + if err != nil { + return + } + out, err := exec.Command(goBin, "version").Output() + if err != nil { + return + } + // "go version go1.27rc1 linux/amd64" + s := string(out) + for _, prefix := range []string{"go version go1.27", "go version go1.28", "go version go1.29", "go version go2."} { + if strings.Contains(s, prefix) { + goVersionGT26 = true + return + } + } + }) + return goVersionGT26 +} + // Special package indices for symbol references. const ( pkgIdxNone = 0x7fffffff diff --git a/asm/goobj_dwarf.go b/asm/goobj_dwarf.go index 6d79ffa..f26c517 100644 --- a/asm/goobj_dwarf.go +++ b/asm/goobj_dwarf.go @@ -181,7 +181,7 @@ func goobjDwarfInfo(fn FuncLayout, name string, fnNpIdx int) ([]byte, []goobjRel out = append(out, 0) // end of children relocs := []goobjReloc{{ - off: int32(addrx), siz: 4, typ: relocDWTXTADDRU4, + off: int32(addrx), siz: 4, typ: relocDWTXTADDRU4(), pkg: pkgIdxNone, sym: uint32(fnNpIdx), }} return out, relocs diff --git a/asm/goobj_dwarf_test.go b/asm/goobj_dwarf_test.go index 815297e..640e155 100644 --- a/asm/goobj_dwarf_test.go +++ b/asm/goobj_dwarf_test.go @@ -169,7 +169,7 @@ func TestGoobjDwarfInfo(t *testing.T) { if !bytes.Equal(die, want) { t.Errorf("DIE = %x, want %x", die, want) } - if len(relocs) != 1 || relocs[0].off != 7 || relocs[0].siz != 4 || relocs[0].typ != relocDWTXTADDRU4 || relocs[0].sym != 3 { + if len(relocs) != 1 || relocs[0].off != 7 || relocs[0].siz != 4 || relocs[0].typ != relocDWTXTADDRU4() || relocs[0].sym != 3 { t.Errorf("relocs = %+v", relocs) } diff --git a/asm/goobj_test.go b/asm/goobj_test.go index f047075..0f235d6 100644 --- a/asm/goobj_test.go +++ b/asm/goobj_test.go @@ -186,7 +186,7 @@ DATA mask<>+8(SB)/8, $0x800f0e0d0c0b0a09 t.Errorf("addq lines reloc = %x", lr) } dr := relocs[23:46] - if dr[4] != 4 || le.Uint16(dr[5:]) != relocDWTXTADDRU4 || + if dr[4] != 4 || le.Uint16(dr[5:]) != relocDWTXTADDRU4() || le.Uint32(dr[15:]) != pkgIdxNone || le.Uint32(dr[19:]) != 4 { t.Errorf("addq DIE reloc = %x", dr) } diff --git a/asm/l64_goobj_test.go b/asm/l64_goobj_test.go index 66aba09..75b7852 100644 --- a/asm/l64_goobj_test.go +++ b/asm/l64_goobj_test.go @@ -153,7 +153,7 @@ DATA ·table<>+0(SB)/8, $0x1122334455667788 t.Errorf("lines reloc = %x", lr) } dr := relocs[23:46] - if int32(le.Uint32(dr[0:])) != 13 || dr[4] != 4 || le.Uint16(dr[5:]) != relocDWTXTADDRU4 || + if int32(le.Uint32(dr[0:])) != 13 || dr[4] != 4 || le.Uint16(dr[5:]) != relocDWTXTADDRU4() || le.Uint32(dr[15:]) != pkgIdxNone || le.Uint32(dr[19:]) != 4 { t.Errorf("die reloc = %x", dr) }