]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: split pe .text section into .text and .rdata
authorAlex Brainman <alex.brainman@gmail.com>
Sat, 2 Jun 2018 05:35:25 +0000 (15:35 +1000)
committerAlex Brainman <alex.brainman@gmail.com>
Sat, 9 Jun 2018 07:34:45 +0000 (07:34 +0000)
Fixes #24725

Change-Id: I2864b88315ab15be036e8940d0a5884d876698d6
Reviewed-on: https://go-review.googlesource.com/115975
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/pe.go
src/cmd/nm/nm_test.go

index be65b7be069f836dd824f7dedadc91070197f7ca..3e4773102d3704871bdd3d1573ae0881f3cac1de 100644 (file)
@@ -1352,9 +1352,8 @@ func (ctxt *Link) dodata() {
        /*
         * We finished data, begin read-only data.
         * Not all systems support a separate read-only non-executable data section.
-        * ELF systems do.
+        * ELF and Windows PE systems do.
         * OS X and Plan 9 do not.
-        * Windows PE may, but if so we have not implemented it.
         * And if we're using external linking mode, the point is moot,
         * since it's not our decision; that code expects the sections in
         * segtext.
@@ -1362,6 +1361,8 @@ func (ctxt *Link) dodata() {
        var segro *sym.Segment
        if ctxt.IsELF && ctxt.LinkMode == LinkInternal {
                segro = &Segrodata
+       } else if ctxt.HeadType == objabi.Hwindows {
+               segro = &Segrodata
        } else {
                segro = &Segtext
        }
@@ -1940,6 +1941,9 @@ func (ctxt *Link) address() {
                Segrodata.Vaddr = va
                Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
                Segrodata.Filelen = 0
+               if ctxt.HeadType == objabi.Hwindows {
+                       Segrodata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
+               }
                for _, s := range Segrodata.Sections {
                        va = uint64(Rnd(int64(va), int64(s.Align)))
                        s.Vaddr = va
@@ -1974,7 +1978,7 @@ func (ctxt *Link) address() {
        Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
        Segdata.Filelen = 0
        if ctxt.HeadType == objabi.Hwindows {
-               Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
+               Segdata.Fileoff = Segrodata.Fileoff + uint64(Rnd(int64(Segrodata.Length), PEFILEALIGN))
        }
        if ctxt.HeadType == objabi.Hplan9 {
                Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
index 8005dc52284122f08f3c569278e57a08456ca1f4..85acb7a11b0b4565b02d10c87b1d28604d2ae480 100644 (file)
@@ -395,6 +395,7 @@ type peFile struct {
        sections       []*peSection
        stringTable    peStringTable
        textSect       *peSection
+       rdataSect      *peSection
        dataSect       *peSection
        bssSect        *peSection
        ctorsSect      *peSection
@@ -548,21 +549,24 @@ func (f *peFile) emitRelocations(ctxt *Link) {
                return relocs
        }
 
-       f.textSect.emitRelocations(ctxt.Out, func() int {
-               n := relocsect(Segtext.Sections[0], ctxt.Textp, Segtext.Vaddr)
-               for _, sect := range Segtext.Sections[1:] {
-                       n += relocsect(sect, datap, Segtext.Vaddr)
-               }
-               return n
-       })
-
-       f.dataSect.emitRelocations(ctxt.Out, func() int {
-               var n int
-               for _, sect := range Segdata.Sections {
-                       n += relocsect(sect, datap, Segdata.Vaddr)
-               }
-               return n
-       })
+       sects := []struct {
+               peSect *peSection
+               seg    *sym.Segment
+               syms   []*sym.Symbol
+       }{
+               {f.textSect, &Segtext, ctxt.Textp},
+               {f.rdataSect, &Segrodata, datap},
+               {f.dataSect, &Segdata, datap},
+       }
+       for _, s := range sects {
+               s.peSect.emitRelocations(ctxt.Out, func() int {
+                       var n int
+                       for _, sect := range s.seg.Sections {
+                               n += relocsect(sect, s.syms, s.seg.Vaddr)
+                       }
+                       return n
+               })
+       }
 
 dwarfLoop:
        for _, sect := range Segdwarf.Sections {
@@ -622,8 +626,11 @@ func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int
        if s.Sect.Seg == &Segtext {
                return f.textSect.index, int64(uint64(s.Value) - Segtext.Vaddr), nil
        }
+       if s.Sect.Seg == &Segrodata {
+               return f.rdataSect.index, int64(uint64(s.Value) - Segrodata.Vaddr), nil
+       }
        if s.Sect.Seg != &Segdata {
-               return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .data section", s.Name)
+               return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", s.Name)
        }
        v := uint64(s.Value) - Segdata.Vaddr
        if linkmode != LinkExternal {
@@ -904,7 +911,11 @@ func Peinit(ctxt *Link) {
        }
 
        if ctxt.LinkMode == LinkExternal {
-               PESECTALIGN = 0
+               // .rdata section will contain "masks" and "shifts" symbols, and they
+               // need to be aligned to 16-bytes. So make all sections aligned
+               // to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external
+               // linker will honour that requirement.
+               PESECTALIGN = 32
                PEFILEALIGN = 0
        }
 
@@ -1325,6 +1336,19 @@ func Asmbpe(ctxt *Link) {
        t.checkSegment(&Segtext)
        pefile.textSect = t
 
+       ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
+       ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
+       if ctxt.LinkMode == LinkExternal {
+               // some data symbols (e.g. masks) end up in the .rdata section, and they normally
+               // expect larger alignment requirement than the default text section alignment.
+               ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
+       } else {
+               // TODO(brainman): should not need IMAGE_SCN_MEM_EXECUTE, but I do not know why it carshes without it
+               ro.characteristics |= IMAGE_SCN_MEM_EXECUTE
+       }
+       ro.checkSegment(&Segrodata)
+       pefile.rdataSect = ro
+
        var d *peSection
        if ctxt.LinkMode != LinkExternal {
                d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
index 4be5d0e74e2da14388e580bce5ed942489d5528d..890df0f9029ae599da5149083c16b417fdbb4408 100644 (file)
@@ -126,6 +126,15 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
                names["main."+f[0]] = f[1]
        }
 
+       runtimeSyms := map[string]string{
+               "runtime.text":      "T",
+               "runtime.etext":     "T",
+               "runtime.rodata":    "R",
+               "runtime.erodata":   "R",
+               "runtime.epclntab":  "R",
+               "runtime.noptrdata": "D",
+       }
+
        out, err = exec.Command(testnmpath, exe).CombinedOutput()
        if err != nil {
                t.Fatalf("go tool nm: %v\n%s", err, string(out))
@@ -147,6 +156,12 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
                if _, found := dups[name]; found {
                        t.Errorf("duplicate name of %q is found", name)
                }
+               if stype, found := runtimeSyms[name]; found {
+                       if want, have := stype, strings.ToUpper(f[1]); have != want {
+                               t.Errorf("want %s type for %s symbol, but have %s", want, name, have)
+                       }
+                       delete(runtimeSyms, name)
+               }
        }
        err = scanner.Err()
        if err != nil {
@@ -155,6 +170,9 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
        if len(names) > 0 {
                t.Errorf("executable is missing %v symbols", names)
        }
+       if len(runtimeSyms) > 0 {
+               t.Errorf("executable is missing %v symbols", runtimeSyms)
+       }
 }
 
 func TestGoExec(t *testing.T) {