cmd/compile,cmd/link: resolve cgo symbols to the correct Go ABI

Currently, Go functions exported to cgo have some confusion around
ABIs that leads to crashes. The cmd/cgo-generated C code references an
exported Go wrapper function (which calls the underlying exported user
function). The linker resolves this reference to the ABI0 entry-point
to that Go wrapper function because all host object references are
currently assumed to be to version 0 of a symbol. This gets passed via
crosscall2 and winds its way to cgocallbackg1, which puts this ABI0
entry-point into a function value and calls it. Unfortunately,
function values always use the ABIInternal calling convention, so
calling this ABI0 entry-point goes poorly.

Fix this by threading definition ABIs through the cgo export mechanism
so the linker can resolve host object references (which have no
concept of multiple ABIs) to the correct Go symbol. This involves a
few pieces:

- The compiler extends the cgo_export_{static,dynamic} directives that
  get passed on to the linker with symbol definition ABIs.

- The linker parses the ABIs in the cgo_export_{static,dynamic}
  directives to look up the right symbol to apply export attributes to
  and put in the dynexp list.

- For internal linking, the linker's Loader structure tracks the right
  symbol (in particular the right ABI) to resolve host object
  references to, and we use this in all of the host object loaders.

- For external linking, we mangle only the non-ABIInternal symbols
  now, so the external linker is able to resolve the correct reference
  from host objects to Go symbols.

Updates #40724.

Change-Id: I70a0b1610596768c3f473745fa1a3e630afbf1a8
Reviewed-on: https://go-review.googlesource.com/c/go/+/309341
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Austin Clements 2021-04-11 15:44:25 -04:00
parent 48531da9e7
commit 69262d4871
9 changed files with 139 additions and 59 deletions

View file

@ -257,6 +257,9 @@ type Loader struct {
// the symbol that triggered the marking of symbol K as live.
Reachparent []Sym
// CgoExports records cgo-exported symbols by SymName.
CgoExports map[string]Sym
flags uint32
hasUnknownPkgPath bool // if any Go object has unknown package path
@ -514,6 +517,36 @@ func (l *Loader) LookupOrCreateSym(name string, ver int) Sym {
return i
}
// AddCgoExport records a cgo-exported symbol in l.CgoExports.
// This table is used to identify the correct Go symbol ABI to use
// to resolve references from host objects (which don't have ABIs).
func (l *Loader) AddCgoExport(s Sym) {
if l.CgoExports == nil {
l.CgoExports = make(map[string]Sym)
}
l.CgoExports[l.SymName(s)] = s
}
// LookupOrCreateCgoExport is like LookupOrCreateSym, but if ver
// indicates a global symbol, it uses the CgoExport table to determine
// the appropriate symbol version (ABI) to use. ver must be either 0
// or a static symbol version.
func (l *Loader) LookupOrCreateCgoExport(name string, ver int) Sym {
if ver >= sym.SymVerStatic {
return l.LookupOrCreateSym(name, ver)
}
if ver != 0 {
panic("ver must be 0 or a static version")
}
// Look for a cgo-exported symbol from Go.
if s, ok := l.CgoExports[name]; ok {
return s
}
// Otherwise, this must just be a symbol in the host object.
// Create a version 0 symbol for it.
return l.LookupOrCreateSym(name, 0)
}
func (l *Loader) IsExternal(i Sym) bool {
r, _ := l.toLocal(i)
return l.isExtReader(r)