Skip to content

Commit 276803d

Browse files
committed
cmd/link: introduce a rel.ro segment
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 13dc4d3 commit 276803d

File tree

11 files changed

+168
-72
lines changed

11 files changed

+168
-72
lines changed

src/cmd/internal/obj/link.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ const (
384384
STEXT
385385
SELFRXSECT
386386

387+
// Read-only sections.
387388
STYPE
388389
SSTRING
389390
SGOSTRING
@@ -393,6 +394,11 @@ const (
393394
SRODATA
394395
SFUNCTAB
395396

397+
SELFROSECT
398+
SMACHOPLT
399+
400+
// Read-only sections with relocations.
401+
//
396402
// Types STYPE-SFUNCTAB above are written to the .rodata section by default.
397403
// When linking a shared object, some conceptually "read only" types need to
398404
// be written to by relocations and putting them in a section called
@@ -412,12 +418,13 @@ const (
412418
SRODATARELRO
413419
SFUNCTABRELRO
414420

421+
// Part of .data.rel.ro if it exists, otherwise part of .rodata.
415422
STYPELINK
416423
SITABLINK
417424
SSYMTAB
418425
SPCLNTAB
419-
SELFROSECT
420-
SMACHOPLT
426+
427+
// Writable sections.
421428
SELFSECT
422429
SMACHO
423430
SMACHOGOT

src/cmd/link/internal/amd64/asm.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,10 +623,16 @@ func asmb(ctxt *ld.Link) {
623623
if ctxt.Debugvlog != 0 {
624624
ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
625625
}
626-
627626
ld.Cseek(int64(ld.Segrodata.Fileoff))
628627
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
629628
}
629+
if ld.Segrelrodata.Filelen > 0 {
630+
if ctxt.Debugvlog != 0 {
631+
ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
632+
}
633+
ld.Cseek(int64(ld.Segrelrodata.Fileoff))
634+
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
635+
}
630636

631637
if ctxt.Debugvlog != 0 {
632638
ctxt.Logf("%5.2f datblk\n", obj.Cputime())

src/cmd/link/internal/arm/asm.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,10 +602,16 @@ func asmb(ctxt *ld.Link) {
602602
if ctxt.Debugvlog != 0 {
603603
ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
604604
}
605-
606605
ld.Cseek(int64(ld.Segrodata.Fileoff))
607606
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
608607
}
608+
if ld.Segrelrodata.Filelen > 0 {
609+
if ctxt.Debugvlog != 0 {
610+
ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
611+
}
612+
ld.Cseek(int64(ld.Segrelrodata.Fileoff))
613+
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
614+
}
609615

610616
if ctxt.Debugvlog != 0 {
611617
ctxt.Logf("%5.2f datblk\n", obj.Cputime())

src/cmd/link/internal/arm64/asm.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,10 +411,16 @@ func asmb(ctxt *ld.Link) {
411411
if ctxt.Debugvlog != 0 {
412412
ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
413413
}
414-
415414
ld.Cseek(int64(ld.Segrodata.Fileoff))
416415
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
417416
}
417+
if ld.Segrelrodata.Filelen > 0 {
418+
if ctxt.Debugvlog != 0 {
419+
ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime())
420+
}
421+
ld.Cseek(int64(ld.Segrelrodata.Fileoff))
422+
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
423+
}
418424

419425
if ctxt.Debugvlog != 0 {
420426
ctxt.Logf("%5.2f datblk\n", obj.Cputime())

src/cmd/link/internal/ld/data.go

Lines changed: 90 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,6 +1508,33 @@ func (ctxt *Link) dodata() {
15081508
}
15091509
sect.Length = uint64(datsize) - sect.Vaddr
15101510

1511+
/* read-only ELF, Mach-O sections */
1512+
for _, s := range data[obj.SELFROSECT] {
1513+
sect = addsection(segro, s.Name, 04)
1514+
sect.Align = symalign(s)
1515+
datsize = Rnd(datsize, int64(sect.Align))
1516+
sect.Vaddr = uint64(datsize)
1517+
s.Sect = sect
1518+
s.Type = obj.SRODATA
1519+
s.Value = int64(uint64(datsize) - sect.Vaddr)
1520+
datsize += s.Size
1521+
sect.Length = uint64(datsize) - sect.Vaddr
1522+
}
1523+
checkdatsize(ctxt, datsize, obj.SELFROSECT)
1524+
1525+
for _, s := range data[obj.SMACHOPLT] {
1526+
sect = addsection(segro, s.Name, 04)
1527+
sect.Align = symalign(s)
1528+
datsize = Rnd(datsize, int64(sect.Align))
1529+
sect.Vaddr = uint64(datsize)
1530+
s.Sect = sect
1531+
s.Type = obj.SRODATA
1532+
s.Value = int64(uint64(datsize) - sect.Vaddr)
1533+
datsize += s.Size
1534+
sect.Length = uint64(datsize) - sect.Vaddr
1535+
}
1536+
checkdatsize(ctxt, datsize, obj.SMACHOPLT)
1537+
15111538
// There is some data that are conceptually read-only but are written to by
15121539
// relocations. On GNU systems, we can arrange for the dynamic linker to
15131540
// mprotect sections after relocations are applied by giving them write
@@ -1518,14 +1545,26 @@ func (ctxt *Link) dodata() {
15181545
// situation.
15191546
// TODO(mwhudson): It would make sense to do this more widely, but it makes
15201547
// the system linker segfault on darwin.
1521-
relroPerms := 04
1522-
relroPrefix := ""
1548+
addrelrosection := func(suffix string) *Section {
1549+
return addsection(segro, suffix, 04)
1550+
}
15231551

15241552
if UseRelro() {
1525-
relroPerms = 06
1526-
relroPrefix = ".data.rel.ro"
1553+
addrelrosection = func(suffix string) *Section {
1554+
seg := &Segrelrodata
1555+
if Linkmode == LinkExternal {
1556+
// Using a separate segment with an external
1557+
// linker results in some programs moving
1558+
// their data sections unexpectedly, which
1559+
// corrupts the moduledata. So we use the
1560+
// rodata segment and let the external linker
1561+
// sort out a rel.ro segment.
1562+
seg = &Segrodata
1563+
}
1564+
return addsection(seg, ".data.rel.ro"+suffix, 06)
1565+
}
15271566
/* data only written by relocations */
1528-
sect = addsection(segro, ".data.rel.ro", 06)
1567+
sect = addrelrosection("")
15291568

15301569
sect.Vaddr = 0
15311570
Linklookup(ctxt, "runtime.types", 0).Sect = sect
@@ -1554,11 +1593,10 @@ func (ctxt *Link) dodata() {
15541593
}
15551594

15561595
sect.Length = uint64(datsize) - sect.Vaddr
1557-
15581596
}
15591597

15601598
/* typelink */
1561-
sect = addsection(segro, relroPrefix+".typelink", relroPerms)
1599+
sect = addrelrosection(".typelink")
15621600
sect.Align = dataMaxAlign[obj.STYPELINK]
15631601
datsize = Rnd(datsize, int64(sect.Align))
15641602
sect.Vaddr = uint64(datsize)
@@ -1575,7 +1613,7 @@ func (ctxt *Link) dodata() {
15751613
sect.Length = uint64(datsize) - sect.Vaddr
15761614

15771615
/* itablink */
1578-
sect = addsection(segro, relroPrefix+".itablink", relroPerms)
1616+
sect = addrelrosection(".itablink")
15791617
sect.Align = dataMaxAlign[obj.SITABLINK]
15801618
datsize = Rnd(datsize, int64(sect.Align))
15811619
sect.Vaddr = uint64(datsize)
@@ -1592,7 +1630,7 @@ func (ctxt *Link) dodata() {
15921630
sect.Length = uint64(datsize) - sect.Vaddr
15931631

15941632
/* gosymtab */
1595-
sect = addsection(segro, relroPrefix+".gosymtab", relroPerms)
1633+
sect = addrelrosection(".gosymtab")
15961634
sect.Align = dataMaxAlign[obj.SSYMTAB]
15971635
datsize = Rnd(datsize, int64(sect.Align))
15981636
sect.Vaddr = uint64(datsize)
@@ -1609,7 +1647,7 @@ func (ctxt *Link) dodata() {
16091647
sect.Length = uint64(datsize) - sect.Vaddr
16101648

16111649
/* gopclntab */
1612-
sect = addsection(segro, relroPrefix+".gopclntab", relroPerms)
1650+
sect = addrelrosection(".gopclntab")
16131651
sect.Align = dataMaxAlign[obj.SPCLNTAB]
16141652
datsize = Rnd(datsize, int64(sect.Align))
16151653
sect.Vaddr = uint64(datsize)
@@ -1625,33 +1663,6 @@ func (ctxt *Link) dodata() {
16251663
checkdatsize(ctxt, datsize, obj.SRODATA)
16261664
sect.Length = uint64(datsize) - sect.Vaddr
16271665

1628-
/* read-only ELF, Mach-O sections */
1629-
for _, s := range data[obj.SELFROSECT] {
1630-
sect = addsection(segro, s.Name, 04)
1631-
sect.Align = symalign(s)
1632-
datsize = Rnd(datsize, int64(sect.Align))
1633-
sect.Vaddr = uint64(datsize)
1634-
s.Sect = sect
1635-
s.Type = obj.SRODATA
1636-
s.Value = int64(uint64(datsize) - sect.Vaddr)
1637-
datsize += s.Size
1638-
sect.Length = uint64(datsize) - sect.Vaddr
1639-
}
1640-
checkdatsize(ctxt, datsize, obj.SELFROSECT)
1641-
1642-
for _, s := range data[obj.SMACHOPLT] {
1643-
sect = addsection(segro, s.Name, 04)
1644-
sect.Align = symalign(s)
1645-
datsize = Rnd(datsize, int64(sect.Align))
1646-
sect.Vaddr = uint64(datsize)
1647-
s.Sect = sect
1648-
s.Type = obj.SRODATA
1649-
s.Value = int64(uint64(datsize) - sect.Vaddr)
1650-
datsize += s.Size
1651-
sect.Length = uint64(datsize) - sect.Vaddr
1652-
}
1653-
checkdatsize(ctxt, datsize, obj.SMACHOPLT)
1654-
16551666
// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
16561667
if datsize != int64(uint32(datsize)) {
16571668
ctxt.Diag("read-only data segment too large")
@@ -1711,6 +1722,10 @@ func (ctxt *Link) dodata() {
17111722
sect.Extnum = int16(n)
17121723
n++
17131724
}
1725+
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
1726+
sect.Extnum = int16(n)
1727+
n++
1728+
}
17141729
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
17151730
sect.Extnum = int16(n)
17161731
n++
@@ -1897,6 +1912,17 @@ func (ctxt *Link) address() {
18971912
if Segrodata.Sect != nil {
18981913
// align to page boundary so as not to mix
18991914
// rodata and executable text.
1915+
//
1916+
// Note: gold or GNU ld will reduce the size of the executable
1917+
// file by arranging for the relro segment to end at a page
1918+
// boundary, and overlap the end of the text segment with the
1919+
// start of the relro segment in the file. The PT_LOAD segments
1920+
// will be such that the last page of the text segment will be
1921+
// mapped twice, once r-x and once starting out rw- and, after
1922+
// relocation processing, changed to r--.
1923+
//
1924+
// Ideally the last page of the text segment would not be
1925+
// writable even for this short period.
19001926
va = uint64(Rnd(int64(va), int64(*FlagRound)))
19011927

19021928
Segrodata.Rwx = 04
@@ -1912,6 +1938,24 @@ func (ctxt *Link) address() {
19121938
Segrodata.Length = va - Segrodata.Vaddr
19131939
Segrodata.Filelen = Segrodata.Length
19141940
}
1941+
if Segrelrodata.Sect != nil {
1942+
// align to page boundary so as not to mix
1943+
// rodata, rel-ro data, and executable text.
1944+
va = uint64(Rnd(int64(va), int64(*FlagRound)))
1945+
1946+
Segrelrodata.Rwx = 06
1947+
Segrelrodata.Vaddr = va
1948+
Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff
1949+
Segrelrodata.Filelen = 0
1950+
for s := Segrelrodata.Sect; s != nil; s = s.Next {
1951+
va = uint64(Rnd(int64(va), int64(s.Align)))
1952+
s.Vaddr = va
1953+
va += s.Length
1954+
}
1955+
1956+
Segrelrodata.Length = va - Segrelrodata.Vaddr
1957+
Segrelrodata.Filelen = Segrelrodata.Length
1958+
}
19151959

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

19802024
Segdwarf.Filelen = va - Segdwarf.Vaddr
19812025

1982-
text := Segtext.Sect
1983-
var rodata *Section
1984-
if Segrodata.Sect != nil {
1985-
rodata = Segrodata.Sect
1986-
} else {
1987-
rodata = text.Next
1988-
}
1989-
var relrodata *Section
1990-
typelink := rodata.Next
1991-
if UseRelro() {
1992-
// There is another section (.data.rel.ro) when building a shared
1993-
// object on elf systems.
1994-
relrodata = typelink
1995-
typelink = typelink.Next
1996-
}
1997-
itablink := typelink.Next
1998-
symtab := itablink.Next
1999-
pclntab := symtab.Next
2026+
var (
2027+
text = Segtext.Sect
2028+
rodata = Linklookup(ctxt, "runtime.rodata", 0).Sect
2029+
typelink = Linklookup(ctxt, "runtime.typelink", 0).Sect
2030+
itablink = Linklookup(ctxt, "runtime.itablink", 0).Sect
2031+
symtab = Linklookup(ctxt, "runtime.symtab", 0).Sect
2032+
pclntab = Linklookup(ctxt, "runtime.pclntab", 0).Sect
2033+
types = Linklookup(ctxt, "runtime.types", 0).Sect
2034+
)
20002035

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

2028-
types := relrodata
2029-
if types == nil {
2030-
types = rodata
2031-
}
2032-
20332063
ctxt.xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
20342064
ctxt.xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
20352065
if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {

src/cmd/link/internal/ld/elf.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,9 @@ func Elfemitreloc(ctxt *Link) {
17831783
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
17841784
elfrelocsect(ctxt, sect, datap)
17851785
}
1786+
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
1787+
elfrelocsect(ctxt, sect, datap)
1788+
}
17861789
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
17871790
elfrelocsect(ctxt, sect, datap)
17881791
}
@@ -2114,6 +2117,9 @@ func Asmbelfsetup(ctxt *Link) {
21142117
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
21152118
elfshalloc(ctxt, sect)
21162119
}
2120+
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
2121+
elfshalloc(ctxt, sect)
2122+
}
21172123
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
21182124
elfshalloc(ctxt, sect)
21192125
}
@@ -2283,6 +2289,9 @@ func Asmbelf(ctxt *Link, symo int64) {
22832289
if Segrodata.Sect != nil {
22842290
elfphload(ctxt, &Segrodata)
22852291
}
2292+
if Segrelrodata.Sect != nil {
2293+
elfphload(ctxt, &Segrelrodata)
2294+
}
22862295
elfphload(ctxt, &Segdata)
22872296

22882297
/* Dynamic linking sections */
@@ -2482,6 +2491,9 @@ elfobj:
24822491
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
24832492
elfshbits(ctxt, sect)
24842493
}
2494+
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
2495+
elfshbits(ctxt, sect)
2496+
}
24852497
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
24862498
elfshbits(ctxt, sect)
24872499
}
@@ -2496,6 +2508,9 @@ elfobj:
24962508
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
24972509
elfshreloc(ctxt, sect)
24982510
}
2511+
for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
2512+
elfshreloc(ctxt, sect)
2513+
}
24992514
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
25002515
elfshreloc(ctxt, sect)
25012516
}

src/cmd/link/internal/ld/lib.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,11 @@ var (
191191
)
192192

193193
var (
194-
Segtext Segment
195-
Segrodata Segment
196-
Segdata Segment
197-
Segdwarf Segment
194+
Segtext Segment
195+
Segrodata Segment
196+
Segrelrodata Segment
197+
Segdata Segment
198+
Segdwarf Segment
198199
)
199200

200201
/* whence for ldpkg */

0 commit comments

Comments
 (0)