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