errorexit()
        }
 
-       // The "init" function is the only user-spellable symbol that
-       // we construct later. Mark it as a function now before
-       // anything can ask for its Linksym.
-       lookup("init").SetFunc(true)
-
        // Phase 4: Decide how to capture closed variables.
        // This needs to run before escape analysis,
        // because variables captured by value do not escape.
 
        WasmDiv = sysvar("wasmDiv")
        WasmTruncS = sysvar("wasmTruncS")
        WasmTruncU = sysvar("wasmTruncU")
-       SigPanic = sysvar("sigpanic")
+       SigPanic = sysfunc("sigpanic")
 }
 
 // buildssa builds an SSA function for fn.
 
        }
        if sym.Func() {
                // This is a function symbol. Mark it as "internal ABI".
-               return Ctxt.LookupInit(sym.LinksymName(), func(s *obj.LSym) {
-                       s.SetABI(obj.ABIInternal)
-               })
+               return Ctxt.LookupABI(sym.LinksymName(), obj.ABIInternal)
        }
        return Ctxt.Lookup(sym.LinksymName())
 }
 
                return
        }
 
-       deferreturn = ctxt.Lookup("runtime.deferreturn")
-       deferreturn.SetABI(obj.ABIInternal)
+       deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal)
 
        symdiv = ctxt.Lookup("runtime._div")
        symdivu = ctxt.Lookup("runtime._divu")
 
        Flag_locationlists bool
        Bso                *bufio.Writer
        Pathname           string
-       hashmu             sync.Mutex       // protects hash
+       hashmu             sync.Mutex       // protects hash, funchash
        hash               map[string]*LSym // name -> sym mapping
+       funchash           map[string]*LSym // name -> sym mapping for ABIInternal syms
        statichash         map[string]*LSym // name -> sym mapping for static syms
        PosTable           src.PosTable
        InlTree            InlTree // global inlining tree used by gc/inl.go
 
 func Linknew(arch *LinkArch) *Link {
        ctxt := new(Link)
        ctxt.hash = make(map[string]*LSym)
+       ctxt.funchash = make(map[string]*LSym)
        ctxt.statichash = make(map[string]*LSym)
        ctxt.Arch = arch
        ctxt.Pathname = objabi.WorkingDir()
        return s
 }
 
+// LookupABI looks up a symbol with the given ABI.
+// If it does not exist, it creates it.
+func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
+       var hash map[string]*LSym
+       switch abi {
+       case ABI0:
+               hash = ctxt.hash
+       case ABIInternal:
+               hash = ctxt.funchash
+       default:
+               panic("unknown ABI")
+       }
+
+       ctxt.hashmu.Lock()
+       s := hash[name]
+       if s == nil {
+               s = &LSym{Name: name}
+               s.SetABI(abi)
+               hash[name] = s
+       }
+       ctxt.hashmu.Unlock()
+       return s
+}
+
 // Lookup looks up the symbol with name name.
 // If it does not exist, it creates it.
 func (ctxt *Link) Lookup(name string) *LSym {
 
        morestack = ctxt.Lookup("runtime.morestack")
        morestackNoCtxt = ctxt.Lookup("runtime.morestack_noctxt")
        gcWriteBarrier = ctxt.Lookup("runtime.gcWriteBarrier")
-       sigpanic = ctxt.Lookup("runtime.sigpanic")
-       sigpanic.SetABI(obj.ABIInternal)
-       deferreturn = ctxt.Lookup("runtime.deferreturn")
-       deferreturn.SetABI(obj.ABIInternal)
-       jmpdefer = ctxt.Lookup(`"".jmpdefer`)
+       sigpanic = ctxt.LookupABI("runtime.sigpanic", obj.ABIInternal)
+       deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal)
+       // jmpdefer is defined in assembly as ABI0, but what we're
+       // looking for is the *call* to jmpdefer from the Go function
+       // deferreturn, so we're looking for the ABIInternal version
+       // of jmpdefer that's called by Go.
+       jmpdefer = ctxt.LookupABI(`"".jmpdefer`, obj.ABIInternal)
 }
 
 func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
 
        case objabi.Hplan9:
                plan9privates = ctxt.Lookup("_privates")
        case objabi.Hnacl:
-               deferreturn = ctxt.Lookup("runtime.deferreturn")
-               deferreturn.SetABI(obj.ABIInternal)
+               deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal)
        }
 
        for i := range avxOptab {
 
--- /dev/null
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type I interface {
+       M(init bool)
+}
+
+var V I
+
+func init() {
+       V = nil
+}
 
--- /dev/null
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+type S struct {
+       a.I
+}
+
+var V a.I
+
+func init() {
+       V = S{}
+}
 
--- /dev/null
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./b"
+
+var v b.S
+
+func main() {}
 
--- /dev/null
+// rundir
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 29610: Symbol import and initialization order caused function
+// symbols to be recorded as non-function symbols.
+
+// This uses rundir not because we actually want to run the final
+// binary, but because we need to at least link it.
+
+package ignored