aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/ld
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/internal/ld')
-rw-r--r--src/cmd/link/internal/ld/data.go3
-rw-r--r--src/cmd/link/internal/ld/elf.go20
-rw-r--r--src/cmd/link/internal/ld/elf_test.go58
3 files changed, 75 insertions, 6 deletions
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 11dc48b18b..feaa3c34d8 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -1850,7 +1850,7 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
}
ldr := ctxt.loader
- // .got
+ // writable .got (note that for PIE binaries .got goes in relro)
if len(state.data[sym.SELFGOT]) > 0 {
state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
}
@@ -2106,6 +2106,7 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
}
}
+ state.assignToSection(sect, sym.SELFRELROSECT, sym.SRODATA)
sect.Length = uint64(state.datsize) - sect.Vaddr
}
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 97b24b0cae..0d8455d92e 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -1113,6 +1113,7 @@ func elfphload(seg *sym.Segment) *ElfPhdr {
func elfphrelro(seg *sym.Segment) {
ph := newElfPhdr()
ph.Type = elf.PT_GNU_RELRO
+ ph.Flags = elf.PF_R
ph.Vaddr = seg.Vaddr
ph.Paddr = seg.Vaddr
ph.Memsz = seg.Length
@@ -1562,7 +1563,11 @@ func (ctxt *Link) doelf() {
/* global offset table */
got := ldr.CreateSymForUpdate(".got", 0)
- got.SetType(sym.SELFGOT) // writable
+ if ctxt.UseRelro() {
+ got.SetType(sym.SELFRELROSECT)
+ } else {
+ got.SetType(sym.SELFGOT) // writable
+ }
/* ppc64 glink resolver */
if ctxt.IsPPC64() {
@@ -1575,7 +1580,11 @@ func (ctxt *Link) doelf() {
hash.SetType(sym.SELFROSECT)
gotplt := ldr.CreateSymForUpdate(".got.plt", 0)
- gotplt.SetType(sym.SELFSECT) // writable
+ if ctxt.UseRelro() && *flagBindNow {
+ gotplt.SetType(sym.SELFRELROSECT)
+ } else {
+ gotplt.SetType(sym.SELFSECT) // writable
+ }
plt := ldr.CreateSymForUpdate(".plt", 0)
if ctxt.IsPPC64() {
@@ -1597,9 +1606,12 @@ func (ctxt *Link) doelf() {
/* define dynamic elf table */
dynamic := ldr.CreateSymForUpdate(".dynamic", 0)
- if thearch.ELF.DynamicReadOnly {
+ switch {
+ case thearch.ELF.DynamicReadOnly:
dynamic.SetType(sym.SELFROSECT)
- } else {
+ case ctxt.UseRelro():
+ dynamic.SetType(sym.SELFRELROSECT)
+ default:
dynamic.SetType(sym.SELFSECT)
}
diff --git a/src/cmd/link/internal/ld/elf_test.go b/src/cmd/link/internal/ld/elf_test.go
index 16bf4039b1..b48cf66038 100644
--- a/src/cmd/link/internal/ld/elf_test.go
+++ b/src/cmd/link/internal/ld/elf_test.go
@@ -198,6 +198,7 @@ func TestElfBindNow(t *testing.T) {
name string
args []string
prog string
+ wantSecsRO []string
mustHaveBuildModePIE bool
mustHaveCGO bool
mustInternalLink bool
@@ -213,6 +214,7 @@ func TestElfBindNow(t *testing.T) {
mustHaveBuildModePIE: true,
mustInternalLink: true,
wantDf1Pie: true,
+ wantSecsRO: []string{".dynamic", ".got"},
},
{
name: "bindnow-linkmode-internal",
@@ -232,6 +234,7 @@ func TestElfBindNow(t *testing.T) {
wantDfBindNow: true,
wantDf1Now: true,
wantDf1Pie: true,
+ wantSecsRO: []string{".dynamic", ".got", ".got.plt"},
},
{
name: "bindnow-pie-linkmode-external",
@@ -242,6 +245,8 @@ func TestElfBindNow(t *testing.T) {
wantDfBindNow: true,
wantDf1Now: true,
wantDf1Pie: true,
+ // NB: external linker produces .plt.got, not .got.plt
+ wantSecsRO: []string{".dynamic", ".got"},
},
}
@@ -251,10 +256,14 @@ func TestElfBindNow(t *testing.T) {
return true
}
}
-
return false
}
+ segContainsSec := func(p *elf.Prog, s *elf.Section) bool {
+ return s.Addr >= p.Vaddr &&
+ s.Addr+s.FileSize <= p.Vaddr+p.Filesz
+ }
+
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.mustInternalLink {
@@ -329,6 +338,53 @@ func TestElfBindNow(t *testing.T) {
if gotDf1Pie := gotDynFlag(flags1, uint64(elf.DF_1_PIE)); gotDf1Pie != test.wantDf1Pie {
t.Fatalf("DT_FLAGS_1 DF_1_PIE got: %v, want: %v", gotDf1Pie, test.wantDf1Pie)
}
+
+ for _, wsroname := range test.wantSecsRO {
+ // Locate section of interest.
+ var wsro *elf.Section
+ for _, s := range elfFile.Sections {
+ if s.Name == wsroname {
+ wsro = s
+ break
+ }
+ }
+ if wsro == nil {
+ t.Fatalf("test %s: can't locate %q section",
+ test.name, wsroname)
+ }
+
+ // Now walk the program headers. Section should be part of
+ // some segment that is readonly.
+ foundRO := false
+ foundSegs := []*elf.Prog{}
+ for _, p := range elfFile.Progs {
+ if segContainsSec(p, wsro) {
+ foundSegs = append(foundSegs, p)
+ if p.Flags == elf.PF_R {
+ foundRO = true
+ }
+ }
+ }
+ if !foundRO {
+ // Things went off the rails. Write out some
+ // useful information for a human looking at the
+ // test failure.
+ t.Logf("test %s: %q section not in readonly segment",
+ wsro.Name, test.name)
+ t.Logf("section %s location: st=0x%x en=0x%x\n",
+ wsro.Name, wsro.Addr, wsro.Addr+wsro.FileSize)
+ t.Logf("sec %s found in these segments: ", wsro.Name)
+ for _, p := range foundSegs {
+ t.Logf(" %q", p.Type)
+ }
+ t.Logf("\nall segments: \n")
+ for k, p := range elfFile.Progs {
+ t.Logf("%d t=%s fl=%s st=0x%x en=0x%x\n",
+ k, p.Type, p.Flags, p.Vaddr, p.Vaddr+p.Filesz)
+ }
+ t.Fatalf("test %s failed", test.name)
+ }
+ }
})
}
}