From dab05a04842e75126fdf880368c2e721485f8a09 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Tue, 8 Oct 2019 15:35:36 -0400 Subject: [PATCH] [dev.link] cmd/link: implement symbol overwrite logic If two defined symbols have the same name, one contentless and one with content, the one with content "wins". This is mainly for go:linkname on data symbols. Support this logic in newobj mode. Introduce an "overwrite" mechanism, letting one symbol overwrite another. This machanism could later be used for the linker overwriting symbol contents (e.g. -X flag). Change-Id: I32ee7d4b82df275f11b38c3abefc99b878ff12d7 Reviewed-on: https://go-review.googlesource.com/c/go/+/200097 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Than McIntosh --- src/cmd/link/internal/objfile/objfile2.go | 39 +++++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/cmd/link/internal/objfile/objfile2.go b/src/cmd/link/internal/objfile/objfile2.go index c48cf960748..b37a665f43b 100644 --- a/src/cmd/link/internal/objfile/objfile2.go +++ b/src/cmd/link/internal/objfile/objfile2.go @@ -97,6 +97,7 @@ type Loader struct { extSyms []nameVer // externally defined symbols symsByName map[nameVer]Sym // map symbol name to index + overwrite map[Sym]Sym // overwrite[i]=j if symbol j overwrites symbol i objByPkg map[string]*oReader // map package path to its Go object reader @@ -111,6 +112,7 @@ func NewLoader() *Loader { objs: []objIdx{{nil, 0}}, symsByName: make(map[nameVer]Sym), objByPkg: make(map[string]*oReader), + overwrite: make(map[Sym]Sym), } } @@ -137,16 +139,34 @@ func (l *Loader) AddObj(pkg string, r *oReader) Sym { } // Add a symbol with a given index, return if it is added. -func (l *Loader) AddSym(name string, ver int, i Sym, dupok bool) bool { +func (l *Loader) AddSym(name string, ver int, i Sym, r *oReader, dupok bool, typ sym.SymKind) bool { if l.extStart != 0 { panic("AddSym called after AddExtSym is called") } nv := nameVer{name, ver} - if _, ok := l.symsByName[nv]; ok { - if dupok || true { // TODO: "true" isn't quite right. need to implement "overwrite" logic. + if oldi, ok := l.symsByName[nv]; ok { + if dupok { + return false + } + overwrite := r.DataSize(int(i-l.StartIndex(r))) != 0 + if overwrite { + // new symbol overwrites old symbol. + oldr, li := l.ToLocal(oldi) + oldsym := goobj2.Sym{} + oldsym.Read(oldr.Reader, oldr.SymOff(li)) + oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type)] + if oldsym.Flag&goobj2.SymFlagDupok == 0 && !((oldtyp == sym.SDATA || oldtyp == sym.SNOPTRDATA || oldtyp == sym.SBSS || oldtyp == sym.SNOPTRBSS) && oldr.DataSize(li) == 0) { // only allow overwriting 0-sized data symbol + log.Fatalf("duplicated definition of symbol " + name) + } + l.overwrite[oldi] = i + } else { + // old symbol overwrites new symbol. + if typ != sym.SDATA && typ != sym.SNOPTRDATA && typ != sym.SBSS && typ != sym.SNOPTRBSS { // only allow overwriting data symbol + log.Fatalf("duplicated definition of symbol " + name) + } + l.overwrite[i] = oldi return false } - panic("duplicated definition of symbol " + name) } l.symsByName[nv] = i return true @@ -171,11 +191,18 @@ func (l *Loader) AddExtSym(name string, ver int) Sym { // Convert a local index to a global index. func (l *Loader) ToGlobal(r *oReader, i int) Sym { - return l.StartIndex(r) + Sym(i) + g := l.StartIndex(r) + Sym(i) + if ov, ok := l.overwrite[g]; ok { + return ov + } + return g } // Convert a global index to a local index. func (l *Loader) ToLocal(i Sym) (*oReader, int) { + if ov, ok := l.overwrite[i]; ok { + i = ov + } if l.extStart != 0 && i >= l.extStart { return nil, int(i - l.extStart) } @@ -389,7 +416,7 @@ func LoadNew(l *Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *s } v := abiToVer(osym.ABI, localSymVersion) dupok := osym.Flag&goobj2.SymFlagDupok != 0 - l.AddSym(name, v, istart+Sym(i), dupok) + l.AddSym(name, v, istart+Sym(i), or, dupok, sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]) } // The caller expects us consuming all the data