@@ -59,6 +59,12 @@ package main
59
59
func main() {}
60
60
`
61
61
62
+ var goSourceWithData = `
63
+ package main
64
+ var globalVar = 42
65
+ func main() { println(&globalVar) }
66
+ `
67
+
62
68
// The linker used to crash if an ELF input file had multiple text sections
63
69
// with the same name.
64
70
func TestSectionsWithSameName (t * testing.T ) {
@@ -569,3 +575,106 @@ func TestFlagR(t *testing.T) {
569
575
t .Errorf ("executable failed to run: %v\n %s" , err , out )
570
576
}
571
577
}
578
+
579
+ func TestFlagD (t * testing.T ) {
580
+ // Test that using the -D flag to specify data section address generates
581
+ // a working binary with data at the specified address.
582
+ t .Parallel ()
583
+ testFlagD (t , "0x10000000" , "" , 0x10000000 )
584
+ }
585
+
586
+ func TestFlagDUnaligned (t * testing.T ) {
587
+ // Test that using the -D flag with an unaligned address errors out
588
+ t .Parallel ()
589
+ testFlagDError (t , "0x10000123" , "" , "invalid -D value 0x10000123" )
590
+ }
591
+
592
+ func TestFlagDWithR (t * testing.T ) {
593
+ // Test that using the -D flag with -R flag errors on unaligned address.
594
+ t .Parallel ()
595
+ testFlagDError (t , "0x30001234" , "8192" , "invalid -D value 0x30001234" )
596
+ }
597
+
598
+ func testFlagD (t * testing.T , dataAddr string , roundQuantum string , expectedAddr uint64 ) {
599
+ testenv .MustHaveGoBuild (t )
600
+ tmpdir := t .TempDir ()
601
+ src := filepath .Join (tmpdir , "x.go" )
602
+ if err := os .WriteFile (src , []byte (goSourceWithData ), 0444 ); err != nil {
603
+ t .Fatal (err )
604
+ }
605
+ exe := filepath .Join (tmpdir , "x.exe" )
606
+
607
+ // Build linker flags
608
+ ldflags := "-D=" + dataAddr
609
+ if roundQuantum != "" {
610
+ ldflags += " -R=" + roundQuantum
611
+ }
612
+
613
+ cmd := testenv .Command (t , testenv .GoToolPath (t ), "build" , "-ldflags=" + ldflags , "-o" , exe , src )
614
+ if out , err := cmd .CombinedOutput (); err != nil {
615
+ t .Fatalf ("build failed: %v, output:\n %s" , err , out )
616
+ }
617
+
618
+ cmd = testenv .Command (t , exe )
619
+ if out , err := cmd .CombinedOutput (); err != nil {
620
+ t .Errorf ("executable failed to run: %v\n %s" , err , out )
621
+ }
622
+
623
+ ef , err := elf .Open (exe )
624
+ if err != nil {
625
+ t .Fatalf ("open elf file failed: %v" , err )
626
+ }
627
+ defer ef .Close ()
628
+
629
+ // Find the first data-related section to verify segment placement
630
+ var firstDataSectionAddr uint64
631
+ var found bool = false
632
+ for _ , sec := range ef .Sections {
633
+ if sec .Type == elf .SHT_PROGBITS || sec .Type == elf .SHT_NOBITS {
634
+ // These sections are writable, allocated at runtime, but not executable
635
+ isWrite := sec .Flags & elf .SHF_WRITE != 0
636
+ isExec := sec .Flags & elf .SHF_EXECINSTR != 0
637
+ isAlloc := sec .Flags & elf .SHF_ALLOC != 0
638
+
639
+ if isWrite && ! isExec && isAlloc {
640
+ addrLower := sec .Addr < firstDataSectionAddr
641
+ if ! found || addrLower {
642
+ firstDataSectionAddr = sec .Addr
643
+ found = true
644
+ }
645
+ }
646
+ }
647
+ }
648
+
649
+ if ! found {
650
+ t .Fatalf ("can't find any writable data sections" )
651
+ }
652
+ if firstDataSectionAddr != expectedAddr {
653
+ t .Errorf ("data section starts at 0x%x, expected 0x%x" , firstDataSectionAddr , expectedAddr )
654
+ }
655
+ }
656
+
657
+ func testFlagDError (t * testing.T , dataAddr string , roundQuantum string , expectedError string ) {
658
+ testenv .MustHaveGoBuild (t )
659
+ tmpdir := t .TempDir ()
660
+ src := filepath .Join (tmpdir , "x.go" )
661
+ if err := os .WriteFile (src , []byte (goSourceWithData ), 0444 ); err != nil {
662
+ t .Fatal (err )
663
+ }
664
+ exe := filepath .Join (tmpdir , "x.exe" )
665
+
666
+ // Build linker flags
667
+ ldflags := "-D=" + dataAddr
668
+ if roundQuantum != "" {
669
+ ldflags += " -R=" + roundQuantum
670
+ }
671
+
672
+ cmd := testenv .Command (t , testenv .GoToolPath (t ), "build" , "-ldflags=" + ldflags , "-o" , exe , src )
673
+ out , err := cmd .CombinedOutput ()
674
+ if err == nil {
675
+ t .Fatalf ("expected build to fail with unaligned data address, but it succeeded" )
676
+ }
677
+ if ! strings .Contains (string (out ), expectedError ) {
678
+ t .Errorf ("expected error message to contain %q, got:\n %s" , expectedError , out )
679
+ }
680
+ }
0 commit comments