// resolve relocations in s.
func relocsym(ctxt *Link, s *sym.Symbol) {
+ // undefinedSyms contains all undefined symbol names.
+ // For successfull builds, it remains nil and does not cause any overhead.
+ var undefinedSyms []string
+
for ri := int32(0); ri < int32(len(s.R)); ri++ {
r := &s.R[ri]
if r.Done {
continue
}
- if r.Sym != nil && ((r.Sym.Type == 0 && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) {
+ if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) {
// When putting the runtime but not main into a shared library
// these symbols are undefined and that's OK.
if ctxt.BuildMode == BuildModeShared {
continue
}
} else {
- Errorf(s, "relocation target %s not defined", r.Sym.Name)
+ reported := false
+ for _, name := range undefinedSyms {
+ if name == r.Sym.Name {
+ reported = true
+ break
+ }
+ }
+ if !reported {
+ // Give a special error message for main symbol (see #24809).
+ if r.Sym.Name == "main.main" {
+ Errorf(s, "function main is undeclared in the main package")
+ } else {
+ Errorf(s, "relocation target %s not defined", r.Sym.Name)
+ }
+ undefinedSyms = append(undefinedSyms, r.Sym.Name)
+ }
continue
}
}
--- /dev/null
+// Copyright 2018 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.
+
+package ld
+
+import (
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+func TestUndefinedRelocErrors(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ out, err := exec.Command(testenv.GoToolPath(t), "build", "./testdata/issue10978").CombinedOutput()
+ if err == nil {
+ t.Fatal("expected build to fail")
+ }
+
+ wantErrors := map[string]int{
+ // Main function has dedicated error message.
+ "function main is undeclared in the main package": 1,
+
+ // Single error reporting per each symbol.
+ // This way, duplicated messages are not reported for
+ // multiple relocations with a same name.
+ "main.defined1: relocation target main.undefined not defined": 1,
+ "main.defined2: relocation target main.undefined not defined": 1,
+ }
+ unexpectedErrors := map[string]int{}
+
+ for _, l := range strings.Split(string(out), "\n") {
+ if strings.HasPrefix(l, "#") || l == "" {
+ continue
+ }
+ matched := ""
+ for want := range wantErrors {
+ if strings.Contains(l, want) {
+ matched = want
+ break
+ }
+ }
+ if matched != "" {
+ wantErrors[matched]--
+ } else {
+ unexpectedErrors[l]++
+ }
+ }
+
+ for want, n := range wantErrors {
+ switch {
+ case n > 0:
+ t.Errorf("unmatched error: %s (x%d)", want, n)
+ case n < 0:
+ t.Errorf("extra errors: %s (x%d)", want, -n)
+ }
+ }
+ for unexpected, n := range unexpectedErrors {
+ t.Errorf("unexpected error: %s (x%d)", unexpected, n)
+ }
+}
}
func (ctxt *Link) undef() {
+ // undefsym performs checks (almost) identical to checks
+ // that report undefined relocations in relocsym.
+ // Both undefsym and relocsym can report same symbol as undefined,
+ // which results in error message duplication (see #10978).
+ //
+ // The undef is run after Arch.Asmb and could detect some
+ // programming errors there, but if object being linked is already
+ // failed with errors, it is better to avoid duplicated errors.
+ if nerrors > 0 {
+ return
+ }
+
for _, s := range ctxt.Textp {
undefsym(ctxt, s)
}
--- /dev/null
+// Copyright 2018 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.
+
+package main
+
+func undefined()
+
+func defined1() int {
+ // To check multiple errors for a single symbol,
+ // reference undefined more than once.
+ undefined()
+ undefined()
+ return 0
+}
+
+func defined2() {
+ undefined()
+ undefined()
+}
+
+func init() {
+ _ = defined1()
+ defined2()
+}
+
+// The "main" function remains undeclared.
--- /dev/null
+// This file is needed to make "go build" work for package with external functions.\r