From 688aa748579f07552a50d2534eccb16afda4174b Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 22 Nov 2019 14:31:13 -0500 Subject: [PATCH] cmd/link: add new linker testpoint for "ld -r" host object This adds a new test that builds a small Go program with linked against a *.syso file that is the result of an "ld -r" link. The sysobj in question has multiple static symbols in the same section with the same name, which triggered a bug in the loader in -newobj mode. Updates #35779. Change-Id: Ibe1a75662dc1d49c4347279e55646ee65a81508e Reviewed-on: https://go-review.googlesource.com/c/go/+/208478 Reviewed-by: Cherry Zhang --- src/cmd/link/elf_test.go | 124 ++++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 16 deletions(-) diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go index 3df9869284b..84f373af8ff 100644 --- a/src/cmd/link/elf_test.go +++ b/src/cmd/link/elf_test.go @@ -7,6 +7,7 @@ package main import ( + "fmt" "internal/testenv" "io/ioutil" "os" @@ -16,6 +17,27 @@ import ( "testing" ) +func getCCAndCCFLAGS(t *testing.T, env []string) (string, []string) { + goTool := testenv.GoToolPath(t) + cmd := exec.Command(goTool, "env", "CC") + cmd.Env = env + ccb, err := cmd.Output() + if err != nil { + t.Fatal(err) + } + cc := strings.TrimSpace(string(ccb)) + + cmd = exec.Command(goTool, "env", "GOGCCFLAGS") + cmd.Env = env + cflagsb, err := cmd.Output() + if err != nil { + t.Fatal(err) + } + cflags := strings.Fields(string(cflagsb)) + + return cc, cflags +} + var asmSource = ` .section .text1,"ax" s1: @@ -61,21 +83,7 @@ func TestSectionsWithSameName(t *testing.T) { } goTool := testenv.GoToolPath(t) - cmd := exec.Command(goTool, "env", "CC") - cmd.Env = env - ccb, err := cmd.Output() - if err != nil { - t.Fatal(err) - } - cc := strings.TrimSpace(string(ccb)) - - cmd = exec.Command(goTool, "env", "GOGCCFLAGS") - cmd.Env = env - cflagsb, err := cmd.Output() - if err != nil { - t.Fatal(err) - } - cflags := strings.Fields(string(cflagsb)) + cc, cflags := getCCAndCCFLAGS(t, env) asmObj := filepath.Join(dir, "x.o") t.Logf("%s %v -c -o %s %s", cc, cflags, asmObj, asmFile) @@ -102,7 +110,91 @@ func TestSectionsWithSameName(t *testing.T) { t.Fatal(err) } - cmd = exec.Command(goTool, "build") + cmd := exec.Command(goTool, "build") + cmd.Dir = dir + cmd.Env = env + t.Logf("%s build", goTool) + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } +} + +var cSources35779 = []string{` +static int blah() { return 42; } +int Cfunc1() { return blah(); } +`, ` +static int blah() { return 42; } +int Cfunc2() { return blah(); } +`, +} + +// TestMinusRSymsWithSameName tests a corner case in the new +// loader. Prior to the fix this failed with the error 'loadelf: +// $WORK/b001/_pkg_.a(ldr.syso): duplicate symbol reference: blah in +// both main(.text) and main(.text)' +func TestMinusRSymsWithSameName(t *testing.T) { + testenv.MustHaveGoBuild(t) + testenv.MustHaveCGO(t) + t.Parallel() + + dir, err := ioutil.TempDir("", "go-link-TestMinusRSymsWithSameName") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + gopath := filepath.Join(dir, "GOPATH") + env := append(os.Environ(), "GOPATH="+gopath) + + if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module elf_test\n"), 0666); err != nil { + t.Fatal(err) + } + + goTool := testenv.GoToolPath(t) + cc, cflags := getCCAndCCFLAGS(t, env) + + objs := []string{} + csrcs := []string{} + for i, content := range cSources35779 { + csrcFile := filepath.Join(dir, fmt.Sprintf("x%d.c", i)) + csrcs = append(csrcs, csrcFile) + if err := ioutil.WriteFile(csrcFile, []byte(content), 0444); err != nil { + t.Fatal(err) + } + + obj := filepath.Join(dir, fmt.Sprintf("x%d.o", i)) + objs = append(objs, obj) + t.Logf("%s %v -c -o %s %s", cc, cflags, obj, csrcFile) + if out, err := exec.Command(cc, append(cflags, "-c", "-o", obj, csrcFile)...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + } + + sysoObj := filepath.Join(dir, "ldr.syso") + t.Logf("%s %v -nostdlib -r -o %s %v", cc, cflags, sysoObj, objs) + if out, err := exec.Command(cc, append(cflags, "-nostdlib", "-r", "-o", sysoObj, objs[0], objs[1])...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + cruft := [][]string{objs, csrcs} + for _, sl := range cruft { + for _, s := range sl { + if err := os.Remove(s); err != nil { + t.Fatal(err) + } + } + } + + goFile := filepath.Join(dir, "main.go") + if err := ioutil.WriteFile(goFile, []byte(goSource), 0444); err != nil { + t.Fatal(err) + } + + t.Logf("%s build", goTool) + cmd := exec.Command(goTool, "build") cmd.Dir = dir cmd.Env = env t.Logf("%s build", goTool)