// once the dust settles, try to move some code to
// libmach, so that other linkers and ar can share.
-func ldpkg(ctxt *Link, f *bio.Reader, pkg string, length int64, filename string, whence int) {
+func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) {
if *flagG {
return
}
return
}
- // In a __.PKGDEF, we only care about the package name.
- // Don't read all the export data.
- if length > 1000 && whence == Pkgdef {
- length = 1000
- }
-
bdata := make([]byte, length)
if _, err := io.ReadFull(f, bdata); err != nil {
fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
data := string(bdata)
// process header lines
- isSafe := false
- isMain := false
for data != "" {
var line string
if i := strings.Index(data, "\n"); i >= 0 {
line, data = data, ""
}
if line == "safe" {
- isSafe = true
+ lib.Safe = true
}
if line == "main" {
- isMain = true
+ lib.Main = true
}
if line == "" {
break
}
}
- if whence == Pkgdef || whence == FileObj {
- if pkg == "main" && !isMain {
- Exitf("%s: not package main", filename)
- }
- if *flagU && whence != ArchiveObj && !isSafe {
- Exitf("load of unsafe package %s", filename)
- }
- }
-
- // __.PKGDEF has no cgo section - those are in the C compiler-generated object files.
- if whence == Pkgdef {
- return
- }
-
// look for cgo section
p0 := strings.Index(data, "\n$$ // cgo")
var p1 int
}
p1 += p0
- loadcgo(ctxt, filename, pkg, data[p0:p1])
+ loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
}
}
Segdwarf sym.Segment
)
-/* whence for ldpkg */
-const (
- FileObj = 0 + iota
- ArchiveObj
- Pkgdef
-)
-
const pkgdef = "__.PKGDEF"
var (
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 {
// 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)