diff options
| author | Than McIntosh <thanm@google.com> | 2022-02-03 08:11:53 -0500 |
|---|---|---|
| committer | Than McIntosh <thanm@google.com> | 2022-03-31 12:55:38 +0000 |
| commit | 821420d6bbc53d4cd8b3f9a903fccd0c6432eb6f (patch) | |
| tree | 811ba517ed3a51c7b540e5bdc230e9d5eb47c3a8 /src/cmd/link | |
| parent | 0a5bbba366de5bf833a742e9001538ea10122d6c (diff) | |
| download | go-821420d6bbc53d4cd8b3f9a903fccd0c6432eb6f.tar.xz | |
cmd/link/internal/loadpe: generalize handling of "__imp_*" syms
The existing PE file loader has a special case for the symbol
"__acrt_iob_func", whose hosting object file contains both an actual
definition and also a DLL import symbol "__imp___acrt_iob_func". The
normal way of handling __imp_XXX symbols is for the host object loader
to rename them to their intended target (e.g. "XXX") however if the
target is also defined locally, you get a duplicate definition.
This patch generalizes the def/import symbol detection to apply to all
symbols in the object file being loaded (not just a hard-coded set),
since it will be needed when reading things like crt2.o.
Updates #35006.
Change-Id: I0d0607c27bb7d5f3cb415bc95db816aa13746ba2
Reviewed-on: https://go-review.googlesource.com/c/go/+/382837
Reviewed-by: Cherry Mui <cherryyz@google.com>
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/cmd/link')
| -rw-r--r-- | src/cmd/link/internal/loadpe/ldpe.go | 68 |
1 files changed, 51 insertions, 17 deletions
diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go index c9fde60d0f..871ec73e01 100644 --- a/src/cmd/link/internal/loadpe/ldpe.go +++ b/src/cmd/link/internal/loadpe/ldpe.go @@ -180,6 +180,7 @@ type peLoaderState struct { arch *sys.Arch f *pe.File sectsyms map[*pe.Section]loader.Sym + defWithImp map[string]struct{} sectdata map[*pe.Section][]byte localSymVersion int } @@ -261,6 +262,13 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read } } + // Make a prepass over the symbols to detect situations where + // we have both a defined symbol X and an import symbol __imp_X + // (needed by readpesym()). + if err := state.preprocessSymbols(); err != nil { + return nil, nil, err + } + // load relocations for _, rsect := range f.Sections { if _, found := state.sectsyms[rsect]; !found { @@ -516,26 +524,20 @@ func (state *peLoaderState) readpesym(pesym *pe.COFFSymbol) (*loader.SymbolBuild name = state.l.SymName(state.sectsyms[state.f.Sections[pesym.SectionNumber-1]]) } else { name = symname - switch state.arch.Family { - case sys.AMD64: - if name == "__imp___acrt_iob_func" { - // Do not rename __imp___acrt_iob_func into __acrt_iob_func, - // because __imp___acrt_iob_func symbol is real - // (see commit b295099 from git://git.code.sf.net/p/mingw-w64/mingw-w64 for details). - } else { - name = strings.TrimPrefix(name, "__imp_") // __imp_Name => Name - } - case sys.I386: - if name == "__imp____acrt_iob_func" { - // Do not rename __imp____acrt_iob_func into ___acrt_iob_func, - // because __imp____acrt_iob_func symbol is real - // (see commit b295099 from git://git.code.sf.net/p/mingw-w64/mingw-w64 for details). + if strings.HasPrefix(symname, "__imp_") { + orig := symname[len("__imp_"):] + if _, ok := state.defWithImp[orig]; ok { + // Don't rename __imp_XXX to XXX, since if we do this + // we'll wind up with a duplicate definition. One + // example is "__acrt_iob_func"; see commit b295099 + // from git://git.code.sf.net/p/mingw-w64/mingw-w64 + // for details. } else { name = strings.TrimPrefix(name, "__imp_") // __imp_Name => Name } - if name[0] == '_' { - name = name[1:] // _Name => Name - } + } + if state.arch.Family == sys.I386 && name[0] == '_' { + name = name[1:] // _Name => Name } } @@ -576,3 +578,35 @@ func (state *peLoaderState) readpesym(pesym *pe.COFFSymbol) (*loader.SymbolBuild return bld, s, nil } + +// preprocessSymbols walks the COFF symbols for the PE file we're +// reading and looks for cases where we have both a symbol definition +// for "XXX" and an "__imp_XXX" symbol, recording these cases in a map +// in the state struct. This information will be used in readpesym() +// above to give such symbols special treatment. +func (state *peLoaderState) preprocessSymbols() error { + imp := make(map[string]struct{}) + def := make(map[string]struct{}) + for i, numaux := 0, 0; i < len(state.f.COFFSymbols); i += numaux + 1 { + pesym := &state.f.COFFSymbols[i] + numaux = int(pesym.NumberOfAuxSymbols) + if pesym.SectionNumber == 0 { // extern + continue + } + symname, err := pesym.FullName(state.f.StringTable) + if err != nil { + return err + } + def[symname] = struct{}{} + if strings.HasPrefix(symname, "__imp_") { + imp[strings.TrimPrefix(symname, "__imp_")] = struct{}{} + } + } + state.defWithImp = make(map[string]struct{}) + for n := range imp { + if _, ok := def[n]; ok { + state.defWithImp[n] = struct{}{} + } + } + return nil +} |
