Skip to content

Commit ffd95aa

Browse files
committed
cmd/link: put read-only data in __DATA_CONST segment
On darwin, we put read-only data in __TEXT segment on AMD64 in exe (non-PIE) buildmode, and in __DATA on everywhere else. This is not ideal: things in __DATA segment are not read-only, and being mapped R/W may use more run-time resources. In fact, newer darwin systems support a __DATA_CONST segment, which the dynamic linker will map it read-only after applying relocations. Use that. Fixes #38830. Change-Id: Ic281e6c6ca8ef5fec4bb7c5b71c50dd5393e78ae Reviewed-on: https://go-review.googlesource.com/c/go/+/253919 Reviewed-by: Than McIntosh <[email protected]>
1 parent a531bd5 commit ffd95aa

File tree

3 files changed

+43
-24
lines changed

3 files changed

+43
-24
lines changed

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ func writeBlock(ctxt *Link, out *OutBuf, ldr *loader.Loader, syms []loader.Sym,
930930
break
931931
}
932932
if val < addr {
933-
ldr.Errorf(s, "phase error: addr=%#x but sym=%#x type=%d", addr, val, ldr.SymType(s))
933+
ldr.Errorf(s, "phase error: addr=%#x but sym=%#x type=%v sect=%v", addr, val, ldr.SymType(s), ldr.SymSect(s).Name)
934934
errorexit()
935935
}
936936
if addr < val {
@@ -1308,9 +1308,9 @@ func (state *dodataState) makeRelroForSharedLib(target *Link) {
13081308
// relro Type before it reaches here.
13091309
isRelro = true
13101310
case sym.SFUNCTAB:
1311-
if target.IsAIX() && ldr.SymName(s) == "runtime.etypes" {
1311+
if ldr.SymName(s) == "runtime.etypes" {
13121312
// runtime.etypes must be at the end of
1313-
// the relro datas.
1313+
// the relro data.
13141314
isRelro = true
13151315
}
13161316
}
@@ -1706,7 +1706,7 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
17061706
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.ebss", 0), sect)
17071707
bssGcEnd := state.datsize - int64(sect.Vaddr)
17081708

1709-
// Emit gcdata for bcc symbols now that symbol values have been assigned.
1709+
// Emit gcdata for bss symbols now that symbol values have been assigned.
17101710
gcsToEmit := []struct {
17111711
symName string
17121712
symKind sym.SymKind
@@ -1826,13 +1826,16 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
18261826
const fallbackPerm = 04
18271827
relroSecPerm := fallbackPerm
18281828
genrelrosecname := func(suffix string) string {
1829+
if suffix == "" {
1830+
return ".rodata"
1831+
}
18291832
return suffix
18301833
}
18311834
seg := segro
18321835

18331836
if ctxt.UseRelro() {
18341837
segrelro := &Segrelrodata
1835-
if ctxt.LinkMode == LinkExternal && ctxt.HeadType != objabi.Haix {
1838+
if ctxt.LinkMode == LinkExternal && !ctxt.IsAIX() && !ctxt.IsDarwin() {
18361839
// Using a separate segment with an external
18371840
// linker results in some programs moving
18381841
// their data sections unexpectedly, which
@@ -1845,9 +1848,12 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
18451848
state.datsize = 0
18461849
}
18471850

1848-
genrelrosecname = func(suffix string) string {
1849-
return ".data.rel.ro" + suffix
1851+
if !ctxt.IsDarwin() { // We don't need the special names on darwin.
1852+
genrelrosecname = func(suffix string) string {
1853+
return ".data.rel.ro" + suffix
1854+
}
18501855
}
1856+
18511857
relroReadOnly := []sym.SymKind{}
18521858
for _, symnro := range sym.ReadOnly {
18531859
symn := sym.RelROMap[symnro]

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

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -499,16 +499,7 @@ func machoadddynlib(lib string, linkmode LinkMode) {
499499
func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
500500
buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
501501

502-
var msect *MachoSect
503-
if sect.Rwx&1 == 0 && segname != "__DWARF" && (ctxt.Arch.Family == sys.ARM64 ||
504-
(ctxt.Arch.Family == sys.AMD64 && ctxt.BuildMode != BuildModeExe)) {
505-
// Darwin external linker on arm64, and on amd64 in c-shared/c-archive buildmode
506-
// complains about absolute relocs in __TEXT, so if the section is not
507-
// executable, put it in __DATA segment.
508-
msect = newMachoSect(mseg, buf, "__DATA")
509-
} else {
510-
msect = newMachoSect(mseg, buf, segname)
511-
}
502+
msect := newMachoSect(mseg, buf, segname)
512503

513504
if sect.Rellen > 0 {
514505
msect.reloc = uint32(sect.Reloff)
@@ -633,13 +624,28 @@ func asmbMacho(ctxt *Link) {
633624
machoshbits(ctxt, ms, sect, "__TEXT")
634625
}
635626

627+
/* rodata */
628+
if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 {
629+
ms = newMachoSeg("__DATA_CONST", 20)
630+
ms.vaddr = Segrelrodata.Vaddr
631+
ms.vsize = Segrelrodata.Length
632+
ms.fileoffset = Segrelrodata.Fileoff
633+
ms.filesize = Segrelrodata.Filelen
634+
ms.prot1 = 3
635+
ms.prot2 = 3
636+
ms.flag = 0x10 // SG_READ_ONLY
637+
}
638+
639+
for _, sect := range Segrelrodata.Sections {
640+
machoshbits(ctxt, ms, sect, "__DATA_CONST")
641+
}
642+
636643
/* data */
637644
if ctxt.LinkMode != LinkExternal {
638-
w := int64(Segdata.Length)
639645
ms = newMachoSeg("__DATA", 20)
640-
ms.vaddr = uint64(va) + uint64(v)
641-
ms.vsize = uint64(w)
642-
ms.fileoffset = uint64(v)
646+
ms.vaddr = Segdata.Vaddr
647+
ms.vsize = Segdata.Length
648+
ms.fileoffset = Segdata.Fileoff
643649
ms.filesize = Segdata.Filelen
644650
ms.prot1 = 3
645651
ms.prot2 = 3
@@ -695,7 +701,7 @@ func asmbMacho(ctxt *Link) {
695701

696702
if ctxt.LinkMode != LinkExternal {
697703
ms := newMachoSeg("__LINKEDIT", 0)
698-
ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(*FlagRound)))
704+
ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound)))
699705
ms.vsize = uint64(s1) + uint64(s2) + uint64(s3) + uint64(s4)
700706
ms.fileoffset = uint64(linkoff)
701707
ms.filesize = ms.vsize
@@ -1008,7 +1014,7 @@ func doMachoLink(ctxt *Link) int64 {
10081014
size := int(ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4))
10091015

10101016
if size > 0 {
1011-
linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
1017+
linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segrelrodata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
10121018
ctxt.Out.SeekSet(linkoff)
10131019

10141020
ctxt.Out.Write(ldr.Data(s1))
@@ -1086,6 +1092,9 @@ func machoEmitReloc(ctxt *Link) {
10861092
for _, sect := range Segtext.Sections[1:] {
10871093
relocSect(ctxt, sect, ctxt.datap)
10881094
}
1095+
for _, sect := range Segrelrodata.Sections {
1096+
relocSect(ctxt, sect, ctxt.datap)
1097+
}
10891098
for _, sect := range Segdata.Sections {
10901099
relocSect(ctxt, sect, ctxt.datap)
10911100
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,12 @@ func (t *Target) IsDynlinkingGo() bool {
7474
func (t *Target) UseRelro() bool {
7575
switch t.BuildMode {
7676
case BuildModeCArchive, BuildModeCShared, BuildModeShared, BuildModePIE, BuildModePlugin:
77-
return t.IsELF || t.HeadType == objabi.Haix
77+
return t.IsELF || t.HeadType == objabi.Haix || t.HeadType == objabi.Hdarwin
7878
default:
79+
if t.HeadType == objabi.Hdarwin && t.IsARM64() {
80+
// On darwin/ARM64, everything is PIE.
81+
return true
82+
}
7983
return t.linkShared || (t.HeadType == objabi.Haix && t.LinkMode == LinkExternal)
8084
}
8185
}

0 commit comments

Comments
 (0)