diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 1b71a66c6f..efca824d98 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -699,12 +699,18 @@ func (l *Loader) checkdup(name string, r *oReader, li uint32, dup Sym) { p := r.Data(li) rdup, ldup := l.toLocal(dup) pdup := rdup.Data(ldup) - if bytes.Equal(p, pdup) { - return - } reason := "same length but different contents" if len(p) != len(pdup) { reason = fmt.Sprintf("new length %d != old length %d", len(p), len(pdup)) + } else if bytes.Equal(p, pdup) { + // For BSS symbols, we need to check size as well, see issue 46653. + szdup := l.SymSize(dup) + sz := int64(r.Sym(li).Siz()) + if szdup == sz { + return + } + reason = fmt.Sprintf("different sizes: new size %d != old size %d", + sz, szdup) } fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason) diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 4d6bc76aca..7230054bed 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -470,10 +470,30 @@ TEXT ·f(SB), NOSPLIT|DUPOK, $0-0 JMP 0(PC) ` +const testStrictDupAsmSrc3 = ` +#include "textflag.h" +GLOBL ·rcon(SB), RODATA|DUPOK, $64 +` + +const testStrictDupAsmSrc4 = ` +#include "textflag.h" +GLOBL ·rcon(SB), RODATA|DUPOK, $32 +` + func TestStrictDup(t *testing.T) { // Check that -strictdups flag works. testenv.MustHaveGoBuild(t) + asmfiles := []struct { + fname string + payload string + }{ + {"a", testStrictDupAsmSrc1}, + {"b", testStrictDupAsmSrc2}, + {"c", testStrictDupAsmSrc3}, + {"d", testStrictDupAsmSrc4}, + } + t.Parallel() tmpdir := t.TempDir() @@ -483,15 +503,12 @@ func TestStrictDup(t *testing.T) { if err != nil { t.Fatal(err) } - src = filepath.Join(tmpdir, "a.s") - err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc1), 0666) - if err != nil { - t.Fatal(err) - } - src = filepath.Join(tmpdir, "b.s") - err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc2), 0666) - if err != nil { - t.Fatal(err) + for _, af := range asmfiles { + src = filepath.Join(tmpdir, af.fname+".s") + err = ioutil.WriteFile(src, []byte(af.payload), 0666) + if err != nil { + t.Fatal(err) + } } src = filepath.Join(tmpdir, "go.mod") err = ioutil.WriteFile(src, []byte("module teststrictdup\n"), 0666) @@ -503,7 +520,7 @@ func TestStrictDup(t *testing.T) { cmd.Dir = tmpdir out, err := cmd.CombinedOutput() if err != nil { - t.Errorf("linking with -strictdups=1 failed: %v", err) + t.Errorf("linking with -strictdups=1 failed: %v\n%s", err, string(out)) } if !bytes.Contains(out, []byte("mismatched payload")) { t.Errorf("unexpected output:\n%s", out) @@ -515,7 +532,11 @@ func TestStrictDup(t *testing.T) { if err == nil { t.Errorf("linking with -strictdups=2 did not fail") } - if !bytes.Contains(out, []byte("mismatched payload")) { + // NB: on amd64 we get the 'new length' error, on arm64 the 'different + // contents' error. + if !(bytes.Contains(out, []byte("mismatched payload: new length")) || + bytes.Contains(out, []byte("mismatched payload: same length but different contents"))) || + !bytes.Contains(out, []byte("mismatched payload: different sizes")) { t.Errorf("unexpected output:\n%s", out) } }