]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: put .got section in __DATA_CONST segment
authorqmuntal <quimmuntal@gmail.com>
Fri, 24 Jan 2025 11:23:42 +0000 (12:23 +0100)
committerQuim Muntal <quimmuntal@gmail.com>
Tue, 25 Feb 2025 19:51:02 +0000 (11:51 -0800)
On Darwin, the .got section can be placed in a read-only segment. Only the dynamic linker should modify it at start-up time.

Other read-only sections, like .typelink and .itablink, are already placed in the __DATA_CONST segment. Do the same for the .got section.

Fixes #71416.

Cq-Include-Trybots: luci.golang.try:gotip-darwin-amd64-longtest
Change-Id: I9cd9c20da63b655fabb61d742feb086c3ef3bea7
Reviewed-on: https://go-review.googlesource.com/c/go/+/644055
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/macho.go
src/cmd/link/internal/ld/macho_test.go [new file with mode: 0644]
src/cmd/link/internal/sym/symkind.go
src/cmd/link/internal/sym/symkind_string.go

index da604e7b0e2094617d00182a58c1b2ad441179fa..0fd3bacd2fb454cea9ed173ebe8bf3004ed64dfe 100644 (file)
@@ -1920,7 +1920,6 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
                sym.SFIPSINFO,
                sym.SELFSECT,
                sym.SMACHO,
-               sym.SMACHOGOT,
                sym.SWINDOWS,
        }
        for _, symn := range writable {
@@ -1932,6 +1931,9 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
        if len(state.data[sym.SELFGOT]) > 0 {
                state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
        }
+       if len(state.data[sym.SMACHOGOT]) > 0 {
+               state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SMACHOGOT, sym.SDATA, 06)
+       }
 
        /* pointer-free data */
        sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrdata", sym.SNOPTRDATA, sym.SDATA, 06)
@@ -2203,6 +2205,7 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
                sect.Length = uint64(state.datsize) - sect.Vaddr
 
                state.allocateSingleSymSections(segrelro, sym.SELFRELROSECT, sym.SRODATA, relroSecPerm)
+               state.allocateSingleSymSections(segrelro, sym.SMACHORELROSECT, sym.SRODATA, relroSecPerm)
        }
 
        /* typelink */
index 1e7c8629ef4b620305f8e13649219eb33795a3be..93b54d81c555ba0e6afbcdd0e7247eedb9cecbbb 100644 (file)
@@ -463,7 +463,11 @@ func (ctxt *Link) domacho() {
 
                s = ctxt.loader.LookupOrCreateSym(".got", 0) // will be __nl_symbol_ptr
                sb = ctxt.loader.MakeSymbolUpdater(s)
-               sb.SetType(sym.SMACHOGOT)
+               if ctxt.UseRelro() {
+                       sb.SetType(sym.SMACHORELROSECT)
+               } else {
+                       sb.SetType(sym.SMACHOGOT)
+               }
                sb.SetReachable(true)
                sb.SetAlign(4)
 
diff --git a/src/cmd/link/internal/ld/macho_test.go b/src/cmd/link/internal/ld/macho_test.go
new file mode 100644 (file)
index 0000000..1a4ffd8
--- /dev/null
@@ -0,0 +1,156 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin
+
+package ld
+
+import (
+       "debug/macho"
+       "fmt"
+       "internal/testenv"
+       "os"
+       "path/filepath"
+       "testing"
+)
+
+func TestMachoSectionsReadOnly(t *testing.T) {
+       t.Parallel()
+       testenv.MustHaveGoBuild(t)
+
+       const (
+               prog  = `package main; func main() {}`
+               progC = `package main; import "C"; func main() {}`
+       )
+
+       tests := []struct {
+               name             string
+               args             []string
+               prog             string
+               wantSecsRO       []string
+               mustHaveCGO      bool
+               mustInternalLink bool
+       }{
+               {
+                       name:             "linkmode-internal",
+                       args:             []string{"-ldflags", "-linkmode=internal"},
+                       prog:             prog,
+                       mustInternalLink: true,
+                       wantSecsRO:       []string{"__nl_symbol_ptr", "__rodata", "__itablink", "__typelink", "__gosymtab", "__gopclntab"},
+               },
+               {
+                       name:       "linkmode-external",
+                       args:       []string{"-ldflags", "-linkmode=external"},
+                       prog:       prog,
+                       wantSecsRO: []string{"__got", "__rodata", "__itablink", "__typelink", "__gopclntab"},
+               },
+               {
+                       name:             "cgo-linkmode-internal",
+                       args:             []string{"-ldflags", "-linkmode=external"},
+                       prog:             progC,
+                       mustHaveCGO:      true,
+                       mustInternalLink: true,
+                       wantSecsRO:       []string{"__got", "__rodata", "__itablink", "__typelink", "__gopclntab"},
+               },
+               {
+                       name:        "cgo-linkmode-external",
+                       args:        []string{"-ldflags", "-linkmode=external"},
+                       prog:        progC,
+                       mustHaveCGO: true,
+                       wantSecsRO:  []string{"__got", "__rodata", "__itablink", "__typelink", "__gopclntab"},
+               },
+       }
+
+       for _, test := range tests {
+               t.Run(test.name, func(t *testing.T) {
+                       if test.mustInternalLink {
+                               testenv.MustInternalLink(t, test.mustHaveCGO)
+                       }
+                       if test.mustHaveCGO {
+                               testenv.MustHaveCGO(t)
+                       }
+
+                       var (
+                               dir     = t.TempDir()
+                               src     = filepath.Join(dir, fmt.Sprintf("macho_%s.go", test.name))
+                               binFile = filepath.Join(dir, test.name)
+                       )
+
+                       if err := os.WriteFile(src, []byte(test.prog), 0666); err != nil {
+                               t.Fatal(err)
+                       }
+
+                       cmdArgs := append([]string{"build", "-o", binFile}, append(test.args, src)...)
+                       cmd := testenv.Command(t, testenv.GoToolPath(t), cmdArgs...)
+
+                       if out, err := cmd.CombinedOutput(); err != nil {
+                               t.Fatalf("failed to build %v: %v:\n%s", cmd.Args, err, out)
+                       }
+
+                       fi, err := os.Open(binFile)
+                       if err != nil {
+                               t.Fatalf("failed to open built file: %v", err)
+                       }
+                       defer fi.Close()
+
+                       machoFile, err := macho.NewFile(fi)
+                       if err != nil {
+                               t.Fatalf("failed to parse macho file: %v", err)
+                       }
+                       defer machoFile.Close()
+
+                       // Load segments
+                       segs := make(map[string]*macho.Segment)
+                       for _, l := range machoFile.Loads {
+                               if s, ok := l.(*macho.Segment); ok {
+                                       segs[s.Name] = s
+                               }
+                       }
+
+                       for _, wsroname := range test.wantSecsRO {
+                               // Now walk the sections. Section should be part of
+                               // some segment that is readonly.
+                               var wsro *macho.Section
+                               foundRO := false
+                               for _, s := range machoFile.Sections {
+                                       if s.Name == wsroname {
+                                               seg := segs[s.Seg]
+                                               if seg == nil {
+                                                       t.Fatalf("test %s: can't locate segment for %q section",
+                                                               test.name, wsroname)
+                                               }
+                                               if seg.Flag == 0x10 { // SG_READ_ONLY
+                                                       foundRO = true
+                                                       wsro = s
+                                                       break
+                                               }
+                                       }
+                               }
+                               if wsro == nil {
+                                       t.Fatalf("test %s: can't locate %q section",
+                                               test.name, wsroname)
+                                       continue
+                               }
+                               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.Size)
+                                       t.Logf("sec %s found in this segment: ", wsro.Seg)
+                                       t.Logf("\nall segments: \n")
+                                       for _, l := range machoFile.Loads {
+                                               if s, ok := l.(*macho.Segment); ok {
+                                                       t.Logf("cmd=%s fl=%d st=0x%x en=0x%x\n",
+                                                               s.Cmd, s.Flag, s.Addr, s.Addr+s.Filesz)
+                                               }
+                                       }
+                                       t.Fatalf("test %s failed", test.name)
+                               }
+                       }
+               })
+       }
+}
index 84783e16d7ba3ee7eb6a55fba17a2ef3821fe625..0671d9d724d25d38d1697b41a772da64f6819d46 100644 (file)
@@ -85,6 +85,7 @@ const (
        SRODATARELRO
        SFUNCTABRELRO
        SELFRELROSECT
+       SMACHORELROSECT
 
        // Part of .data.rel.ro if it exists, otherwise part of .rodata.
        STYPELINK
index 5e66eb2d79c6a583e3ded50b56591e081b13a94e..5395c9571ba8b8eea33ce9f4080fe2f4f042345d 100644 (file)
@@ -36,63 +36,64 @@ func _() {
        _ = x[SRODATARELRO-25]
        _ = x[SFUNCTABRELRO-26]
        _ = x[SELFRELROSECT-27]
-       _ = x[STYPELINK-28]
-       _ = x[SITABLINK-29]
-       _ = x[SSYMTAB-30]
-       _ = x[SPCLNTAB-31]
-       _ = x[SFirstWritable-32]
-       _ = x[SBUILDINFO-33]
-       _ = x[SFIPSINFO-34]
-       _ = x[SELFSECT-35]
-       _ = x[SMACHO-36]
-       _ = x[SMACHOGOT-37]
-       _ = x[SWINDOWS-38]
-       _ = x[SELFGOT-39]
-       _ = x[SNOPTRDATA-40]
-       _ = x[SNOPTRDATAFIPSSTART-41]
-       _ = x[SNOPTRDATAFIPS-42]
-       _ = x[SNOPTRDATAFIPSEND-43]
-       _ = x[SNOPTRDATAEND-44]
-       _ = x[SINITARR-45]
-       _ = x[SDATA-46]
-       _ = x[SDATAFIPSSTART-47]
-       _ = x[SDATAFIPS-48]
-       _ = x[SDATAFIPSEND-49]
-       _ = x[SDATAEND-50]
-       _ = x[SXCOFFTOC-51]
-       _ = x[SBSS-52]
-       _ = x[SNOPTRBSS-53]
-       _ = x[SLIBFUZZER_8BIT_COUNTER-54]
-       _ = x[SCOVERAGE_COUNTER-55]
-       _ = x[SCOVERAGE_AUXVAR-56]
-       _ = x[STLSBSS-57]
-       _ = x[SXREF-58]
-       _ = x[SMACHOSYMSTR-59]
-       _ = x[SMACHOSYMTAB-60]
-       _ = x[SMACHOINDIRECTPLT-61]
-       _ = x[SMACHOINDIRECTGOT-62]
-       _ = x[SFILEPATH-63]
-       _ = x[SDYNIMPORT-64]
-       _ = x[SHOSTOBJ-65]
-       _ = x[SUNDEFEXT-66]
-       _ = x[SDWARFSECT-67]
-       _ = x[SDWARFCUINFO-68]
-       _ = x[SDWARFCONST-69]
-       _ = x[SDWARFFCN-70]
-       _ = x[SDWARFABSFCN-71]
-       _ = x[SDWARFTYPE-72]
-       _ = x[SDWARFVAR-73]
-       _ = x[SDWARFRANGE-74]
-       _ = x[SDWARFLOC-75]
-       _ = x[SDWARFLINES-76]
-       _ = x[SDWARFADDR-77]
-       _ = x[SSEHUNWINDINFO-78]
-       _ = x[SSEHSECT-79]
+       _ = x[SMACHORELROSECT-28]
+       _ = x[STYPELINK-29]
+       _ = x[SITABLINK-30]
+       _ = x[SSYMTAB-31]
+       _ = x[SPCLNTAB-32]
+       _ = x[SFirstWritable-33]
+       _ = x[SBUILDINFO-34]
+       _ = x[SFIPSINFO-35]
+       _ = x[SELFSECT-36]
+       _ = x[SMACHO-37]
+       _ = x[SMACHOGOT-38]
+       _ = x[SWINDOWS-39]
+       _ = x[SELFGOT-40]
+       _ = x[SNOPTRDATA-41]
+       _ = x[SNOPTRDATAFIPSSTART-42]
+       _ = x[SNOPTRDATAFIPS-43]
+       _ = x[SNOPTRDATAFIPSEND-44]
+       _ = x[SNOPTRDATAEND-45]
+       _ = x[SINITARR-46]
+       _ = x[SDATA-47]
+       _ = x[SDATAFIPSSTART-48]
+       _ = x[SDATAFIPS-49]
+       _ = x[SDATAFIPSEND-50]
+       _ = x[SDATAEND-51]
+       _ = x[SXCOFFTOC-52]
+       _ = x[SBSS-53]
+       _ = x[SNOPTRBSS-54]
+       _ = x[SLIBFUZZER_8BIT_COUNTER-55]
+       _ = x[SCOVERAGE_COUNTER-56]
+       _ = x[SCOVERAGE_AUXVAR-57]
+       _ = x[STLSBSS-58]
+       _ = x[SXREF-59]
+       _ = x[SMACHOSYMSTR-60]
+       _ = x[SMACHOSYMTAB-61]
+       _ = x[SMACHOINDIRECTPLT-62]
+       _ = x[SMACHOINDIRECTGOT-63]
+       _ = x[SFILEPATH-64]
+       _ = x[SDYNIMPORT-65]
+       _ = x[SHOSTOBJ-66]
+       _ = x[SUNDEFEXT-67]
+       _ = x[SDWARFSECT-68]
+       _ = x[SDWARFCUINFO-69]
+       _ = x[SDWARFCONST-70]
+       _ = x[SDWARFFCN-71]
+       _ = x[SDWARFABSFCN-72]
+       _ = x[SDWARFTYPE-73]
+       _ = x[SDWARFVAR-74]
+       _ = x[SDWARFRANGE-75]
+       _ = x[SDWARFLOC-76]
+       _ = x[SDWARFLINES-77]
+       _ = x[SDWARFADDR-78]
+       _ = x[SSEHUNWINDINFO-79]
+       _ = x[SSEHSECT-80]
 }
 
-const _SymKind_name = "SxxxSTEXTSTEXTFIPSSTARTSTEXTFIPSSTEXTFIPSENDSTEXTENDSELFRXSECTSMACHOPLTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASRODATAFIPSSTARTSRODATAFIPSSRODATAFIPSENDSRODATAENDSFUNCTABSELFROSECTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSELFRELROSECTSTYPELINKSITABLINKSSYMTABSPCLNTABSFirstWritableSBUILDINFOSFIPSINFOSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASNOPTRDATAFIPSSTARTSNOPTRDATAFIPSSNOPTRDATAFIPSENDSNOPTRDATAENDSINITARRSDATASDATAFIPSSTARTSDATAFIPSSDATAFIPSENDSDATAENDSXCOFFTOCSBSSSNOPTRBSSSLIBFUZZER_8BIT_COUNTERSCOVERAGE_COUNTERSCOVERAGE_AUXVARSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSDYNIMPORTSHOSTOBJSUNDEFEXTSDWARFSECTSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSDWARFADDRSSEHUNWINDINFOSSEHSECT"
+const _SymKind_name = "SxxxSTEXTSTEXTFIPSSTARTSTEXTFIPSSTEXTFIPSENDSTEXTENDSELFRXSECTSMACHOPLTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASRODATAFIPSSTARTSRODATAFIPSSRODATAFIPSENDSRODATAENDSFUNCTABSELFROSECTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSELFRELROSECTSMACHORELROSECTSTYPELINKSITABLINKSSYMTABSPCLNTABSFirstWritableSBUILDINFOSFIPSINFOSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASNOPTRDATAFIPSSTARTSNOPTRDATAFIPSSNOPTRDATAFIPSENDSNOPTRDATAENDSINITARRSDATASDATAFIPSSTARTSDATAFIPSSDATAFIPSENDSDATAENDSXCOFFTOCSBSSSNOPTRBSSSLIBFUZZER_8BIT_COUNTERSCOVERAGE_COUNTERSCOVERAGE_AUXVARSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSDYNIMPORTSHOSTOBJSUNDEFEXTSDWARFSECTSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSDWARFADDRSSEHUNWINDINFOSSEHSECT"
 
-var _SymKind_index = [...]uint16{0, 4, 9, 23, 32, 44, 52, 62, 71, 76, 83, 92, 99, 106, 113, 129, 140, 154, 164, 172, 182, 192, 204, 218, 230, 242, 254, 267, 280, 289, 298, 305, 313, 327, 337, 346, 354, 360, 369, 377, 384, 394, 413, 427, 444, 457, 465, 470, 484, 493, 505, 513, 522, 526, 535, 558, 575, 591, 598, 603, 615, 627, 644, 661, 670, 680, 688, 697, 707, 719, 730, 739, 751, 761, 770, 781, 790, 801, 811, 825, 833}
+var _SymKind_index = [...]uint16{0, 4, 9, 23, 32, 44, 52, 62, 71, 76, 83, 92, 99, 106, 113, 129, 140, 154, 164, 172, 182, 192, 204, 218, 230, 242, 254, 267, 280, 295, 304, 313, 320, 328, 342, 352, 361, 369, 375, 384, 392, 399, 409, 428, 442, 459, 472, 480, 485, 499, 508, 520, 528, 537, 541, 550, 573, 590, 606, 613, 618, 630, 642, 659, 676, 685, 695, 703, 712, 722, 734, 745, 754, 766, 776, 785, 796, 805, 816, 826, 840, 848}
 
 func (i SymKind) String() string {
        if i >= SymKind(len(_SymKind_index)-1) {