From: Ian Lance Taylor Date: Tue, 18 Nov 2025 04:20:26 +0000 (-0800) Subject: cmd/link: test that moduledata is in its own section X-Git-Url: https://git.feebdaed.xyz/?a=commitdiff_plain;h=f1bbc66a10a545811a21dcf9f9431e783aafcb42;p=0xmirror%2Fgo.git cmd/link: test that moduledata is in its own section This is a test for CL 720660. For #76038 Change-Id: I2f630b738ddb5a9c48e3c5d4374c1e995910541a Reviewed-on: https://go-review.googlesource.com/c/go/+/721480 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: David Chase --- diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 77bbc3c1f8..0c4cde0399 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -2114,3 +2114,100 @@ func TestFuncdataPlacement(t *testing.T) { t.Errorf("findfunctab address %#x not between %#x and %#x", moddata.findfunctab, pclntabAddr, pclntabEnd) } } + +// Test that moduledata winds up in its own .go.module section. +func TestModuledataPlacement(t *testing.T) { + testenv.MustHaveGoBuild(t) + t.Parallel() + + tmpdir := t.TempDir() + src := filepath.Join(tmpdir, "x.go") + if err := os.WriteFile(src, []byte(trivialSrc), 0o444); err != nil { + t.Fatal(err) + } + + exe := filepath.Join(tmpdir, "x.exe") + cmd := goCmd(t, "build", "-o", exe, src) + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("build failed; %v, output:\n%s", err, out) + } + + ef, _ := elf.Open(exe) + mf, _ := macho.Open(exe) + pf, _ := pe.Open(exe) + xf, _ := xcoff.Open(exe) + // TODO: plan9 + if ef == nil && mf == nil && pf == nil && xf == nil { + t.Skip("unrecognized executable file format") + } + + const moddataSymName = "runtime.firstmoduledata" + switch { + case ef != nil: + defer ef.Close() + + syms, err := ef.Symbols() + if err != nil { + t.Fatal(err) + } + for _, sym := range syms { + if sym.Name == moddataSymName { + sec := ef.Sections[sym.Section] + if sec.Name != ".go.module" { + t.Errorf("moduledata in section %s, not .go.module", sec.Name) + } + if sym.Value != sec.Addr { + t.Errorf("moduledata address %#x != section start address %#x", sym.Value, sec.Addr) + } + break + } + } + + case mf != nil: + defer mf.Close() + + for _, sym := range mf.Symtab.Syms { + if sym.Name == moddataSymName { + if sym.Sect == 0 { + t.Error("moduledata not in a section") + } else { + sec := mf.Sections[sym.Sect-1] + if sec.Name != "__go_module" { + t.Errorf("moduledata in section %s, not __go.module", sec.Name) + } + if sym.Value != sec.Addr { + t.Errorf("moduledata address %#x != section start address %#x", sym.Value, sec.Addr) + } + } + break + } + } + + case pf != nil: + defer pf.Close() + + // On Windows all the Go specific sections seem to + // get stuffed into a few Windows sections, + // so there is nothing to test here. + + case xf != nil: + defer xf.Close() + + for _, sym := range xf.Symbols { + if sym.Name == moddataSymName { + if sym.SectionNumber == 0 { + t.Errorf("moduledata not in a section") + } else { + sec := xf.Sections[sym.SectionNumber-1] + if sec.Name != ".go.module" { + t.Errorf("moduledata in section %s, not .go.module", sec.Name) + } + if sym.Value != sec.VirtualAddress { + t.Errorf("moduledata address %#x != section start address %#x", sym.Value, sec.VirtualAddress) + } + } + break + } + } + } +}