From 69262d48717771cedb1da86563eb3f1b094b4e92 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sun, 11 Apr 2021 15:44:25 -0400 Subject: 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 Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/link/internal/loader/loader.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'src/cmd/link/internal/loader/loader.go') diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index adc8195ace..141dd0ac68 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -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) -- cgit v1.3