Skip to content

Commit

Permalink
cmd/link: introduce a rel.ro segment
Browse files Browse the repository at this point in the history
When internally linking with using rel.ro sections, this segment covers
the sections. To do this, move to other read-only sections, SELFROSECT
and SMACHOPLT, out of the way.

Part of adding PIE internal linking on linux/amd64.

Change-Id: I4fb3d180e92f7e801789ab89864010faf5a2cb6d
Reviewed-on: https://go-review.googlesource.com/28538
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
  • Loading branch information
crawshaw committed Sep 11, 2016
1 parent 13dc4d3 commit 276803d
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 72 deletions.
11 changes: 9 additions & 2 deletions src/cmd/internal/obj/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ const (
STEXT
SELFRXSECT

// Read-only sections.
STYPE
SSTRING
SGOSTRING
Expand All @@ -393,6 +394,11 @@ const (
SRODATA
SFUNCTAB

SELFROSECT
SMACHOPLT

// Read-only sections with relocations.
//
// Types STYPE-SFUNCTAB above are written to the .rodata section by default.
// When linking a shared object, some conceptually "read only" types need to
// be written to by relocations and putting them in a section called
Expand All @@ -412,12 +418,13 @@ const (
SRODATARELRO
SFUNCTABRELRO

// Part of .data.rel.ro if it exists, otherwise part of .rodata.
STYPELINK
SITABLINK
SSYMTAB
SPCLNTAB
SELFROSECT
SMACHOPLT

// Writable sections.
SELFSECT
SMACHO
SMACHOGOT
Expand Down
8 changes: 7 additions & 1 deletion src/cmd/link/internal/amd64/asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -623,10 +623,16 @@ func asmb(ctxt *ld.Link) {
if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}

ld.Cseek(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
}
ld.Cseek(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}

if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f datblk\n", obj.Cputime())
Expand Down
8 changes: 7 additions & 1 deletion src/cmd/link/internal/arm/asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -602,10 +602,16 @@ func asmb(ctxt *ld.Link) {
if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}

ld.Cseek(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
}
ld.Cseek(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}

if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f datblk\n", obj.Cputime())
Expand Down
8 changes: 7 additions & 1 deletion src/cmd/link/internal/arm64/asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,16 @@ func asmb(ctxt *ld.Link) {
if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}

ld.Cseek(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
}
ld.Cseek(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}

if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f datblk\n", obj.Cputime())
Expand Down
150 changes: 90 additions & 60 deletions src/cmd/link/internal/ld/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,33 @@ func (ctxt *Link) dodata() {
}
sect.Length = uint64(datsize) - sect.Vaddr

/* read-only ELF, Mach-O sections */
for _, s := range data[obj.SELFROSECT] {
sect = addsection(segro, s.Name, 04)
sect.Align = symalign(s)
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
sect.Length = uint64(datsize) - sect.Vaddr
}
checkdatsize(ctxt, datsize, obj.SELFROSECT)

for _, s := range data[obj.SMACHOPLT] {
sect = addsection(segro, s.Name, 04)
sect.Align = symalign(s)
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
sect.Length = uint64(datsize) - sect.Vaddr
}
checkdatsize(ctxt, datsize, obj.SMACHOPLT)

// There is some data that are conceptually read-only but are written to by
// relocations. On GNU systems, we can arrange for the dynamic linker to
// mprotect sections after relocations are applied by giving them write
Expand All @@ -1518,14 +1545,26 @@ func (ctxt *Link) dodata() {
// situation.
// TODO(mwhudson): It would make sense to do this more widely, but it makes
// the system linker segfault on darwin.
relroPerms := 04
relroPrefix := ""
addrelrosection := func(suffix string) *Section {
return addsection(segro, suffix, 04)
}

if UseRelro() {
relroPerms = 06
relroPrefix = ".data.rel.ro"
addrelrosection = func(suffix string) *Section {
seg := &Segrelrodata
if Linkmode == LinkExternal {
// Using a separate segment with an external
// linker results in some programs moving
// their data sections unexpectedly, which
// corrupts the moduledata. So we use the
// rodata segment and let the external linker
// sort out a rel.ro segment.
seg = &Segrodata
}
return addsection(seg, ".data.rel.ro"+suffix, 06)
}
/* data only written by relocations */
sect = addsection(segro, ".data.rel.ro", 06)
sect = addrelrosection("")

sect.Vaddr = 0
Linklookup(ctxt, "runtime.types", 0).Sect = sect
Expand Down Expand Up @@ -1554,11 +1593,10 @@ func (ctxt *Link) dodata() {
}

sect.Length = uint64(datsize) - sect.Vaddr

}

/* typelink */
sect = addsection(segro, relroPrefix+".typelink", relroPerms)
sect = addrelrosection(".typelink")
sect.Align = dataMaxAlign[obj.STYPELINK]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Expand All @@ -1575,7 +1613,7 @@ func (ctxt *Link) dodata() {
sect.Length = uint64(datsize) - sect.Vaddr

/* itablink */
sect = addsection(segro, relroPrefix+".itablink", relroPerms)
sect = addrelrosection(".itablink")
sect.Align = dataMaxAlign[obj.SITABLINK]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Expand All @@ -1592,7 +1630,7 @@ func (ctxt *Link) dodata() {
sect.Length = uint64(datsize) - sect.Vaddr

/* gosymtab */
sect = addsection(segro, relroPrefix+".gosymtab", relroPerms)
sect = addrelrosection(".gosymtab")
sect.Align = dataMaxAlign[obj.SSYMTAB]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Expand All @@ -1609,7 +1647,7 @@ func (ctxt *Link) dodata() {
sect.Length = uint64(datsize) - sect.Vaddr

/* gopclntab */
sect = addsection(segro, relroPrefix+".gopclntab", relroPerms)
sect = addrelrosection(".gopclntab")
sect.Align = dataMaxAlign[obj.SPCLNTAB]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
Expand All @@ -1625,33 +1663,6 @@ func (ctxt *Link) dodata() {
checkdatsize(ctxt, datsize, obj.SRODATA)
sect.Length = uint64(datsize) - sect.Vaddr

/* read-only ELF, Mach-O sections */
for _, s := range data[obj.SELFROSECT] {
sect = addsection(segro, s.Name, 04)
sect.Align = symalign(s)
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
sect.Length = uint64(datsize) - sect.Vaddr
}
checkdatsize(ctxt, datsize, obj.SELFROSECT)

for _, s := range data[obj.SMACHOPLT] {
sect = addsection(segro, s.Name, 04)
sect.Align = symalign(s)
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
sect.Length = uint64(datsize) - sect.Vaddr
}
checkdatsize(ctxt, datsize, obj.SMACHOPLT)

// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
if datsize != int64(uint32(datsize)) {
ctxt.Diag("read-only data segment too large")
Expand Down Expand Up @@ -1711,6 +1722,10 @@ func (ctxt *Link) dodata() {
sect.Extnum = int16(n)
n++
}
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
sect.Extnum = int16(n)
n++
}
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
sect.Extnum = int16(n)
n++
Expand Down Expand Up @@ -1897,6 +1912,17 @@ func (ctxt *Link) address() {
if Segrodata.Sect != nil {
// align to page boundary so as not to mix
// rodata and executable text.
//
// Note: gold or GNU ld will reduce the size of the executable
// file by arranging for the relro segment to end at a page
// boundary, and overlap the end of the text segment with the
// start of the relro segment in the file. The PT_LOAD segments
// will be such that the last page of the text segment will be
// mapped twice, once r-x and once starting out rw- and, after
// relocation processing, changed to r--.
//
// Ideally the last page of the text segment would not be
// writable even for this short period.
va = uint64(Rnd(int64(va), int64(*FlagRound)))

Segrodata.Rwx = 04
Expand All @@ -1912,6 +1938,24 @@ func (ctxt *Link) address() {
Segrodata.Length = va - Segrodata.Vaddr
Segrodata.Filelen = Segrodata.Length
}
if Segrelrodata.Sect != nil {
// align to page boundary so as not to mix
// rodata, rel-ro data, and executable text.
va = uint64(Rnd(int64(va), int64(*FlagRound)))

Segrelrodata.Rwx = 06
Segrelrodata.Vaddr = va
Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff
Segrelrodata.Filelen = 0
for s := Segrelrodata.Sect; s != nil; s = s.Next {
va = uint64(Rnd(int64(va), int64(s.Align)))
s.Vaddr = va
va += s.Length
}

Segrelrodata.Length = va - Segrelrodata.Vaddr
Segrelrodata.Filelen = Segrelrodata.Length
}

va = uint64(Rnd(int64(va), int64(*FlagRound)))
Segdata.Rwx = 06
Expand Down Expand Up @@ -1979,24 +2023,15 @@ func (ctxt *Link) address() {

Segdwarf.Filelen = va - Segdwarf.Vaddr

text := Segtext.Sect
var rodata *Section
if Segrodata.Sect != nil {
rodata = Segrodata.Sect
} else {
rodata = text.Next
}
var relrodata *Section
typelink := rodata.Next
if UseRelro() {
// There is another section (.data.rel.ro) when building a shared
// object on elf systems.
relrodata = typelink
typelink = typelink.Next
}
itablink := typelink.Next
symtab := itablink.Next
pclntab := symtab.Next
var (
text = Segtext.Sect
rodata = Linklookup(ctxt, "runtime.rodata", 0).Sect
typelink = Linklookup(ctxt, "runtime.typelink", 0).Sect
itablink = Linklookup(ctxt, "runtime.itablink", 0).Sect
symtab = Linklookup(ctxt, "runtime.symtab", 0).Sect
pclntab = Linklookup(ctxt, "runtime.pclntab", 0).Sect
types = Linklookup(ctxt, "runtime.types", 0).Sect
)

for _, s := range datap {
ctxt.Cursym = s
Expand Down Expand Up @@ -2025,11 +2060,6 @@ func (ctxt *Link) address() {
s.Value = int64(sectSym.Sect.Vaddr + 16)
}

types := relrodata
if types == nil {
types = rodata
}

ctxt.xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
ctxt.xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
Expand Down
15 changes: 15 additions & 0 deletions src/cmd/link/internal/ld/elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -1783,6 +1783,9 @@ func Elfemitreloc(ctxt *Link) {
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
elfrelocsect(ctxt, sect, datap)
}
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
elfrelocsect(ctxt, sect, datap)
}
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfrelocsect(ctxt, sect, datap)
}
Expand Down Expand Up @@ -2114,6 +2117,9 @@ func Asmbelfsetup(ctxt *Link) {
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
elfshalloc(ctxt, sect)
}
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
elfshalloc(ctxt, sect)
}
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfshalloc(ctxt, sect)
}
Expand Down Expand Up @@ -2283,6 +2289,9 @@ func Asmbelf(ctxt *Link, symo int64) {
if Segrodata.Sect != nil {
elfphload(ctxt, &Segrodata)
}
if Segrelrodata.Sect != nil {
elfphload(ctxt, &Segrelrodata)
}
elfphload(ctxt, &Segdata)

/* Dynamic linking sections */
Expand Down Expand Up @@ -2482,6 +2491,9 @@ elfobj:
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
elfshbits(ctxt, sect)
}
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
elfshbits(ctxt, sect)
}
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfshbits(ctxt, sect)
}
Expand All @@ -2496,6 +2508,9 @@ elfobj:
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
elfshreloc(ctxt, sect)
}
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
elfshreloc(ctxt, sect)
}
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfshreloc(ctxt, sect)
}
Expand Down
9 changes: 5 additions & 4 deletions src/cmd/link/internal/ld/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,11 @@ var (
)

var (
Segtext Segment
Segrodata Segment
Segdata Segment
Segdwarf Segment
Segtext Segment
Segrodata Segment
Segrelrodata Segment
Segdata Segment
Segdwarf Segment
)

/* whence for ldpkg */
Expand Down
Loading

0 comments on commit 276803d

Please sign in to comment.