p.To.Reg = REGTMP
                        p.To.Offset = 8 * 4 // offset of m.divmod
 
-                       /* MOV b,REGTMP */
+                       /* MOV b, R8 */
                        p = obj.Appendp(ctxt, p)
                        p.As = AMOVW
                        p.Lineno = q1.Lineno
                                p.From.Reg = q1.To.Reg
                        }
                        p.To.Type = obj.TYPE_REG
-                       p.To.Reg = REGTMP
+                       p.To.Reg = REG_R8
                        p.To.Offset = 0
 
                        /* CALL appropriate */
 
        R_ADDRMIPSTLS
 )
 
+// IsDirectJump returns whether r is a relocation for a direct jump.
+// A direct jump is a CALL or JMP instruction that takes the target address
+// as immediate. The address is embedded into the instruction, possibly
+// with limited width.
+// An indirect jump is a CALL or JMP instruction that takes the target address
+// in register or memory.
+func (r RelocType) IsDirectJump() bool {
+       switch r {
+       case R_CALL, R_CALLARM, R_CALLARM64, R_CALLPOWER, R_CALLMIPS, R_JMPMIPS:
+               return true
+       }
+       return false
+}
+
 type Auto struct {
        Asym    *LSym
        Link    *Auto
 
        Addcall(ctxt, initfunc, addmoduledata)
        //    c:        c3                      retq
        o(0xc3)
-       ctxt.Textp = append(ctxt.Textp, initfunc)
        if ld.Buildmode == ld.BuildmodePlugin {
                ctxt.Textp = append(ctxt.Textp, addmoduledata)
        }
+       ctxt.Textp = append(ctxt.Textp, initfunc)
        initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
        initarray_entry.Attr |= ld.AttrReachable
        initarray_entry.Attr |= ld.AttrLocal
 
        rel.Type = obj.R_PCREL
        rel.Add = 4
 
-       ctxt.Textp = append(ctxt.Textp, initfunc)
        if ld.Buildmode == ld.BuildmodePlugin {
                ctxt.Textp = append(ctxt.Textp, addmoduledata)
        }
+       ctxt.Textp = append(ctxt.Textp, initfunc)
        initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
        initarray_entry.Attr |= ld.AttrReachable
        initarray_entry.Attr |= ld.AttrLocal
        return 0
 }
 
+// sign extend a 24-bit integer
+func signext24(x int64) int32 {
+       return (int32(x) << 8) >> 8
+}
+
+// Convert the direct jump relocation r to refer to a trampoline if the target is too far
+func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
+       switch r.Type {
+       case obj.R_CALLARM:
+               // r.Add is the instruction
+               // low 24-bit encodes the target address
+               t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
+               if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
+                       // direct call too far, need to insert trampoline
+                       offset := (signext24(r.Add&0xffffff) + 2) * 4
+                       var tramp *ld.Symbol
+                       for i := 0; ; i++ {
+                               name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i)
+                               tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
+                               if tramp.Value == 0 {
+                                       // either the trampoline does not exist -- we need to create one,
+                                       // or found one the address which is not assigned -- this will be
+                                       // laid down immediately after the current function. use this one.
+                                       break
+                               }
+
+                               t = (ld.Symaddr(tramp) - 8 - (s.Value + int64(r.Off))) / 4
+                               if t >= -0x800000 && t < 0x7fffff {
+                                       // found an existing trampoline that is not too far
+                                       // we can just use it
+                                       break
+                               }
+                       }
+                       if tramp.Type == 0 {
+                               // trampoline does not exist, create one
+                               ctxt.AddTramp(tramp)
+                               tramp.Size = 12 // 3 instructions
+                               tramp.P = make([]byte, tramp.Size)
+                               t = ld.Symaddr(r.Sym) + int64(offset)
+                               o1 := uint32(0xe5900000 | 11<<12 | 15<<16) // MOVW (R15), R11 // R15 is actual pc + 8
+                               o2 := uint32(0xe12fff10 | 11)              // JMP  (R11)
+                               o3 := uint32(t)                            // WORD $target
+                               ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
+                               ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
+                               ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
+                       }
+                       // modify reloc to point to tramp, which will be resolved later
+                       r.Sym = tramp
+                       r.Add = r.Add&0xff000000 | 0xfffffe // clear the offset embedded in the instruction
+                       r.Done = 0
+               }
+       default:
+               ld.Errorf(s, "trampoline called with non-jump reloc: %v", r.Type)
+       }
+}
+
 func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
        if ld.Linkmode == ld.LinkExternal {
                switch r.Type {
                        // set up addend for eventual relocation via outer symbol.
                        rs := r.Sym
 
-                       r.Xadd = r.Add
-                       if r.Xadd&0x800000 != 0 {
-                               r.Xadd |= ^0xffffff
-                       }
+                       r.Xadd = int64(signext24(r.Add & 0xffffff))
                        r.Xadd *= 4
                        for rs.Outer != nil {
                                r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
                                r.Xadd -= ld.Symaddr(s) + int64(r.Off)
                        }
 
+                       if r.Xadd/4 > 0x7fffff || r.Xadd/4 < -0x800000 {
+                               ld.Errorf(s, "direct call too far %d", r.Xadd/4)
+                       }
+
                        *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4))))
                        return 0
                }
                return 0
 
        case obj.R_CALLARM: // bl XXXXXX or b YYYYYY
-               *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32((ld.Symaddr(r.Sym)+int64((uint32(r.Add))*4)-(s.Value+int64(r.Off)))/4))))
+               // r.Add is the instruction
+               // low 24-bit encodes the target address
+               t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
+               if t > 0x7fffff || t < -0x800000 {
+                       ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
+               }
+               *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&t)))
 
                return 0
        }
 
        ld.Thearch.Archinit = archinit
        ld.Thearch.Archreloc = archreloc
        ld.Thearch.Archrelocvariant = archrelocvariant
+       ld.Thearch.Trampoline = trampoline
        ld.Thearch.Asmb = asmb
        ld.Thearch.Elfreloc1 = elfreloc1
        ld.Thearch.Elfsetupplt = elfsetupplt
 
                        pname := fmt.Sprintf("%s(%s)", name, arhdr.name)
                        l = atolwhex(arhdr.size)
 
-                       h := ldobj(ctxt, f, "libgcc", l, pname, name, ArchiveObj)
+                       libgcc := Library{Pkg: "libgcc"}
+                       h := ldobj(ctxt, f, &libgcc, l, pname, name, ArchiveObj)
                        f.Seek(h.off, 0)
                        h.ld(ctxt, f, h.pkg, h.length, h.pn)
                }
 
        return l
 }
 
+// isRuntimeDepPkg returns whether pkg is the runtime package or its dependency
+func isRuntimeDepPkg(pkg string) bool {
+       switch pkg {
+       case "runtime",
+               "sync/atomic": // runtime may call to sync/atomic, due to go:linkname
+               return true
+       }
+       return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test")
+}
+
+// detect too-far jumps in function s, and add trampolines if necessary
+// (currently only ARM supports trampoline insertion)
+func trampoline(ctxt *Link, s *Symbol) {
+       if Thearch.Trampoline == nil {
+               return // no need or no support of trampolines on this arch
+       }
+       if Linkmode == LinkExternal {
+               return // currently only support internal linking
+       }
+
+       for ri := range s.R {
+               r := &s.R[ri]
+               if !r.Type.IsDirectJump() {
+                       continue
+               }
+               if Symaddr(r.Sym) == 0 && r.Sym.Type != obj.SDYNIMPORT {
+                       if r.Sym.File != s.File {
+                               if !isRuntimeDepPkg(s.File) || !isRuntimeDepPkg(r.Sym.File) {
+                                       Errorf(s, "unresolved inter-package jump to %s(%s)", r.Sym, r.Sym.File)
+                               }
+                               // runtime and its dependent packages may call to each other.
+                               // they are fine, as they will be laid down together.
+                       }
+                       continue
+               }
+
+               Thearch.Trampoline(ctxt, r, s)
+       }
+
+}
+
+// resolve relocations in s.
 func relocsym(ctxt *Link, s *Symbol) {
        var r *Reloc
        var rs *Symbol
 
        for ri := int32(0); ri < int32(len(s.R)); ri++ {
                r = &s.R[ri]
+
                r.Done = 1
                off = r.Off
                siz = int32(r.Siz)
        va := uint64(*FlagTextAddr)
        n := 1
        sect.Vaddr = va
+       ntramps := 0
        for _, sym := range ctxt.Textp {
-               sym.Sect = sect
-               if sym.Type&obj.SSUB != 0 {
-                       continue
-               }
-               if sym.Align != 0 {
-                       va = uint64(Rnd(int64(va), int64(sym.Align)))
-               } else {
-                       va = uint64(Rnd(int64(va), int64(Funcalign)))
-               }
-               sym.Value = 0
-               for sub := sym; sub != nil; sub = sub.Sub {
-                       sub.Value += int64(va)
+               sect, n, va = assignAddress(ctxt, sect, n, sym, va)
+
+               trampoline(ctxt, sym) // resolve jumps, may add trampolines if jump too far
+
+               // lay down trampolines after each function
+               for ; ntramps < len(ctxt.tramps); ntramps++ {
+                       tramp := ctxt.tramps[ntramps]
+                       sect, n, va = assignAddress(ctxt, sect, n, tramp, va)
                }
-               funcsize := uint64(MINFUNC) // spacing required for findfunctab
-               if sym.Size > MINFUNC {
-                       funcsize = uint64(sym.Size)
+       }
+
+       sect.Length = va - sect.Vaddr
+       ctxt.Syms.Lookup("runtime.etext", 0).Sect = sect
+
+       // merge tramps into Textp, keeping Textp in address order
+       if ntramps != 0 {
+               newtextp := make([]*Symbol, 0, len(ctxt.Textp)+ntramps)
+               i := 0
+               for _, sym := range ctxt.Textp {
+                       for ; i < ntramps && ctxt.tramps[i].Value < sym.Value; i++ {
+                               newtextp = append(newtextp, ctxt.tramps[i])
+                       }
+                       newtextp = append(newtextp, sym)
                }
+               newtextp = append(newtextp, ctxt.tramps[i:ntramps]...)
+
+               ctxt.Textp = newtextp
+       }
+}
+
+// assigns address for a text symbol, returns (possibly new) section, its number, and the address
+// Note: once we have trampoline insertion support for external linking, this function
+// will not need to create new text sections, and so no need to return sect and n.
+func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64) (*Section, int, uint64) {
+       sym.Sect = sect
+       if sym.Type&obj.SSUB != 0 {
+               return sect, n, va
+       }
+       if sym.Align != 0 {
+               va = uint64(Rnd(int64(va), int64(sym.Align)))
+       } else {
+               va = uint64(Rnd(int64(va), int64(Funcalign)))
+       }
+       sym.Value = 0
+       for sub := sym; sub != nil; sub = sub.Sub {
+               sub.Value += int64(va)
+       }
+
+       funcsize := uint64(MINFUNC) // spacing required for findfunctab
+       if sym.Size > MINFUNC {
+               funcsize = uint64(sym.Size)
+       }
 
-               // On ppc64x a text section should not be larger than 2^26 bytes due to the size of
-               // call target offset field in the bl instruction.  Splitting into smaller text
-               // sections smaller than this limit allows the GNU linker to modify the long calls
-               // appropriately.  The limit allows for the space needed for tables inserted by the linker.
+       // On ppc64x a text section should not be larger than 2^26 bytes due to the size of
+       // call target offset field in the bl instruction.  Splitting into smaller text
+       // sections smaller than this limit allows the GNU linker to modify the long calls
+       // appropriately.  The limit allows for the space needed for tables inserted by the linker.
 
-               // If this function doesn't fit in the current text section, then create a new one.
+       // If this function doesn't fit in the current text section, then create a new one.
 
-               // Only break at outermost syms.
+       // Only break at outermost syms.
 
-               if SysArch.InFamily(sys.PPC64) && sym.Outer == nil && Iself && Linkmode == LinkExternal && va-sect.Vaddr+funcsize > 0x1c00000 {
+       if SysArch.InFamily(sys.PPC64) && sym.Outer == nil && Iself && Linkmode == LinkExternal && va-sect.Vaddr+funcsize > 0x1c00000 {
 
-                       // Set the length for the previous text section
-                       sect.Length = va - sect.Vaddr
+               // Set the length for the previous text section
+               sect.Length = va - sect.Vaddr
 
-                       // Create new section, set the starting Vaddr
-                       sect = addsection(&Segtext, ".text", 05)
-                       sect.Vaddr = va
+               // Create new section, set the starting Vaddr
+               sect = addsection(&Segtext, ".text", 05)
+               sect.Vaddr = va
 
-                       // Create a symbol for the start of the secondary text sections
-                       ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
-                       n++
-               }
-               va += funcsize
+               // Create a symbol for the start of the secondary text sections
+               ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
+               n++
        }
+       va += funcsize
 
-       sect.Length = va - sect.Vaddr
-       ctxt.Syms.Lookup("runtime.etext", 0).Sect = sect
+       return sect, n, va
 }
 
 // assign addresses
        ctxt.xdefine("runtime.enoptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
        ctxt.xdefine("runtime.end", obj.SBSS, int64(Segdata.Vaddr+Segdata.Length))
 }
+
+// add a trampoline with symbol s (to be laid down after the current function)
+func (ctxt *Link) AddTramp(s *Symbol) {
+       s.Type = obj.STEXT
+       s.Attr |= AttrReachable
+       s.Attr |= AttrOnList
+       ctxt.tramps = append(ctxt.tramps, s)
+       if *FlagDebugTramp > 0 && ctxt.Debugvlog > 0 {
+               ctxt.Logf("trampoline %s inserted\n", s)
+       }
+}
 
 import (
        "cmd/internal/obj"
        "cmd/internal/sys"
+       "flag"
        "fmt"
+       "path/filepath"
        "strings"
        "unicode"
 )
                if *FlagLinkshared && (Buildmode == BuildmodeExe || Buildmode == BuildmodePIE) {
                        names = append(names, "main.main", "main.init")
                } else if Buildmode == BuildmodePlugin {
-                       pluginInit := d.ctxt.Library[0].Pkg + ".init"
+                       pluginName := strings.TrimSuffix(filepath.Base(flag.Arg(0)), ".a")
+                       pluginInit := pluginName + ".init"
                        names = append(names, pluginInit, "go.plugin.tabs")
 
                        // We don't keep the go.plugin.exports symbol,
 
        "strings"
 )
 
-func addlib(ctxt *Link, src string, obj string, pathname string) {
+func addlib(ctxt *Link, src string, obj string, pathname string) *Library {
        name := path.Clean(pathname)
 
        // runtime.a -> runtime, runtime.6 -> runtime
        // already loaded?
        for i := 0; i < len(ctxt.Library); i++ {
                if ctxt.Library[i].Pkg == pkg {
-                       return
+                       return ctxt.Library[i]
                }
        }
 
        }
 
        if isshlib {
-               addlibpath(ctxt, src, obj, "", pkg, pname)
-       } else {
-               addlibpath(ctxt, src, obj, pname, pkg, "")
+               return addlibpath(ctxt, src, obj, "", pkg, pname)
        }
+       return addlibpath(ctxt, src, obj, pname, pkg, "")
 }
 
 /*
- * add library to library list.
+ * add library to library list, return added library.
  *     srcref: src file referring to package
  *     objref: object file referring to package
  *     file: object file, e.g., /home/rsc/go/pkg/container/vector.a
  *     pkg: package import path, e.g. container/vector
  */
-func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlibnamefile string) {
+func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlibnamefile string) *Library {
        for i := 0; i < len(ctxt.Library); i++ {
                if pkg == ctxt.Library[i].Pkg {
-                       return
+                       return ctxt.Library[i]
                }
        }
 
                }
                l.Shlib = strings.TrimSpace(string(shlibbytes))
        }
+       return l
 }
 
 func atolwhex(s string) int64 {
 
        Archinit         func(*Link)
        Archreloc        func(*Link, *Reloc, *Symbol, *int64) int
        Archrelocvariant func(*Link, *Reloc, *Symbol, int64) int64
+       Trampoline       func(*Link, *Reloc, *Symbol)
        Asmb             func(*Link)
        Elfreloc1        func(*Link, *Reloc, int64) int
        Elfsetupplt      func(*Link)
        Exit(0)
 }
 
-func loadinternal(ctxt *Link, name string) {
-       found := 0
+func loadinternal(ctxt *Link, name string) *Library {
        for i := 0; i < len(ctxt.Libdir); i++ {
                if *FlagLinkshared {
                        shlibname := filepath.Join(ctxt.Libdir[i], name+".shlibname")
                                ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
                        }
                        if _, err := os.Stat(shlibname); err == nil {
-                               addlibpath(ctxt, "internal", "internal", "", name, shlibname)
-                               found = 1
-                               break
+                               return addlibpath(ctxt, "internal", "internal", "", name, shlibname)
                        }
                }
                pname := filepath.Join(ctxt.Libdir[i], name+".a")
                        ctxt.Logf("searching for %s.a in %s\n", name, pname)
                }
                if _, err := os.Stat(pname); err == nil {
-                       addlibpath(ctxt, "internal", "internal", pname, name, "")
-                       found = 1
-                       break
+                       return addlibpath(ctxt, "internal", "internal", pname, name, "")
                }
        }
 
-       if found == 0 {
-               ctxt.Logf("warning: unable to find %s.a\n", name)
-       }
+       ctxt.Logf("warning: unable to find %s.a\n", name)
+       return nil
 }
 
 // findLibPathCmd uses cmd command to find gcc library libname.
        }
 
        importcycles()
+
+       // put symbols into Textp
+       // do it in postorder so that packages are laid down in dependency order
+       // internal first, then everything else
+       ctxt.Library = postorder(ctxt.Library)
+       for _, doInternal := range [2]bool{true, false} {
+               for _, lib := range ctxt.Library {
+                       if isRuntimeDepPkg(lib.Pkg) != doInternal {
+                               continue
+                       }
+                       ctxt.Textp = append(ctxt.Textp, lib.textp...)
+                       for _, s := range lib.dupTextSyms {
+                               if !s.Attr.OnList() {
+                                       ctxt.Textp = append(ctxt.Textp, s)
+                                       s.Attr |= AttrOnList
+                               }
+                       }
+               }
+       }
+
+       if len(ctxt.Shlibs) > 0 {
+               // We might have overwritten some functions above (this tends to happen for the
+               // autogenerated type equality/hashing functions) and we don't want to generated
+               // pcln table entries for these any more so remove them from Textp.
+               textp := make([]*Symbol, 0, len(ctxt.Textp))
+               for _, s := range ctxt.Textp {
+                       if s.Type != obj.SDYNIMPORT {
+                               textp = append(textp, s)
+                       }
+               }
+               ctxt.Textp = textp
+       }
 }
 
 /*
                l := f.Seek(0, 2)
 
                f.Seek(0, 0)
-               ldobj(ctxt, f, pkg, l, lib.File, lib.File, FileObj)
+               ldobj(ctxt, f, lib, l, lib.File, lib.File, FileObj)
                f.Close()
 
                return
 
                pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
                l = atolwhex(arhdr.size)
-               ldobj(ctxt, f, pkg, l, pname, lib.File, ArchiveObj)
+               ldobj(ctxt, f, lib, l, pname, lib.File, ArchiveObj)
        }
 
 out:
 // ldobj loads an input object. If it is a host object (an object
 // compiled by a non-Go compiler) it returns the Hostobj pointer. If
 // it is a Go object, it returns nil.
-func ldobj(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string, file string, whence int) *Hostobj {
-       eof := f.Offset() + length
+func ldobj(ctxt *Link, f *bio.Reader, lib *Library, length int64, pn string, file string, whence int) *Hostobj {
+       pkg := pathtoprefix(lib.Pkg)
 
+       eof := f.Offset() + length
        start := f.Offset()
        c1 := bgetc(f)
        c2 := bgetc(f)
        ldpkg(ctxt, f, pkg, import1-import0-2, pn, whence) // -2 for !\n
        f.Seek(import1, 0)
 
-       LoadObjFile(ctxt, f, pkg, eof-f.Offset(), pn)
+       LoadObjFile(ctxt, f, lib, eof-f.Offset(), pn)
        return nil
 }
 
                }
        }
 
-       // We might have overwritten some functions above (this tends to happen for the
-       // autogenerated type equality/hashing functions) and we don't want to generated
-       // pcln table entries for these any more so remove them from Textp.
-       textp := make([]*Symbol, 0, len(ctxt.Textp))
-       for _, s := range ctxt.Textp {
-               if s.Type != obj.SDYNIMPORT {
-                       textp = append(textp, s)
-               }
-       }
-       ctxt.Textp = textp
-
        ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdataAddresses: gcdataAddresses})
 }
 
        }
        return int(c)
 }
+
+type markKind uint8 // for postorder traversal
+const (
+       unvisited markKind = iota
+       visiting
+       visited
+)
+
+func postorder(libs []*Library) []*Library {
+       order := make([]*Library, 0, len(libs)) // hold the result
+       mark := make(map[*Library]markKind, len(libs))
+       for _, lib := range libs {
+               dfs(lib, mark, &order)
+       }
+       return order
+}
+
+func dfs(lib *Library, mark map[*Library]markKind, order *[]*Library) {
+       if mark[lib] == visited {
+               return
+       }
+       if mark[lib] == visiting {
+               panic("found import cycle while visiting " + lib.Pkg)
+       }
+       mark[lib] = visiting
+       for _, i := range lib.imports {
+               dfs(i, mark, order)
+       }
+       mark[lib] = visited
+       *order = append(*order, lib)
+}
 
        Textp      []*Symbol
        Filesyms   []*Symbol
        Moduledata *Symbol
+
+       tramps []*Symbol // trampolines
 }
 
 // The smallest possible offset from the hardware stack pointer to a local
 }
 
 type Library struct {
-       Objref string
-       Srcref string
-       File   string
-       Pkg    string
-       Shlib  string
-       hash   []byte
+       Objref      string
+       Srcref      string
+       File        string
+       Pkg         string
+       Shlib       string
+       hash        []byte
+       imports     []*Library
+       textp       []*Symbol // text symbols defined in this library
+       dupTextSyms []*Symbol // dupok text symbols defined in this library
+}
+
+func (l Library) String() string {
+       return l.Pkg
 }
 
 type FuncInfo struct {
 
        FlagW           = flag.Bool("w", false, "disable DWARF generation")
        Flag8           bool // use 64-bit addresses in symbol table
        flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
+       FlagDebugTramp  = flag.Int("debugtramp", 0, "debug trampolines")
 
        FlagRound       = flag.Int("R", -1, "set address rounding `quantum`")
        FlagTextAddr    = flag.Int64("T", -1, "set text segment `address`")
 
 type objReader struct {
        rd              *bufio.Reader
        ctxt            *Link
-       pkg             string
+       lib             *Library
        pn              string
        dupSym          *Symbol
        localSymVersion int
        file        []*Symbol
 }
 
-func LoadObjFile(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
+func LoadObjFile(ctxt *Link, f *bio.Reader, lib *Library, length int64, pn string) {
+
        start := f.Offset()
        r := &objReader{
                rd:              f.Reader,
-               pkg:             pkg,
+               lib:             lib,
                ctxt:            ctxt,
                pn:              pn,
                dupSym:          &Symbol{Name: ".dup"},
 }
 
 func (r *objReader) loadObjFile() {
+       pkg := pathtoprefix(r.lib.Pkg)
 
        // Magic header
        var buf [8]uint8
                if lib == "" {
                        break
                }
-               addlib(r.ctxt, r.pkg, r.pn, lib)
+               l := addlib(r.ctxt, pkg, r.pn, lib)
+               if l != nil {
+                       r.lib.imports = append(r.lib.imports, l)
+               }
        }
 
        // Symbol references
        typ := r.readSymIndex()
        data := r.readData()
        nreloc := r.readInt()
+       pkg := pathtoprefix(r.lib.Pkg)
        isdup := false
 
        var dup *Symbol
        }
 
 overwrite:
-       s.File = r.pkg
+       s.File = pkg
        if dupok {
                s.Attr |= AttrDuplicateOK
        }
                        pc.File[i] = r.readSymIndex()
                }
 
-               if !isdup {
+               if !dupok {
                        if s.Attr.OnList() {
                                log.Fatalf("symbol %s listed multiple times", s.Name)
                        }
                        s.Attr |= AttrOnList
-                       r.ctxt.Textp = append(r.ctxt.Textp, s)
+                       r.lib.textp = append(r.lib.textp, s)
+               } else {
+                       // there may ba a dup in another package
+                       // put into a temp list and add to text later
+                       if !isdup {
+                               r.lib.dupTextSyms = append(r.lib.dupTextSyms, s)
+                       } else {
+                               r.lib.dupTextSyms = append(r.lib.dupTextSyms, dup)
+                       }
                }
        }
        if s.Type == obj.SDWARFINFO {
        if p == -1 {
                return
        }
-       pkgprefix := []byte(r.pkg + ".")
+       pkgprefix := []byte(pathtoprefix(r.lib.Pkg) + ".")
        patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
 
        s.P = append(patched, s.P[e:]...)
 
 // readSymName reads a symbol name, replacing all "". with pkg.
 func (r *objReader) readSymName() string {
-       pkg := r.pkg
+       pkg := pathtoprefix(r.lib.Pkg)
        n := r.readInt()
        if n == 0 {
                r.readInt64()
 
        }
 
        // Generate little thunks that load the PC of the next instruction into a register.
+       thunks := make([]*ld.Symbol, 0, 7+len(ctxt.Textp))
        for _, r := range [...]struct {
                name string
                num  uint8
                // c3           ret
                o(0xc3)
 
-               ctxt.Textp = append(ctxt.Textp, thunkfunc)
+               thunks = append(thunks, thunkfunc)
        }
+       ctxt.Textp = append(thunks, ctxt.Textp...) // keep Textp in dependency order
 
        addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
        if addmoduledata.Type == obj.STEXT && ld.Buildmode != ld.BuildmodePlugin {
 
        o(0xc3)
 
-       ctxt.Textp = append(ctxt.Textp, initfunc)
        if ld.Buildmode == ld.BuildmodePlugin {
                ctxt.Textp = append(ctxt.Textp, addmoduledata)
        }
+       ctxt.Textp = append(ctxt.Textp, initfunc)
        initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
        initarray_entry.Attr |= ld.AttrReachable
        initarray_entry.Attr |= ld.AttrLocal
 
                cgocall(_cgo_notify_runtime_init_done, nil)
        }
 
-       main_init()
+       fn := main_init // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
+       fn()
        close(main_init_done)
 
        needUnlock = false
                // has a main, but it is not executed.
                return
        }
-       main_main()
+       fn = main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
+       fn()
        if raceenabled {
                racefini()
        }
 
 DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384
 GLOBL fast_udiv_tab<>(SB), RODATA, $64
 
-// The linker will pass numerator in RTMP, and it also
-// expects the result in RTMP
+// The linker will pass numerator in R8
+#define Rn R8
+// The linker expects the result in RTMP
 #define RTMP R11
 
 TEXT _divu(SB), NOSPLIT, $16-0
        MOVW    Rs, 12(R13)
        MOVW    RM, 16(R13)
 
-       MOVW    RTMP, Rr                /* numerator */
+       MOVW    Rn, Rr                  /* numerator */
        MOVW    g_m(g), Rq
        MOVW    m_divmod(Rq), Rq        /* denominator */
        BL      udiv(SB)
        MOVW    Rs, 12(R13)
        MOVW    RM, 16(R13)
 
-       MOVW    RTMP, Rr                /* numerator */
+       MOVW    Rn, Rr                  /* numerator */
        MOVW    g_m(g), Rq
        MOVW    m_divmod(Rq), Rq        /* denominator */
        BL      udiv(SB)
        MOVW    Rr, 8(R13)
        MOVW    Rs, 12(R13)
        MOVW    RM, 16(R13)
-       MOVW    RTMP, Rr                /* numerator */
+       MOVW    Rn, Rr                  /* numerator */
        MOVW    g_m(g), Rq
        MOVW    m_divmod(Rq), Rq        /* denominator */
        CMP     $0, Rr
 d0:
        BL      udiv(SB)                /* none/both neg */
        MOVW    Rq, RTMP
-       B               out1
+       B       out1
 d1:
        CMP     $0, Rq
        BGE     d0
        MOVW    Rr, 8(R13)
        MOVW    Rs, 12(R13)
        MOVW    RM, 16(R13)
-       MOVW    RTMP, Rr                /* numerator */
+       MOVW    Rn, Rr                  /* numerator */
        MOVW    g_m(g), Rq
        MOVW    m_divmod(Rq), Rq        /* denominator */
        CMP     $0, Rq