diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go index efe6dd0ad7..28f091010d 100644 --- a/src/cmd/link/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -11,7 +11,6 @@ import ( "cmd/internal/obj" "fmt" "os" - "strconv" "strings" ) @@ -22,37 +21,11 @@ func expandpkg(t0 string, pkg string) string { return strings.Replace(t0, `"".`, pkg+".", -1) } -// accumulate all type information from .6 files. -// check for inconsistencies. - // 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. -/* - * package import data - */ -type Import struct { - prefix string // "type", "var", "func", "const" - name string - def string - file string -} - -// importmap records type information about imported symbols to detect inconsistencies. -// Entries are keyed by qualified symbol name (e.g., "runtime.Callers" or "net/url.Error"). -var importmap = map[string]*Import{} - -func lookupImport(name string) *Import { - if x, ok := importmap[name]; ok { - return x - } - x := &Import{name: name} - importmap[name] = x - return x -} - func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) { var p0, p1 int @@ -68,6 +41,12 @@ func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) 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 int64(obj.Bread(f, bdata)) != length { fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) @@ -95,6 +74,9 @@ func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) // second marks end of exports / beginning of local data p1 = strings.Index(data[p0:], "\n$$\n") + if p1 < 0 && whence == Pkgdef { + p1 = len(data) - p0 + } if p1 < 0 { fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename) if Debug['u'] != 0 { @@ -141,8 +123,6 @@ func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) if pkg == "main" && name != "main" { Exitf("%s: not package main (package %s)", filename, name) } - - loadpkgdata(filename, pkg, data[p0:p1]) } // __.PKGDEF has no cgo section - those are in the C compiler-generated object files. @@ -181,195 +161,6 @@ func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) } } -func loadpkgdata(file string, pkg string, data string) { - var prefix string - var name string - var def string - - p := data - for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 { - x := lookupImport(name) - if x.prefix == "" { - x.prefix = prefix - x.def = def - x.file = file - } else if x.prefix != prefix { - fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name) - fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", x.file, x.prefix, name) - fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", file, prefix, name) - nerrors++ - } else if x.def != def { - fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name) - fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", x.file, x.prefix, name, x.def) - fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", file, prefix, name, def) - nerrors++ - } - } -} - -func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int { - // skip white space - p := *pp - -loop: - for len(p) > 0 && (p[0] == ' ' || p[0] == '\t' || p[0] == '\n') { - p = p[1:] - } - if len(p) == 0 || strings.HasPrefix(p, "$$\n") { - return 0 - } - - // prefix: (var|type|func|const) - prefix := p - - if len(p) < 7 { - return -1 - } - if strings.HasPrefix(p, "var ") { - p = p[4:] - } else if strings.HasPrefix(p, "type ") { - p = p[5:] - } else if strings.HasPrefix(p, "func ") { - p = p[5:] - } else if strings.HasPrefix(p, "const ") { - p = p[6:] - } else if strings.HasPrefix(p, "import ") { - p = p[7:] - for len(p) > 0 && p[0] != ' ' { - p = p[1:] - } - p = p[1:] - line := p - for len(p) > 0 && p[0] != '\n' { - p = p[1:] - } - if len(p) == 0 { - fmt.Fprintf(os.Stderr, "%s: %s: confused in import line\n", os.Args[0], file) - nerrors++ - return -1 - } - line = line[:len(line)-len(p)] - line = strings.TrimSuffix(line, " // indirect") - path, err := strconv.Unquote(line) - if err != nil { - fmt.Fprintf(os.Stderr, "%s: %s: confused in import path: %q\n", os.Args[0], file, line) - nerrors++ - return -1 - } - p = p[1:] - imported(pkg, path) - goto loop - } else { - fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix) - nerrors++ - return -1 - } - - prefix = prefix[:len(prefix)-len(p)-1] - - // name: a.b followed by space - name := p - - inquote := false - for len(p) > 0 { - if p[0] == ' ' && !inquote { - break - } - - if p[0] == '\\' { - p = p[1:] - } else if p[0] == '"' { - inquote = !inquote - } - - p = p[1:] - } - - if len(p) == 0 { - return -1 - } - name = name[:len(name)-len(p)] - p = p[1:] - - // def: free form to new line - def := p - - for len(p) > 0 && p[0] != '\n' { - p = p[1:] - } - if len(p) == 0 { - return -1 - } - def = def[:len(def)-len(p)] - var defbuf *bytes.Buffer - p = p[1:] - - // include methods on successive lines in def of named type - var meth string - for parsemethod(&p, &meth) > 0 { - if defbuf == nil { - defbuf = new(bytes.Buffer) - defbuf.WriteString(def) - } - defbuf.WriteString("\n\t") - defbuf.WriteString(meth) - } - if defbuf != nil { - def = defbuf.String() - } - - name = expandpkg(name, pkg) - def = expandpkg(def, pkg) - - // done - *pp = p - - *prefixp = prefix - *namep = name - *defp = def - return 1 -} - -func parsemethod(pp *string, methp *string) int { - // skip white space - p := *pp - - for len(p) > 0 && (p[0] == ' ' || p[0] == '\t') { - p = p[1:] - } - if len(p) == 0 { - return 0 - } - - // might be a comment about the method - if strings.HasPrefix(p, "//") { - goto useline - } - - // if it says "func (", it's a method - if strings.HasPrefix(p, "func (") { - goto useline - } - return 0 - - // definition to end of line -useline: - *methp = p - - for len(p) > 0 && p[0] != '\n' { - p = p[1:] - } - if len(p) == 0 { - fmt.Fprintf(os.Stderr, "%s: lost end of line in method definition\n", os.Args[0]) - *pp = "" - return -1 - } - - *methp = (*methp)[:len(*methp)-len(p)] - *pp = p[1:] - return 1 -} - func loadcgo(file string, pkg string, p string) { var next string var q string diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index acbb2ac883..5bb206afa8 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -809,9 +809,7 @@ func objfile(lib *Library) { off += l - if Debug['u'] != 0 { - ldpkg(f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef) - } + ldpkg(f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef) /* * load all the object files from the archive now. diff --git a/test/linkmain.go b/test/linkmain.go new file mode 100644 index 0000000000..dcfbf50320 --- /dev/null +++ b/test/linkmain.go @@ -0,0 +1,12 @@ +// +build ignore + +// Copyright 2015 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. + +// For linkmain_run.go. + +package notmain + +func main() { +} diff --git a/test/linkmain_run.go b/test/linkmain_run.go new file mode 100644 index 0000000000..a5d2c79b26 --- /dev/null +++ b/test/linkmain_run.go @@ -0,0 +1,65 @@ +// +build !nacl +// run + +// Copyright 2014 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. + +// Run the sinit test. + +package main + +import ( + "fmt" + "os" + "os/exec" + "strings" +) + +func cleanup() { + os.Remove("linkmain.o") + os.Remove("linkmain.a") + os.Remove("linkmain1.o") + os.Remove("linkmain1.a") + os.Remove("linkmain.exe") +} + +func run(cmdline string) { + args := strings.Fields(cmdline) + cmd := exec.Command(args[0], args[1:]...) + out, err := cmd.CombinedOutput() + if err != nil { + fmt.Printf("$ %s\n", strings.Join(args, " ")) + fmt.Println(string(out)) + fmt.Println(err) + cleanup() + os.Exit(1) + } +} + +func runFail(args ...string) { + cmd := exec.Command(args[0], args[1:]...) + out, err := cmd.CombinedOutput() + if err == nil { + fmt.Printf("$ %s\n", strings.Join(args, " ")) + fmt.Println(string(out)) + fmt.Println("SHOULD HAVE FAILED!") + cleanup() + os.Exit(1) + } +} + +func main() { + // helloworld.go is package main + run("go tool compile -o linkmain.o helloworld.go") + run("go tool compile -pack -o linkmain.a helloworld.go") + run("go tool link -o linkmain.exe linkmain.o") + run("go tool link -o linkmain.exe linkmain.a") + + // linkmain.go is not + run("go tool compile -o linkmain.o linkmain.go") + run("go tool compile -pack -o linkmain.a linkmain.go") + runFail("go tool link -o linkmain.exe linkmain1.o") + runFail("go tool link -o linkmain.exe linkmain1.a") + cleanup() +}