// symbol in an executable, which is typical when internally
// linking PIE binaries.
TLSIEtoLE func(s *sym.Symbol, off, size int)
+
+ // optional override for assignAddress
+ AssignAddress func(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint64, isTramp bool) (*sym.Section, int, uint64)
}
var (
- Thearch Arch
+ thearch Arch
Lcsize int32
rpath Rpath
Spsize int32
Segdwarf sym.Segment
)
-/* whence for ldpkg */
-const (
- FileObj = 0 + iota
- ArchiveObj
- Pkgdef
-)
-
const pkgdef = "__.PKGDEF"
var (
}
func libinit(ctxt *Link) {
- Funcalign = Thearch.Funcalign
+ Funcalign = thearch.Funcalign
// add goroot to the end of the libdir list.
suffix := ""
return nil
}
- for i := 0; i < len(ctxt.Libdir); i++ {
+ for _, libdir := range ctxt.Libdir {
if ctxt.linkShared {
- shlibname := filepath.Join(ctxt.Libdir[i], name+".shlibname")
+ shlibname := filepath.Join(libdir, name+".shlibname")
if ctxt.Debugvlog != 0 {
ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
}
return addlibpath(ctxt, "internal", "internal", "", name, shlibname)
}
}
- pname := filepath.Join(ctxt.Libdir[i], name+".a")
+ pname := filepath.Join(libdir, name+".a")
if ctxt.Debugvlog != 0 {
ctxt.Logf("searching for %s.a in %s\n", name, pname)
}
toc.Type = sym.SDYNIMPORT
}
- if ctxt.LinkMode == LinkExternal && !iscgo && ctxt.LibraryByPkg["runtime/cgo"] == nil {
+ if ctxt.LinkMode == LinkExternal && !iscgo && ctxt.LibraryByPkg["runtime/cgo"] == nil && !(objabi.GOOS == "darwin" && (ctxt.Arch.Family == sys.AMD64 || ctxt.Arch.Family == sys.I386)) {
// This indicates a user requested -linkmode=external.
// The startup code uses an import of runtime/cgo to decide
// whether to initialize the TLS. So give it one. This could
// recording the value of GOARM.
if ctxt.Arch.Family == sys.ARM {
s := ctxt.Syms.Lookup("runtime.goarm", 0)
- s.Type = sym.SRODATA
+ s.Type = sym.SDATA
s.Size = 0
s.AddUint8(uint8(objabi.GOARM))
}
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
s := ctxt.Syms.Lookup("runtime.framepointer_enabled", 0)
- s.Type = sym.SRODATA
+ s.Type = sym.SDATA
s.Size = 0
s.AddUint8(1)
}
x = sym.AttrCgoExportStatic
}
w := 0
- for i := 0; i < len(dynexp); i++ {
+ for i := range dynexp {
if dynexp[i].Attr&x != 0 {
dynexp[w] = dynexp[i]
w++
}
// If package versioning is required, generate a hash of the
- // the packages used in the link.
+ // packages used in the link.
if ctxt.BuildMode == BuildModeShared || ctxt.BuildMode == BuildModePlugin || ctxt.CanUsePlugins() {
for _, lib := range ctxt.Library {
if lib.Shlib == "" {
Errorf(nil, "%s: short read on archive file symbol header", lib.File)
return
}
+ if arhdr.name != pkgdef {
+ Errorf(nil, "%s: missing package data entry", lib.File)
+ return
+ }
h := sha1.New()
if err != nil {
Exitf("cannot open file %s: %v", lib.File, err)
}
+ defer f.Close()
+ defer func() {
+ if pkg == "main" && !lib.Main {
+ Exitf("%s: not package main", lib.File)
+ }
+
+ // Ideally, we'd check that *all* object files within
+ // the archive were marked safe, but here we settle
+ // for *any*.
+ //
+ // Historically, cmd/link only checked the __.PKGDEF
+ // file, which in turn came from the first object
+ // file, typically produced by cmd/compile. The
+ // remaining object files are normally produced by
+ // cmd/asm, which doesn't support marking files as
+ // safe anyway. So at least in practice, this matches
+ // how safe mode has always worked.
+ if *flagU && !lib.Safe {
+ Exitf("%s: load of unsafe package %s", lib.File, pkg)
+ }
+ }()
for i := 0; i < len(ARMAG); i++ {
if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
/* load it as a regular file */
l := f.Seek(0, 2)
-
f.Seek(0, 0)
- ldobj(ctxt, f, lib, l, lib.File, lib.File, FileObj)
- f.Close()
-
+ ldobj(ctxt, f, lib, l, lib.File, lib.File)
return
}
- /* process __.PKGDEF */
- off := f.Offset()
-
- var arhdr ArHdr
- l := nextar(f, off, &arhdr)
- var pname string
- if l <= 0 {
- Errorf(nil, "%s: short read on archive file symbol header", lib.File)
- goto out
- }
-
- if !strings.HasPrefix(arhdr.name, pkgdef) {
- Errorf(nil, "%s: cannot find package header", lib.File)
- goto out
- }
-
- off += l
-
- ldpkg(ctxt, f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef)
-
/*
* load all the object files from the archive now.
* this gives us sequential file access and keeps us
* loading every object will also make it possible to
* load foreign objects not referenced by __.PKGDEF.
*/
+ var arhdr ArHdr
+ off := f.Offset()
for {
- l = nextar(f, off, &arhdr)
+ l := nextar(f, off, &arhdr)
if l == 0 {
break
}
if l < 0 {
Exitf("%s: malformed archive", lib.File)
}
-
off += l
- pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
+ // __.PKGDEF isn't a real Go object file, and it's
+ // absent in -linkobj builds anyway. Skipping it
+ // ensures consistency between -linkobj and normal
+ // build modes.
+ if arhdr.name == pkgdef {
+ continue
+ }
+
+ pname := fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
l = atolwhex(arhdr.size)
- ldobj(ctxt, f, lib, l, pname, lib.File, ArchiveObj)
+ ldobj(ctxt, f, lib, l, pname, lib.File)
}
-
-out:
- f.Close()
}
type Hostobj struct {
func ldhostobj(ld func(*Link, *bio.Reader, string, int64, string), headType objabi.HeadType, f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
isinternal := false
- for i := 0; i < len(internalpkg); i++ {
- if pkg == internalpkg[i] {
+ for _, intpkg := range internalpkg {
+ if pkg == intpkg {
isinternal = true
break
}
// does not work, the resulting programs will not run. See
// issue #17847. To avoid this problem pass -no-pie to the
// toolchain if it is supported.
- if ctxt.BuildMode == BuildModeExe {
+ if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared {
src := filepath.Join(*flagTmpdir, "trivial.c")
if err := ioutil.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
Errorf(nil, "WriteFile trivial.c failed: %v", err)
}
if !*FlagS && !*FlagW && !debug_s && ctxt.HeadType == objabi.Hdarwin {
- // Skip combining dwarf on arm.
- if !ctxt.Arch.InFamily(sys.ARM, sys.ARM64) {
- dsym := filepath.Join(*flagTmpdir, "go.dwarf")
- if out, err := exec.Command("dsymutil", "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
- Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
- }
- // Skip combining if `dsymutil` didn't generate a file. See #11994.
- if _, err := os.Stat(dsym); os.IsNotExist(err) {
- return
- }
- // For os.Rename to work reliably, must be in same directory as outfile.
- combinedOutput := *flagOutfile + "~"
- if err := machoCombineDwarf(*flagOutfile, dsym, combinedOutput, ctxt.BuildMode); err != nil {
- Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
- }
+ dsym := filepath.Join(*flagTmpdir, "go.dwarf")
+ if out, err := exec.Command("dsymutil", "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
+ Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
+ }
+ // Skip combining if `dsymutil` didn't generate a file. See #11994.
+ if _, err := os.Stat(dsym); os.IsNotExist(err) {
+ return
+ }
+ // For os.Rename to work reliably, must be in same directory as outfile.
+ combinedOutput := *flagOutfile + "~"
+ isIOS, err := machoCombineDwarf(*flagOutfile, dsym, combinedOutput, ctxt.BuildMode)
+ if err != nil {
+ Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
+ }
+ if !isIOS {
os.Remove(*flagOutfile)
if err := os.Rename(combinedOutput, *flagOutfile); err != nil {
Exitf("%s: %v", os.Args[0], err)
// ldobj loads an input object. If it is a host object (an object
// compiled by a non-Go compiler) it returns the Hostobj pointer. If
// it is a Go object, it returns nil.
-func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string, whence int) *Hostobj {
+func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
pkg := objabi.PathToPrefix(lib.Pkg)
eof := f.Offset() + length
import1 := f.Offset()
f.Seek(import0, 0)
- ldpkg(ctxt, f, pkg, import1-import0-2, pn, whence) // -2 for !\n
+ ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
f.Seek(import1, 0)
objfile.Load(ctxt.Arch, ctxt.Syms, f, lib, eof-f.Offset(), pn)
// should never be called directly.
// onlyctxt.Diagnose the direct caller.
// TODO(mwhudson): actually think about this.
+ // TODO(khr): disabled for now. Calls to external functions can only happen on the g0 stack.
+ // See the trampolines in src/runtime/sys_darwin_$ARCH.go.
if depth == 1 && s.Type != sym.SXREF && !ctxt.DynlinkingGo() &&
ctxt.BuildMode != BuildModeCArchive && ctxt.BuildMode != BuildModePIE && ctxt.BuildMode != BuildModeCShared && ctxt.BuildMode != BuildModePlugin {
-
- Errorf(s, "call to external function")
+ //Errorf(s, "call to external function")
}
return -1
}
func usage() {
fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
- objabi.Flagprint(2)
+ objabi.Flagprint(os.Stderr)
Exit(2)
}
-func doversion() {
- Exitf("version %s", objabi.Version)
-}
-
type SymbolType int8
const (
// see also http://9p.io/magic/man2html/1/nm
TextSym SymbolType = 'T'
- DataSym = 'D'
- BSSSym = 'B'
- UndefinedSym = 'U'
- TLSSym = 't'
- FrameSym = 'm'
- ParamSym = 'p'
- AutoSym = 'a'
+ DataSym SymbolType = 'D'
+ BSSSym SymbolType = 'B'
+ UndefinedSym SymbolType = 'U'
+ TLSSym SymbolType = 't'
+ FrameSym SymbolType = 'm'
+ ParamSym SymbolType = 'p'
+ AutoSym SymbolType = 'a'
// Deleted auto (not a real sym, just placeholder for type)
DeletedAutoSym = 'x'
type markKind uint8 // for postorder traversal
const (
- unvisited markKind = iota
+ _ markKind = iota
visiting
visited
)