mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.link] cmd/link: restore -strictdups flag in newobj mode
Change-Id: I93ad769595fa343400afa342af12e1445abff084 Reviewed-on: https://go-review.googlesource.com/c/go/+/204918 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
ab4a71fca7
commit
db75205a9b
3 changed files with 147 additions and 14 deletions
|
|
@ -378,7 +378,16 @@ func (ctxt *Link) findLibPath(libname string) string {
|
||||||
|
|
||||||
func (ctxt *Link) loadlib() {
|
func (ctxt *Link) loadlib() {
|
||||||
if *flagNewobj {
|
if *flagNewobj {
|
||||||
ctxt.loader = loader.NewLoader()
|
var flags uint32
|
||||||
|
switch *FlagStrictDups {
|
||||||
|
case 0:
|
||||||
|
// nothing to do
|
||||||
|
case 1, 2:
|
||||||
|
flags = loader.FlagStrictDups
|
||||||
|
default:
|
||||||
|
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
|
||||||
|
}
|
||||||
|
ctxt.loader = loader.NewLoader(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxt.cgo_export_static = make(map[string]bool)
|
ctxt.cgo_export_static = make(map[string]bool)
|
||||||
|
|
@ -550,6 +559,10 @@ func (ctxt *Link) loadlib() {
|
||||||
ctxt.Loaded = true
|
ctxt.Loaded = true
|
||||||
|
|
||||||
importcycles()
|
importcycles()
|
||||||
|
|
||||||
|
if *flagNewobj {
|
||||||
|
strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up dynexp list.
|
// Set up dynexp list.
|
||||||
|
|
|
||||||
|
|
@ -119,9 +119,18 @@ type Loader struct {
|
||||||
Reachparent []Sym
|
Reachparent []Sym
|
||||||
|
|
||||||
relocBatch []sym.Reloc // for bulk allocation of relocations
|
relocBatch []sym.Reloc // for bulk allocation of relocations
|
||||||
|
|
||||||
|
flags uint32
|
||||||
|
|
||||||
|
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLoader() *Loader {
|
const (
|
||||||
|
// Loader.flags
|
||||||
|
FlagStrictDups = 1 << iota
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewLoader(flags uint32) *Loader {
|
||||||
nbuiltin := goobj2.NBuiltin()
|
nbuiltin := goobj2.NBuiltin()
|
||||||
return &Loader{
|
return &Loader{
|
||||||
start: make(map[*oReader]Sym),
|
start: make(map[*oReader]Sym),
|
||||||
|
|
@ -132,6 +141,7 @@ func NewLoader() *Loader {
|
||||||
itablink: make(map[Sym]struct{}),
|
itablink: make(map[Sym]struct{}),
|
||||||
extStaticSyms: make(map[nameVer]Sym),
|
extStaticSyms: make(map[nameVer]Sym),
|
||||||
builtinSyms: make([]Sym, nbuiltin),
|
builtinSyms: make([]Sym, nbuiltin),
|
||||||
|
flags: flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,6 +180,9 @@ func (l *Loader) AddSym(name string, ver int, i Sym, r *oReader, dupok bool, typ
|
||||||
}
|
}
|
||||||
if oldi, ok := l.symsByName[ver][name]; ok {
|
if oldi, ok := l.symsByName[ver][name]; ok {
|
||||||
if dupok {
|
if dupok {
|
||||||
|
if l.flags&FlagStrictDups != 0 {
|
||||||
|
l.checkdup(name, i, r, oldi)
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
oldr, li := l.toLocal(oldi)
|
oldr, li := l.toLocal(oldi)
|
||||||
|
|
@ -366,6 +379,42 @@ func (l *Loader) IsDup(i Sym) bool {
|
||||||
return l.symsByName[ver][name] != i
|
return l.symsByName[ver][name] != i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that duplicate symbols have same contents.
|
||||||
|
func (l *Loader) checkdup(name string, i Sym, r *oReader, dup Sym) {
|
||||||
|
li := int(i - l.startIndex(r))
|
||||||
|
p := r.Data(li)
|
||||||
|
if strings.HasPrefix(name, "go.info.") {
|
||||||
|
p, _ = patchDWARFName1(p, r)
|
||||||
|
}
|
||||||
|
rdup, ldup := l.toLocal(dup)
|
||||||
|
pdup := rdup.Data(ldup)
|
||||||
|
if strings.HasPrefix(name, "go.info.") {
|
||||||
|
pdup, _ = patchDWARFName1(pdup, rdup)
|
||||||
|
}
|
||||||
|
if bytes.Equal(p, pdup) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reason := "same length but different contents"
|
||||||
|
if len(p) != len(pdup) {
|
||||||
|
reason = fmt.Sprintf("new length %d != old length %d", len(p), len(pdup))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason)
|
||||||
|
|
||||||
|
// For the moment, whitelist DWARF subprogram DIEs for
|
||||||
|
// auto-generated wrapper functions. What seems to happen
|
||||||
|
// here is that we get different line numbers on formal
|
||||||
|
// params; I am guessing that the pos is being inherited
|
||||||
|
// from the spot where the wrapper is needed.
|
||||||
|
whitelist := strings.HasPrefix(name, "go.info.go.interface") ||
|
||||||
|
strings.HasPrefix(name, "go.info.go.builtin") ||
|
||||||
|
strings.HasPrefix(name, "go.debuglines")
|
||||||
|
if !whitelist {
|
||||||
|
l.strictDupMsgs++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Loader) NStrictDupMsgs() int { return l.strictDupMsgs }
|
||||||
|
|
||||||
// Number of total symbols.
|
// Number of total symbols.
|
||||||
func (l *Loader) NSym() int {
|
func (l *Loader) NSym() int {
|
||||||
return int(l.max + 1)
|
return int(l.max + 1)
|
||||||
|
|
@ -1194,24 +1243,30 @@ func loadObjFull(l *Loader, r *oReader) {
|
||||||
|
|
||||||
var emptyPkg = []byte(`"".`)
|
var emptyPkg = []byte(`"".`)
|
||||||
|
|
||||||
func patchDWARFName(s *sym.Symbol, r *oReader) {
|
func patchDWARFName1(p []byte, r *oReader) ([]byte, int) {
|
||||||
// This is kind of ugly. Really the package name should not
|
// This is kind of ugly. Really the package name should not
|
||||||
// even be included here.
|
// even be included here.
|
||||||
if s.Size < 1 || s.P[0] != dwarf.DW_ABRV_FUNCTION {
|
if len(p) < 1 || p[0] != dwarf.DW_ABRV_FUNCTION {
|
||||||
return
|
return p, -1
|
||||||
}
|
}
|
||||||
e := bytes.IndexByte(s.P, 0)
|
e := bytes.IndexByte(p, 0)
|
||||||
|
if e == -1 {
|
||||||
|
return p, -1
|
||||||
|
}
|
||||||
|
if !bytes.Contains(p[:e], emptyPkg) {
|
||||||
|
return p, -1
|
||||||
|
}
|
||||||
|
pkgprefix := []byte(r.pkgprefix)
|
||||||
|
patched := bytes.Replace(p[:e], emptyPkg, pkgprefix, -1)
|
||||||
|
return append(patched, p[e:]...), e
|
||||||
|
}
|
||||||
|
|
||||||
|
func patchDWARFName(s *sym.Symbol, r *oReader) {
|
||||||
|
patched, e := patchDWARFName1(s.P, r)
|
||||||
if e == -1 {
|
if e == -1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p := bytes.Index(s.P[:e], emptyPkg)
|
s.P = patched
|
||||||
if p == -1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pkgprefix := []byte(r.pkgprefix)
|
|
||||||
patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
|
|
||||||
|
|
||||||
s.P = append(patched, s.P[e:]...)
|
|
||||||
s.Attr.Set(sym.AttrReadOnly, false)
|
s.Attr.Set(sym.AttrReadOnly, false)
|
||||||
delta := int64(len(s.P)) - s.Size
|
delta := int64(len(s.P)) - s.Size
|
||||||
s.Size = int64(len(s.P))
|
s.Size = int64(len(s.P))
|
||||||
|
|
|
||||||
|
|
@ -376,3 +376,68 @@ func TestIssue34788Android386TLSSequence(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const testStrictDupGoSrc = `
|
||||||
|
package main
|
||||||
|
func f()
|
||||||
|
func main() { f() }
|
||||||
|
`
|
||||||
|
|
||||||
|
const testStrictDupAsmSrc1 = `
|
||||||
|
#include "textflag.h"
|
||||||
|
TEXT ·f(SB), NOSPLIT|DUPOK, $0-0
|
||||||
|
RET
|
||||||
|
`
|
||||||
|
|
||||||
|
const testStrictDupAsmSrc2 = `
|
||||||
|
#include "textflag.h"
|
||||||
|
TEXT ·f(SB), NOSPLIT|DUPOK, $0-0
|
||||||
|
JMP 0(PC)
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestStrictDup(t *testing.T) {
|
||||||
|
// Check that -strictdups flag works.
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
|
||||||
|
tmpdir, err := ioutil.TempDir("", "TestStrictDup")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpdir)
|
||||||
|
|
||||||
|
src := filepath.Join(tmpdir, "x.go")
|
||||||
|
err = ioutil.WriteFile(src, []byte(testStrictDupGoSrc), 0666)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
src = filepath.Join(tmpdir, "a.s")
|
||||||
|
err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc1), 0666)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
src = filepath.Join(tmpdir, "b.s")
|
||||||
|
err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc2), 0666)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-strictdups=1")
|
||||||
|
cmd.Dir = tmpdir
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("linking with -strictdups=1 failed: %v", err)
|
||||||
|
}
|
||||||
|
if !bytes.Contains(out, []byte("mismatched payload")) {
|
||||||
|
t.Errorf("unexpected output:\n%s", out)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-strictdups=2")
|
||||||
|
cmd.Dir = tmpdir
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("linking with -strictdups=2 did not fail")
|
||||||
|
}
|
||||||
|
if !bytes.Contains(out, []byte("mismatched payload")) {
|
||||||
|
t.Errorf("unexpected output:\n%s", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue