]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/link/internal/ld/lib.go
cmd/internal/link: merge .pdata and .xdata sections from host object files
[gostls13.git] / src / cmd / link / internal / ld / lib.go
index 02c6908407bdf408e2ca0c34632415932bec10a1..b603fba6c7181fa83e6723f6ed3614322076cb3e 100644 (file)
@@ -44,6 +44,7 @@ import (
        "os/exec"
        "path/filepath"
        "runtime"
+       "sort"
        "strings"
        "sync"
 
@@ -119,6 +120,10 @@ type ArchSyms struct {
        DynStr  loader.Sym
 
        unreachableMethod loader.Sym
+
+       // Symbol containing a list of all the inittasks that need
+       // to be run at startup.
+       mainInittasks loader.Sym
 }
 
 // mkArchSym is a helper for setArchSyms, to set up a special symbol.
@@ -324,8 +329,10 @@ var (
        Segrelrodata sym.Segment
        Segdata      sym.Segment
        Segdwarf     sym.Segment
+       Segpdata     sym.Segment // windows-only
+       Segxdata     sym.Segment // windows-only
 
-       Segments = []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf}
+       Segments = []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf, &Segpdata, &Segxdata}
 )
 
 const pkgdef = "__.PKGDEF"
@@ -522,8 +529,7 @@ func (ctxt *Link) loadlib() {
        default:
                log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
        }
-       elfsetstring1 := func(str string, off int) { elfsetstring(ctxt, 0, str, off) }
-       ctxt.loader = loader.NewLoader(flags, elfsetstring1, &ctxt.ErrorReporter.ErrorReporter)
+       ctxt.loader = loader.NewLoader(flags, &ctxt.ErrorReporter.ErrorReporter)
        ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
                return ctxt.loader.SymName(s)
        }
@@ -979,21 +985,38 @@ func (ctxt *Link) mangleTypeSym() {
 // Leave type:runtime. symbols alone, because other parts of
 // the linker manipulates them.
 func typeSymbolMangle(name string) string {
-       if !strings.HasPrefix(name, "type:") {
+       isType := strings.HasPrefix(name, "type:")
+       if !isType && !strings.Contains(name, "@") {
+               // Issue 58800: instantiated symbols may include a type name, which may contain "@"
                return name
        }
        if strings.HasPrefix(name, "type:runtime.") {
                return name
        }
+       if strings.HasPrefix(name, "go:string.") {
+               // String symbols will be grouped to a single go:string.* symbol.
+               // No need to mangle individual symbol names.
+               return name
+       }
        if len(name) <= 14 && !strings.Contains(name, "@") { // Issue 19529
                return name
        }
-       hash := notsha256.Sum256([]byte(name))
-       prefix := "type:"
-       if name[5] == '.' {
-               prefix = "type:."
+       if isType {
+               hash := notsha256.Sum256([]byte(name[5:]))
+               prefix := "type:"
+               if name[5] == '.' {
+                       prefix = "type:."
+               }
+               return prefix + base64.StdEncoding.EncodeToString(hash[:6])
+       }
+       // instantiated symbol, replace type name in []
+       i := strings.IndexByte(name, '[')
+       j := strings.LastIndexByte(name, ']')
+       if j == -1 || j <= i {
+               j = len(name)
        }
-       return prefix + base64.StdEncoding.EncodeToString(hash[:6])
+       hash := notsha256.Sum256([]byte(name[i+1 : j]))
+       return name[:i+1] + base64.StdEncoding.EncodeToString(hash[:6]) + name[j:]
 }
 
 /*
@@ -1372,7 +1395,7 @@ func (ctxt *Link) hostlink() {
                if ctxt.HeadType == objabi.Hdarwin {
                        // Recent versions of macOS print
                        //      ld: warning: option -s is obsolete and being ignored
-                       // so do not pass any arguments.
+                       // so do not pass any arguments (but we strip symbols below).
                } else {
                        argv = append(argv, "-s")
                }
@@ -1380,7 +1403,7 @@ func (ctxt *Link) hostlink() {
 
        // On darwin, whether to combine DWARF into executable.
        // Only macOS supports unmapped segments such as our __DWARF segment.
-       combineDwarf := ctxt.IsDarwin() && !*FlagS && !*FlagW && !debug_s && machoPlatform == PLATFORM_MACOS
+       combineDwarf := ctxt.IsDarwin() && !*FlagW && machoPlatform == PLATFORM_MACOS
 
        switch ctxt.HeadType {
        case objabi.Hdarwin:
@@ -1399,10 +1422,22 @@ func (ctxt *Link) hostlink() {
                }
                if !combineDwarf {
                        argv = append(argv, "-Wl,-S") // suppress STAB (symbolic debugging) symbols
+                       if debug_s {
+                               // We are generating a binary with symbol table suppressed.
+                               // Suppress local symbols. We need to keep dynamically exported
+                               // and referenced symbols so the dynamic linker can resolve them.
+                               argv = append(argv, "-Wl,-x")
+                       }
                }
        case objabi.Hopenbsd:
                argv = append(argv, "-Wl,-nopie")
                argv = append(argv, "-pthread")
+               if ctxt.Arch.InFamily(sys.ARM64) {
+                       // Disable execute-only on openbsd/arm64 - the Go arm64 assembler
+                       // currently stores constants in the text section rather than in rodata.
+                       // See issue #59615.
+                       argv = append(argv, "-Wl,--no-execute-only")
+               }
        case objabi.Hwindows:
                if windowsgui {
                        argv = append(argv, "-mwindows")
@@ -1647,9 +1682,12 @@ func (ctxt *Link) hostlink() {
                if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
                        argv = append(argv, "-rdynamic")
                } else {
+                       var exports []string
                        ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
-                               argv = append(argv, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
+                               exports = append(exports, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
                        })
+                       sort.Strings(exports)
+                       argv = append(argv, exports...)
                }
        }
        if ctxt.HeadType == objabi.Haix {
@@ -1870,6 +1908,16 @@ func (ctxt *Link) hostlink() {
                                out = append(out[:i], out[i+len(noPieWarning):]...)
                        }
                }
+               if ctxt.IsDarwin() {
+                       const bindAtLoadWarning = "ld: warning: -bind_at_load is deprecated on macOS\n"
+                       if i := bytes.Index(out, []byte(bindAtLoadWarning)); i >= 0 {
+                               // -bind_at_load is deprecated with ld-prime, but needed for
+                               // correctness with older versions of ld64. Swallow the warning.
+                               // TODO: maybe pass -bind_at_load conditionally based on C
+                               // linker version.
+                               out = append(out[:i], out[i+len(bindAtLoadWarning):]...)
+                       }
+               }
                ctxt.Logf("%s", out)
        }
 
@@ -1893,12 +1941,38 @@ func (ctxt *Link) hostlink() {
                stripCmd := strings.TrimSuffix(string(out), "\n")
 
                dsym := filepath.Join(*flagTmpdir, "go.dwarf")
-               if out, err := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
+               cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
+               // dsymutil may not clean up its temp directory at exit.
+               // Set DSYMUTIL_REPRODUCER_PATH to work around. see issue 59026.
+               cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+*flagTmpdir)
+               if ctxt.Debugvlog != 0 {
+                       ctxt.Logf("host link dsymutil:")
+                       for _, v := range cmd.Args {
+                               ctxt.Logf(" %q", v)
+                       }
+                       ctxt.Logf("\n")
+               }
+               if out, err := cmd.CombinedOutput(); err != nil {
                        Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
                }
                // Remove STAB (symbolic debugging) symbols after we are done with them (by dsymutil).
                // They contain temporary file paths and make the build not reproducible.
-               if out, err := exec.Command(stripCmd, "-S", *flagOutfile).CombinedOutput(); err != nil {
+               var stripArgs = []string{"-S"}
+               if debug_s {
+                       // We are generating a binary with symbol table suppressed.
+                       // Suppress local symbols. We need to keep dynamically exported
+                       // and referenced symbols so the dynamic linker can resolve them.
+                       stripArgs = append(stripArgs, "-x")
+               }
+               stripArgs = append(stripArgs, *flagOutfile)
+               if ctxt.Debugvlog != 0 {
+                       ctxt.Logf("host link strip: %q", stripCmd)
+                       for _, v := range stripArgs {
+                               ctxt.Logf(" %q", v)
+                       }
+                       ctxt.Logf("\n")
+               }
+               if out, err := exec.Command(stripCmd, stripArgs...).CombinedOutput(); err != nil {
                        Exitf("%s: running strip failed: %v\n%s", os.Args[0], err, out)
                }
                // Skip combining if `dsymutil` didn't generate a file. See #11994.
@@ -1991,10 +2065,11 @@ func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
        if altLinker != "" {
                flags = append(flags, "-fuse-ld="+altLinker)
        }
-       flags = append(flags, flag, "trivial.c")
+       trivialPath := filepath.Join(*flagTmpdir, "trivial.c")
+       outPath := filepath.Join(*flagTmpdir, "a.out")
+       flags = append(flags, "-o", outPath, flag, trivialPath)
 
        cmd := exec.Command(linker, flags...)
-       cmd.Dir = *flagTmpdir
        cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
        out, err := cmd.CombinedOutput()
        // GCC says "unrecognized command line option ‘-no-pie’"
@@ -2145,15 +2220,21 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
                0xc401, // arm
                0x64aa: // arm64
                ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
-                       textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
+                       ls, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
                        if err != nil {
                                Errorf(nil, "%v", err)
                                return
                        }
-                       if len(rsrc) != 0 {
-                               setpersrc(ctxt, rsrc)
+                       if len(ls.Resources) != 0 {
+                               setpersrc(ctxt, ls.Resources)
                        }
-                       ctxt.Textp = append(ctxt.Textp, textp...)
+                       if ls.PData != 0 {
+                               sehp.pdata = append(sehp.pdata, ls.PData)
+                       }
+                       if ls.XData != 0 {
+                               sehp.xdata = append(sehp.xdata, ls.XData)
+                       }
+                       ctxt.Textp = append(ctxt.Textp, ls.Textp...)
                }
                return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
        }