Commit d67db881 authored by Alex Brainman's avatar Alex Brainman

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 <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 1f137052
...@@ -1352,9 +1352,8 @@ func (ctxt *Link) dodata() { ...@@ -1352,9 +1352,8 @@ func (ctxt *Link) dodata() {
/* /*
* We finished data, begin read-only data. * We finished data, begin read-only data.
* Not all systems support a separate read-only non-executable data section. * 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. * 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, * And if we're using external linking mode, the point is moot,
* since it's not our decision; that code expects the sections in * since it's not our decision; that code expects the sections in
* segtext. * segtext.
...@@ -1362,6 +1361,8 @@ func (ctxt *Link) dodata() { ...@@ -1362,6 +1361,8 @@ func (ctxt *Link) dodata() {
var segro *sym.Segment var segro *sym.Segment
if ctxt.IsELF && ctxt.LinkMode == LinkInternal { if ctxt.IsELF && ctxt.LinkMode == LinkInternal {
segro = &Segrodata segro = &Segrodata
} else if ctxt.HeadType == objabi.Hwindows {
segro = &Segrodata
} else { } else {
segro = &Segtext segro = &Segtext
} }
...@@ -1940,6 +1941,9 @@ func (ctxt *Link) address() { ...@@ -1940,6 +1941,9 @@ func (ctxt *Link) address() {
Segrodata.Vaddr = va Segrodata.Vaddr = va
Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
Segrodata.Filelen = 0 Segrodata.Filelen = 0
if ctxt.HeadType == objabi.Hwindows {
Segrodata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
}
for _, s := range Segrodata.Sections { for _, s := range Segrodata.Sections {
va = uint64(Rnd(int64(va), int64(s.Align))) va = uint64(Rnd(int64(va), int64(s.Align)))
s.Vaddr = va s.Vaddr = va
...@@ -1974,7 +1978,7 @@ func (ctxt *Link) address() { ...@@ -1974,7 +1978,7 @@ func (ctxt *Link) address() {
Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
Segdata.Filelen = 0 Segdata.Filelen = 0
if ctxt.HeadType == objabi.Hwindows { 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 { if ctxt.HeadType == objabi.Hplan9 {
Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
......
...@@ -395,6 +395,7 @@ type peFile struct { ...@@ -395,6 +395,7 @@ type peFile struct {
sections []*peSection sections []*peSection
stringTable peStringTable stringTable peStringTable
textSect *peSection textSect *peSection
rdataSect *peSection
dataSect *peSection dataSect *peSection
bssSect *peSection bssSect *peSection
ctorsSect *peSection ctorsSect *peSection
...@@ -548,21 +549,24 @@ func (f *peFile) emitRelocations(ctxt *Link) { ...@@ -548,21 +549,24 @@ func (f *peFile) emitRelocations(ctxt *Link) {
return relocs return relocs
} }
f.textSect.emitRelocations(ctxt.Out, func() int { sects := []struct {
n := relocsect(Segtext.Sections[0], ctxt.Textp, Segtext.Vaddr) peSect *peSection
for _, sect := range Segtext.Sections[1:] { seg *sym.Segment
n += relocsect(sect, datap, Segtext.Vaddr) syms []*sym.Symbol
}{
{f.textSect, &Segtext, ctxt.Textp},
{f.rdataSect, &Segrodata, datap},
{f.dataSect, &Segdata, datap},
} }
return n for _, s := range sects {
}) s.peSect.emitRelocations(ctxt.Out, func() int {
f.dataSect.emitRelocations(ctxt.Out, func() int {
var n int var n int
for _, sect := range Segdata.Sections { for _, sect := range s.seg.Sections {
n += relocsect(sect, datap, Segdata.Vaddr) n += relocsect(sect, s.syms, s.seg.Vaddr)
} }
return n return n
}) })
}
dwarfLoop: dwarfLoop:
for _, sect := range Segdwarf.Sections { for _, sect := range Segdwarf.Sections {
...@@ -622,8 +626,11 @@ func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int ...@@ -622,8 +626,11 @@ func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int
if s.Sect.Seg == &Segtext { if s.Sect.Seg == &Segtext {
return f.textSect.index, int64(uint64(s.Value) - Segtext.Vaddr), nil 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 { 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 v := uint64(s.Value) - Segdata.Vaddr
if linkmode != LinkExternal { if linkmode != LinkExternal {
...@@ -904,7 +911,11 @@ func Peinit(ctxt *Link) { ...@@ -904,7 +911,11 @@ func Peinit(ctxt *Link) {
} }
if ctxt.LinkMode == LinkExternal { 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 PEFILEALIGN = 0
} }
...@@ -1325,6 +1336,19 @@ func Asmbpe(ctxt *Link) { ...@@ -1325,6 +1336,19 @@ func Asmbpe(ctxt *Link) {
t.checkSegment(&Segtext) t.checkSegment(&Segtext)
pefile.textSect = t 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 var d *peSection
if ctxt.LinkMode != LinkExternal { if ctxt.LinkMode != LinkExternal {
d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen)) d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
......
...@@ -126,6 +126,15 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { ...@@ -126,6 +126,15 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
names["main."+f[0]] = f[1] 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() out, err = exec.Command(testnmpath, exe).CombinedOutput()
if err != nil { if err != nil {
t.Fatalf("go tool nm: %v\n%s", err, string(out)) t.Fatalf("go tool nm: %v\n%s", err, string(out))
...@@ -147,6 +156,12 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { ...@@ -147,6 +156,12 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
if _, found := dups[name]; found { if _, found := dups[name]; found {
t.Errorf("duplicate name of %q is found", name) 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() err = scanner.Err()
if err != nil { if err != nil {
...@@ -155,6 +170,9 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { ...@@ -155,6 +170,9 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
if len(names) > 0 { if len(names) > 0 {
t.Errorf("executable is missing %v symbols", names) 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) { func TestGoExec(t *testing.T) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment