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:
parent
c226f6432d
commit
3235f7c072
112
src/cmd/link/elf_test.go
Normal file
112
src/cmd/link/elf_test.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user