func main() {}
`
+var goSourceWithData = `
+package main
+var globalVar = 42
+func main() { println(&globalVar) }
+`
+
// The linker used to crash if an ELF input file had multiple text sections
// with the same name.
func TestSectionsWithSameName(t *testing.T) {
t.Errorf("executable failed to run: %v\n%s", err, out)
}
}
+
+func TestFlagD(t *testing.T) {
+ // Test that using the -D flag to specify data section address generates
+ // a working binary with data at the specified address.
+ t.Parallel()
+ testFlagD(t, "0x10000000", "", 0x10000000)
+}
+
+func TestFlagDUnaligned(t *testing.T) {
+ // Test that using the -D flag with an unaligned address errors out
+ t.Parallel()
+ testFlagDError(t, "0x10000123", "", "invalid -D value 0x10000123")
+}
+
+func TestFlagDWithR(t *testing.T) {
+ // Test that using the -D flag with -R flag errors on unaligned address.
+ t.Parallel()
+ testFlagDError(t, "0x30001234", "8192", "invalid -D value 0x30001234")
+}
+
+func testFlagD(t *testing.T, dataAddr string, roundQuantum string, expectedAddr uint64) {
+ testenv.MustHaveGoBuild(t)
+ tmpdir := t.TempDir()
+ src := filepath.Join(tmpdir, "x.go")
+ if err := os.WriteFile(src, []byte(goSourceWithData), 0444); err != nil {
+ t.Fatal(err)
+ }
+ exe := filepath.Join(tmpdir, "x.exe")
+
+ // Build linker flags
+ ldflags := "-D=" + dataAddr
+ if roundQuantum != "" {
+ ldflags += " -R=" + roundQuantum
+ }
+
+ cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags="+ldflags, "-o", exe, src)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("build failed: %v, output:\n%s", err, out)
+ }
+
+ cmd = testenv.Command(t, exe)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Errorf("executable failed to run: %v\n%s", err, out)
+ }
+
+ ef, err := elf.Open(exe)
+ if err != nil {
+ t.Fatalf("open elf file failed: %v", err)
+ }
+ defer ef.Close()
+
+ // Find the first data-related section to verify segment placement
+ var firstDataSectionAddr uint64
+ var found bool = false
+ for _, sec := range ef.Sections {
+ if sec.Type == elf.SHT_PROGBITS || sec.Type == elf.SHT_NOBITS {
+ // These sections are writable, allocated at runtime, but not executable
+ isWrite := sec.Flags&elf.SHF_WRITE != 0
+ isExec := sec.Flags&elf.SHF_EXECINSTR != 0
+ isAlloc := sec.Flags&elf.SHF_ALLOC != 0
+
+ if isWrite && !isExec && isAlloc {
+ addrLower := sec.Addr < firstDataSectionAddr
+ if !found || addrLower {
+ firstDataSectionAddr = sec.Addr
+ found = true
+ }
+ }
+ }
+ }
+
+ if !found {
+ t.Fatalf("can't find any writable data sections")
+ }
+ if firstDataSectionAddr != expectedAddr {
+ t.Errorf("data section starts at 0x%x, expected 0x%x", firstDataSectionAddr, expectedAddr)
+ }
+}
+
+func testFlagDError(t *testing.T, dataAddr string, roundQuantum string, expectedError string) {
+ testenv.MustHaveGoBuild(t)
+ tmpdir := t.TempDir()
+ src := filepath.Join(tmpdir, "x.go")
+ if err := os.WriteFile(src, []byte(goSourceWithData), 0444); err != nil {
+ t.Fatal(err)
+ }
+ exe := filepath.Join(tmpdir, "x.exe")
+
+ // Build linker flags
+ ldflags := "-D=" + dataAddr
+ if roundQuantum != "" {
+ ldflags += " -R=" + roundQuantum
+ }
+
+ cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags="+ldflags, "-o", exe, src)
+ out, err := cmd.CombinedOutput()
+ if err == nil {
+ t.Fatalf("expected build to fail with unaligned data address, but it succeeded")
+ }
+ if !strings.Contains(string(out), expectedError) {
+ t.Errorf("expected error message to contain %q, got:\n%s", expectedError, out)
+ }
+}
t.Errorf("Trampoline b-tramp0 exists unnecessarily")
}
}
+
+func TestRounding(t *testing.T) {
+ testCases := []struct {
+ input int64
+ quantum int64
+ expected int64
+ }{
+ {0x30000000, 0x2000, 0x30000000}, // Already aligned
+ {0x30002000, 0x2000, 0x30002000}, // Exactly on boundary
+ {0x30001234, 0x2000, 0x30002000},
+ {0x30001000, 0x2000, 0x30002000},
+ {0x30001fff, 0x2000, 0x30002000},
+ }
+
+ for _, tc := range testCases {
+ result := Rnd(tc.input, tc.quantum)
+ if result != tc.expected {
+ t.Errorf("Rnd(0x%x, 0x%x) = 0x%x, expected 0x%x",
+ tc.input, tc.quantum, result, tc.expected)
+ }
+ }
+}
FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
FlagRound = flag.Int64("R", -1, "set address rounding `quantum`")
FlagTextAddr = flag.Int64("T", -1, "set the start address of text symbols")
+ FlagDataAddr = flag.Int64("D", -1, "set the start address of data symbols")
FlagFuncAlign = flag.Int("funcalign", 0, "set function align to `N` bytes")
flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
flagPruneWeakMap = flag.Bool("pruneweakmap", true, "prune weak mapinit refs")
bench.Start("Archinit")
thearch.Archinit(ctxt)
+ if *FlagDataAddr != -1 && *FlagDataAddr%*FlagRound != 0 {
+ Exitf("invalid -D value 0x%x: not aligned to rounding quantum 0x%x", *FlagDataAddr, *FlagRound)
+ }
+
if ctxt.linkShared && !ctxt.IsELF {
Exitf("-linkshared can only be used on elf systems")
}