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() {
/*
* 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
......
......@@ -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)
sects := []struct {
peSect *peSection
seg *sym.Segment
syms []*sym.Symbol
}{
{f.textSect, &Segtext, ctxt.Textp},
{f.rdataSect, &Segrodata, datap},
{f.dataSect, &Segdata, datap},
}
return n
})
f.dataSect.emitRelocations(ctxt.Out, func() int {
for _, s := range sects {
s.peSect.emitRelocations(ctxt.Out, func() int {
var n int
for _, sect := range Segdata.Sections {
n += relocsect(sect, datap, Segdata.Vaddr)
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))
......
......@@ -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) {
......
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