]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.11] cmd/link: don't fail if multiple ELF sections have the same...
authorIan Lance Taylor <iant@golang.org>
Thu, 18 Apr 2019 05:41:51 +0000 (22:41 -0700)
committerIan Lance Taylor <iant@golang.org>
Thu, 18 Apr 2019 15:46:21 +0000 (15:46 +0000)
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

src/cmd/link/elf_test.go [new file with mode: 0644]
src/cmd/link/internal/loadelf/ldelf.go

diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go
new file mode 100644 (file)
index 0000000..9eb8d1a
--- /dev/null
@@ -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)
+       }
+}
index 8e32e7dee61906119f51c74e9b3bcc265a96ee77..57d000a8bc3f92b20572221137880f63316de4a0 100644 (file)
@@ -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) {