2015-02-27 22:57:28 -05:00
|
|
|
// Copyright 2009 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.
|
|
|
|
|
|
2015-04-24 20:24:49 -07:00
|
|
|
// go-specific code shared across loaders (5l, 6l, 8l).
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
package ld
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
2016-04-06 21:45:29 -07:00
|
|
|
"cmd/internal/bio"
|
2017-04-18 12:53:25 -07:00
|
|
|
"cmd/internal/objabi"
|
2019-12-06 20:11:36 -05:00
|
|
|
"cmd/link/internal/loader"
|
2017-10-04 17:54:04 -04:00
|
|
|
"cmd/link/internal/sym"
|
2018-04-11 15:37:16 -07:00
|
|
|
"encoding/json"
|
2015-02-27 22:57:28 -05:00
|
|
|
"fmt"
|
2016-04-08 18:19:10 +02:00
|
|
|
"io"
|
2015-02-27 22:57:28 -05:00
|
|
|
"os"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// go-specific code shared across loaders (5l, 6l, 8l).
|
|
|
|
|
|
|
|
|
|
// replace all "". with pkg.
|
|
|
|
|
func expandpkg(t0 string, pkg string) string {
|
|
|
|
|
return strings.Replace(t0, `"".`, pkg+".", -1)
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 12:30:23 -04:00
|
|
|
func resolveABIAlias(s *sym.Symbol) *sym.Symbol {
|
|
|
|
|
if s.Type != sym.SABIALIAS {
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
target := s.R[0].Sym
|
|
|
|
|
if target.Type == sym.SABIALIAS {
|
|
|
|
|
panic(fmt.Sprintf("ABI alias %s references another ABI alias %s", s, target))
|
|
|
|
|
}
|
|
|
|
|
return target
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
// TODO:
|
|
|
|
|
// generate debugging section in binary.
|
|
|
|
|
// once the dust settles, try to move some code to
|
|
|
|
|
// libmach, so that other linkers and ar can share.
|
|
|
|
|
|
2018-03-23 10:28:39 -07:00
|
|
|
func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) {
|
2016-08-21 18:34:24 -04:00
|
|
|
if *flagG {
|
2015-02-27 22:57:28 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if int64(int(length)) != length {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
|
2016-08-21 18:34:24 -04:00
|
|
|
if *flagU {
|
2015-04-09 07:37:17 -04:00
|
|
|
errorexit()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 12:35:15 -05:00
|
|
|
bdata := make([]byte, length)
|
2016-04-08 18:19:10 +02:00
|
|
|
if _, err := io.ReadFull(f, bdata); err != nil {
|
2015-02-27 22:57:28 -05:00
|
|
|
fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
|
2016-08-21 18:34:24 -04:00
|
|
|
if *flagU {
|
2015-04-09 07:37:17 -04:00
|
|
|
errorexit()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
2015-03-02 12:35:15 -05:00
|
|
|
data := string(bdata)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2016-04-26 21:50:59 -04:00
|
|
|
// process header lines
|
|
|
|
|
for data != "" {
|
|
|
|
|
var line string
|
|
|
|
|
if i := strings.Index(data, "\n"); i >= 0 {
|
|
|
|
|
line, data = data[:i], data[i+1:]
|
|
|
|
|
} else {
|
|
|
|
|
line, data = data, ""
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-04-26 21:50:59 -04:00
|
|
|
if line == "safe" {
|
2018-03-23 10:28:39 -07:00
|
|
|
lib.Safe = true
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-04-26 21:50:59 -04:00
|
|
|
if line == "main" {
|
2018-03-23 10:28:39 -07:00
|
|
|
lib.Main = true
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-04-26 21:50:59 -04:00
|
|
|
if line == "" {
|
|
|
|
|
break
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-04-26 21:50:59 -04:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// look for cgo section
|
2017-10-01 14:39:04 +11:00
|
|
|
p0 := strings.Index(data, "\n$$ // cgo")
|
|
|
|
|
var p1 int
|
2015-02-27 22:57:28 -05:00
|
|
|
if p0 >= 0 {
|
|
|
|
|
p0 += p1
|
|
|
|
|
i := strings.IndexByte(data[p0+1:], '\n')
|
|
|
|
|
if i < 0 {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
|
2016-08-21 18:34:24 -04:00
|
|
|
if *flagU {
|
2015-04-09 07:37:17 -04:00
|
|
|
errorexit()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
p0 += 1 + i
|
|
|
|
|
|
|
|
|
|
p1 = strings.Index(data[p0:], "\n$$")
|
|
|
|
|
if p1 < 0 {
|
|
|
|
|
p1 = strings.Index(data[p0:], "\n!\n")
|
|
|
|
|
}
|
|
|
|
|
if p1 < 0 {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
|
2016-08-21 18:34:24 -04:00
|
|
|
if *flagU {
|
2015-04-09 07:37:17 -04:00
|
|
|
errorexit()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
p1 += p0
|
2019-10-04 22:05:41 -04:00
|
|
|
loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
func loadcgo(ctxt *Link, file string, pkg string, p string) {
|
2018-04-11 15:37:16 -07:00
|
|
|
var directives [][]string
|
|
|
|
|
if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err)
|
|
|
|
|
nerrors++
|
|
|
|
|
return
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-10-04 22:05:41 -04:00
|
|
|
// Find cgo_export symbols. They are roots in the deadcode pass.
|
|
|
|
|
for _, f := range directives {
|
|
|
|
|
switch f[0] {
|
|
|
|
|
case "cgo_export_static", "cgo_export_dynamic":
|
|
|
|
|
if len(f) < 2 || len(f) > 3 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
local := f[1]
|
|
|
|
|
switch ctxt.BuildMode {
|
|
|
|
|
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
|
|
|
|
|
if local == "main" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
local = expandpkg(local, pkg)
|
|
|
|
|
if f[0] == "cgo_export_static" {
|
|
|
|
|
ctxt.cgo_export_static[local] = true
|
|
|
|
|
} else {
|
|
|
|
|
ctxt.cgo_export_dynamic[local] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-11 16:49:29 -05:00
|
|
|
// Record the directives. We'll process them later after Symbols are created.
|
|
|
|
|
ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives})
|
2019-10-04 22:05:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set symbol attributes or flags based on cgo directives.
|
2019-12-06 20:11:36 -05:00
|
|
|
// Any newly discovered HOSTOBJ syms are added to 'hostObjSyms'.
|
2020-01-31 14:35:37 -05:00
|
|
|
func setCgoAttr(ctxt *Link, lookup func(string, int) loader.Sym, file string, pkg string, directives [][]string, hostObjSyms map[loader.Sym]struct{}) {
|
2019-12-06 20:11:36 -05:00
|
|
|
l := ctxt.loader
|
|
|
|
|
for _, f := range directives {
|
|
|
|
|
switch f[0] {
|
|
|
|
|
case "cgo_import_dynamic":
|
|
|
|
|
if len(f) < 2 || len(f) > 4 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
local := f[1]
|
|
|
|
|
remote := local
|
|
|
|
|
if len(f) > 2 {
|
|
|
|
|
remote = f[2]
|
|
|
|
|
}
|
|
|
|
|
lib := ""
|
|
|
|
|
if len(f) > 3 {
|
|
|
|
|
lib = f[3]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if *FlagD {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
|
|
|
|
|
nerrors++
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if local == "_" && remote == "_" {
|
|
|
|
|
// allow #pragma dynimport _ _ "foo.so"
|
|
|
|
|
// to force a link of foo.so.
|
|
|
|
|
havedynamic = 1
|
|
|
|
|
|
|
|
|
|
if ctxt.HeadType == objabi.Hdarwin {
|
|
|
|
|
machoadddynlib(lib, ctxt.LinkMode)
|
|
|
|
|
} else {
|
|
|
|
|
dynlib = append(dynlib, lib)
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
local = expandpkg(local, pkg)
|
|
|
|
|
q := ""
|
|
|
|
|
if i := strings.Index(remote, "#"); i >= 0 {
|
|
|
|
|
remote, q = remote[:i], remote[i+1:]
|
|
|
|
|
}
|
|
|
|
|
s := lookup(local, 0)
|
|
|
|
|
st := l.SymType(s)
|
|
|
|
|
if st == 0 || st == sym.SXREF || st == sym.SBSS || st == sym.SNOPTRBSS || st == sym.SHOSTOBJ {
|
|
|
|
|
l.SetSymDynimplib(s, lib)
|
|
|
|
|
l.SetSymExtname(s, remote)
|
|
|
|
|
l.SetSymDynimpvers(s, q)
|
|
|
|
|
if st != sym.SHOSTOBJ {
|
2020-02-12 17:23:47 -05:00
|
|
|
su := l.MakeSymbolUpdater(s)
|
2019-12-06 20:11:36 -05:00
|
|
|
su.SetType(sym.SDYNIMPORT)
|
|
|
|
|
} else {
|
|
|
|
|
hostObjSyms[s] = struct{}{}
|
|
|
|
|
}
|
|
|
|
|
havedynamic = 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
case "cgo_import_static":
|
|
|
|
|
if len(f) != 2 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
local := f[1]
|
|
|
|
|
|
2020-02-12 17:23:47 -05:00
|
|
|
s := lookup(local, 0)
|
|
|
|
|
su := l.MakeSymbolUpdater(s)
|
2019-12-06 20:11:36 -05:00
|
|
|
su.SetType(sym.SHOSTOBJ)
|
|
|
|
|
su.SetSize(0)
|
|
|
|
|
hostObjSyms[s] = struct{}{}
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
case "cgo_export_static", "cgo_export_dynamic":
|
|
|
|
|
if len(f) < 2 || len(f) > 3 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
local := f[1]
|
|
|
|
|
remote := local
|
|
|
|
|
if len(f) > 2 {
|
|
|
|
|
remote = f[2]
|
|
|
|
|
}
|
|
|
|
|
local = expandpkg(local, pkg)
|
|
|
|
|
|
|
|
|
|
// The compiler arranges for an ABI0 wrapper
|
|
|
|
|
// to be available for all cgo-exported
|
|
|
|
|
// functions. Link.loadlib will resolve any
|
|
|
|
|
// ABI aliases we find here (since we may not
|
|
|
|
|
// yet know it's an alias).
|
|
|
|
|
s := lookup(local, 0)
|
|
|
|
|
|
|
|
|
|
if l.SymType(s) == sym.SHOSTOBJ {
|
|
|
|
|
hostObjSyms[s] = struct{}{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ctxt.BuildMode {
|
|
|
|
|
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
|
|
|
|
|
if s == lookup("main", 0) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// export overrides import, for openbsd/cgo.
|
|
|
|
|
// see issue 4878.
|
|
|
|
|
if l.SymDynimplib(s) != "" {
|
|
|
|
|
l.SetSymDynimplib(s, "")
|
|
|
|
|
l.SetSymDynimpvers(s, "")
|
|
|
|
|
l.SetSymExtname(s, "")
|
|
|
|
|
var su *loader.SymbolBuilder
|
2020-02-12 17:23:47 -05:00
|
|
|
su = l.MakeSymbolUpdater(s)
|
2019-12-06 20:11:36 -05:00
|
|
|
su.SetType(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !(l.AttrCgoExportStatic(s) || l.AttrCgoExportDynamic(s)) {
|
|
|
|
|
l.SetSymExtname(s, remote)
|
|
|
|
|
} else if l.SymExtname(s) != remote {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], l.SymName(s), l.SymExtname(s), remote)
|
|
|
|
|
nerrors++
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if f[0] == "cgo_export_static" {
|
|
|
|
|
l.SetAttrCgoExportStatic(s, true)
|
|
|
|
|
} else {
|
|
|
|
|
l.SetAttrCgoExportDynamic(s, true)
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
case "cgo_dynamic_linker":
|
|
|
|
|
if len(f) != 2 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if *flagInterpreter == "" {
|
|
|
|
|
if interpreter != "" && interpreter != f[1] {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
|
|
|
|
|
nerrors++
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interpreter = f[1]
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
case "cgo_ldflag":
|
|
|
|
|
if len(f) != 2 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
ldflag = append(ldflag, f[1])
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f)
|
|
|
|
|
nerrors++
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-12 15:59:15 +12:00
|
|
|
var seenlib = make(map[string]bool)
|
2015-05-12 15:40:13 +12:00
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
func adddynlib(ctxt *Link, lib string) {
|
2017-10-05 10:20:17 -04:00
|
|
|
if seenlib[lib] || ctxt.LinkMode == LinkExternal {
|
2015-05-12 15:40:13 +12:00
|
|
|
return
|
|
|
|
|
}
|
2015-05-12 15:59:15 +12:00
|
|
|
seenlib[lib] = true
|
2015-05-12 15:40:13 +12:00
|
|
|
|
2017-10-07 13:43:38 -04:00
|
|
|
if ctxt.IsELF {
|
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
|
|
|
s := ctxt.Syms.Lookup(".dynstr", 0)
|
2015-05-12 15:40:13 +12:00
|
|
|
if s.Size == 0 {
|
2016-09-20 15:31:26 +12:00
|
|
|
Addstring(s, "")
|
2015-05-12 15:40:13 +12:00
|
|
|
}
|
2016-09-20 15:31:26 +12:00
|
|
|
Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
|
2015-05-12 15:40:13 +12:00
|
|
|
} else {
|
2016-09-17 09:39:33 -04:00
|
|
|
Errorf(nil, "adddynlib: unsupported binary format")
|
2015-05-12 15:40:13 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-04 17:54:04 -04:00
|
|
|
func Adddynsym(ctxt *Link, s *sym.Symbol) {
|
2017-10-05 10:20:17 -04:00
|
|
|
if s.Dynid >= 0 || ctxt.LinkMode == LinkExternal {
|
2015-05-12 15:59:15 +12:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-07 13:43:38 -04:00
|
|
|
if ctxt.IsELF {
|
2017-08-28 14:57:47 +09:00
|
|
|
elfadddynsym(ctxt, s)
|
2017-10-07 13:49:44 -04:00
|
|
|
} else if ctxt.HeadType == objabi.Hdarwin {
|
2018-07-17 11:02:57 -04:00
|
|
|
Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname())
|
2017-10-07 13:49:44 -04:00
|
|
|
} else if ctxt.HeadType == objabi.Hwindows {
|
2015-05-12 15:59:15 +12:00
|
|
|
// already taken care of
|
|
|
|
|
} else {
|
2016-09-17 09:39:33 -04:00
|
|
|
Errorf(s, "adddynsym: unsupported binary format")
|
2015-05-12 15:59:15 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cmd/link: prune unused methods
Today the linker keeps all methods of reachable types. This is
necessary if a program uses reflect.Value.Call. But while use of
reflection is widespread in Go for encoders and decoders, using
it to call a method is rare.
This CL looks for the use of reflect.Value.Call in a program, and
if it is absent, adopts a (reasonably conservative) method pruning
strategy as part of dead code elimination. Any method that is
directly called is kept, and any method that matches a used
interface's method signature is kept.
Whether or not a method body is kept is determined by the relocation
from its receiver's *rtype to its *rtype. A small change in the
compiler marks these relocations as R_METHOD so they can be easily
collected and manipulated by the linker.
As a bonus, this technique removes the text segment of methods that
have been inlined. Looking at the output of building cmd/objdump with
-ldflags=-v=2 shows that inlined methods like
runtime.(*traceAllocBlockPtr).ptr are removed from the program.
Relatively little work is necessary to do this. Linking two
examples, jujud and cmd/objdump show no more than +2% link time.
Binaries that do not use reflect.Call.Value drop 4 - 20% in size:
addr2line: -793KB (18%)
asm: -346KB (8%)
cgo: -490KB (10%)
compile: -564KB (4%)
dist: -736KB (17%)
fix: -404KB (12%)
link: -328KB (7%)
nm: -827KB (19%)
objdump: -712KB (16%)
pack: -327KB (14%)
yacc: -350KB (10%)
Binaries that do use reflect.Call.Value see a modest size decrease
of 2 - 6% thanks to pruning of unexported methods:
api: -151KB (3%)
cover: -222KB (4%)
doc: -106KB (2.5%)
pprof: -314KB (3%)
trace: -357KB (4%)
vet: -187KB (2.7%)
jujud: -4.4MB (5.8%)
cmd/go: -384KB (3.4%)
The trivial Hello example program goes from 2MB to 1.68MB:
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
}
Method pruning also helps when building small binaries with
"-ldflags=-s -w". The above program goes from 1.43MB to 1.2MB.
Unfortunately the linker can only tell if reflect.Value.Call has been
statically linked, not if it is dynamically used. And while use is
rare, it is linked into a very common standard library package,
text/template. The result is programs like cmd/go, which don't use
reflect.Value.Call, see limited benefit from this CL. If binary size
is important enough it may be possible to address this in future work.
For #6853.
Change-Id: Iabe90e210e813b08c3f8fd605f841f0458973396
Reviewed-on: https://go-review.googlesource.com/20483
Reviewed-by: Russ Cox <rsc@golang.org>
2016-03-07 23:45:04 -05:00
|
|
|
func fieldtrack(ctxt *Link) {
|
2015-02-27 22:57:28 -05:00
|
|
|
// record field tracking references
|
2015-03-03 22:20:16 -05:00
|
|
|
var buf bytes.Buffer
|
2016-09-20 14:59:39 +12:00
|
|
|
for _, s := range ctxt.Syms.Allsym {
|
2015-02-27 22:57:28 -05:00
|
|
|
if strings.HasPrefix(s.Name, "go.track.") {
|
2017-10-04 17:54:04 -04:00
|
|
|
s.Attr |= sym.AttrSpecial // do not lay out in data segment
|
|
|
|
|
s.Attr |= sym.AttrNotInSymbolTable
|
2016-03-02 07:59:49 -05:00
|
|
|
if s.Attr.Reachable() {
|
2015-03-03 22:20:16 -05:00
|
|
|
buf.WriteString(s.Name[9:])
|
2018-06-28 15:42:20 -04:00
|
|
|
for p := ctxt.Reachparent[s]; p != nil; p = ctxt.Reachparent[p] {
|
2015-03-03 22:20:16 -05:00
|
|
|
buf.WriteString("\t")
|
|
|
|
|
buf.WriteString(p.Name)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2015-03-03 22:20:16 -05:00
|
|
|
buf.WriteString("\n")
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2017-10-04 17:54:04 -04:00
|
|
|
s.Type = sym.SCONST
|
2015-02-27 22:57:28 -05:00
|
|
|
s.Value = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-21 18:34:24 -04:00
|
|
|
if *flagFieldTrack == "" {
|
2015-02-27 22:57:28 -05:00
|
|
|
return
|
|
|
|
|
}
|
2018-01-09 10:10:46 -05:00
|
|
|
s := ctxt.Syms.ROLookup(*flagFieldTrack, 0)
|
|
|
|
|
if s == nil || !s.Attr.Reachable() {
|
2015-02-27 22:57:28 -05:00
|
|
|
return
|
|
|
|
|
}
|
2017-10-04 17:54:04 -04:00
|
|
|
s.Type = sym.SDATA
|
2018-01-09 10:10:46 -05:00
|
|
|
addstrdata(ctxt, *flagFieldTrack, buf.String())
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
func (ctxt *Link) addexport() {
|
2019-09-29 16:59:56 -07:00
|
|
|
// Track undefined external symbols during external link.
|
|
|
|
|
if ctxt.LinkMode == LinkExternal {
|
|
|
|
|
for _, s := range ctxt.Syms.Allsym {
|
|
|
|
|
if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if s.Type != sym.STEXT {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
for i := range s.R {
|
|
|
|
|
r := &s.R[i]
|
|
|
|
|
if r.Sym != nil && r.Sym.Type == sym.Sxxx {
|
|
|
|
|
r.Sym.Type = sym.SUNDEFEXT
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:02:16 +02:00
|
|
|
// TODO(aix)
|
|
|
|
|
if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix {
|
2015-02-27 22:57:28 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-12 16:07:05 +12:00
|
|
|
for _, exp := range dynexp {
|
2016-08-19 22:40:38 -04:00
|
|
|
Adddynsym(ctxt, exp)
|
2015-05-12 16:07:05 +12:00
|
|
|
}
|
|
|
|
|
for _, lib := range dynlib {
|
2016-08-19 22:40:38 -04:00
|
|
|
adddynlib(ctxt, lib)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Pkg struct {
|
2015-03-05 17:45:11 -08:00
|
|
|
mark bool
|
|
|
|
|
checked bool
|
|
|
|
|
path string
|
2015-02-27 22:57:28 -05:00
|
|
|
impby []*Pkg
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-09 15:04:45 +10:00
|
|
|
var pkgall []*Pkg
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2015-03-05 17:45:11 -08:00
|
|
|
func (p *Pkg) cycle() *Pkg {
|
|
|
|
|
if p.checked {
|
2015-02-27 22:57:28 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-05 17:45:11 -08:00
|
|
|
if p.mark {
|
2015-02-27 22:57:28 -05:00
|
|
|
nerrors++
|
|
|
|
|
fmt.Printf("import cycle:\n")
|
2015-03-05 17:45:11 -08:00
|
|
|
fmt.Printf("\t%s\n", p.path)
|
2015-02-27 22:57:28 -05:00
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-05 17:45:11 -08:00
|
|
|
p.mark = true
|
|
|
|
|
for _, q := range p.impby {
|
|
|
|
|
if bad := q.cycle(); bad != nil {
|
|
|
|
|
p.mark = false
|
|
|
|
|
p.checked = true
|
|
|
|
|
fmt.Printf("\timports %s\n", p.path)
|
2015-02-27 22:57:28 -05:00
|
|
|
if bad == p {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return bad
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-05 17:45:11 -08:00
|
|
|
p.checked = true
|
|
|
|
|
p.mark = false
|
2015-02-27 22:57:28 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func importcycles() {
|
2015-03-05 17:45:11 -08:00
|
|
|
for _, p := range pkgall {
|
|
|
|
|
p.cycle()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|