aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-04-17 22:41:51 -0700
committerIan Lance Taylor <iant@golang.org>2019-04-18 15:46:21 +0000
commit01c8062308e2c8cf0fe7b1577318f2227771ebf5 (patch)
treeba77fcb7499d6f9884b8d5dca7ceb1e7f34a36ac
parent428e5f29a957b591d82e640b619b684aa25fba4e (diff)
downloadgo-01c8062308e2c8cf0fe7b1577318f2227771ebf5.tar.gz
go-01c8062308e2c8cf0fe7b1577318f2227771ebf5.zip
[release-branch.go1.11] cmd/link: don't fail if multiple ELF sections have the same name
New versions of clang can generate multiple sections named ".text" when using vague C++ linkage. This is valid ELF, but would cause the Go linker to report an error when using internal linking: symbol PACKAGEPATH(.text) listed multiple times Avoid the problem by renaming section symbol names if there is a name collision. Change-Id: I41127e95003d5b4554aaf849177b3fe000382c02 Reviewed-on: https://go-review.googlesource.com/c/go/+/172697 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com> (cherry picked from commit 3235f7c0720338a160debe6e9c632b8af968b4dd) Reviewed-on: https://go-review.googlesource.com/c/go/+/172702
-rw-r--r--src/cmd/link/elf_test.go112
-rw-r--r--src/cmd/link/internal/loadelf/ldelf.go8
2 files changed, 120 insertions, 0 deletions
diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go
new file mode 100644
index 0000000000..9eb8d1a14b
--- /dev/null
+++ b/src/cmd/link/elf_test.go
@@ -0,0 +1,112 @@
+// Copyright 2019 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.
+
+// +build dragonfly freebsd linux netbsd openbsd
+
+package main
+
+import (
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+var asmSource = `
+ .section .text1,"ax"
+s1:
+ .byte 0
+ .section .text2,"ax"
+s2:
+ .byte 0
+`
+
+var goSource = `
+package main
+func main() {}
+`
+
+// The linker used to crash if an ELF input file had multiple text sections
+// with the same name.
+func TestSectionsWithSameName(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ t.Parallel()
+
+ objcopy, err := exec.LookPath("objcopy")
+ if err != nil {
+ t.Skipf("can't find objcopy: %v", err)
+ }
+
+ dir, err := ioutil.TempDir("", "go-link-TestSectionsWithSameName")
+ 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)
+ }
+
+ asmFile := filepath.Join(dir, "x.s")
+ if err := ioutil.WriteFile(asmFile, []byte(asmSource), 0444); err != nil {
+ t.Fatal(err)
+ }
+
+ 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))
+
+ asmObj := filepath.Join(dir, "x.o")
+ t.Logf("%s %v -o %s %s", cc, cflags, asmObj, asmFile)
+ if out, err := exec.Command(cc, append(cflags, "-c", "-o", asmObj, asmFile)...).CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ asm2Obj := filepath.Join(dir, "x2.syso")
+ t.Logf("%s --rename-section .text2=.text1 %s %s", objcopy, asmObj, asm2Obj)
+ if out, err := exec.Command(objcopy, "--rename-section", ".text2=.text1", asmObj, asm2Obj).CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ for _, s := range []string{asmFile, asmObj} {
+ 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)
+ }
+
+ 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)
+ }
+}
diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go
index 8e32e7dee6..57d000a8bc 100644
--- a/src/cmd/link/internal/loadelf/ldelf.go
+++ b/src/cmd/link/internal/loadelf/ldelf.go
@@ -678,6 +678,8 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
// as well use one large chunk.
// create symbols for elfmapped sections
+ sectsymNames := make(map[string]bool)
+ counter := 0
for i := 0; uint(i) < elfobj.nsect; i++ {
sect = &elfobj.sect[i]
if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" {
@@ -709,6 +711,12 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
}
name := fmt.Sprintf("%s(%s)", pkg, sect.name)
+ for sectsymNames[name] {
+ counter++
+ name = fmt.Sprintf("%s(%s%d)", pkg, sect.name, counter)
+ }
+ sectsymNames[name] = true
+
s := syms.Lookup(name, localSymVersion)
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {