]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: add new linker testpoint for "ld -r" host object
authorThan McIntosh <thanm@google.com>
Fri, 22 Nov 2019 19:31:13 +0000 (14:31 -0500)
committerThan McIntosh <thanm@google.com>
Sat, 23 Nov 2019 00:06:55 +0000 (00:06 +0000)
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 <cherryyz@google.com>
src/cmd/link/elf_test.go

index 3df9869284b85f1f0a230484eebd8e51293c82e1..84f373af8ffc51b98dd860d5db119daabb796673 100644 (file)
@@ -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)