Skip to content

Commit 66065c3

Browse files
committed
cmd/link: fix confusing error on unresolved symbol
Currently, if an assembly file includes a static reference to an undefined symbol, and another package also has an undefined reference to that symbol, the linker can report an error like: x: relocation target zero not defined for ABI0 (but is defined for ABI0) Since the symbol is referenced in another package, the code in ErrorUnresolved that looks for alternative ABI symbols finds that symbol in the symbol table, but doesn't check that it's actually defined, which is where the "but is defined for ABI0" comes from. The "not defined for ABI0" is because ErrorUnresolved failed to turn the static symbol's version back into an ABI, and it happened to print the zero value for an ABI. This CL fixes both of these problems. It explicitly maps the relocation version back to an ABI and detects if it can't be mapped back (e.g., because it's a static reference). Then, if it finds a symbol with a different ABI in the symbol table, it checks to make sure it's a definition, and not simply an unresolved reference. Fixes #29852. Change-Id: Ice45cc41c1907919ce5750f74588e8047eaa888c Reviewed-on: https://go-review.googlesource.com/c/159518 Run-TryBot: Austin Clements <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent c00595c commit 66065c3

File tree

3 files changed

+75
-9
lines changed

3 files changed

+75
-9
lines changed

src/cmd/link/internal/ld/link.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,16 @@ func (ctxt *Link) ErrorUnresolved(s *sym.Symbol, r *sym.Reloc) {
113113
// Try to find symbol under another ABI.
114114
var reqABI, haveABI obj.ABI
115115
haveABI = ^obj.ABI(0)
116-
for abi := obj.ABI(0); abi < obj.ABICount; abi++ {
117-
v := sym.ABIToVersion(abi)
118-
if v == -1 {
119-
continue
120-
}
121-
if v == int(r.Sym.Version) {
122-
reqABI = abi
123-
} else if ctxt.Syms.ROLookup(r.Sym.Name, v) != nil {
124-
haveABI = abi
116+
reqABI, ok := sym.VersionToABI(int(r.Sym.Version))
117+
if ok {
118+
for abi := obj.ABI(0); abi < obj.ABICount; abi++ {
119+
v := sym.ABIToVersion(abi)
120+
if v == -1 {
121+
continue
122+
}
123+
if rs := ctxt.Syms.ROLookup(r.Sym.Name, v); rs != nil && rs.Type != sym.Sxxx {
124+
haveABI = abi
125+
}
125126
}
126127
}
127128

src/cmd/link/internal/sym/symbol.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ func ABIToVersion(abi obj.ABI) int {
6868
return -1
6969
}
7070

71+
func VersionToABI(v int) (obj.ABI, bool) {
72+
switch v {
73+
case SymVerABI0:
74+
return obj.ABI0, true
75+
case SymVerABIInternal:
76+
return obj.ABIInternal, true
77+
}
78+
return ^obj.ABI(0), false
79+
}
80+
7181
func (s *Symbol) String() string {
7282
if s.Version == 0 {
7383
return s.Name

src/cmd/link/link_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"os/exec"
88
"path/filepath"
9+
"regexp"
910
"strings"
1011
"testing"
1112
)
@@ -116,3 +117,57 @@ func TestIssue28429(t *testing.T) {
116117
// to compile the extra section.
117118
runGo("tool", "link", "main.a")
118119
}
120+
121+
func TestUnresolved(t *testing.T) {
122+
testenv.MustHaveGoBuild(t)
123+
124+
tmpdir, err := ioutil.TempDir("", "unresolved-")
125+
if err != nil {
126+
t.Fatalf("failed to create temp dir: %v", err)
127+
}
128+
defer os.RemoveAll(tmpdir)
129+
130+
write := func(name, content string) {
131+
err := ioutil.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666)
132+
if err != nil {
133+
t.Fatal(err)
134+
}
135+
}
136+
137+
// Test various undefined references. Because of issue #29852,
138+
// this used to give confusing error messages because the
139+
// linker would find an undefined reference to "zero" created
140+
// by the runtime package.
141+
142+
write("main.go", `package main
143+
144+
func main() {
145+
x()
146+
}
147+
148+
func x()
149+
`)
150+
write("main.s", `
151+
TEXT ·x(SB),0,$0
152+
MOVD zero<>(SB), AX
153+
MOVD zero(SB), AX
154+
MOVD ·zero(SB), AX
155+
RET
156+
`)
157+
cmd := exec.Command(testenv.GoToolPath(t), "build")
158+
cmd.Dir = tmpdir
159+
cmd.Env = append(os.Environ(), []string{"GOARCH=amd64", "GOOS=linux"}...)
160+
out, err := cmd.CombinedOutput()
161+
if err == nil {
162+
t.Fatalf("expected build to fail, but it succeeded")
163+
}
164+
out = regexp.MustCompile("(?m)^#.*\n").ReplaceAll(out, nil)
165+
got := string(out)
166+
want := `main.x: relocation target zero not defined
167+
main.x: relocation target zero not defined
168+
main.x: relocation target main.zero not defined
169+
`
170+
if want != got {
171+
t.Fatalf("want:\n%sgot:\n%s", want, got)
172+
}
173+
}

0 commit comments

Comments
 (0)