From 32a9804c7ba3f4a0e0bd26cc24b9204860a49ec8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 2 Dec 2025 17:01:57 -0800 Subject: [PATCH] cmd/link: don't update offset of existing ELF section name Fixes #76656 Change-Id: If2e823ba1577700af00f5883e4ea5c139e4749c1 Reviewed-on: https://go-review.googlesource.com/c/go/+/726100 Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Michael Stapelberg Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/cmd/link/elf_test.go | 76 ++++++++++++++++++++++++++++++++- src/cmd/link/internal/ld/elf.go | 4 +- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go index f11cc4bcf8..adf255a7e3 100644 --- a/src/cmd/link/elf_test.go +++ b/src/cmd/link/elf_test.go @@ -11,6 +11,7 @@ import ( "cmd/internal/hash" "cmd/link/internal/ld" "debug/elf" + "encoding/binary" "fmt" "internal/platform" "internal/testenv" @@ -22,6 +23,7 @@ import ( "sync" "testing" "text/template" + "unsafe" ) func getCCAndCCFLAGS(t *testing.T, env []string) (string, []string) { @@ -677,12 +679,23 @@ func testFlagDError(t *testing.T, dataAddr string, roundQuantum string, expected } func TestELFHeadersSorted(t *testing.T) { + for _, buildmode := range []string{"exe", "pie"} { + t.Run(buildmode, func(t *testing.T) { + testELFHeadersSorted(t, buildmode) + }) + } +} + +func testELFHeadersSorted(t *testing.T, buildmode string) { testenv.MustHaveGoBuild(t) // We can only test this for internal linking mode. // For external linking the external linker will // decide how to sort the sections. testenv.MustInternalLink(t, testenv.NoSpecialBuildTypes) + if buildmode == "pie" { + testenv.MustInternalLinkPIE(t) + } t.Parallel() @@ -693,12 +706,71 @@ func TestELFHeadersSorted(t *testing.T) { } exe := filepath.Join(tmpdir, "x.exe") - cmd := goCmd(t, "build", "-ldflags=-linkmode=internal", "-o", exe, src) + cmd := goCmd(t, "build", "-buildmode="+buildmode, "-ldflags=-linkmode=internal", "-o", exe, src) if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("build failed: %v, output:\n%s", err, out) } - ef, err := elf.Open(exe) + // Check that the first section header is all zeroes. + f, err := os.Open(exe) + if err != nil { + t.Fatal(err) + } + defer f.Close() + + var ident [elf.EI_NIDENT]byte + if _, err := f.Read(ident[:]); err != nil { + t.Fatal(err) + } + + var bo binary.ByteOrder + switch elf.Data(ident[elf.EI_DATA]) { + case elf.ELFDATA2LSB: + bo = binary.LittleEndian + case elf.ELFDATA2MSB: + bo = binary.BigEndian + default: + t.Fatalf("unrecognized data encoding %d", ident[elf.EI_DATA]) + } + + var shoff int64 + var shsize int + switch elf.Class(ident[elf.EI_CLASS]) { + case elf.ELFCLASS32: + var hdr elf.Header32 + data := make([]byte, unsafe.Sizeof(hdr)) + if _, err := f.ReadAt(data, 0); err != nil { + t.Fatal(err) + } + shoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Shoff):])) + shsize = int(unsafe.Sizeof(elf.Section32{})) + + case elf.ELFCLASS64: + var hdr elf.Header64 + data := make([]byte, unsafe.Sizeof(hdr)) + if _, err := f.ReadAt(data, 0); err != nil { + t.Fatal(err) + } + shoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Shoff):])) + shsize = int(unsafe.Sizeof(elf.Section64{})) + + default: + t.Fatalf("unrecognized class %d", ident[elf.EI_CLASS]) + } + + if shoff > 0 { + data := make([]byte, shsize) + if _, err := f.ReadAt(data, shoff); err != nil { + t.Fatal(err) + } + for i, c := range data { + if c != 0 { + t.Errorf("section header 0 byte %d is %d, should be zero", i, c) + } + } + } + + ef, err := elf.NewFile(f) if err != nil { t.Fatal(err) } diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index c9480222c3..12218feb31 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -434,7 +434,9 @@ func elfWriteShstrtab(ctxt *Link) uint32 { // are likely to be the only match. for _, sh := range shdr { if suffix, ok := strings.CutPrefix(sh.nameString, elfRelType); ok { - m[suffix] = off + uint32(len(elfRelType)) + if _, found := m[suffix]; !found { + m[suffix] = off + uint32(len(elfRelType)) + } writeString(sh.nameString) } } -- 2.52.0