// GenABIWrappers applies ABI information to Funcs and generates ABI
// wrapper functions where necessary.
func (s *SymABIs) GenABIWrappers() {
- // The linker expects an ABI0 wrapper for all cgo-exported
- // functions.
- for _, prag := range typecheck.Target.CgoPragmas {
+ // For cgo exported symbols, we tell the linker to export the
+ // definition ABI to C. That also means that we don't want to
+ // create ABI wrappers even if there's a linkname.
+ //
+ // TODO(austin): Maybe we want to create the ABI wrappers, but
+ // ensure the linker exports the right ABI definition under
+ // the unmangled name?
+ cgoExports := make(map[string][]*[]string)
+ for i, prag := range typecheck.Target.CgoPragmas {
switch prag[0] {
case "cgo_export_static", "cgo_export_dynamic":
- s.refs[s.canonicalize(prag[1])] |= obj.ABISetOf(obj.ABI0)
+ symName := s.canonicalize(prag[1])
+ pprag := &typecheck.Target.CgoPragmas[i]
+ cgoExports[symName] = append(cgoExports[symName], pprag)
}
}
fn.ABI = obj.ABI0
}
+ // If cgo-exported, add the definition ABI to the cgo
+ // pragmas.
+ cgoExport := cgoExports[symName]
+ for _, pprag := range cgoExport {
+ // The export pragmas have the form:
+ //
+ // cgo_export_* <local> [<remote>]
+ //
+ // If <remote> is omitted, it's the same as
+ // <local>.
+ //
+ // Expand to
+ //
+ // cgo_export_* <local> <remote> <ABI>
+ if len(*pprag) == 2 {
+ *pprag = append(*pprag, (*pprag)[1])
+ }
+ // Add the ABI argument.
+ *pprag = append(*pprag, fn.ABI.String())
+ }
+
// Apply references.
if abis, ok := s.refs[symName]; ok {
fn.ABIRefs |= abis
// it's defined in this package since other packages
// may "pull" symbols using linkname and we don't want
// to create duplicate ABI wrappers.
+ //
+ // However, if it's given a linkname for exporting to
+ // C, then we don't make ABI wrappers because the cgo
+ // tool wants the original definition.
hasBody := len(fn.Body) != 0
- if sym.Linkname != "" && (hasBody || hasDefABI) {
+ if sym.Linkname != "" && (hasBody || hasDefABI) && len(cgoExport) == 0 {
fn.ABIRefs |= obj.ABISetCallable
}
+ // Double check that cgo-exported symbols don't get
+ // any wrappers.
+ if len(cgoExport) > 0 && fn.ABIRefs&^obj.ABISetOf(fn.ABI) != 0 {
+ base.Fatalf("cgo exported function %s cannot have ABI wrappers", fn)
+ }
+
if !objabi.Experiment.RegabiWrappers {
// We'll generate ABI aliases instead of
// wrappers once we have LSyms in InitLSym.
import (
"bytes"
"cmd/internal/bio"
+ "cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
continue
case "cgo_export_static", "cgo_export_dynamic":
- if len(f) < 2 || len(f) > 3 {
+ if len(f) < 2 || len(f) > 4 {
break
}
local := f[1]
remote = f[2]
}
local = expandpkg(local, pkg)
+ // The compiler adds a fourth argument giving
+ // the definition ABI of function symbols.
+ abi := obj.ABI0
+ if len(f) > 3 {
+ var ok bool
+ abi, ok = obj.ParseABI(f[3])
+ if !ok {
+ fmt.Fprintf(os.Stderr, "%s: bad ABI in cgo_export directive %s\n", os.Args[0], f)
+ nerrors++
+ return
+ }
+ }
- // The compiler arranges for an ABI0 wrapper
- // to be available for all cgo-exported
- // functions. Link.loadlib will resolve any
- // ABI aliases we find here (since we may not
- // yet know it's an alias).
- s := l.LookupOrCreateSym(local, 0)
+ s := l.LookupOrCreateSym(local, sym.ABIToVersion(abi))
if l.SymType(s) == sym.SHOSTOBJ {
hostObjSyms[s] = struct{}{}
// in the exported symbol table.
ctxt.dynexp = append(ctxt.dynexp, s)
}
+ if ctxt.LinkMode == LinkInternal {
+ // For internal linking, we're
+ // responsible for resolving
+ // relocations from host objects.
+ // Record the right Go symbol
+ // version to use.
+ l.AddCgoExport(s)
+ }
l.SetAttrCgoExportStatic(s, true)
} else {
if ctxt.LinkMode == LinkInternal && !l.AttrCgoExportDynamic(s) {
panic("dynexp entry not reachable")
}
- // Resolve ABI aliases in the list of cgo-exported functions.
- // This is necessary because we load the ABI0 symbol for all
- // cgo exports.
- if ctxt.loader.SymType(s) == sym.SABIALIAS {
- t := ctxt.loader.ResolveABIAlias(s)
- ctxt.loader.CopyAttributes(s, t)
- ctxt.loader.SetSymExtname(t, ctxt.loader.SymExtname(s))
- s = t
- }
-
Adddynsym(ctxt.loader, &ctxt.Target, &ctxt.ArchSyms, s)
}
import (
"bytes"
"cmd/internal/codesign"
+ "cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
sb.AddUint8(0)
}
- // Do not export C symbols dynamically in plugins, as runtime C symbols like crosscall2
- // are in pclntab and end up pointing at the host binary, breaking unwinding.
- // See Issue #18190.
+ // Un-export runtime symbols from plugins. Since the runtime
+ // is included in both the main binary and each plugin, these
+ // symbols appear in both images. If we leave them exported in
+ // the plugin, then the dynamic linker will resolve
+ // relocations to these functions in the plugin's functab to
+ // point to the main image, causing the runtime to think the
+ // plugin's functab is corrupted. By unexporting them, these
+ // become static references, which are resolved to the
+ // plugin's text.
+ //
+ // It would be better to omit the runtime from plugins. (Using
+ // relative PCs in the functab instead of relocations would
+ // also address this.)
+ //
+ // See issue #18190.
if ctxt.BuildMode == BuildModePlugin {
for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
- s := ctxt.loader.Lookup(name, 0)
+ // Most of these are data symbols or C
+ // symbols, so they have symbol version 0.
+ ver := 0
+ // _cgo_panic is a Go function, so it uses ABIInternal.
+ if name == "_cgo_panic" {
+ ver = sym.ABIToVersion(obj.ABIInternal)
+ }
+ s := ctxt.loader.Lookup(name, ver)
if s != 0 {
ctxt.loader.SetAttrCgoExportDynamic(s, false)
}
// For functions with ABI wrappers, we have to make sure that we
// don't wind up with two elf symbol table entries with the same
// name (since this will generated an error from the external
- // linker). In the CgoExportStatic case, we want the ABI0 symbol
- // to have the primary symbol table entry (since it's going to be
- // called from C), so we rename the ABIInternal symbol. In all
- // other cases, we rename the ABI0 symbol, since we want
- // cross-load-module calls to target ABIInternal.
- //
- // TODO: this is currently only used on ELF and PE. Other platforms?
+ // linker). If we have wrappers, keep the ABIInternal name
+ // unmangled since we want cross-load-module calls to target
+ // ABIInternal, and rename other symbols.
//
// TODO: avoid the ldr.Lookup calls below by instead using an aux
// sym or marker relocation to associate the wrapper with the
// wrapped function.
- //
if !objabi.Experiment.RegabiWrappers {
return name
}
- if !ldr.IsExternal(x) && ldr.SymType(x) == sym.STEXT {
- // First case
- if ldr.SymVersion(x) == sym.SymVerABIInternal {
- if s2 := ldr.Lookup(name, sym.SymVerABI0); s2 != 0 && ldr.AttrCgoExportStatic(s2) && ldr.SymType(s2) == sym.STEXT {
- name = name + ".abiinternal"
- }
- }
- // Second case
- if ldr.SymVersion(x) == sym.SymVerABI0 && !ldr.AttrCgoExportStatic(x) {
- if s2 := ldr.Lookup(name, sym.SymVerABIInternal); s2 != 0 && ldr.SymType(s2) == sym.STEXT {
- name = name + ".abi0"
- }
+
+ if !ldr.IsExternal(x) && ldr.SymType(x) == sym.STEXT && ldr.SymVersion(x) != sym.SymVerABIInternal {
+ if s2 := ldr.Lookup(name, sym.SymVerABIInternal); s2 != 0 && ldr.SymType(s2) == sym.STEXT {
+ name = fmt.Sprintf("%s.abi%d", name, ldr.SymVersion(x))
}
}
return name
newSym := func(name string, version int) loader.Sym {
return l.CreateStaticSym(name)
}
- lookup := func(name string, version int) loader.Sym {
- return l.LookupOrCreateSym(name, version)
- }
+ lookup := l.LookupOrCreateCgoExport
errorf := func(str string, args ...interface{}) ([]loader.Sym, uint32, error) {
return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...))
}
// 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
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)
if machsym.type_&N_EXT == 0 {
v = localSymVersion
}
- s := l.LookupOrCreateSym(name, v)
+ s := l.LookupOrCreateCgoExport(name, v)
if machsym.type_&N_EXT == 0 {
l.SetAttrDuplicateOK(s, true)
}
// If an .rsrc section or set of .rsrc$xx sections is found, its symbols are
// returned as rsrc.
func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, rsrc []loader.Sym, err error) {
- lookup := func(name string, version int) (*loader.SymbolBuilder, loader.Sym) {
- s := l.LookupOrCreateSym(name, version)
- sb := l.MakeSymbolUpdater(s)
- return sb, s
- }
+ lookup := l.LookupOrCreateCgoExport
sectsyms := make(map[*pe.Section]loader.Sym)
sectdata := make(map[*pe.Section][]byte)
}
name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
- bld, s := lookup(name, localSymVersion)
+ s := lookup(name, localSymVersion)
+ bld := l.MakeSymbolUpdater(s)
switch sect.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
}
pesym := &f.COFFSymbols[r.SymbolTableIndex]
- _, gosym, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion)
+ _, gosym, err := readpesym(l, arch, lookup, f, pesym, sectsyms, localSymVersion)
if err != nil {
return nil, nil, err
}
}
}
- bld, s, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion)
+ bld, s, err := readpesym(l, arch, lookup, f, pesym, sectsyms, localSymVersion)
if err != nil {
return nil, nil, err
}
}
sb := l.MakeSymbolUpdater(sect.sym)
for _, rx := range sect.Relocs {
- rSym := l.LookupOrCreateSym(rx.Symbol.Name, 0)
+ rSym := l.LookupOrCreateCgoExport(rx.Symbol.Name, 0)
if uint64(int32(rx.VirtualAddress)) != rx.VirtualAddress {
return errorf("virtual address of a relocation is too big: 0x%x", rx.VirtualAddress)
}