From: Alex Brainman Date: Sat, 2 Jun 2018 05:35:25 +0000 (+1000) Subject: cmd/link: split pe .text section into .text and .rdata X-Git-Tag: go1.11beta1~169 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=d67db881465320b46e8142d5eac1b808c3ac659d;p=gostls13.git cmd/link: split pe .text section into .text and .rdata Fixes #24725 Change-Id: I2864b88315ab15be036e8940d0a5884d876698d6 Reviewed-on: https://go-review.googlesource.com/115975 Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index be65b7be06..3e4773102d 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -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 diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 8005dc5228..85acb7a11b 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -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)) diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index 4be5d0e74e..890df0f902 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -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) {