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) }