1
0
mirror of https://github.com/golang/go synced 2024-11-17 13:54:46 -07:00

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>
This commit is contained in:
Ian Lance Taylor 2019-04-17 22:41:51 -07:00
parent c226f6432d
commit 3235f7c072
2 changed files with 120 additions and 0 deletions

112
src/cmd/link/elf_test.go Normal file
View File

@ -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)
}
}

View 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) {