aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd/internal/obj/link.go20
-rw-r--r--src/cmd/link/internal/ld/data.go77
-rw-r--r--src/cmd/link/internal/ld/elf.go33
-rw-r--r--src/cmd/link/internal/ld/lib.go20
-rw-r--r--src/cmd/link/internal/ld/symtab.go28
-rw-r--r--src/cmd/newlink/testdata/autosection.6bin897 -> 937 bytes
-rw-r--r--src/cmd/newlink/testdata/autoweak.6bin346 -> 386 bytes
-rw-r--r--src/cmd/newlink/testdata/dead.6bin809 -> 849 bytes
-rw-r--r--src/cmd/newlink/testdata/hello.6bin189 -> 229 bytes
-rw-r--r--src/cmd/newlink/testdata/layout.6bin356 -> 396 bytes
-rw-r--r--src/cmd/newlink/testdata/pclntab.6bin3764 -> 3804 bytes
11 files changed, 160 insertions, 18 deletions
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index a5d622a70a..6066493baf 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -334,6 +334,7 @@ const (
Sxxx = iota
STEXT
SELFRXSECT
+
STYPE
SSTRING
SGOSTRING
@@ -341,6 +342,25 @@ const (
SGCBITS
SRODATA
SFUNCTAB
+
+ // 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
+ // ".rodata" interacts poorly with the system linkers. The GNU linkers
+ // support this situation by arranging for sections of the name
+ // ".data.rel.ro.XXX" to be mprotected read only by the dynamic linker after
+ // relocations have applied, so when the Go linker is creating a shared
+ // object it checks all objects of the above types and bumps any object that
+ // has a relocation to it to the corresponding type below, which are then
+ // written to sections with appropriate magic names.
+ STYPERELRO
+ SSTRINGRELRO
+ SGOSTRINGRELRO
+ SGOFUNCRELRO
+ SGCBITSRELRO
+ SRODATARELRO
+ SFUNCTABRELRO
+
STYPELINK
SSYMTAB
SPCLNTAB
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index f1561d3c82..4263e8cf26 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -1207,6 +1207,31 @@ func dodata() {
*l = nil
+ if UseRelro() {
+ // "read only" data with relocations needs to go in its own section
+ // when building a shared library. We do this by boosting objects of
+ // type SXXX with relocations to type SXXXRELRO.
+ for s := datap; s != nil; s = s.Next {
+ if (s.Type >= obj.STYPE && s.Type <= obj.SFUNCTAB && len(s.R) > 0) || s.Type == obj.SGOSTRING {
+ s.Type += (obj.STYPERELRO - obj.STYPE)
+ if s.Outer != nil {
+ s.Outer.Type = s.Type
+ }
+ }
+ }
+ // Check that we haven't made two symbols with the same .Outer into
+ // different types (because references two symbols with non-nil Outer
+ // become references to the outer symbol + offset it's vital that the
+ // symbol and the outer end up in the same section).
+ for s := datap; s != nil; s = s.Next {
+ if s.Outer != nil && s.Outer.Type != s.Type {
+ Diag("inconsistent types for %s and its Outer %s (%d != %d)",
+ s.Name, s.Outer.Name, s.Type, s.Outer.Type)
+ }
+ }
+
+ }
+
datap = listsort(datap, datcmp, listnextp)
if Iself {
@@ -1465,12 +1490,12 @@ func dodata() {
/* read-only data */
sect = addsection(segro, ".rodata", 04)
- sect.Align = maxalign(s, obj.STYPELINK-1)
+ sect.Align = maxalign(s, obj.STYPERELRO-1)
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = 0
Linklookup(Ctxt, "runtime.rodata", 0).Sect = sect
Linklookup(Ctxt, "runtime.erodata", 0).Sect = sect
- for ; s != nil && s.Type < obj.STYPELINK; s = s.Next {
+ for ; s != nil && s.Type < obj.STYPERELRO; s = s.Next {
datsize = aligndatsize(datsize, s)
s.Sect = sect
s.Type = obj.SRODATA
@@ -1480,8 +1505,45 @@ func dodata() {
sect.Length = uint64(datsize) - sect.Vaddr
+ // 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
+ // permissions in the object file and calling them ".data.rel.ro.FOO". We
+ // divide the .rodata section between actual .rodata and .data.rel.ro.rodata,
+ // but for the other sections that this applies to, we just write a read-only
+ // .FOO section or a read-write .data.rel.ro.FOO section depending on the
+ // situation.
+ // TODO(mwhudson): It would make sense to do this more widely, but it makes
+ // the system linker segfault on darwin.
+ relro_perms := 04
+ relro_prefix := ""
+
+ if UseRelro() {
+ relro_perms = 06
+ relro_prefix = ".data.rel.ro"
+ /* data only written by relocations */
+ sect = addsection(segro, ".data.rel.ro", 06)
+
+ sect.Align = maxalign(s, obj.STYPELINK-1)
+ datsize = Rnd(datsize, int64(sect.Align))
+ sect.Vaddr = 0
+ for ; s != nil && s.Type < obj.STYPELINK; s = s.Next {
+ datsize = aligndatsize(datsize, s)
+ if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
+ Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name)
+ }
+ s.Sect = sect
+ s.Type = obj.SRODATA
+ s.Value = int64(uint64(datsize) - sect.Vaddr)
+ growdatsize(&datsize, s)
+ }
+
+ sect.Length = uint64(datsize) - sect.Vaddr
+
+ }
+
/* typelink */
- sect = addsection(segro, ".typelink", 04)
+ sect = addsection(segro, relro_prefix+".typelink", relro_perms)
sect.Align = maxalign(s, obj.STYPELINK)
datsize = Rnd(datsize, int64(sect.Align))
@@ -1499,7 +1561,7 @@ func dodata() {
sect.Length = uint64(datsize) - sect.Vaddr
/* gosymtab */
- sect = addsection(segro, ".gosymtab", 04)
+ sect = addsection(segro, relro_prefix+".gosymtab", relro_perms)
sect.Align = maxalign(s, obj.SPCLNTAB-1)
datsize = Rnd(datsize, int64(sect.Align))
@@ -1517,7 +1579,7 @@ func dodata() {
sect.Length = uint64(datsize) - sect.Vaddr
/* gopclntab */
- sect = addsection(segro, ".gopclntab", 04)
+ sect = addsection(segro, relro_prefix+".gopclntab", relro_perms)
sect.Align = maxalign(s, obj.SELFROSECT-1)
datsize = Rnd(datsize, int64(sect.Align))
@@ -1723,6 +1785,11 @@ func address() {
rodata = text.Next
}
typelink := rodata.Next
+ if UseRelro() {
+ // There is another section (.data.rel.ro) when building a shared
+ // object on elf systems.
+ typelink = typelink.Next
+ }
symtab := typelink.Next
pclntab := symtab.Next
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 187643e41b..a842cf6df4 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -1690,9 +1690,18 @@ func doelf() {
}
Addstring(shstrtab, ".elfdata")
Addstring(shstrtab, ".rodata")
- Addstring(shstrtab, ".typelink")
- Addstring(shstrtab, ".gosymtab")
- Addstring(shstrtab, ".gopclntab")
+ if Buildmode == BuildmodeShared || Buildmode == BuildmodeCShared {
+ Addstring(shstrtab, ".data.rel.ro")
+ }
+ // See the comment about data.rel.ro.FOO section names in data.go.
+ relro_prefix := ""
+
+ if UseRelro() {
+ relro_prefix = ".data.rel.ro"
+ }
+ Addstring(shstrtab, relro_prefix+".typelink")
+ Addstring(shstrtab, relro_prefix+".gosymtab")
+ Addstring(shstrtab, relro_prefix+".gopclntab")
if Linkmode == LinkExternal {
Debug['d'] = 1
@@ -1701,20 +1710,26 @@ func doelf() {
case '6', '7', '9':
Addstring(shstrtab, ".rela.text")
Addstring(shstrtab, ".rela.rodata")
- Addstring(shstrtab, ".rela.typelink")
- Addstring(shstrtab, ".rela.gosymtab")
- Addstring(shstrtab, ".rela.gopclntab")
+ Addstring(shstrtab, ".rela"+relro_prefix+".typelink")
+ Addstring(shstrtab, ".rela"+relro_prefix+".gosymtab")
+ Addstring(shstrtab, ".rela"+relro_prefix+".gopclntab")
Addstring(shstrtab, ".rela.noptrdata")
Addstring(shstrtab, ".rela.data")
+ if UseRelro() {
+ Addstring(shstrtab, ".rela.data.rel.ro")
+ }
default:
Addstring(shstrtab, ".rel.text")
Addstring(shstrtab, ".rel.rodata")
- Addstring(shstrtab, ".rel.typelink")
- Addstring(shstrtab, ".rel.gosymtab")
- Addstring(shstrtab, ".rel.gopclntab")
+ Addstring(shstrtab, ".rel"+relro_prefix+".typelink")
+ Addstring(shstrtab, ".rel"+relro_prefix+".gosymtab")
+ Addstring(shstrtab, ".rel"+relro_prefix+".gopclntab")
Addstring(shstrtab, ".rel.noptrdata")
Addstring(shstrtab, ".rel.data")
+ if UseRelro() {
+ Addstring(shstrtab, ".rel.data.rel.ro")
+ }
}
// add a .note.GNU-stack section to mark the stack as non-executable
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 89f805d483..6d265b2d30 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -174,6 +174,12 @@ func DynlinkingGo() bool {
return Buildmode == BuildmodeShared || Linkshared
}
+// UseRelro returns whether to make use of "read only relocations" aka
+// relro.
+func UseRelro() bool {
+ return (Buildmode == BuildmodeCShared || Buildmode == BuildmodeShared) && Iself
+}
+
var (
Thestring string
Thelinkarch *LinkArch
@@ -980,6 +986,9 @@ func hostlink() {
argv = append(argv, "-dynamiclib")
} else {
argv = append(argv, "-Wl,-Bsymbolic")
+ if UseRelro() {
+ argv = append(argv, "-Wl,-z,relro")
+ }
argv = append(argv, "-shared")
}
case BuildmodeShared:
@@ -991,7 +1000,10 @@ func hostlink() {
// think we may well end up wanting to use -Bsymbolic here
// anyway.
argv = append(argv, "-Wl,-Bsymbolic-functions")
- argv = append(argv, "-shared")
+ if UseRelro() {
+ argv = append(argv, "-shared")
+ }
+ argv = append(argv, "-Wl,-z,relro")
}
if Linkshared && Iself {
@@ -1771,6 +1783,12 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
obj.SGOSTRING,
obj.SGOFUNC,
obj.SGCBITS,
+ obj.STYPERELRO,
+ obj.SSTRINGRELRO,
+ obj.SGOSTRINGRELRO,
+ obj.SGOFUNCRELRO,
+ obj.SGCBITSRELRO,
+ obj.SRODATARELRO,
obj.SWINDOWS:
if !s.Reachable {
continue
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index 250c053143..918ca8ac13 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -350,13 +350,29 @@ func symtab() {
// pseudo-symbols to mark locations of type, string, and go string data.
var symtype *LSym
- if !DynlinkingGo() {
+ var symtyperel *LSym
+ if UseRelro() && Buildmode == BuildmodeCShared {
+ s = Linklookup(Ctxt, "type.*", 0)
+
+ s.Type = obj.STYPE
+ s.Size = 0
+ s.Reachable = true
+ symtype = s
+
+ s = Linklookup(Ctxt, "typerel.*", 0)
+
+ s.Type = obj.STYPERELRO
+ s.Size = 0
+ s.Reachable = true
+ symtyperel = s
+ } else if !DynlinkingGo() {
s = Linklookup(Ctxt, "type.*", 0)
s.Type = obj.STYPE
s.Size = 0
s.Reachable = true
symtype = s
+ symtyperel = s
}
s = Linklookup(Ctxt, "go.string.*", 0)
@@ -381,6 +397,7 @@ func symtab() {
symgcbits := s
symtypelink := Linklookup(Ctxt, "runtime.typelink", 0)
+ symtypelink.Type = obj.STYPELINK
symt = Linklookup(Ctxt, "runtime.symtab", 0)
symt.Local = true
@@ -400,9 +417,14 @@ func symtab() {
}
if strings.HasPrefix(s.Name, "type.") && !DynlinkingGo() {
- s.Type = obj.STYPE
s.Hide = 1
- s.Outer = symtype
+ if UseRelro() && len(s.R) > 0 {
+ s.Type = obj.STYPERELRO
+ s.Outer = symtyperel
+ } else {
+ s.Type = obj.STYPE
+ s.Outer = symtype
+ }
}
if strings.HasPrefix(s.Name, "go.typelink.") {
diff --git a/src/cmd/newlink/testdata/autosection.6 b/src/cmd/newlink/testdata/autosection.6
index 3681f70db8..90c842792c 100644
--- a/src/cmd/newlink/testdata/autosection.6
+++ b/src/cmd/newlink/testdata/autosection.6
Binary files differ
diff --git a/src/cmd/newlink/testdata/autoweak.6 b/src/cmd/newlink/testdata/autoweak.6
index 99cf465928..c95dd20214 100644
--- a/src/cmd/newlink/testdata/autoweak.6
+++ b/src/cmd/newlink/testdata/autoweak.6
Binary files differ
diff --git a/src/cmd/newlink/testdata/dead.6 b/src/cmd/newlink/testdata/dead.6
index 5b17ef1adb..a3ec719808 100644
--- a/src/cmd/newlink/testdata/dead.6
+++ b/src/cmd/newlink/testdata/dead.6
Binary files differ
diff --git a/src/cmd/newlink/testdata/hello.6 b/src/cmd/newlink/testdata/hello.6
index 1f08d2155e..6731f525d0 100644
--- a/src/cmd/newlink/testdata/hello.6
+++ b/src/cmd/newlink/testdata/hello.6
Binary files differ
diff --git a/src/cmd/newlink/testdata/layout.6 b/src/cmd/newlink/testdata/layout.6
index d1669866a4..fcfbe1b3de 100644
--- a/src/cmd/newlink/testdata/layout.6
+++ b/src/cmd/newlink/testdata/layout.6
Binary files differ
diff --git a/src/cmd/newlink/testdata/pclntab.6 b/src/cmd/newlink/testdata/pclntab.6
index dfe53ddc38..abc8aef0ab 100644
--- a/src/cmd/newlink/testdata/pclntab.6
+++ b/src/cmd/newlink/testdata/pclntab.6
Binary files differ