]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: introduce a rel.ro segment
authorDavid Crawshaw <crawshaw@golang.org>
Tue, 6 Sep 2016 03:29:16 +0000 (23:29 -0400)
committerDavid Crawshaw <crawshaw@golang.org>
Sun, 11 Sep 2016 20:10:47 +0000 (20:10 +0000)
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>
src/cmd/internal/obj/link.go
src/cmd/link/internal/amd64/asm.go
src/cmd/link/internal/arm/asm.go
src/cmd/link/internal/arm64/asm.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/mips64/asm.go
src/cmd/link/internal/ppc64/asm.go
src/cmd/link/internal/s390x/asm.go
src/cmd/link/internal/x86/asm.go

index 513e00b825d5c2973033c6b5877bfe7aec5559f6..614be6f74f80df2c17c156ea803fde4b5d430c13 100644 (file)
@@ -384,6 +384,7 @@ const (
        STEXT
        SELFRXSECT
 
+       // Read-only sections.
        STYPE
        SSTRING
        SGOSTRING
@@ -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
@@ -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
index 639aae9fe7bc9bc8a5b8d1b01eef85a71e3955b1..5abf79f8187c348d0bacb3a70c17ceb613e8300a 100644 (file)
@@ -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())
index 881b559e68316bdeb41fc79c2e66c9aaae109ae6..ae6f35dde570e9cdb76612fb3c0df14e1957c0d4 100644 (file)
@@ -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())
index 70a6cfd1fac2774d7e0c3e1eb84f0d78ebbe6b86..66613d46867950c46b13513026a528e4d3a3afb2 100644 (file)
@@ -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())
index 649645806175d5230b82851cc519cfed76917ace..07911e2328e14ee389a9186a14f5d66af1a15563 100644 (file)
@@ -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
@@ -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
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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")
@@ -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++
@@ -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
@@ -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
@@ -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
@@ -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 {
index 3275c10d7846fedb487d460e222d5ed3f8c07748..6d09d173b8785f230d1598cfbfc770f21c55fe23 100644 (file)
@@ -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)
        }
@@ -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)
        }
@@ -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 */
@@ -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)
        }
@@ -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)
                }
index 4f4473cc12d3948c15b7b7d70c7ab4a9db6a2d08..c7e2c2433ff292ed8095cb8efc36480e14463448 100644 (file)
@@ -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 */
index 1c7751dc161d27663e9e82c5d45e5e3739be80b1..f0c5926a19790a56f545e55a1ab41c94f04434af 100644 (file)
@@ -203,10 +203,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 rodatblk\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())
index 9cbd34b981f6eae21886469e9638de32c162465d..3bbe9ec8baaa68eea4816c9145999036d1520e71 100644 (file)
@@ -824,10 +824,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())
index 47e042d4fadfac1694778e40a39e6bfe22d1f247..0c44ccd384c4f737b2daeecb41c4448484bf00c6 100644 (file)
@@ -519,10 +519,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 rodatblk\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())
index c80d9629e187b3244fb8bf3a5c387da140595467..972fc80bf0ec0fba90a5cd343f709888d87be510 100644 (file)
@@ -649,6 +649,13 @@ func asmb(ctxt *ld.Link) {
                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())