]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/new5l etc: convert from C to Go
authorRuss Cox <rsc@golang.org>
Sat, 28 Feb 2015 03:57:28 +0000 (22:57 -0500)
committerRuss Cox <rsc@golang.org>
Sun, 1 Mar 2015 00:39:38 +0000 (00:39 +0000)
Using rsc.io/c2go rev fc8cbfa's run.ld script.

Change-Id: I4d4d14fce96f8ce7a934bf8b9701b84fa9cf772d
Reviewed-on: https://go-review.googlesource.com/6335
Reviewed-by: Rob Pike <r@golang.org>
38 files changed:
src/cmd/internal/ld/ar.go [new file with mode: 0644]
src/cmd/internal/ld/arch.go [new file with mode: 0644]
src/cmd/internal/ld/data.go [new file with mode: 0644]
src/cmd/internal/ld/decodesym.go [new file with mode: 0644]
src/cmd/internal/ld/dwarf.go [new file with mode: 0644]
src/cmd/internal/ld/dwarf_defs.go [new file with mode: 0644]
src/cmd/internal/ld/elf.go [new file with mode: 0644]
src/cmd/internal/ld/fmt.go [new file with mode: 0644]
src/cmd/internal/ld/go.go [new file with mode: 0644]
src/cmd/internal/ld/ld.go [new file with mode: 0644]
src/cmd/internal/ld/ldelf.go [new file with mode: 0644]
src/cmd/internal/ld/ldmacho.go [new file with mode: 0644]
src/cmd/internal/ld/ldpe.go [new file with mode: 0644]
src/cmd/internal/ld/lib.go [new file with mode: 0644]
src/cmd/internal/ld/link.go [new file with mode: 0644]
src/cmd/internal/ld/macho.go [new file with mode: 0644]
src/cmd/internal/ld/objfile.go [new file with mode: 0644]
src/cmd/internal/ld/pcln.go [new file with mode: 0644]
src/cmd/internal/ld/pe.go [new file with mode: 0644]
src/cmd/internal/ld/pobj.go [new file with mode: 0644]
src/cmd/internal/ld/sym.go [new file with mode: 0644]
src/cmd/internal/ld/symtab.go [new file with mode: 0644]
src/cmd/internal/ld/textflag.go [new file with mode: 0644]
src/cmd/internal/ld/util.go [new file with mode: 0644]
src/cmd/internal/ld/z.go [new file with mode: 0644]
src/cmd/new5l/asm.go [new file with mode: 0644]
src/cmd/new5l/l.go [new file with mode: 0644]
src/cmd/new5l/obj.go [new file with mode: 0644]
src/cmd/new6l/asm.go [new file with mode: 0644]
src/cmd/new6l/l.go [new file with mode: 0644]
src/cmd/new6l/obj.go [new file with mode: 0644]
src/cmd/new6l/z.go [new file with mode: 0644]
src/cmd/new8l/asm.go [new file with mode: 0644]
src/cmd/new8l/l.go [new file with mode: 0644]
src/cmd/new8l/obj.go [new file with mode: 0644]
src/cmd/new9l/asm.go [new file with mode: 0644]
src/cmd/new9l/l.go [new file with mode: 0644]
src/cmd/new9l/obj.go [new file with mode: 0644]

diff --git a/src/cmd/internal/ld/ar.go b/src/cmd/internal/ld/ar.go
new file mode 100644 (file)
index 0000000..c464a62
--- /dev/null
@@ -0,0 +1,51 @@
+// Inferno utils/include/ar.h
+// http://code.google.com/p/inferno-os/source/browse/utils/include/ar.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+const (
+       SARMAG  = 8
+       SARNAME = 16
+       SAR_HDR = 16 + 44
+)
+
+var ARMAG string = "!<arch>\n"
+
+var ARFMAG string = "`\n"
+
+type ArHdr struct {
+       name string
+       date string
+       uid  string
+       gid  string
+       mode string
+       size string
+       fmag string
+}
diff --git a/src/cmd/internal/ld/arch.go b/src/cmd/internal/ld/arch.go
new file mode 100644 (file)
index 0000000..3dd6a5f
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2015 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 ld
+
+import "encoding/binary"
+
+var Linkarm = LinkArch{
+       ByteOrder: binary.LittleEndian,
+       Name:      "arm",
+       Thechar:   '5',
+       Endian:    LittleEndian,
+       Minlc:     4,
+       Ptrsize:   4,
+       Regsize:   4,
+}
+
+var Linkamd64 = LinkArch{
+       ByteOrder: binary.LittleEndian,
+       Name:      "amd64",
+       Thechar:   '6',
+       Endian:    LittleEndian,
+       Minlc:     1,
+       Ptrsize:   8,
+       Regsize:   8,
+}
+
+var Linkamd64p32 = LinkArch{
+       ByteOrder: binary.LittleEndian,
+       Name:      "amd64p32",
+       Thechar:   '6',
+       Endian:    LittleEndian,
+       Minlc:     1,
+       Ptrsize:   4,
+       Regsize:   8,
+}
+
+var Link386 = LinkArch{
+       ByteOrder: binary.LittleEndian,
+       Name:      "386",
+       Thechar:   '8',
+       Endian:    LittleEndian,
+       Minlc:     1,
+       Ptrsize:   4,
+       Regsize:   4,
+}
+
+var Linkppc64 = LinkArch{
+       ByteOrder: binary.BigEndian,
+       Name:      "ppc64",
+       Thechar:   '9',
+       Endian:    BigEndian,
+       Minlc:     4,
+       Ptrsize:   8,
+       Regsize:   8,
+}
+
+var Linkppc64le = LinkArch{
+       ByteOrder: binary.LittleEndian,
+       Name:      "ppc64le",
+       Thechar:   '9',
+       Endian:    LittleEndian,
+       Minlc:     4,
+       Ptrsize:   8,
+       Regsize:   8,
+}
diff --git a/src/cmd/internal/ld/data.go b/src/cmd/internal/ld/data.go
new file mode 100644 (file)
index 0000000..ff2d09f
--- /dev/null
@@ -0,0 +1,1798 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+       "strings"
+)
+
+func Symgrow(ctxt *Link, s *LSym, siz int64) {
+       if int64(int(siz)) != siz {
+               log.Fatalf("symgrow size %d too long", siz)
+       }
+       if int64(len(s.P)) >= siz {
+               return
+       }
+       for cap(s.P) < int(siz) {
+               s.P = append(s.P[:len(s.P)], 0)
+       }
+       s.P = s.P[:siz]
+}
+
+func Addrel(s *LSym) *Reloc {
+       s.R = append(s.R, Reloc{})
+       return &s.R[len(s.R)-1]
+}
+
+func setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
+       if s.Type == 0 {
+               s.Type = SDATA
+       }
+       s.Reachable = true
+       if s.Size < off+wid {
+               s.Size = off + wid
+               Symgrow(ctxt, s, s.Size)
+       }
+
+       switch wid {
+       case 1:
+               s.P[off] = uint8(v)
+       case 2:
+               ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(v))
+       case 4:
+               ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
+       case 8:
+               ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(v))
+       }
+
+       return off + wid
+}
+
+func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 {
+       var off int64
+
+       off = s.Size
+       setuintxx(ctxt, s, off, v, int64(wid))
+       return off
+}
+
+func Adduint8(ctxt *Link, s *LSym, v uint8) int64 {
+       return adduintxx(ctxt, s, uint64(v), 1)
+}
+
+func Adduint16(ctxt *Link, s *LSym, v uint16) int64 {
+       return adduintxx(ctxt, s, uint64(v), 2)
+}
+
+func Adduint32(ctxt *Link, s *LSym, v uint32) int64 {
+       return adduintxx(ctxt, s, uint64(v), 4)
+}
+
+func Adduint64(ctxt *Link, s *LSym, v uint64) int64 {
+       return adduintxx(ctxt, s, v, 8)
+}
+
+func setuint8(ctxt *Link, s *LSym, r int64, v uint8) int64 {
+       return setuintxx(ctxt, s, r, uint64(v), 1)
+}
+
+func setuint32(ctxt *Link, s *LSym, r int64, v uint32) int64 {
+       return setuintxx(ctxt, s, r, uint64(v), 4)
+}
+
+func Addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+       var i int64
+       var r *Reloc
+
+       if s.Type == 0 {
+               s.Type = SDATA
+       }
+       s.Reachable = true
+       i = s.Size
+       s.Size += int64(ctxt.Arch.Ptrsize)
+       Symgrow(ctxt, s, s.Size)
+       r = Addrel(s)
+       r.Sym = t
+       r.Off = int32(i)
+       r.Siz = uint8(ctxt.Arch.Ptrsize)
+       r.Type = R_ADDR
+       r.Add = add
+       return i + int64(r.Siz)
+}
+
+func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+       var i int64
+       var r *Reloc
+
+       if s.Type == 0 {
+               s.Type = SDATA
+       }
+       s.Reachable = true
+       i = s.Size
+       s.Size += 4
+       Symgrow(ctxt, s, s.Size)
+       r = Addrel(s)
+       r.Sym = t
+       r.Off = int32(i)
+       r.Add = add
+       r.Type = R_PCREL
+       r.Siz = 4
+       return i + int64(r.Siz)
+}
+
+func Addaddr(ctxt *Link, s *LSym, t *LSym) int64 {
+       return Addaddrplus(ctxt, s, t, 0)
+}
+
+func setaddrplus(ctxt *Link, s *LSym, off int64, t *LSym, add int64) int64 {
+       var r *Reloc
+
+       if s.Type == 0 {
+               s.Type = SDATA
+       }
+       s.Reachable = true
+       if off+int64(ctxt.Arch.Ptrsize) > s.Size {
+               s.Size = off + int64(ctxt.Arch.Ptrsize)
+               Symgrow(ctxt, s, s.Size)
+       }
+
+       r = Addrel(s)
+       r.Sym = t
+       r.Off = int32(off)
+       r.Siz = uint8(ctxt.Arch.Ptrsize)
+       r.Type = R_ADDR
+       r.Add = add
+       return off + int64(r.Siz)
+}
+
+func setaddr(ctxt *Link, s *LSym, off int64, t *LSym) int64 {
+       return setaddrplus(ctxt, s, off, t, 0)
+}
+
+func addsize(ctxt *Link, s *LSym, t *LSym) int64 {
+       var i int64
+       var r *Reloc
+
+       if s.Type == 0 {
+               s.Type = SDATA
+       }
+       s.Reachable = true
+       i = s.Size
+       s.Size += int64(ctxt.Arch.Ptrsize)
+       Symgrow(ctxt, s, s.Size)
+       r = Addrel(s)
+       r.Sym = t
+       r.Off = int32(i)
+       r.Siz = uint8(ctxt.Arch.Ptrsize)
+       r.Type = R_SIZE
+       return i + int64(r.Siz)
+}
+
+func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+       var i int64
+       var r *Reloc
+
+       if s.Type == 0 {
+               s.Type = SDATA
+       }
+       s.Reachable = true
+       i = s.Size
+       s.Size += 4
+       Symgrow(ctxt, s, s.Size)
+       r = Addrel(s)
+       r.Sym = t
+       r.Off = int32(i)
+       r.Siz = 4
+       r.Type = R_ADDR
+       r.Add = add
+       return i + int64(r.Siz)
+}
+
+/*
+ * divide-and-conquer list-link
+ * sort of LSym* structures.
+ * Used for the data block.
+ */
+func datcmp(s1 *LSym, s2 *LSym) int {
+       if s1.Type != s2.Type {
+               return int(s1.Type) - int(s2.Type)
+       }
+
+       // For ppc64, we want to interleave the .got and .toc sections
+       // from input files.  Both are type SELFGOT, so in that case
+       // fall through to the name comparison (conveniently, .got
+       // sorts before .toc).
+       if s1.Type != SELFGOT && s1.Size != s2.Size {
+               if s1.Size < s2.Size {
+                       return -1
+               }
+               return +1
+       }
+
+       return stringsCompare(s1.Name, s2.Name)
+}
+
+func listnextp(s *LSym) **LSym {
+       return &s.Next
+}
+
+func listsubp(s *LSym) **LSym {
+       return &s.Sub
+}
+
+func listsort(l *LSym, cmp func(*LSym, *LSym) int, nextp func(*LSym) **LSym) *LSym {
+       var l1 *LSym
+       var l2 *LSym
+       var le *LSym
+
+       if l == nil || *nextp(l) == nil {
+               return l
+       }
+
+       l1 = l
+       l2 = l
+       for {
+               l2 = *nextp(l2)
+               if l2 == nil {
+                       break
+               }
+               l2 = *nextp(l2)
+               if l2 == nil {
+                       break
+               }
+               l1 = *nextp(l1)
+       }
+
+       l2 = *nextp(l1)
+       *nextp(l1) = nil
+       l1 = listsort(l, cmp, nextp)
+       l2 = listsort(l2, cmp, nextp)
+
+       /* set up lead element */
+       if cmp(l1, l2) < 0 {
+               l = l1
+               l1 = *nextp(l1)
+       } else {
+               l = l2
+               l2 = *nextp(l2)
+       }
+
+       le = l
+
+       for {
+               if l1 == nil {
+                       for l2 != nil {
+                               *nextp(le) = l2
+                               le = l2
+                               l2 = *nextp(l2)
+                       }
+
+                       *nextp(le) = nil
+                       break
+               }
+
+               if l2 == nil {
+                       for l1 != nil {
+                               *nextp(le) = l1
+                               le = l1
+                               l1 = *nextp(l1)
+                       }
+
+                       break
+               }
+
+               if cmp(l1, l2) < 0 {
+                       *nextp(le) = l1
+                       le = l1
+                       l1 = *nextp(l1)
+               } else {
+                       *nextp(le) = l2
+                       le = l2
+                       l2 = *nextp(l2)
+               }
+       }
+
+       *nextp(le) = nil
+       return l
+}
+
+func relocsym(s *LSym) {
+       var r *Reloc
+       var rs *LSym
+       var i16 int16
+       var ri int32
+       var off int32
+       var siz int32
+       var fl int32
+       var o int64
+
+       Ctxt.Cursym = s
+       for ri = 0; ri < int32(len(s.R)); ri++ {
+               r = &s.R[ri]
+               r.Done = 1
+               off = r.Off
+               siz = int32(r.Siz)
+               if off < 0 || off+siz > int32(len(s.P)) {
+                       Diag("%s: invalid relocation %d+%d not in [%d,%d)", s.Name, off, siz, 0, len(s.P))
+                       continue
+               }
+
+               if r.Sym != nil && (r.Sym.Type&(SMASK|SHIDDEN) == 0 || r.Sym.Type&SMASK == SXREF) {
+                       Diag("%s: not defined", r.Sym.Name)
+                       continue
+               }
+
+               if r.Type >= 256 {
+                       continue
+               }
+               if r.Siz == 0 { // informational relocation - no work to do
+                       continue
+               }
+
+               // Solaris needs the ability to reference dynimport symbols.
+               if HEADTYPE != Hsolaris && r.Sym != nil && r.Sym.Type == SDYNIMPORT {
+                       Diag("unhandled relocation for %s (type %d rtype %d)", r.Sym.Name, r.Sym.Type, r.Type)
+               }
+               if r.Sym != nil && r.Sym.Type != STLSBSS && !r.Sym.Reachable {
+                       Diag("unreachable sym in relocation: %s %s", s.Name, r.Sym.Name)
+               }
+
+               // Android emulates runtime.tlsg as a regular variable.
+               if r.Type == R_TLS && goos == "android" {
+                       r.Type = R_ADDR
+               }
+
+               switch r.Type {
+               default:
+                       o = 0
+                       if Thearch.Archreloc(r, s, &o) < 0 {
+                               Diag("unknown reloc %d", r.Type)
+                       }
+
+               case R_TLS:
+                       if Linkmode == LinkInternal && Iself && Thearch.Thechar == '5' {
+                               // On ELF ARM, the thread pointer is 8 bytes before
+                               // the start of the thread-local data block, so add 8
+                               // to the actual TLS offset (r->sym->value).
+                               // This 8 seems to be a fundamental constant of
+                               // ELF on ARM (or maybe Glibc on ARM); it is not
+                               // related to the fact that our own TLS storage happens
+                               // to take up 8 bytes.
+                               o = 8 + r.Sym.Value
+
+                               break
+                       }
+
+                       r.Done = 0
+                       o = 0
+                       if Thearch.Thechar != '6' {
+                               o = r.Add
+                       }
+
+               case R_TLS_LE:
+                       if Linkmode == LinkExternal && Iself && HEADTYPE != Hopenbsd {
+                               r.Done = 0
+                               r.Sym = Ctxt.Tlsg
+                               r.Xsym = Ctxt.Tlsg
+                               r.Xadd = r.Add
+                               o = 0
+                               if Thearch.Thechar != '6' {
+                                       o = r.Add
+                               }
+                               break
+                       }
+
+                       o = int64(Ctxt.Tlsoffset) + r.Add
+
+               case R_TLS_IE:
+                       if Linkmode == LinkExternal && Iself && HEADTYPE != Hopenbsd {
+                               r.Done = 0
+                               r.Sym = Ctxt.Tlsg
+                               r.Xsym = Ctxt.Tlsg
+                               r.Xadd = r.Add
+                               o = 0
+                               if Thearch.Thechar != '6' {
+                                       o = r.Add
+                               }
+                               break
+                       }
+
+                       if Iself || Ctxt.Headtype == Hplan9 {
+                               o = int64(Ctxt.Tlsoffset) + r.Add
+                       } else if Ctxt.Headtype == Hwindows {
+                               o = r.Add
+                       } else {
+                               log.Fatalf("unexpected R_TLS_IE relocation for %s", Headstr(Ctxt.Headtype))
+                       }
+
+               case R_ADDR:
+                       if Linkmode == LinkExternal && r.Sym.Type != SCONST {
+                               r.Done = 0
+
+                               // set up addend for eventual relocation via outer symbol.
+                               rs = r.Sym
+
+                               r.Xadd = r.Add
+                               for rs.Outer != nil {
+                                       r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
+                                       rs = rs.Outer
+                               }
+
+                               if rs.Type != SHOSTOBJ && rs.Type != SDYNIMPORT && rs.Sect == nil {
+                                       Diag("missing section for %s", rs.Name)
+                               }
+                               r.Xsym = rs
+
+                               o = r.Xadd
+                               if Iself {
+                                       if Thearch.Thechar == '6' {
+                                               o = 0
+                                       }
+                               } else if HEADTYPE == Hdarwin {
+                                       if rs.Type != SHOSTOBJ {
+                                               o += Symaddr(rs)
+                                       }
+                               } else {
+                                       Diag("unhandled pcrel relocation for %s", headstring)
+                               }
+
+                               break
+                       }
+
+                       o = Symaddr(r.Sym) + r.Add
+
+                       // On amd64, 4-byte offsets will be sign-extended, so it is impossible to
+                       // access more than 2GB of static data; fail at link time is better than
+                       // fail at runtime. See http://golang.org/issue/7980.
+                       // Instead of special casing only amd64, we treat this as an error on all
+                       // 64-bit architectures so as to be future-proof.
+                       if int32(o) < 0 && Thearch.Ptrsize > 4 && siz == 4 {
+                               Diag("non-pc-relative relocation address is too big: %#x", uint64(o))
+                               Errorexit()
+                       }
+
+                       // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
+               case R_CALL,
+                       R_PCREL:
+                       if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != SCONST && r.Sym.Sect != Ctxt.Cursym.Sect {
+                               r.Done = 0
+
+                               // set up addend for eventual relocation via outer symbol.
+                               rs = r.Sym
+
+                               r.Xadd = r.Add
+                               for rs.Outer != nil {
+                                       r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
+                                       rs = rs.Outer
+                               }
+
+                               r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
+                               if rs.Type != SHOSTOBJ && rs.Type != SDYNIMPORT && rs.Sect == nil {
+                                       Diag("missing section for %s", rs.Name)
+                               }
+                               r.Xsym = rs
+
+                               o = r.Xadd
+                               if Iself {
+                                       if Thearch.Thechar == '6' {
+                                               o = 0
+                                       }
+                               } else if HEADTYPE == Hdarwin {
+                                       if r.Type == R_CALL {
+                                               if rs.Type != SHOSTOBJ {
+                                                       o += int64(uint64(Symaddr(rs)) - (rs.Sect.(*Section)).Vaddr)
+                                               }
+                                               o -= int64(r.Off) // relative to section offset, not symbol
+                                       } else {
+                                               o += int64(r.Siz)
+                                       }
+                               } else {
+                                       Diag("unhandled pcrel relocation for %s", headstring)
+                               }
+
+                               break
+                       }
+
+                       o = 0
+                       if r.Sym != nil {
+                               o += Symaddr(r.Sym)
+                       }
+
+                       // NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c
+                       // compiler. The expression s->value + r->off + r->siz is int32 + int32 +
+                       // uchar, and Plan 9 8c incorrectly treats the expression as type uint32
+                       // instead of int32, causing incorrect values when sign extended for adding
+                       // to o. The bug only occurs on Plan 9, because this C program is compiled by
+                       // the standard host compiler (gcc on most other systems).
+                       o += r.Add - (s.Value + int64(r.Off) + int64(int32(r.Siz)))
+
+               case R_SIZE:
+                       o = r.Sym.Size + r.Add
+               }
+
+               if r.Variant != RV_NONE {
+                       o = Thearch.Archrelocvariant(r, s, o)
+               }
+
+               //print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "<nil>", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o);
+               switch siz {
+               default:
+                       Ctxt.Cursym = s
+                       Diag("bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
+                       fallthrough
+
+                       // TODO(rsc): Remove.
+               case 1:
+                       s.P[off] = byte(int8(o))
+
+               case 2:
+                       if o != int64(int16(o)) {
+                               Diag("relocation address is too big: %#x", o)
+                       }
+                       i16 = int16(o)
+                       Ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
+
+               case 4:
+                       if r.Type == R_PCREL || r.Type == R_CALL {
+                               if o != int64(int32(o)) {
+                                       Diag("pc-relative relocation address is too big: %#x", o)
+                               }
+                       } else {
+                               if o != int64(int32(o)) && o != int64(uint32(o)) {
+                                       Diag("non-pc-relative relocation address is too big: %#x", uint64(o))
+                               }
+                       }
+
+                       fl = int32(o)
+                       Ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
+
+               case 8:
+                       Ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
+               }
+       }
+}
+
+func reloc() {
+       var s *LSym
+
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
+       }
+       Bflush(&Bso)
+
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               relocsym(s)
+       }
+       for s = datap; s != nil; s = s.Next {
+               relocsym(s)
+       }
+}
+
+func dynrelocsym(s *LSym) {
+       var ri int
+       var r *Reloc
+
+       if HEADTYPE == Hwindows {
+               var rel *LSym
+               var targ *LSym
+
+               rel = Linklookup(Ctxt, ".rel", 0)
+               if s == rel {
+                       return
+               }
+               for ri = 0; ri < len(s.R); ri++ {
+                       r = &s.R[ri]
+                       targ = r.Sym
+                       if targ == nil {
+                               continue
+                       }
+                       if !targ.Reachable {
+                               Diag("internal inconsistency: dynamic symbol %s is not reachable.", targ.Name)
+                       }
+                       if r.Sym.Plt == -2 && r.Sym.Got != -2 { // make dynimport JMP table for PE object files.
+                               targ.Plt = int32(rel.Size)
+                               r.Sym = rel
+                               r.Add = int64(targ.Plt)
+
+                               // jmp *addr
+                               if Thearch.Thechar == '8' {
+                                       Adduint8(Ctxt, rel, 0xff)
+                                       Adduint8(Ctxt, rel, 0x25)
+                                       Addaddr(Ctxt, rel, targ)
+                                       Adduint8(Ctxt, rel, 0x90)
+                                       Adduint8(Ctxt, rel, 0x90)
+                               } else {
+                                       Adduint8(Ctxt, rel, 0xff)
+                                       Adduint8(Ctxt, rel, 0x24)
+                                       Adduint8(Ctxt, rel, 0x25)
+                                       addaddrplus4(Ctxt, rel, targ, 0)
+                                       Adduint8(Ctxt, rel, 0x90)
+                               }
+                       } else if r.Sym.Plt >= 0 {
+                               r.Sym = rel
+                               r.Add = int64(targ.Plt)
+                       }
+               }
+
+               return
+       }
+
+       for ri = 0; ri < len(s.R); ri++ {
+               r = &s.R[ri]
+               if r.Sym != nil && r.Sym.Type == SDYNIMPORT || r.Type >= 256 {
+                       if r.Sym != nil && !r.Sym.Reachable {
+                               Diag("internal inconsistency: dynamic symbol %s is not reachable.", r.Sym.Name)
+                       }
+                       Thearch.Adddynrel(s, r)
+               }
+       }
+}
+
+func dynreloc() {
+       var s *LSym
+
+       // -d suppresses dynamic loader format, so we may as well not
+       // compute these sections or mark their symbols as reachable.
+       if Debug['d'] != 0 && HEADTYPE != Hwindows {
+               return
+       }
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
+       }
+       Bflush(&Bso)
+
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               dynrelocsym(s)
+       }
+       for s = datap; s != nil; s = s.Next {
+               dynrelocsym(s)
+       }
+       if Iself {
+               elfdynhash()
+       }
+}
+
+func blk(start *LSym, addr int64, size int64) {
+       var sym *LSym
+       var eaddr int64
+       var p []byte
+       var ep []byte
+
+       for sym = start; sym != nil; sym = sym.Next {
+               if sym.Type&SSUB == 0 && sym.Value >= addr {
+                       break
+               }
+       }
+
+       eaddr = addr + size
+       for ; sym != nil; sym = sym.Next {
+               if sym.Type&SSUB != 0 {
+                       continue
+               }
+               if sym.Value >= eaddr {
+                       break
+               }
+               Ctxt.Cursym = sym
+               if sym.Value < addr {
+                       Diag("phase error: addr=%#x but sym=%#x type=%d", int64(addr), int64(sym.Value), sym.Type)
+                       Errorexit()
+               }
+
+               for ; addr < sym.Value; addr++ {
+                       Cput(0)
+               }
+               p = sym.P
+               ep = p[len(sym.P):]
+               for -cap(p) < -cap(ep) {
+                       Cput(uint8(p[0]))
+                       p = p[1:]
+               }
+               addr += int64(len(sym.P))
+               for ; addr < sym.Value+sym.Size; addr++ {
+                       Cput(0)
+               }
+               if addr != sym.Value+sym.Size {
+                       Diag("phase error: addr=%#x value+size=%#x", int64(addr), int64(sym.Value)+sym.Size)
+                       Errorexit()
+               }
+
+               if sym.Value+sym.Size >= eaddr {
+                       break
+               }
+       }
+
+       for ; addr < eaddr; addr++ {
+               Cput(0)
+       }
+       Cflush()
+}
+
+func Codeblk(addr int64, size int64) {
+       var sym *LSym
+       var eaddr int64
+       var n int64
+       var q []byte
+
+       if Debug['a'] != 0 {
+               fmt.Fprintf(&Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+       }
+
+       blk(Ctxt.Textp, addr, size)
+
+       /* again for printing */
+       if Debug['a'] == 0 {
+               return
+       }
+
+       for sym = Ctxt.Textp; sym != nil; sym = sym.Next {
+               if !sym.Reachable {
+                       continue
+               }
+               if sym.Value >= addr {
+                       break
+               }
+       }
+
+       eaddr = addr + size
+       for ; sym != nil; sym = sym.Next {
+               if !sym.Reachable {
+                       continue
+               }
+               if sym.Value >= eaddr {
+                       break
+               }
+
+               if addr < sym.Value {
+                       fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr)))
+                       for ; addr < sym.Value; addr++ {
+                               fmt.Fprintf(&Bso, " %.2x", 0)
+                       }
+                       fmt.Fprintf(&Bso, "\n")
+               }
+
+               fmt.Fprintf(&Bso, "%.6x\t%-20s\n", uint64(int64(addr)), sym.Name)
+               n = sym.Size
+               q = sym.P
+
+               for n >= 16 {
+                       fmt.Fprintf(&Bso, "%.6x\t%%-20.16I\n", uint64(addr), q)
+                       addr += 16
+                       q = q[16:]
+                       n -= 16
+               }
+
+               if n > 0 {
+                       fmt.Fprintf(&Bso, "%.6x\t%%-20.*I\n", uint64(addr), int(n), q)
+               }
+               addr += n
+       }
+
+       if addr < eaddr {
+               fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr)))
+               for ; addr < eaddr; addr++ {
+                       fmt.Fprintf(&Bso, " %.2x", 0)
+               }
+       }
+
+       Bflush(&Bso)
+}
+
+func Datblk(addr int64, size int64) {
+       var sym *LSym
+       var i int64
+       var eaddr int64
+       var p []byte
+       var ep []byte
+       var typ string
+       var rsname string
+       var r *Reloc
+
+       if Debug['a'] != 0 {
+               fmt.Fprintf(&Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+       }
+
+       blk(datap, addr, size)
+
+       /* again for printing */
+       if Debug['a'] == 0 {
+               return
+       }
+
+       for sym = datap; sym != nil; sym = sym.Next {
+               if sym.Value >= addr {
+                       break
+               }
+       }
+
+       eaddr = addr + size
+       for ; sym != nil; sym = sym.Next {
+               if sym.Value >= eaddr {
+                       break
+               }
+               if addr < sym.Value {
+                       fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint64(addr))
+                       addr = sym.Value
+               }
+
+               fmt.Fprintf(&Bso, "%s\n\t%.8x|", sym.Name, uint(addr))
+               p = sym.P
+               ep = p[len(sym.P):]
+               for -cap(p) < -cap(ep) {
+                       if -cap(p) > -cap(sym.P) && int(-cap(p)+cap(sym.P))%16 == 0 {
+                               fmt.Fprintf(&Bso, "\n\t%.8x|", uint(addr+int64(-cap(p)+cap(sym.P))))
+                       }
+                       fmt.Fprintf(&Bso, " %.2x", p[0])
+                       p = p[1:]
+               }
+
+               addr += int64(len(sym.P))
+               for ; addr < sym.Value+sym.Size; addr++ {
+                       fmt.Fprintf(&Bso, " %.2x", 0)
+               }
+               fmt.Fprintf(&Bso, "\n")
+
+               if Linkmode == LinkExternal {
+                       for i = 0; i < int64(len(sym.R)); i++ {
+                               r = &sym.R[i]
+                               rsname = ""
+                               if r.Sym != nil {
+                                       rsname = r.Sym.Name
+                               }
+                               typ = "?"
+                               switch r.Type {
+                               case R_ADDR:
+                                       typ = "addr"
+
+                               case R_PCREL:
+                                       typ = "pcrel"
+
+                               case R_CALL:
+                                       typ = "call"
+                               }
+
+                               fmt.Fprintf(&Bso, "\treloc %.8x/%d %s %s+%#x [%#x]\n", uint(sym.Value+int64(r.Off)), r.Siz, typ, rsname, int64(r.Add), int64(r.Sym.Value+r.Add))
+                       }
+               }
+       }
+
+       if addr < eaddr {
+               fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint(addr))
+       }
+       fmt.Fprintf(&Bso, "\t%.8x|\n", uint(eaddr))
+}
+
+func strnput(s string, n int) {
+       for ; n > 0 && s != ""; s = s[1:] {
+               Cput(uint8(s[0]))
+               n--
+       }
+
+       for n > 0 {
+               Cput(0)
+               n--
+       }
+}
+
+var addstrdata_name string
+
+func addstrdata1(arg string) {
+       if strings.HasPrefix(arg, "VALUE:") {
+               addstrdata(addstrdata_name, arg[6:])
+       } else {
+               addstrdata_name = arg
+       }
+}
+
+func addstrdata(name string, value string) {
+       var s *LSym
+       var sp *LSym
+       var p string
+       var reachable bool
+
+       p = fmt.Sprintf("%s.str", name)
+       sp = Linklookup(Ctxt, p, 0)
+
+       Addstring(sp, value)
+       sp.Type = SRODATA
+
+       s = Linklookup(Ctxt, name, 0)
+       s.Size = 0
+       s.Dupok = 1
+       reachable = s.Reachable
+       Addaddr(Ctxt, s, sp)
+       adduintxx(Ctxt, s, uint64(len(value)), Thearch.Ptrsize)
+
+       // addstring, addaddr, etc., mark the symbols as reachable.
+       // In this case that is not necessarily true, so stick to what
+       // we know before entering this function.
+       s.Reachable = reachable
+
+       sp.Reachable = reachable
+}
+
+func Addstring(s *LSym, str string) int64 {
+       var n int
+       var r int32
+
+       if s.Type == 0 {
+               s.Type = SNOPTRDATA
+       }
+       s.Reachable = true
+       r = int32(s.Size)
+       n = len(str) + 1
+       if s.Name == ".shstrtab" {
+               elfsetstring(str, int(r))
+       }
+       Symgrow(Ctxt, s, int64(r)+int64(n))
+       copy(s.P[r:], str)
+       s.P[int(r)+len(str)] = 0
+       s.Size += int64(n)
+       return int64(r)
+}
+
+func dosymtype() {
+       var s *LSym
+
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if len(s.P) > 0 {
+                       if s.Type == SBSS {
+                               s.Type = SDATA
+                       }
+                       if s.Type == SNOPTRBSS {
+                               s.Type = SNOPTRDATA
+                       }
+               }
+       }
+}
+
+func symalign(s *LSym) int32 {
+       var align int32
+
+       if s.Align != 0 {
+               return s.Align
+       }
+
+       align = int32(Thearch.Maxalign)
+       for int64(align) > s.Size && align > 1 {
+               align >>= 1
+       }
+       if align < s.Align {
+               align = s.Align
+       }
+       return align
+}
+
+func aligndatsize(datsize int64, s *LSym) int64 {
+       return Rnd(datsize, int64(symalign(s)))
+}
+
+// maxalign returns the maximum required alignment for
+// the list of symbols s; the list stops when s->type exceeds type.
+func maxalign(s *LSym, type_ int) int32 {
+       var align int32
+       var max int32
+
+       max = 0
+       for ; s != nil && int(s.Type) <= type_; s = s.Next {
+               align = symalign(s)
+               if max < align {
+                       max = align
+               }
+       }
+
+       return max
+}
+
+// Helper object for building GC type programs.
+type ProgGen struct {
+       s        *LSym
+       datasize int32
+       data     [256 / obj.PointersPerByte]uint8
+       pos      int64
+}
+
+func proggeninit(g *ProgGen, s *LSym) {
+       g.s = s
+       g.datasize = 0
+       g.pos = 0
+       g.data = [256 / obj.PointersPerByte]uint8{}
+}
+
+func proggenemit(g *ProgGen, v uint8) {
+       Adduint8(Ctxt, g.s, v)
+}
+
+// Writes insData block from g->data.
+func proggendataflush(g *ProgGen) {
+       var i int32
+       var s int32
+
+       if g.datasize == 0 {
+               return
+       }
+       proggenemit(g, obj.InsData)
+       proggenemit(g, uint8(g.datasize))
+       s = (g.datasize + obj.PointersPerByte - 1) / obj.PointersPerByte
+       for i = 0; i < s; i++ {
+               proggenemit(g, g.data[i])
+       }
+       g.datasize = 0
+       g.data = [256 / obj.PointersPerByte]uint8{}
+}
+
+func proggendata(g *ProgGen, d uint8) {
+       g.data[g.datasize/obj.PointersPerByte] |= d << uint((g.datasize%obj.PointersPerByte)*obj.BitsPerPointer)
+       g.datasize++
+       if g.datasize == 255 {
+               proggendataflush(g)
+       }
+}
+
+// Skip v bytes due to alignment, etc.
+func proggenskip(g *ProgGen, off int64, v int64) {
+       var i int64
+
+       for i = off; i < off+v; i++ {
+               if (i % int64(Thearch.Ptrsize)) == 0 {
+                       proggendata(g, obj.BitsScalar)
+               }
+       }
+}
+
+// Emit insArray instruction.
+func proggenarray(g *ProgGen, length int64) {
+       var i int32
+
+       proggendataflush(g)
+       proggenemit(g, obj.InsArray)
+       for i = 0; i < int32(Thearch.Ptrsize); (func() { i++; length >>= 8 })() {
+               proggenemit(g, uint8(length))
+       }
+}
+
+func proggenarrayend(g *ProgGen) {
+       proggendataflush(g)
+       proggenemit(g, obj.InsArrayEnd)
+}
+
+func proggenfini(g *ProgGen, size int64) {
+       proggenskip(g, g.pos, size-g.pos)
+       proggendataflush(g)
+       proggenemit(g, obj.InsEnd)
+}
+
+// This function generates GC pointer info for global variables.
+func proggenaddsym(g *ProgGen, s *LSym) {
+       var gcprog *LSym
+       var mask []byte
+       var i int64
+       var size int64
+
+       if s.Size == 0 {
+               return
+       }
+
+       // Skip alignment hole from the previous symbol.
+       proggenskip(g, g.pos, s.Value-g.pos)
+
+       g.pos += s.Value - g.pos
+
+       // The test for names beginning with . here is meant
+       // to keep .dynamic and .dynsym from turning up as
+       // conservative symbols. They should be marked SELFSECT
+       // and not SDATA, but sometimes that doesn't happen.
+       // Leave debugging the SDATA issue for the Go rewrite.
+
+       if s.Gotype == nil && s.Size >= int64(Thearch.Ptrsize) && s.Name[0] != '.' {
+               // conservative scan
+               Diag("missing Go type information for global symbol: %s size %d", s.Name, int(s.Size))
+
+               if (s.Size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
+                       Diag("proggenaddsym: unaligned conservative symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
+               }
+               size = (s.Size + int64(Thearch.Ptrsize) - 1) / int64(Thearch.Ptrsize) * int64(Thearch.Ptrsize)
+               if size < int64(32*Thearch.Ptrsize) {
+                       // Emit small symbols as data.
+                       for i = 0; i < size/int64(Thearch.Ptrsize); i++ {
+                               proggendata(g, obj.BitsPointer)
+                       }
+               } else {
+                       // Emit large symbols as array.
+                       proggenarray(g, size/int64(Thearch.Ptrsize))
+
+                       proggendata(g, obj.BitsPointer)
+                       proggenarrayend(g)
+               }
+
+               g.pos = s.Value + size
+       } else if s.Gotype == nil || decodetype_noptr(s.Gotype) != 0 || s.Size < int64(Thearch.Ptrsize) || s.Name[0] == '.' {
+               // no scan
+               if s.Size < int64(32*Thearch.Ptrsize) {
+                       // Emit small symbols as data.
+                       // This case also handles unaligned and tiny symbols, so tread carefully.
+                       for i = s.Value; i < s.Value+s.Size; i++ {
+                               if (i % int64(Thearch.Ptrsize)) == 0 {
+                                       proggendata(g, obj.BitsScalar)
+                               }
+                       }
+               } else {
+                       // Emit large symbols as array.
+                       if (s.Size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
+                               Diag("proggenaddsym: unaligned noscan symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
+                       }
+                       proggenarray(g, s.Size/int64(Thearch.Ptrsize))
+                       proggendata(g, obj.BitsScalar)
+                       proggenarrayend(g)
+               }
+
+               g.pos = s.Value + s.Size
+       } else if decodetype_usegcprog(s.Gotype) != 0 {
+               // gc program, copy directly
+               proggendataflush(g)
+
+               gcprog = decodetype_gcprog(s.Gotype)
+               size = decodetype_size(s.Gotype)
+               if (size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
+                       Diag("proggenaddsym: unaligned gcprog symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
+               }
+               for i = 0; i < int64(len(gcprog.P)-1); i++ {
+                       proggenemit(g, uint8(gcprog.P[i]))
+               }
+               g.pos = s.Value + size
+       } else {
+               // gc mask, it's small so emit as data
+               mask = decodetype_gcmask(s.Gotype)
+
+               size = decodetype_size(s.Gotype)
+               if (size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
+                       Diag("proggenaddsym: unaligned gcmask symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
+               }
+               for i = 0; i < size; i += int64(Thearch.Ptrsize) {
+                       proggendata(g, uint8((mask[i/int64(Thearch.Ptrsize)/2]>>uint64((i/int64(Thearch.Ptrsize)%2)*4+2))&obj.BitsMask))
+               }
+               g.pos = s.Value + size
+       }
+}
+
+func growdatsize(datsizep *int64, s *LSym) {
+       var datsize int64
+
+       datsize = *datsizep
+       if s.Size < 0 {
+               Diag("negative size (datsize = %d, s->size = %d)", datsize, s.Size)
+       }
+       if datsize+s.Size < datsize {
+               Diag("symbol too large (datsize = %d, s->size = %d)", datsize, s.Size)
+       }
+       *datsizep = datsize + s.Size
+}
+
+func dodata() {
+       var n int32
+       var datsize int64
+       var sect *Section
+       var segro *Segment
+       var s *LSym
+       var last *LSym
+       var l **LSym
+       var toc *LSym
+       var gcdata *LSym
+       var gcbss *LSym
+       var gen ProgGen
+
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "%5.2f dodata\n", obj.Cputime())
+       }
+       Bflush(&Bso)
+
+       last = nil
+       datap = nil
+
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if !s.Reachable || s.Special != 0 {
+                       continue
+               }
+               if STEXT < s.Type && s.Type < SXREF {
+                       if s.Onlist != 0 {
+                               log.Fatalf("symbol %s listed multiple times", s.Name)
+                       }
+                       s.Onlist = 1
+                       if last == nil {
+                               datap = s
+                       } else {
+                               last.Next = s
+                       }
+                       s.Next = nil
+                       last = s
+               }
+       }
+
+       for s = datap; s != nil; s = s.Next {
+               if int64(len(s.P)) > s.Size {
+                       Diag("%s: initialize bounds (%d < %d)", s.Name, int64(s.Size), len(s.P))
+               }
+       }
+
+       /*
+        * now that we have the datap list, but before we start
+        * to assign addresses, record all the necessary
+        * dynamic relocations.  these will grow the relocation
+        * symbol, which is itself data.
+        *
+        * on darwin, we need the symbol table numbers for dynreloc.
+        */
+       if HEADTYPE == Hdarwin {
+               machosymorder()
+       }
+       dynreloc()
+
+       /* some symbols may no longer belong in datap (Mach-O) */
+       for l = &datap; ; {
+               s = *l
+               if s == nil {
+                       break
+               }
+
+               if s.Type <= STEXT || SXREF <= s.Type {
+                       *l = s.Next
+               } else {
+                       l = &s.Next
+               }
+       }
+
+       *l = nil
+
+       datap = listsort(datap, datcmp, listnextp)
+
+       /*
+        * allocate sections.  list is sorted by type,
+        * so we can just walk it for each piece we want to emit.
+        * segdata is processed before segtext, because we need
+        * to see all symbols in the .data and .bss sections in order
+        * to generate garbage collection information.
+        */
+
+       /* begin segdata */
+
+       /* skip symbols belonging to segtext */
+       s = datap
+
+       for ; s != nil && s.Type < SELFSECT; s = s.Next {
+       }
+
+       /* writable ELF sections */
+       datsize = 0
+
+       for ; s != nil && s.Type < SELFGOT; s = s.Next {
+               sect = addsection(&Segdata, s.Name, 06)
+               sect.Align = symalign(s)
+               datsize = Rnd(datsize, int64(sect.Align))
+               sect.Vaddr = uint64(datsize)
+               s.Sect = sect
+               s.Type = SDATA
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+               sect.Length = uint64(datsize) - sect.Vaddr
+       }
+
+       /* .got (and .toc on ppc64) */
+       if s.Type == SELFGOT {
+               sect = addsection(&Segdata, ".got", 06)
+               sect.Align = maxalign(s, SELFGOT)
+               datsize = Rnd(datsize, int64(sect.Align))
+               sect.Vaddr = uint64(datsize)
+               for ; s != nil && s.Type == SELFGOT; s = s.Next {
+                       datsize = aligndatsize(datsize, s)
+                       s.Sect = sect
+                       s.Type = SDATA
+                       s.Value = int64(uint64(datsize) - sect.Vaddr)
+
+                       // Resolve .TOC. symbol for this object file (ppc64)
+                       toc = Linkrlookup(Ctxt, ".TOC.", int(s.Version))
+
+                       if toc != nil {
+                               toc.Sect = sect
+                               toc.Outer = s
+                               toc.Sub = s.Sub
+                               s.Sub = toc
+
+                               toc.Value = 0x8000
+                       }
+
+                       growdatsize(&datsize, s)
+               }
+
+               sect.Length = uint64(datsize) - sect.Vaddr
+       }
+
+       /* pointer-free data */
+       sect = addsection(&Segdata, ".noptrdata", 06)
+
+       sect.Align = maxalign(s, SINITARR-1)
+       datsize = Rnd(datsize, int64(sect.Align))
+       sect.Vaddr = uint64(datsize)
+       Linklookup(Ctxt, "runtime.noptrdata", 0).Sect = sect
+       Linklookup(Ctxt, "runtime.enoptrdata", 0).Sect = sect
+       for ; s != nil && s.Type < SINITARR; s = s.Next {
+               datsize = aligndatsize(datsize, s)
+               s.Sect = sect
+               s.Type = SDATA
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+       }
+
+       sect.Length = uint64(datsize) - sect.Vaddr
+
+       /* shared library initializer */
+       if Flag_shared != 0 {
+               sect = addsection(&Segdata, ".init_array", 06)
+               sect.Align = maxalign(s, SINITARR)
+               datsize = Rnd(datsize, int64(sect.Align))
+               sect.Vaddr = uint64(datsize)
+               for ; s != nil && s.Type == SINITARR; s = s.Next {
+                       datsize = aligndatsize(datsize, s)
+                       s.Sect = sect
+                       s.Value = int64(uint64(datsize) - sect.Vaddr)
+                       growdatsize(&datsize, s)
+               }
+
+               sect.Length = uint64(datsize) - sect.Vaddr
+       }
+
+       /* data */
+       sect = addsection(&Segdata, ".data", 06)
+
+       sect.Align = maxalign(s, SBSS-1)
+       datsize = Rnd(datsize, int64(sect.Align))
+       sect.Vaddr = uint64(datsize)
+       Linklookup(Ctxt, "runtime.data", 0).Sect = sect
+       Linklookup(Ctxt, "runtime.edata", 0).Sect = sect
+       gcdata = Linklookup(Ctxt, "runtime.gcdata", 0)
+       proggeninit(&gen, gcdata)
+       for ; s != nil && s.Type < SBSS; s = s.Next {
+               if s.Type == SINITARR {
+                       Ctxt.Cursym = s
+                       Diag("unexpected symbol type %d", s.Type)
+               }
+
+               s.Sect = sect
+               s.Type = SDATA
+               datsize = aligndatsize(datsize, s)
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               proggenaddsym(&gen, s) // gc
+               growdatsize(&datsize, s)
+       }
+
+       sect.Length = uint64(datsize) - sect.Vaddr
+       proggenfini(&gen, int64(sect.Length)) // gc
+
+       /* bss */
+       sect = addsection(&Segdata, ".bss", 06)
+
+       sect.Align = maxalign(s, SNOPTRBSS-1)
+       datsize = Rnd(datsize, int64(sect.Align))
+       sect.Vaddr = uint64(datsize)
+       Linklookup(Ctxt, "runtime.bss", 0).Sect = sect
+       Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect
+       gcbss = Linklookup(Ctxt, "runtime.gcbss", 0)
+       proggeninit(&gen, gcbss)
+       for ; s != nil && s.Type < SNOPTRBSS; s = s.Next {
+               s.Sect = sect
+               datsize = aligndatsize(datsize, s)
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               proggenaddsym(&gen, s) // gc
+               growdatsize(&datsize, s)
+       }
+
+       sect.Length = uint64(datsize) - sect.Vaddr
+       proggenfini(&gen, int64(sect.Length)) // gc
+
+       /* pointer-free bss */
+       sect = addsection(&Segdata, ".noptrbss", 06)
+
+       sect.Align = maxalign(s, SNOPTRBSS)
+       datsize = Rnd(datsize, int64(sect.Align))
+       sect.Vaddr = uint64(datsize)
+       Linklookup(Ctxt, "runtime.noptrbss", 0).Sect = sect
+       Linklookup(Ctxt, "runtime.enoptrbss", 0).Sect = sect
+       for ; s != nil && s.Type == SNOPTRBSS; s = s.Next {
+               datsize = aligndatsize(datsize, s)
+               s.Sect = sect
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+       }
+
+       sect.Length = uint64(datsize) - sect.Vaddr
+       Linklookup(Ctxt, "runtime.end", 0).Sect = sect
+
+       // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
+       if datsize != int64(uint32(datsize)) {
+               Diag("data or bss segment too large")
+       }
+
+       if Iself && Linkmode == LinkExternal && s != nil && s.Type == STLSBSS && HEADTYPE != Hopenbsd {
+               sect = addsection(&Segdata, ".tbss", 06)
+               sect.Align = int32(Thearch.Ptrsize)
+               sect.Vaddr = 0
+               datsize = 0
+               for ; s != nil && s.Type == STLSBSS; s = s.Next {
+                       datsize = aligndatsize(datsize, s)
+                       s.Sect = sect
+                       s.Value = int64(uint64(datsize) - sect.Vaddr)
+                       growdatsize(&datsize, s)
+               }
+
+               sect.Length = uint64(datsize)
+       } else {
+               // Might be internal linking but still using cgo.
+               // In that case, the only possible STLSBSS symbol is runtime.tlsg.
+               // Give it offset 0, because it's the only thing here.
+               if s != nil && s.Type == STLSBSS && s.Name == "runtime.tlsg" {
+                       s.Value = 0
+                       s = s.Next
+               }
+       }
+
+       if s != nil {
+               Ctxt.Cursym = nil
+               Diag("unexpected symbol type %d for %s", s.Type, s.Name)
+       }
+
+       /*
+        * We finished data, begin read-only data.
+        * Not all systems support a separate read-only non-executable data section.
+        * ELF systems do.
+        * OS X and Plan 9 do not.
+        * Windows PE may, but if so we have not implemented it.
+        * And if we're using external linking mode, the point is moot,
+        * since it's not our decision; that code expects the sections in
+        * segtext.
+        */
+       if Iself && Linkmode == LinkInternal {
+               segro = &Segrodata
+       } else {
+               segro = &Segtext
+       }
+
+       s = datap
+
+       datsize = 0
+
+       /* read-only executable ELF, Mach-O sections */
+       for ; s != nil && s.Type < STYPE; s = s.Next {
+               sect = addsection(&Segtext, s.Name, 04)
+               sect.Align = symalign(s)
+               datsize = Rnd(datsize, int64(sect.Align))
+               sect.Vaddr = uint64(datsize)
+               s.Sect = sect
+               s.Type = SRODATA
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+               sect.Length = uint64(datsize) - sect.Vaddr
+       }
+
+       /* read-only data */
+       sect = addsection(segro, ".rodata", 04)
+
+       sect.Align = maxalign(s, STYPELINK-1)
+       datsize = Rnd(datsize, int64(sect.Align))
+       sect.Vaddr = 0
+       Linklookup(Ctxt, "runtime.rodata", 0).Sect = sect
+       Linklookup(Ctxt, "runtime.erodata", 0).Sect = sect
+       for ; s != nil && s.Type < STYPELINK; s = s.Next {
+               datsize = aligndatsize(datsize, s)
+               s.Sect = sect
+               s.Type = SRODATA
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+       }
+
+       sect.Length = uint64(datsize) - sect.Vaddr
+
+       /* typelink */
+       sect = addsection(segro, ".typelink", 04)
+
+       sect.Align = maxalign(s, STYPELINK)
+       datsize = Rnd(datsize, int64(sect.Align))
+       sect.Vaddr = uint64(datsize)
+       Linklookup(Ctxt, "runtime.typelink", 0).Sect = sect
+       Linklookup(Ctxt, "runtime.etypelink", 0).Sect = sect
+       for ; s != nil && s.Type == STYPELINK; s = s.Next {
+               datsize = aligndatsize(datsize, s)
+               s.Sect = sect
+               s.Type = SRODATA
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+       }
+
+       sect.Length = uint64(datsize) - sect.Vaddr
+
+       /* gosymtab */
+       sect = addsection(segro, ".gosymtab", 04)
+
+       sect.Align = maxalign(s, SPCLNTAB-1)
+       datsize = Rnd(datsize, int64(sect.Align))
+       sect.Vaddr = uint64(datsize)
+       Linklookup(Ctxt, "runtime.symtab", 0).Sect = sect
+       Linklookup(Ctxt, "runtime.esymtab", 0).Sect = sect
+       for ; s != nil && s.Type < SPCLNTAB; s = s.Next {
+               datsize = aligndatsize(datsize, s)
+               s.Sect = sect
+               s.Type = SRODATA
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+       }
+
+       sect.Length = uint64(datsize) - sect.Vaddr
+
+       /* gopclntab */
+       sect = addsection(segro, ".gopclntab", 04)
+
+       sect.Align = maxalign(s, SELFROSECT-1)
+       datsize = Rnd(datsize, int64(sect.Align))
+       sect.Vaddr = uint64(datsize)
+       Linklookup(Ctxt, "runtime.pclntab", 0).Sect = sect
+       Linklookup(Ctxt, "runtime.epclntab", 0).Sect = sect
+       for ; s != nil && s.Type < SELFROSECT; s = s.Next {
+               datsize = aligndatsize(datsize, s)
+               s.Sect = sect
+               s.Type = SRODATA
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+       }
+
+       sect.Length = uint64(datsize) - sect.Vaddr
+
+       /* read-only ELF, Mach-O sections */
+       for ; s != nil && s.Type < SELFSECT; s = s.Next {
+               sect = addsection(segro, s.Name, 04)
+               sect.Align = symalign(s)
+               datsize = Rnd(datsize, int64(sect.Align))
+               sect.Vaddr = uint64(datsize)
+               s.Sect = sect
+               s.Type = SRODATA
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+               sect.Length = uint64(datsize) - sect.Vaddr
+       }
+
+       // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
+       if datsize != int64(uint32(datsize)) {
+               Diag("read-only data segment too large")
+       }
+
+       /* number the sections */
+       n = 1
+
+       for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+               sect.Extnum = int16(n)
+               n++
+       }
+       for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+               sect.Extnum = int16(n)
+               n++
+       }
+       for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+               sect.Extnum = int16(n)
+               n++
+       }
+}
+
+// assign addresses to text
+func textaddress() {
+       var va uint64
+       var sect *Section
+       var sym *LSym
+       var sub *LSym
+
+       addsection(&Segtext, ".text", 05)
+
+       // Assign PCs in text segment.
+       // Could parallelize, by assigning to text
+       // and then letting threads copy down, but probably not worth it.
+       sect = Segtext.Sect
+
+       sect.Align = int32(Funcalign)
+       Linklookup(Ctxt, "runtime.text", 0).Sect = sect
+       Linklookup(Ctxt, "runtime.etext", 0).Sect = sect
+       va = uint64(INITTEXT)
+       sect.Vaddr = va
+       for sym = Ctxt.Textp; sym != nil; sym = sym.Next {
+               sym.Sect = sect
+               if sym.Type&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)
+               }
+               if sym.Size == 0 && sym.Sub != nil {
+                       Ctxt.Cursym = sym
+               }
+               if sym.Size < MINFUNC {
+                       va += MINFUNC // spacing required for findfunctab
+               } else {
+                       va += uint64(sym.Size)
+               }
+       }
+
+       sect.Length = va - sect.Vaddr
+}
+
+// assign addresses
+func address() {
+       var s *Section
+       var text *Section
+       var data *Section
+       var rodata *Section
+       var symtab *Section
+       var pclntab *Section
+       var noptr *Section
+       var bss *Section
+       var noptrbss *Section
+       var typelink *Section
+       var sym *LSym
+       var sub *LSym
+       var va uint64
+       var vlen int64
+
+       va = uint64(INITTEXT)
+       Segtext.Rwx = 05
+       Segtext.Vaddr = va
+       Segtext.Fileoff = uint64(HEADR)
+       for s = Segtext.Sect; s != nil; s = s.Next {
+               va = uint64(Rnd(int64(va), int64(s.Align)))
+               s.Vaddr = va
+               va += s.Length
+       }
+
+       Segtext.Length = va - uint64(INITTEXT)
+       Segtext.Filelen = Segtext.Length
+       if HEADTYPE == Hnacl {
+               va += 32 // room for the "halt sled"
+       }
+
+       if Segrodata.Sect != nil {
+               // align to page boundary so as not to mix
+               // rodata and executable text.
+               va = uint64(Rnd(int64(va), int64(INITRND)))
+
+               Segrodata.Rwx = 04
+               Segrodata.Vaddr = va
+               Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
+               Segrodata.Filelen = 0
+               for s = Segrodata.Sect; s != nil; s = s.Next {
+                       va = uint64(Rnd(int64(va), int64(s.Align)))
+                       s.Vaddr = va
+                       va += s.Length
+               }
+
+               Segrodata.Length = va - Segrodata.Vaddr
+               Segrodata.Filelen = Segrodata.Length
+       }
+
+       va = uint64(Rnd(int64(va), int64(INITRND)))
+       Segdata.Rwx = 06
+       Segdata.Vaddr = va
+       Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
+       Segdata.Filelen = 0
+       if HEADTYPE == Hwindows {
+               Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
+       }
+       if HEADTYPE == Hplan9 {
+               Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
+       }
+       data = nil
+       noptr = nil
+       bss = nil
+       noptrbss = nil
+       for s = Segdata.Sect; s != nil; s = s.Next {
+               vlen = int64(s.Length)
+               if s.Next != nil {
+                       vlen = int64(s.Next.Vaddr - s.Vaddr)
+               }
+               s.Vaddr = va
+               va += uint64(vlen)
+               Segdata.Length = va - Segdata.Vaddr
+               if s.Name == ".data" {
+                       data = s
+               }
+               if s.Name == ".noptrdata" {
+                       noptr = s
+               }
+               if s.Name == ".bss" {
+                       bss = s
+               }
+               if s.Name == ".noptrbss" {
+                       noptrbss = s
+               }
+       }
+
+       Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
+
+       text = Segtext.Sect
+       if Segrodata.Sect != nil {
+               rodata = Segrodata.Sect
+       } else {
+               rodata = text.Next
+       }
+       typelink = rodata.Next
+       symtab = typelink.Next
+       pclntab = symtab.Next
+
+       for sym = datap; sym != nil; sym = sym.Next {
+               Ctxt.Cursym = sym
+               if sym.Sect != nil {
+                       sym.Value += int64((sym.Sect.(*Section)).Vaddr)
+               }
+               for sub = sym.Sub; sub != nil; sub = sub.Sub {
+                       sub.Value += sym.Value
+               }
+       }
+
+       xdefine("runtime.text", STEXT, int64(text.Vaddr))
+       xdefine("runtime.etext", STEXT, int64(text.Vaddr+text.Length))
+       xdefine("runtime.rodata", SRODATA, int64(rodata.Vaddr))
+       xdefine("runtime.erodata", SRODATA, int64(rodata.Vaddr+rodata.Length))
+       xdefine("runtime.typelink", SRODATA, int64(typelink.Vaddr))
+       xdefine("runtime.etypelink", SRODATA, int64(typelink.Vaddr+typelink.Length))
+
+       sym = Linklookup(Ctxt, "runtime.gcdata", 0)
+       xdefine("runtime.egcdata", SRODATA, Symaddr(sym)+sym.Size)
+       Linklookup(Ctxt, "runtime.egcdata", 0).Sect = sym.Sect
+
+       sym = Linklookup(Ctxt, "runtime.gcbss", 0)
+       xdefine("runtime.egcbss", SRODATA, Symaddr(sym)+sym.Size)
+       Linklookup(Ctxt, "runtime.egcbss", 0).Sect = sym.Sect
+
+       xdefine("runtime.symtab", SRODATA, int64(symtab.Vaddr))
+       xdefine("runtime.esymtab", SRODATA, int64(symtab.Vaddr+symtab.Length))
+       xdefine("runtime.pclntab", SRODATA, int64(pclntab.Vaddr))
+       xdefine("runtime.epclntab", SRODATA, int64(pclntab.Vaddr+pclntab.Length))
+       xdefine("runtime.noptrdata", SNOPTRDATA, int64(noptr.Vaddr))
+       xdefine("runtime.enoptrdata", SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
+       xdefine("runtime.bss", SBSS, int64(bss.Vaddr))
+       xdefine("runtime.ebss", SBSS, int64(bss.Vaddr+bss.Length))
+       xdefine("runtime.data", SDATA, int64(data.Vaddr))
+       xdefine("runtime.edata", SDATA, int64(data.Vaddr+data.Length))
+       xdefine("runtime.noptrbss", SNOPTRBSS, int64(noptrbss.Vaddr))
+       xdefine("runtime.enoptrbss", SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
+       xdefine("runtime.end", SBSS, int64(Segdata.Vaddr+Segdata.Length))
+}
diff --git a/src/cmd/internal/ld/decodesym.go b/src/cmd/internal/ld/decodesym.go
new file mode 100644 (file)
index 0000000..c7b1a2f
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright 2012 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 ld
+
+import "cmd/internal/obj"
+
+// Decoding the type.* symbols.         This has to be in sync with
+// ../../runtime/type.go, or more specifically, with what
+// ../gc/reflect.c stuffs in these.
+
+func decode_reloc(s *LSym, off int32) *Reloc {
+       var i int
+
+       for i = 0; i < len(s.R); i++ {
+               if s.R[i].Off == off {
+                       return &s.R[i:][0]
+               }
+       }
+       return nil
+}
+
+func decode_reloc_sym(s *LSym, off int32) *LSym {
+       var r *Reloc
+
+       r = decode_reloc(s, off)
+       if r == nil {
+               return nil
+       }
+       return r.Sym
+}
+
+func decode_inuxi(p []byte, sz int) uint64 {
+       switch sz {
+       case 2:
+               return uint64(Ctxt.Arch.ByteOrder.Uint16(p))
+       case 4:
+               return uint64(Ctxt.Arch.ByteOrder.Uint32(p))
+       case 8:
+               return Ctxt.Arch.ByteOrder.Uint64(p)
+       }
+       Diag("dwarf: decode inuxi %d", sz)
+       Errorexit()
+       return 0
+}
+
+func commonsize() int {
+       return 8*Thearch.Ptrsize + 8
+}
+
+// Type.commonType.kind
+func decodetype_kind(s *LSym) uint8 {
+       return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindMask) //  0x13 / 0x1f
+}
+
+// Type.commonType.kind
+func decodetype_noptr(s *LSym) uint8 {
+       return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindNoPointers) //  0x13 / 0x1f
+}
+
+// Type.commonType.kind
+func decodetype_usegcprog(s *LSym) uint8 {
+       return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindGCProg) //  0x13 / 0x1f
+}
+
+// Type.commonType.size
+func decodetype_size(s *LSym) int64 {
+       return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10
+}
+
+// Type.commonType.gc
+func decodetype_gcprog(s *LSym) *LSym {
+       return decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize))
+}
+
+func decodetype_gcmask(s *LSym) []byte {
+       var mask *LSym
+
+       mask = decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
+       return mask.P
+}
+
+// Type.ArrayType.elem and Type.SliceType.Elem
+func decodetype_arrayelem(s *LSym) *LSym {
+       return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+}
+
+func decodetype_arraylen(s *LSym) int64 {
+       return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Ptrsize))
+}
+
+// Type.PtrType.elem
+func decodetype_ptrelem(s *LSym) *LSym {
+       return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+}
+
+// Type.MapType.key, elem
+func decodetype_mapkey(s *LSym) *LSym {
+       return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+}
+
+func decodetype_mapvalue(s *LSym) *LSym {
+       return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)) // 0x20 / 0x38
+}
+
+// Type.ChanType.elem
+func decodetype_chanelem(s *LSym) *LSym {
+       return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+}
+
+// Type.FuncType.dotdotdot
+func decodetype_funcdotdotdot(s *LSym) int {
+       return int(s.P[commonsize()])
+}
+
+// Type.FuncType.in.length
+func decodetype_funcincount(s *LSym) int {
+       return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
+}
+
+func decodetype_funcoutcount(s *LSym) int {
+       return int(decode_inuxi(s.P[commonsize()+3*Thearch.Ptrsize+2*Thearch.Intsize:], Thearch.Intsize))
+}
+
+func decodetype_funcintype(s *LSym, i int) *LSym {
+       var r *Reloc
+
+       r = decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize))
+       if r == nil {
+               return nil
+       }
+       return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
+}
+
+func decodetype_funcouttype(s *LSym, i int) *LSym {
+       var r *Reloc
+
+       r = decode_reloc(s, int32(commonsize())+2*int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize))
+       if r == nil {
+               return nil
+       }
+       return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
+}
+
+// Type.StructType.fields.Slice::length
+func decodetype_structfieldcount(s *LSym) int {
+       return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
+}
+
+func structfieldsize() int {
+       return 5 * Thearch.Ptrsize
+}
+
+// Type.StructType.fields[]-> name, typ and offset.
+func decodetype_structfieldname(s *LSym, i int) string {
+       var r *Reloc
+
+       // go.string."foo"  0x28 / 0x40
+       s = decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize()))
+
+       if s == nil { // embedded structs have a nil name.
+               return ""
+       }
+       r = decode_reloc(s, 0) // s has a pointer to the string data at offset 0
+       if r == nil {          // shouldn't happen.
+               return ""
+       }
+       return cstring(r.Sym.P[r.Add:])
+}
+
+func decodetype_structfieldtype(s *LSym, i int) *LSym {
+       return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize())+2*int32(Thearch.Ptrsize))
+}
+
+func decodetype_structfieldoffs(s *LSym, i int) int64 {
+       return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize+2*Thearch.Intsize+i*structfieldsize()+4*Thearch.Ptrsize:], Thearch.Intsize))
+}
+
+// InterfaceTYpe.methods.length
+func decodetype_ifacemethodcount(s *LSym) int64 {
+       return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
+}
diff --git a/src/cmd/internal/ld/dwarf.go b/src/cmd/internal/ld/dwarf.go
new file mode 100644 (file)
index 0000000..490795c
--- /dev/null
@@ -0,0 +1,2744 @@
+// Copyright 2010 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 ld
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "strings"
+)
+
+/*
+ * Offsets and sizes of the debug_* sections in the cout file.
+ */
+var abbrevo int64
+
+var abbrevsize int64
+
+var abbrevsym *LSym
+
+var abbrevsympos int64
+
+var lineo int64
+
+var linesize int64
+
+var linesym *LSym
+
+var linesympos int64
+
+var infoo int64 // also the base for DWDie->offs and reference attributes.
+
+var infosize int64
+
+var infosym *LSym
+
+var infosympos int64
+
+var frameo int64
+
+var framesize int64
+
+var framesym *LSym
+
+var framesympos int64
+
+var pubnameso int64
+
+var pubnamessize int64
+
+var pubtypeso int64
+
+var pubtypessize int64
+
+var arangeso int64
+
+var arangessize int64
+
+var gdbscripto int64
+
+var gdbscriptsize int64
+
+var infosec *LSym
+
+var inforeloco int64
+
+var inforelocsize int64
+
+var arangessec *LSym
+
+var arangesreloco int64
+
+var arangesrelocsize int64
+
+var linesec *LSym
+
+var linereloco int64
+
+var linerelocsize int64
+
+var framesec *LSym
+
+var framereloco int64
+
+var framerelocsize int64
+
+var gdbscript string
+
+/*
+ *  Basic I/O
+ */
+func addrput(addr int64) {
+       switch Thearch.Ptrsize {
+       case 4:
+               Thearch.Lput(uint32(addr))
+
+       case 8:
+               Thearch.Vput(uint64(addr))
+       }
+}
+
+func uleb128enc(v uint64, dst []byte) int {
+       var c uint8
+       var length uint8
+
+       length = 0
+       for {
+               c = uint8(v & 0x7f)
+               v >>= 7
+               if v != 0 {
+                       c |= 0x80
+               }
+               if dst != nil {
+                       dst[0] = byte(c)
+                       dst = dst[1:]
+               }
+               length++
+               if c&0x80 == 0 {
+                       break
+               }
+       }
+
+       return int(length)
+}
+
+func sleb128enc(v int64, dst []byte) int {
+       var c uint8
+       var s uint8
+       var length uint8
+
+       length = 0
+       for {
+               c = uint8(v & 0x7f)
+               s = uint8(v & 0x40)
+               v >>= 7
+               if (v != -1 || s == 0) && (v != 0 || s != 0) {
+                       c |= 0x80
+               }
+               if dst != nil {
+                       dst[0] = byte(c)
+                       dst = dst[1:]
+               }
+               length++
+               if c&0x80 == 0 {
+                       break
+               }
+       }
+
+       return int(length)
+}
+
+func uleb128put(v int64) {
+       var buf [10]byte
+       n := uleb128enc(uint64(v), buf[:])
+       Cwrite(buf[:n])
+}
+
+func sleb128put(v int64) {
+       var buf [10]byte
+       n := sleb128enc(v, buf[:])
+       Cwrite(buf[:n])
+}
+
+/*
+ * Defining Abbrevs.  This is hardcoded, and there will be
+ * only a handful of them.  The DWARF spec places no restriction on
+ * the ordering of attributes in the Abbrevs and DIEs, and we will
+ * always write them out in the order of declaration in the abbrev.
+ */
+type DWAttrForm struct {
+       attr uint16
+       form uint8
+}
+
+// Go-specific type attributes.
+const (
+       DW_AT_go_kind           = 0x2900
+       DW_AT_go_key            = 0x2901
+       DW_AT_go_elem           = 0x2902
+       DW_AT_internal_location = 253
+)
+
+// Index into the abbrevs table below.
+// Keep in sync with ispubname() and ispubtype() below.
+// ispubtype considers >= NULLTYPE public
+const (
+       DW_ABRV_NULL = iota
+       DW_ABRV_COMPUNIT
+       DW_ABRV_FUNCTION
+       DW_ABRV_VARIABLE
+       DW_ABRV_AUTO
+       DW_ABRV_PARAM
+       DW_ABRV_STRUCTFIELD
+       DW_ABRV_FUNCTYPEPARAM
+       DW_ABRV_DOTDOTDOT
+       DW_ABRV_ARRAYRANGE
+       DW_ABRV_NULLTYPE
+       DW_ABRV_BASETYPE
+       DW_ABRV_ARRAYTYPE
+       DW_ABRV_CHANTYPE
+       DW_ABRV_FUNCTYPE
+       DW_ABRV_IFACETYPE
+       DW_ABRV_MAPTYPE
+       DW_ABRV_PTRTYPE
+       DW_ABRV_BARE_PTRTYPE
+       DW_ABRV_SLICETYPE
+       DW_ABRV_STRINGTYPE
+       DW_ABRV_STRUCTTYPE
+       DW_ABRV_TYPEDECL
+       DW_NABRV
+)
+
+type DWAbbrev struct {
+       tag      uint8
+       children uint8
+       attr     [30]DWAttrForm
+}
+
+var abbrevs = [DW_NABRV]struct {
+       tag      uint8
+       children uint8
+       attr     [30]DWAttrForm
+}{
+       /* The mandatory DW_ABRV_NULL entry. */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{0, 0, [30]DWAttrForm{}},
+
+       /* COMPUNIT */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_compile_unit,
+               DW_CHILDREN_yes,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_language, DW_FORM_data1},
+                       DWAttrForm{DW_AT_low_pc, DW_FORM_addr},
+                       DWAttrForm{DW_AT_high_pc, DW_FORM_addr},
+                       DWAttrForm{DW_AT_stmt_list, DW_FORM_data4},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* FUNCTION */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_subprogram,
+               DW_CHILDREN_yes,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_low_pc, DW_FORM_addr},
+                       DWAttrForm{DW_AT_high_pc, DW_FORM_addr},
+                       DWAttrForm{DW_AT_external, DW_FORM_flag},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* VARIABLE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_variable,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_location, DW_FORM_block1},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{DW_AT_external, DW_FORM_flag},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* AUTO */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_variable,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_location, DW_FORM_block1},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* PARAM */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_formal_parameter,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_location, DW_FORM_block1},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* STRUCTFIELD */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_member,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_data_member_location, DW_FORM_block1},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* FUNCTYPEPARAM */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_formal_parameter,
+               DW_CHILDREN_no,
+
+               // No name!
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* DOTDOTDOT */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_unspecified_parameters,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{DWAttrForm{0, 0}},
+       },
+
+       /* ARRAYRANGE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_subrange_type,
+               DW_CHILDREN_no,
+
+               // No name!
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{DW_AT_count, DW_FORM_udata},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       // Below here are the types considered public by ispubtype
+       /* NULLTYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_unspecified_type,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* BASETYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_base_type,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_encoding, DW_FORM_data1},
+                       DWAttrForm{DW_AT_byte_size, DW_FORM_data1},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* ARRAYTYPE */
+       // child is subrange with upper bound
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_array_type,
+               DW_CHILDREN_yes,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{DW_AT_byte_size, DW_FORM_udata},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* CHANTYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_typedef,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{DW_AT_go_elem, DW_FORM_ref_addr},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* FUNCTYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_subroutine_type,
+               DW_CHILDREN_yes,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+
+                       //              {DW_AT_type,    DW_FORM_ref_addr},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* IFACETYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_typedef,
+               DW_CHILDREN_yes,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* MAPTYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_typedef,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{DW_AT_go_key, DW_FORM_ref_addr},
+                       DWAttrForm{DW_AT_go_elem, DW_FORM_ref_addr},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* PTRTYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_pointer_type,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* BARE_PTRTYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_pointer_type,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* SLICETYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_structure_type,
+               DW_CHILDREN_yes,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_byte_size, DW_FORM_udata},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{DW_AT_go_elem, DW_FORM_ref_addr},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* STRINGTYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_structure_type,
+               DW_CHILDREN_yes,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_byte_size, DW_FORM_udata},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* STRUCTTYPE */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_structure_type,
+               DW_CHILDREN_yes,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_byte_size, DW_FORM_udata},
+                       DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
+                       DWAttrForm{0, 0},
+               },
+       },
+
+       /* TYPEDECL */
+       struct {
+               tag      uint8
+               children uint8
+               attr     [30]DWAttrForm
+       }{
+               DW_TAG_typedef,
+               DW_CHILDREN_no,
+               [30]DWAttrForm{
+                       DWAttrForm{DW_AT_name, DW_FORM_string},
+                       DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
+                       DWAttrForm{0, 0},
+               },
+       },
+}
+
+func writeabbrev() {
+       var i int
+       var j int
+       var f *DWAttrForm
+
+       abbrevo = Cpos()
+       for i = 1; i < DW_NABRV; i++ {
+               // See section 7.5.3
+               uleb128put(int64(i))
+
+               uleb128put(int64(abbrevs[i].tag))
+               Cput(abbrevs[i].children)
+               for j = 0; j < len(abbrevs[i].attr); j++ {
+                       f = &abbrevs[i].attr[j]
+                       uleb128put(int64(f.attr))
+                       uleb128put(int64(f.form))
+                       if f.attr == 0 {
+                               break
+                       }
+               }
+       }
+
+       Cput(0)
+       abbrevsize = Cpos() - abbrevo
+}
+
+/*
+ * Debugging Information Entries and their attributes.
+ */
+const (
+       HASHSIZE = 107
+)
+
+func dwarfhashstr(s string) uint32 {
+       var h uint32
+
+       h = 0
+       for s != "" {
+               h = h + h + h + uint32(s[0])
+               s = s[1:]
+       }
+       return h % HASHSIZE
+}
+
+// For DW_CLS_string and _block, value should contain the length, and
+// data the data, for _reference, value is 0 and data is a DWDie* to
+// the referenced instance, for all others, value is the whole thing
+// and data is null.
+
+type DWAttr struct {
+       link  *DWAttr
+       atr   uint16
+       cls   uint8
+       value int64
+       data  interface{}
+}
+
+type DWDie struct {
+       abbrev int
+       link   *DWDie
+       child  *DWDie
+       attr   *DWAttr
+       offs   int64
+       hash   []*DWDie
+       hlink  *DWDie
+}
+
+/*
+ * Root DIEs for compilation units, types and global variables.
+ */
+var dwroot DWDie
+
+var dwtypes DWDie
+
+var dwglobals DWDie
+
+func newattr(die *DWDie, attr uint16, cls int, value int64, data interface{}) *DWAttr {
+       var a *DWAttr
+
+       a = new(DWAttr)
+       a.link = die.attr
+       die.attr = a
+       a.atr = attr
+       a.cls = uint8(cls)
+       a.value = value
+       a.data = data
+       return a
+}
+
+// Each DIE (except the root ones) has at least 1 attribute: its
+// name. getattr moves the desired one to the front so
+// frequently searched ones are found faster.
+func getattr(die *DWDie, attr uint16) *DWAttr {
+       var a *DWAttr
+       var b *DWAttr
+
+       if die.attr.atr == attr {
+               return die.attr
+       }
+
+       a = die.attr
+       b = a.link
+       for b != nil {
+               if b.atr == attr {
+                       a.link = b.link
+                       b.link = die.attr
+                       die.attr = b
+                       return b
+               }
+
+               a = b
+               b = b.link
+       }
+
+       return nil
+}
+
+// Every DIE has at least a DW_AT_name attribute (but it will only be
+// written out if it is listed in the abbrev). If its parent is
+// keeping an index, the new DIE will be inserted there.
+func newdie(parent *DWDie, abbrev int, name string) *DWDie {
+       var die *DWDie
+       var h int
+
+       die = new(DWDie)
+       die.abbrev = abbrev
+       die.link = parent.child
+       parent.child = die
+
+       newattr(die, DW_AT_name, DW_CLS_STRING, int64(len(name)), name)
+
+       if parent.hash != nil {
+               h = int(dwarfhashstr(name))
+               die.hlink = parent.hash[h]
+               parent.hash[h] = die
+       }
+
+       return die
+}
+
+func mkindex(die *DWDie) {
+       die.hash = make([]*DWDie, HASHSIZE)
+}
+
+func walktypedef(die *DWDie) *DWDie {
+       var attr *DWAttr
+
+       // Resolve typedef if present.
+       if die.abbrev == DW_ABRV_TYPEDECL {
+               for attr = die.attr; attr != nil; attr = attr.link {
+                       if attr.atr == DW_AT_type && attr.cls == DW_CLS_REFERENCE && attr.data != nil {
+                               return attr.data.(*DWDie)
+                       }
+               }
+       }
+
+       return die
+}
+
+// Find child by AT_name using hashtable if available or linear scan
+// if not.
+func find(die *DWDie, name string) *DWDie {
+       var a *DWDie
+       var b *DWDie
+       var die2 *DWDie
+       var h int
+
+top:
+       if die.hash == nil {
+               for a = die.child; a != nil; a = a.link {
+                       if name == getattr(a, DW_AT_name).data {
+                               return a
+                       }
+               }
+               goto notfound
+       }
+
+       h = int(dwarfhashstr(name))
+       a = die.hash[h]
+
+       if a == nil {
+               goto notfound
+       }
+
+       if name == getattr(a, DW_AT_name).data {
+               return a
+       }
+
+       // Move found ones to head of the list.
+       b = a.hlink
+
+       for b != nil {
+               if name == getattr(b, DW_AT_name).data {
+                       a.hlink = b.hlink
+                       b.hlink = die.hash[h]
+                       die.hash[h] = b
+                       return b
+               }
+
+               a = b
+               b = b.hlink
+       }
+
+notfound:
+       die2 = walktypedef(die)
+       if die2 != die {
+               die = die2
+               goto top
+       }
+
+       return nil
+}
+
+func find_or_diag(die *DWDie, name string) *DWDie {
+       var r *DWDie
+       r = find(die, name)
+       if r == nil {
+               Diag("dwarf find: %s %p has no %s", getattr(die, DW_AT_name).data, die, name)
+               Errorexit()
+       }
+
+       return r
+}
+
+func adddwarfrel(sec *LSym, sym *LSym, offsetbase int64, siz int, addend int64) {
+       var r *Reloc
+
+       r = Addrel(sec)
+       r.Sym = sym
+       r.Xsym = sym
+       r.Off = int32(Cpos() - offsetbase)
+       r.Siz = uint8(siz)
+       r.Type = R_ADDR
+       r.Add = addend
+       r.Xadd = addend
+       if Iself && Thearch.Thechar == '6' {
+               addend = 0
+       }
+       switch siz {
+       case 4:
+               Thearch.Lput(uint32(addend))
+
+       case 8:
+               Thearch.Vput(uint64(addend))
+
+       default:
+               Diag("bad size in adddwarfrel")
+       }
+}
+
+func newrefattr(die *DWDie, attr uint16, ref *DWDie) *DWAttr {
+       if ref == nil {
+               return nil
+       }
+       return newattr(die, attr, DW_CLS_REFERENCE, 0, ref)
+}
+
+var fwdcount int
+
+func putattr(abbrev int, form int, cls int, value int64, data interface{}) {
+       var off int64
+       var p []byte
+       var i int
+
+       switch form {
+       case DW_FORM_addr: // address
+               if Linkmode == LinkExternal {
+                       value -= (data.(*LSym)).Value
+                       adddwarfrel(infosec, data.(*LSym), infoo, Thearch.Ptrsize, value)
+                       break
+               }
+
+               addrput(value)
+
+       case DW_FORM_block1: // block
+               if cls == DW_CLS_ADDRESS {
+                       Cput(uint8(1 + Thearch.Ptrsize))
+                       Cput(DW_OP_addr)
+                       if Linkmode == LinkExternal {
+                               value -= (data.(*LSym)).Value
+                               adddwarfrel(infosec, data.(*LSym), infoo, Thearch.Ptrsize, value)
+                               break
+                       }
+
+                       addrput(value)
+                       break
+               }
+
+               value &= 0xff
+               Cput(uint8(value))
+               p = data.([]byte)
+               for i = 0; int64(i) < value; i++ {
+                       Cput(uint8(p[i]))
+               }
+
+       case DW_FORM_block2: // block
+               value &= 0xffff
+
+               Thearch.Wput(uint16(value))
+               p = data.([]byte)
+               for i = 0; int64(i) < value; i++ {
+                       Cput(uint8(p[i]))
+               }
+
+       case DW_FORM_block4: // block
+               value &= 0xffffffff
+
+               Thearch.Lput(uint32(value))
+               p = data.([]byte)
+               for i = 0; int64(i) < value; i++ {
+                       Cput(uint8(p[i]))
+               }
+
+       case DW_FORM_block: // block
+               uleb128put(value)
+
+               p = data.([]byte)
+               for i = 0; int64(i) < value; i++ {
+                       Cput(uint8(p[i]))
+               }
+
+       case DW_FORM_data1: // constant
+               Cput(uint8(value))
+
+       case DW_FORM_data2: // constant
+               Thearch.Wput(uint16(value))
+
+       case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
+               if Linkmode == LinkExternal && cls == DW_CLS_PTR {
+                       adddwarfrel(infosec, linesym, infoo, 4, value)
+                       break
+               }
+
+               Thearch.Lput(uint32(value))
+
+       case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
+               Thearch.Vput(uint64(value))
+
+       case DW_FORM_sdata: // constant
+               sleb128put(value)
+
+       case DW_FORM_udata: // constant
+               uleb128put(value)
+
+       case DW_FORM_string: // string
+               strnput(data.(string), int(value+1))
+
+       case DW_FORM_flag: // flag
+               if value != 0 {
+                       Cput(1)
+               } else {
+                       Cput(0)
+               }
+
+               // In DWARF 2 (which is what we claim to generate),
+       // the ref_addr is the same size as a normal address.
+       // In DWARF 3 it is always 32 bits, unless emitting a large
+       // (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
+       case DW_FORM_ref_addr: // reference to a DIE in the .info section
+               if data == nil {
+                       Diag("dwarf: null reference in %d", abbrev)
+                       if Thearch.Ptrsize == 8 {
+                               Thearch.Vput(0) // invalid dwarf, gdb will complain.
+                       } else {
+                               Thearch.Lput(0) // invalid dwarf, gdb will complain.
+                       }
+               } else {
+                       off = (data.(*DWDie)).offs
+                       if off == 0 {
+                               fwdcount++
+                       }
+                       if Linkmode == LinkExternal {
+                               adddwarfrel(infosec, infosym, infoo, Thearch.Ptrsize, off)
+                               break
+                       }
+
+                       addrput(off)
+               }
+
+       case DW_FORM_ref1, // reference within the compilation unit
+               DW_FORM_ref2,      // reference
+               DW_FORM_ref4,      // reference
+               DW_FORM_ref8,      // reference
+               DW_FORM_ref_udata, // reference
+
+               DW_FORM_strp,     // string
+               DW_FORM_indirect: // (see Section 7.5.3)
+               fallthrough
+       default:
+               Diag("dwarf: unsupported attribute form %d / class %d", form, cls)
+
+               Errorexit()
+       }
+}
+
+// Note that we can (and do) add arbitrary attributes to a DIE, but
+// only the ones actually listed in the Abbrev will be written out.
+func putattrs(abbrev int, attr *DWAttr) {
+       var af []DWAttrForm
+       var ap *DWAttr
+
+       for af = abbrevs[abbrev].attr[:]; af[0].attr != 0; af = af[1:] {
+               for ap = attr; ap != nil; ap = ap.link {
+                       if ap.atr == af[0].attr {
+                               putattr(abbrev, int(af[0].form), int(ap.cls), ap.value, ap.data)
+                               goto done
+                       }
+               }
+
+               putattr(abbrev, int(af[0].form), 0, 0, nil)
+       done:
+       }
+}
+
+func putdies(die *DWDie) {
+       for ; die != nil; die = die.link {
+               putdie(die)
+       }
+}
+
+func putdie(die *DWDie) {
+       die.offs = Cpos() - infoo
+       uleb128put(int64(die.abbrev))
+       putattrs(die.abbrev, die.attr)
+       if abbrevs[die.abbrev].children != 0 {
+               putdies(die.child)
+               Cput(0)
+       }
+}
+
+func reverselist(list **DWDie) {
+       var curr *DWDie
+       var prev *DWDie
+
+       curr = *list
+       prev = nil
+       for curr != nil {
+               var next *DWDie = curr.link
+               curr.link = prev
+               prev = curr
+               curr = next
+       }
+
+       *list = prev
+}
+
+func reversetree(list **DWDie) {
+       var die *DWDie
+
+       reverselist(list)
+       for die = *list; die != nil; die = die.link {
+               if abbrevs[die.abbrev].children != 0 {
+                       reversetree(&die.child)
+               }
+       }
+}
+
+func newmemberoffsetattr(die *DWDie, offs int32) {
+       var block [20]byte
+       var i int
+
+       i = 0
+       block[i] = DW_OP_plus_uconst
+       i++
+       i += uleb128enc(uint64(offs), block[i:])
+       newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, int64(i), block[:i])
+}
+
+// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
+// location expression that evals to a const.
+func newabslocexprattr(die *DWDie, addr int64, sym *LSym) {
+       newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, sym)
+       // below
+}
+
+// Lookup predefined types
+func lookup_or_diag(n string) *LSym {
+       var s *LSym
+
+       s = Linkrlookup(Ctxt, n, 0)
+       if s == nil || s.Size == 0 {
+               Diag("dwarf: missing type: %s", n)
+               Errorexit()
+       }
+
+       return s
+}
+
+func dotypedef(parent *DWDie, name string, def *DWDie) {
+       var die *DWDie
+
+       // Only emit typedefs for real names.
+       if strings.HasPrefix(name, "map[") {
+               return
+       }
+       if strings.HasPrefix(name, "struct {") {
+               return
+       }
+       if strings.HasPrefix(name, "chan ") {
+               return
+       }
+       if name[0] == '[' || name[0] == '*' {
+               return
+       }
+       if def == nil {
+               Diag("dwarf: bad def in dotypedef")
+       }
+
+       // The typedef entry must be created after the def,
+       // so that future lookups will find the typedef instead
+       // of the real definition. This hooks the typedef into any
+       // circular definition loops, so that gdb can understand them.
+       die = newdie(parent, DW_ABRV_TYPEDECL, name)
+
+       newrefattr(die, DW_AT_type, def)
+}
+
+// Define gotype, for composite ones recurse into constituents.
+func defgotype(gotype *LSym) *DWDie {
+       var die *DWDie
+       var fld *DWDie
+       var s *LSym
+       var name string
+       var f string
+       var kind uint8
+       var bytesize int64
+       var i int
+       var nfields int
+
+       if gotype == nil {
+               return find_or_diag(&dwtypes, "<unspecified>")
+       }
+
+       if !strings.HasPrefix(gotype.Name, "type.") {
+               Diag("dwarf: type name doesn't start with \".type\": %s", gotype.Name)
+               return find_or_diag(&dwtypes, "<unspecified>")
+       }
+
+       name = gotype.Name[5:] // could also decode from Type.string
+
+       die = find(&dwtypes, name)
+
+       if die != nil {
+               return die
+       }
+
+       if false && Debug['v'] > 2 {
+               fmt.Printf("new type: %%Y\n", gotype)
+       }
+
+       kind = decodetype_kind(gotype)
+       bytesize = decodetype_size(gotype)
+
+       switch kind {
+       case obj.KindBool:
+               die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+               newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+       case obj.KindInt,
+               obj.KindInt8,
+               obj.KindInt16,
+               obj.KindInt32,
+               obj.KindInt64:
+               die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+               newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+       case obj.KindUint,
+               obj.KindUint8,
+               obj.KindUint16,
+               obj.KindUint32,
+               obj.KindUint64,
+               obj.KindUintptr:
+               die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+               newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+       case obj.KindFloat32,
+               obj.KindFloat64:
+               die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+               newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+       case obj.KindComplex64,
+               obj.KindComplex128:
+               die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+               newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+       case obj.KindArray:
+               die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name)
+               dotypedef(&dwtypes, name, die)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+               s = decodetype_arrayelem(gotype)
+               newrefattr(die, DW_AT_type, defgotype(s))
+               fld = newdie(die, DW_ABRV_ARRAYRANGE, "range")
+
+               // use actual length not upper bound; correct for 0-length arrays.
+               newattr(fld, DW_AT_count, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0)
+
+               newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"))
+
+       case obj.KindChan:
+               die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+               s = decodetype_chanelem(gotype)
+               newrefattr(die, DW_AT_go_elem, defgotype(s))
+
+       case obj.KindFunc:
+               die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name)
+               dotypedef(&dwtypes, name, die)
+               newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"))
+               nfields = decodetype_funcincount(gotype)
+               for i = 0; i < nfields; i++ {
+                       s = decodetype_funcintype(gotype, i)
+                       fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:])
+                       newrefattr(fld, DW_AT_type, defgotype(s))
+               }
+
+               if decodetype_funcdotdotdot(gotype) != 0 {
+                       newdie(die, DW_ABRV_DOTDOTDOT, "...")
+               }
+               nfields = decodetype_funcoutcount(gotype)
+               for i = 0; i < nfields; i++ {
+                       s = decodetype_funcouttype(gotype, i)
+                       fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:])
+                       newrefattr(fld, DW_AT_type, defptrto(defgotype(s)))
+               }
+
+       case obj.KindInterface:
+               die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name)
+               dotypedef(&dwtypes, name, die)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+               nfields = int(decodetype_ifacemethodcount(gotype))
+               if nfields == 0 {
+                       s = lookup_or_diag("type.runtime.eface")
+               } else {
+                       s = lookup_or_diag("type.runtime.iface")
+               }
+               newrefattr(die, DW_AT_type, defgotype(s))
+
+       case obj.KindMap:
+               die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name)
+               s = decodetype_mapkey(gotype)
+               newrefattr(die, DW_AT_go_key, defgotype(s))
+               s = decodetype_mapvalue(gotype)
+               newrefattr(die, DW_AT_go_elem, defgotype(s))
+
+       case obj.KindPtr:
+               die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name)
+               dotypedef(&dwtypes, name, die)
+               s = decodetype_ptrelem(gotype)
+               newrefattr(die, DW_AT_type, defgotype(s))
+
+       case obj.KindSlice:
+               die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name)
+               dotypedef(&dwtypes, name, die)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+               s = decodetype_arrayelem(gotype)
+               newrefattr(die, DW_AT_go_elem, defgotype(s))
+
+       case obj.KindString:
+               die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+       case obj.KindStruct:
+               die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name)
+               dotypedef(&dwtypes, name, die)
+               newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+               nfields = decodetype_structfieldcount(gotype)
+               for i = 0; i < nfields; i++ {
+                       f = decodetype_structfieldname(gotype, i)
+                       s = decodetype_structfieldtype(gotype, i)
+                       if f == "" {
+                               f = s.Name[5:] // skip "type."
+                       }
+                       fld = newdie(die, DW_ABRV_STRUCTFIELD, f)
+                       newrefattr(fld, DW_AT_type, defgotype(s))
+                       newmemberoffsetattr(fld, int32(decodetype_structfieldoffs(gotype, i)))
+               }
+
+       case obj.KindUnsafePointer:
+               die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name)
+
+       default:
+               Diag("dwarf: definition of unknown kind %d: %s", kind, gotype.Name)
+               die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name)
+               newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>"))
+       }
+
+       newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, int64(kind), 0)
+
+       return die
+}
+
+// Find or construct *T given T.
+func defptrto(dwtype *DWDie) *DWDie {
+       var ptrname string
+       var die *DWDie
+
+       ptrname = fmt.Sprintf("*%s", getattr(dwtype, DW_AT_name).data)
+       die = find(&dwtypes, ptrname)
+       if die == nil {
+               die = newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname)
+               newrefattr(die, DW_AT_type, dwtype)
+       }
+
+       return die
+}
+
+// Copies src's children into dst. Copies attributes by value.
+// DWAttr.data is copied as pointer only.  If except is one of
+// the top-level children, it will not be copied.
+func copychildrenexcept(dst *DWDie, src *DWDie, except *DWDie) {
+       var c *DWDie
+       var a *DWAttr
+
+       for src = src.child; src != nil; src = src.link {
+               if src == except {
+                       continue
+               }
+               c = newdie(dst, src.abbrev, getattr(src, DW_AT_name).data.(string))
+               for a = src.attr; a != nil; a = a.link {
+                       newattr(c, a.atr, int(a.cls), a.value, a.data)
+               }
+               copychildrenexcept(c, src, nil)
+       }
+
+       reverselist(&dst.child)
+}
+
+func copychildren(dst *DWDie, src *DWDie) {
+       copychildrenexcept(dst, src, nil)
+}
+
+// Search children (assumed to have DW_TAG_member) for the one named
+// field and set its DW_AT_type to dwtype
+func substitutetype(structdie *DWDie, field string, dwtype *DWDie) {
+       var child *DWDie
+       var a *DWAttr
+
+       child = find_or_diag(structdie, field)
+       if child == nil {
+               return
+       }
+
+       a = getattr(child, DW_AT_type)
+       if a != nil {
+               a.data = dwtype
+       } else {
+               newrefattr(child, DW_AT_type, dwtype)
+       }
+}
+
+func synthesizestringtypes(die *DWDie) {
+       var prototype *DWDie
+
+       prototype = walktypedef(defgotype(lookup_or_diag("type.runtime._string")))
+       if prototype == nil {
+               return
+       }
+
+       for ; die != nil; die = die.link {
+               if die.abbrev != DW_ABRV_STRINGTYPE {
+                       continue
+               }
+               copychildren(die, prototype)
+       }
+}
+
+func synthesizeslicetypes(die *DWDie) {
+       var prototype *DWDie
+       var elem *DWDie
+
+       prototype = walktypedef(defgotype(lookup_or_diag("type.runtime.slice")))
+       if prototype == nil {
+               return
+       }
+
+       for ; die != nil; die = die.link {
+               if die.abbrev != DW_ABRV_SLICETYPE {
+                       continue
+               }
+               copychildren(die, prototype)
+               elem = getattr(die, DW_AT_go_elem).data.(*DWDie)
+               substitutetype(die, "array", defptrto(elem))
+       }
+}
+
+func mkinternaltypename(base string, arg1 string, arg2 string) string {
+       var buf string
+       var n string
+
+       if arg2 == "" {
+               buf = fmt.Sprintf("%s<%s>", base, arg1)
+       } else {
+               buf = fmt.Sprintf("%s<%s,%s>", base, arg1, arg2)
+       }
+       n = buf
+       return n
+}
+
+// synthesizemaptypes is way too closely married to runtime/hashmap.c
+const (
+       MaxKeySize = 128
+       MaxValSize = 128
+       BucketSize = 8
+)
+
+func synthesizemaptypes(die *DWDie) {
+       var hash *DWDie
+       var bucket *DWDie
+       var dwh *DWDie
+       var dwhk *DWDie
+       var dwhv *DWDie
+       var dwhb *DWDie
+       var keytype *DWDie
+       var valtype *DWDie
+       var fld *DWDie
+       var t *DWDie
+       var indirect_key int
+       var indirect_val int
+       var keysize int
+       var valsize int
+       var a *DWAttr
+
+       hash = walktypedef(defgotype(lookup_or_diag("type.runtime.hmap")))
+       bucket = walktypedef(defgotype(lookup_or_diag("type.runtime.bmap")))
+
+       if hash == nil {
+               return
+       }
+
+       for ; die != nil; die = die.link {
+               if die.abbrev != DW_ABRV_MAPTYPE {
+                       continue
+               }
+
+               keytype = walktypedef(getattr(die, DW_AT_go_key).data.(*DWDie))
+               valtype = walktypedef(getattr(die, DW_AT_go_elem).data.(*DWDie))
+
+               // compute size info like hashmap.c does.
+               a = getattr(keytype, DW_AT_byte_size)
+
+               if a != nil {
+                       keysize = int(a.value)
+               } else {
+                       keysize = Thearch.Ptrsize
+               }
+               a = getattr(valtype, DW_AT_byte_size)
+               if a != nil {
+                       valsize = int(a.value)
+               } else {
+                       valsize = Thearch.Ptrsize
+               }
+               indirect_key = 0
+               indirect_val = 0
+               if keysize > MaxKeySize {
+                       keysize = Thearch.Ptrsize
+                       indirect_key = 1
+               }
+
+               if valsize > MaxValSize {
+                       valsize = Thearch.Ptrsize
+                       indirect_val = 1
+               }
+
+               // Construct type to represent an array of BucketSize keys
+               dwhk = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, mkinternaltypename("[]key", getattr(keytype, DW_AT_name).data.(string), ""))
+
+               newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(keysize), 0)
+               t = keytype
+               if indirect_key != 0 {
+                       t = defptrto(keytype)
+               }
+               newrefattr(dwhk, DW_AT_type, t)
+               fld = newdie(dwhk, DW_ABRV_ARRAYRANGE, "size")
+               newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
+               newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"))
+
+               // Construct type to represent an array of BucketSize values
+               dwhv = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, mkinternaltypename("[]val", getattr(valtype, DW_AT_name).data.(string), ""))
+
+               newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(valsize), 0)
+               t = valtype
+               if indirect_val != 0 {
+                       t = defptrto(valtype)
+               }
+               newrefattr(dwhv, DW_AT_type, t)
+               fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size")
+               newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
+               newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"))
+
+               // Construct bucket<K,V>
+               dwhb = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("bucket", getattr(keytype, DW_AT_name).data.(string), getattr(valtype, DW_AT_name).data.(string)))
+
+               // Copy over all fields except the field "data" from the generic bucket.
+               // "data" will be replaced with keys/values below.
+               copychildrenexcept(dwhb, bucket, find(bucket, "data"))
+
+               fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys")
+               newrefattr(fld, DW_AT_type, dwhk)
+               newmemberoffsetattr(fld, BucketSize)
+               fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values")
+               newrefattr(fld, DW_AT_type, dwhv)
+               newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
+               fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow")
+               newrefattr(fld, DW_AT_type, defptrto(dwhb))
+               newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
+               if Thearch.Regsize > Thearch.Ptrsize {
+                       fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad")
+                       newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"))
+                       newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(Thearch.Ptrsize))
+               }
+
+               newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*int64(keysize)+BucketSize*int64(valsize)+int64(Thearch.Regsize), 0)
+
+               // Construct hash<K,V>
+               dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("hash", getattr(keytype, DW_AT_name).data.(string), getattr(valtype, DW_AT_name).data.(string)))
+
+               copychildren(dwh, hash)
+               substitutetype(dwh, "buckets", defptrto(dwhb))
+               substitutetype(dwh, "oldbuckets", defptrto(dwhb))
+               newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hash, DW_AT_byte_size).value, nil)
+
+               // make map type a pointer to hash<K,V>
+               newrefattr(die, DW_AT_type, defptrto(dwh))
+       }
+}
+
+func synthesizechantypes(die *DWDie) {
+       var sudog *DWDie
+       var waitq *DWDie
+       var hchan *DWDie
+       var dws *DWDie
+       var dww *DWDie
+       var dwh *DWDie
+       var elemtype *DWDie
+       var a *DWAttr
+       var elemsize int
+       var sudogsize int
+
+       sudog = walktypedef(defgotype(lookup_or_diag("type.runtime.sudog")))
+       waitq = walktypedef(defgotype(lookup_or_diag("type.runtime.waitq")))
+       hchan = walktypedef(defgotype(lookup_or_diag("type.runtime.hchan")))
+       if sudog == nil || waitq == nil || hchan == nil {
+               return
+       }
+
+       sudogsize = int(getattr(sudog, DW_AT_byte_size).value)
+
+       for ; die != nil; die = die.link {
+               if die.abbrev != DW_ABRV_CHANTYPE {
+                       continue
+               }
+               elemtype = getattr(die, DW_AT_go_elem).data.(*DWDie)
+               a = getattr(elemtype, DW_AT_byte_size)
+               if a != nil {
+                       elemsize = int(a.value)
+               } else {
+                       elemsize = Thearch.Ptrsize
+               }
+
+               // sudog<T>
+               dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("sudog", getattr(elemtype, DW_AT_name).data.(string), ""))
+
+               copychildren(dws, sudog)
+               substitutetype(dws, "elem", elemtype)
+               if elemsize > 8 {
+                       elemsize -= 8
+               } else {
+                       elemsize = 0
+               }
+               newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, int64(sudogsize)+int64(elemsize), nil)
+
+               // waitq<T>
+               dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("waitq", getattr(elemtype, DW_AT_name).data.(string), ""))
+
+               copychildren(dww, waitq)
+               substitutetype(dww, "first", defptrto(dws))
+               substitutetype(dww, "last", defptrto(dws))
+               newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(waitq, DW_AT_byte_size).value, nil)
+
+               // hchan<T>
+               dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("hchan", getattr(elemtype, DW_AT_name).data.(string), ""))
+
+               copychildren(dwh, hchan)
+               substitutetype(dwh, "recvq", dww)
+               substitutetype(dwh, "sendq", dww)
+               newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hchan, DW_AT_byte_size).value, nil)
+
+               newrefattr(die, DW_AT_type, defptrto(dwh))
+       }
+}
+
+// For use with pass.c::genasmsym
+func defdwsymb(sym *LSym, s string, t int, v int64, size int64, ver int, gotype *LSym) {
+       var dv *DWDie
+       var dt *DWDie
+
+       if strings.HasPrefix(s, "go.string.") {
+               return
+       }
+
+       if strings.HasPrefix(s, "type.") && s != "type.*" && !strings.HasPrefix(s, "type..") {
+               defgotype(sym)
+               return
+       }
+
+       dv = nil
+
+       switch t {
+       default:
+               return
+
+       case 'd',
+               'b',
+               'D',
+               'B':
+               dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s)
+               newabslocexprattr(dv, v, sym)
+               if ver == 0 {
+                       newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0)
+               }
+               fallthrough
+
+               // fallthrough
+       case 'a',
+               'p':
+               dt = defgotype(gotype)
+       }
+
+       if dv != nil {
+               newrefattr(dv, DW_AT_type, dt)
+       }
+}
+
+func movetomodule(parent *DWDie) {
+       var die *DWDie
+
+       die = dwroot.child.child
+       for die.link != nil {
+               die = die.link
+       }
+       die.link = parent.child
+}
+
+// If the pcln table contains runtime/runtime.go, use that to set gdbscript path.
+func finddebugruntimepath(s *LSym) {
+       var i int
+       var p string
+       var f *LSym
+
+       if gdbscript != "" {
+               return
+       }
+
+       for i = 0; i < s.Pcln.Nfile; i++ {
+               f = s.Pcln.File[i]
+               _ = p
+               if i := strings.Index(f.Name, "runtime/runtime.go"); i >= 0 {
+                       gdbscript = f.Name[:i] + "runtime/runtime-gdb.py"
+                       break
+               }
+       }
+}
+
+/*
+ * Generate short opcodes when possible, long ones when necessary.
+ * See section 6.2.5
+ */
+const (
+       LINE_BASE   = -1
+       LINE_RANGE  = 4
+       OPCODE_BASE = 10
+)
+
+func putpclcdelta(delta_pc int64, delta_lc int64) {
+       if LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE {
+               var opcode int64 = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc)
+               if OPCODE_BASE <= opcode && opcode < 256 {
+                       Cput(uint8(opcode))
+                       return
+               }
+       }
+
+       if delta_pc != 0 {
+               Cput(DW_LNS_advance_pc)
+               sleb128put(delta_pc)
+       }
+
+       Cput(DW_LNS_advance_line)
+       sleb128put(delta_lc)
+       Cput(DW_LNS_copy)
+}
+
+func newcfaoffsetattr(die *DWDie, offs int32) {
+       var block [20]byte
+       var i int
+
+       i = 0
+
+       block[i] = DW_OP_call_frame_cfa
+       i++
+       if offs != 0 {
+               block[i] = DW_OP_consts
+               i++
+               i += sleb128enc(int64(offs), block[i:])
+               block[i] = DW_OP_plus
+               i++
+       }
+
+       newattr(die, DW_AT_location, DW_CLS_BLOCK, int64(i), block[:i])
+}
+
+func mkvarname(name string, da int) string {
+       var buf string
+       var n string
+
+       buf = fmt.Sprintf("%s#%d", name, da)
+       n = buf
+       return n
+}
+
+/*
+ * Walk prog table, emit line program and build DIE tree.
+ */
+
+// flush previous compilation unit.
+func flushunit(dwinfo *DWDie, pc int64, pcsym *LSym, unitstart int64, header_length int32) {
+       var here int64
+
+       if dwinfo != nil && pc != 0 {
+               newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, pcsym)
+       }
+
+       if unitstart >= 0 {
+               Cput(0) // start extended opcode
+               uleb128put(1)
+               Cput(DW_LNE_end_sequence)
+
+               here = Cpos()
+               Cseek(unitstart)
+               Thearch.Lput(uint32(here - unitstart - 4)) // unit_length
+               Thearch.Wput(2)                            // dwarf version
+               Thearch.Lput(uint32(header_length))        // header length starting here
+               Cseek(here)
+       }
+}
+
+func writelines() {
+       var s *LSym
+       var epcs *LSym
+       var a *Auto
+       var unitstart int64
+       var headerend int64
+       var offs int64
+       var pc int64
+       var epc int64
+       var i int
+       var lang int
+       var da int
+       var dt int
+       var line int
+       var file int
+       var dwinfo *DWDie
+       var dwfunc *DWDie
+       var dwvar *DWDie
+       var dws **DWDie
+       var varhash [HASHSIZE]*DWDie
+       var n string
+       var nn string
+       var pcfile Pciter
+       var pcline Pciter
+       var files []*LSym
+       var f *LSym
+
+       if linesec == nil {
+               linesec = Linklookup(Ctxt, ".dwarfline", 0)
+       }
+       linesec.R = linesec.R[:0]
+
+       unitstart = -1
+       headerend = -1
+       epc = 0
+       epcs = nil
+       lineo = Cpos()
+       dwinfo = nil
+
+       flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10))
+       unitstart = Cpos()
+
+       lang = DW_LANG_Go
+
+       s = Ctxt.Textp
+
+       dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go")
+       newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0)
+       newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart-lineo, 0)
+       newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s)
+
+       // Write .debug_line Line Number Program Header (sec 6.2.4)
+       // Fields marked with (*) must be changed for 64-bit dwarf
+       Thearch.Lput(0) // unit_length (*), will be filled in by flushunit.
+       Thearch.Wput(2) // dwarf version (appendix F)
+       Thearch.Lput(0) // header_length (*), filled in by flushunit.
+
+       // cpos == unitstart + 4 + 2 + 4
+       Cput(1)                // minimum_instruction_length
+       Cput(1)                // default_is_stmt
+       Cput(LINE_BASE & 0xFF) // line_base
+       Cput(LINE_RANGE)       // line_range
+       Cput(OPCODE_BASE)      // opcode_base
+       Cput(0)                // standard_opcode_lengths[1]
+       Cput(1)                // standard_opcode_lengths[2]
+       Cput(1)                // standard_opcode_lengths[3]
+       Cput(1)                // standard_opcode_lengths[4]
+       Cput(1)                // standard_opcode_lengths[5]
+       Cput(0)                // standard_opcode_lengths[6]
+       Cput(0)                // standard_opcode_lengths[7]
+       Cput(0)                // standard_opcode_lengths[8]
+       Cput(1)                // standard_opcode_lengths[9]
+       Cput(0)                // include_directories  (empty)
+
+       files = make([]*LSym, Ctxt.Nhistfile)
+
+       for f = Ctxt.Filesyms; f != nil; f = f.Next {
+               files[f.Value-1] = f
+       }
+
+       for i = 0; int32(i) < Ctxt.Nhistfile; i++ {
+               strnput(files[i].Name, len(files[i].Name)+4)
+       }
+
+       // 4 zeros: the string termination + 3 fields.
+       Cput(0)
+       // terminate file_names.
+       headerend = Cpos()
+
+       Cput(0) // start extended opcode
+       uleb128put(1 + int64(Thearch.Ptrsize))
+       Cput(DW_LNE_set_address)
+
+       pc = s.Value
+       line = 1
+       file = 1
+       if Linkmode == LinkExternal {
+               adddwarfrel(linesec, s, lineo, Thearch.Ptrsize, 0)
+       } else {
+               addrput(pc)
+       }
+
+       for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
+               s = Ctxt.Cursym
+
+               dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s.Name)
+               newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s)
+               epc = s.Value + s.Size
+               epcs = s
+               newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, s)
+               if s.Version == 0 {
+                       newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0)
+               }
+
+               if s.Pcln == nil {
+                       continue
+               }
+
+               finddebugruntimepath(s)
+
+               pciterinit(Ctxt, &pcfile, &s.Pcln.Pcfile)
+               pciterinit(Ctxt, &pcline, &s.Pcln.Pcline)
+               epc = pc
+               for pcfile.done == 0 && pcline.done == 0 {
+                       if epc-s.Value >= int64(pcfile.nextpc) {
+                               pciternext(&pcfile)
+                               continue
+                       }
+
+                       if epc-s.Value >= int64(pcline.nextpc) {
+                               pciternext(&pcline)
+                               continue
+                       }
+
+                       if int32(file) != pcfile.value {
+                               Cput(DW_LNS_set_file)
+                               uleb128put(int64(pcfile.value))
+                               file = int(pcfile.value)
+                       }
+
+                       putpclcdelta(s.Value+int64(pcline.pc)-pc, int64(pcline.value)-int64(line))
+
+                       pc = s.Value + int64(pcline.pc)
+                       line = int(pcline.value)
+                       if pcfile.nextpc < pcline.nextpc {
+                               epc = int64(pcfile.nextpc)
+                       } else {
+                               epc = int64(pcline.nextpc)
+                       }
+                       epc += s.Value
+               }
+
+               da = 0
+               dwfunc.hash = varhash[:] // enable indexing of children by name
+               varhash = [HASHSIZE]*DWDie{}
+               for a = s.Autom; a != nil; a = a.Link {
+                       switch a.Name {
+                       case A_AUTO:
+                               dt = DW_ABRV_AUTO
+                               offs = int64(a.Aoffset) - int64(Thearch.Ptrsize)
+
+                       case A_PARAM:
+                               dt = DW_ABRV_PARAM
+                               offs = int64(a.Aoffset)
+
+                       default:
+                               continue
+                       }
+
+                       if strings.Contains(a.Asym.Name, ".autotmp_") {
+                               continue
+                       }
+                       if find(dwfunc, a.Asym.Name) != nil {
+                               n = mkvarname(a.Asym.Name, da)
+                       } else {
+                               n = a.Asym.Name
+                       }
+
+                       // Drop the package prefix from locals and arguments.
+                       _ = nn
+                       if i := strings.LastIndex(n, "."); i >= 0 {
+                               n = n[i+1:]
+                       }
+
+                       dwvar = newdie(dwfunc, dt, n)
+                       newcfaoffsetattr(dwvar, int32(offs))
+                       newrefattr(dwvar, DW_AT_type, defgotype(a.Gotype))
+
+                       // push dwvar down dwfunc->child to preserve order
+                       newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil)
+
+                       dwfunc.child = dwvar.link // take dwvar out from the top of the list
+                       for dws = &dwfunc.child; *dws != nil; dws = &(*dws).link {
+                               if offs > getattr(*dws, DW_AT_internal_location).value {
+                                       break
+                               }
+                       }
+                       dwvar.link = *dws
+                       *dws = dwvar
+
+                       da++
+               }
+
+               dwfunc.hash = nil
+       }
+
+       flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10))
+       linesize = Cpos() - lineo
+}
+
+/*
+ *  Emit .debug_frame
+ */
+const (
+       CIERESERVE          = 16
+       DATAALIGNMENTFACTOR = -4
+       FAKERETURNCOLUMN    = 16
+)
+
+func putpccfadelta(deltapc int64, cfa int64) {
+       Cput(DW_CFA_def_cfa_offset_sf)
+       sleb128put(cfa / DATAALIGNMENTFACTOR)
+
+       if deltapc < 0x40 {
+               Cput(uint8(DW_CFA_advance_loc + deltapc))
+       } else if deltapc < 0x100 {
+               Cput(DW_CFA_advance_loc1)
+               Cput(uint8(deltapc))
+       } else if deltapc < 0x10000 {
+               Cput(DW_CFA_advance_loc2)
+               Thearch.Wput(uint16(deltapc))
+       } else {
+               Cput(DW_CFA_advance_loc4)
+               Thearch.Lput(uint32(deltapc))
+       }
+}
+
+func writeframes() {
+       var s *LSym
+       var fdeo int64
+       var fdesize int64
+       var pad int64
+       var pcsp Pciter
+       var nextpc uint32
+
+       if framesec == nil {
+               framesec = Linklookup(Ctxt, ".dwarfframe", 0)
+       }
+       framesec.R = framesec.R[:0]
+       frameo = Cpos()
+
+       // Emit the CIE, Section 6.4.1
+       Thearch.Lput(CIERESERVE)        // initial length, must be multiple of thearch.ptrsize
+       Thearch.Lput(0xffffffff)        // cid.
+       Cput(3)                         // dwarf version (appendix F)
+       Cput(0)                         // augmentation ""
+       uleb128put(1)                   // code_alignment_factor
+       sleb128put(DATAALIGNMENTFACTOR) // guess
+       uleb128put(FAKERETURNCOLUMN)    // return_address_register
+
+       Cput(DW_CFA_def_cfa)
+
+       uleb128put(int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h)
+       uleb128put(int64(Thearch.Ptrsize))    // offset
+
+       Cput(DW_CFA_offset + FAKERETURNCOLUMN)                    // return address
+       uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4
+
+       // 4 is to exclude the length field.
+       pad = CIERESERVE + frameo + 4 - Cpos()
+
+       if pad < 0 {
+               Diag("dwarf: CIERESERVE too small by %d bytes.", -pad)
+               Errorexit()
+       }
+
+       strnput("", int(pad))
+
+       for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
+               s = Ctxt.Cursym
+               if s.Pcln == nil {
+                       continue
+               }
+
+               fdeo = Cpos()
+
+               // Emit a FDE, Section 6.4.1, starting wit a placeholder.
+               Thearch.Lput(0) // length, must be multiple of thearch.ptrsize
+               Thearch.Lput(0) // Pointer to the CIE above, at offset 0
+               addrput(0)      // initial location
+               addrput(0)      // address range
+
+               for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
+                       nextpc = pcsp.nextpc
+
+                       // pciterinit goes up to the end of the function,
+                       // but DWARF expects us to stop just before the end.
+                       if int64(nextpc) == s.Size {
+                               nextpc--
+                               if nextpc < pcsp.pc {
+                                       continue
+                               }
+                       }
+
+                       putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value))
+               }
+
+               fdesize = Cpos() - fdeo - 4 // exclude the length field.
+               pad = Rnd(fdesize, int64(Thearch.Ptrsize)) - fdesize
+               strnput("", int(pad))
+               fdesize += pad
+
+               // Emit the FDE header for real, Section 6.4.1.
+               Cseek(fdeo)
+
+               Thearch.Lput(uint32(fdesize))
+               if Linkmode == LinkExternal {
+                       adddwarfrel(framesec, framesym, frameo, 4, 0)
+                       adddwarfrel(framesec, s, frameo, Thearch.Ptrsize, 0)
+               } else {
+                       Thearch.Lput(0)
+                       addrput(s.Value)
+               }
+
+               addrput(s.Size)
+               Cseek(fdeo + 4 + fdesize)
+       }
+
+       Cflush()
+       framesize = Cpos() - frameo
+}
+
+/*
+ *  Walk DWarfDebugInfoEntries, and emit .debug_info
+ */
+const (
+       COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
+)
+
+func writeinfo() {
+       var compunit *DWDie
+       var unitstart int64
+       var here int64
+
+       fwdcount = 0
+       if infosec == nil {
+               infosec = Linklookup(Ctxt, ".dwarfinfo", 0)
+       }
+       infosec.R = infosec.R[:0]
+
+       if arangessec == nil {
+               arangessec = Linklookup(Ctxt, ".dwarfaranges", 0)
+       }
+       arangessec.R = arangessec.R[:0]
+
+       for compunit = dwroot.child; compunit != nil; compunit = compunit.link {
+               unitstart = Cpos()
+
+               // Write .debug_info Compilation Unit Header (sec 7.5.1)
+               // Fields marked with (*) must be changed for 64-bit dwarf
+               // This must match COMPUNITHEADERSIZE above.
+               Thearch.Lput(0) // unit_length (*), will be filled in later.
+               Thearch.Wput(2) // dwarf version (appendix F)
+
+               // debug_abbrev_offset (*)
+               if Linkmode == LinkExternal {
+                       adddwarfrel(infosec, abbrevsym, infoo, 4, 0)
+               } else {
+                       Thearch.Lput(0)
+               }
+
+               Cput(uint8(Thearch.Ptrsize)) // address_size
+
+               putdie(compunit)
+
+               here = Cpos()
+               Cseek(unitstart)
+               Thearch.Lput(uint32(here - unitstart - 4)) // exclude the length field.
+               Cseek(here)
+       }
+
+       Cflush()
+}
+
+/*
+ *  Emit .debug_pubnames/_types.  _info must have been written before,
+ *  because we need die->offs and infoo/infosize;
+ */
+func ispubname(die *DWDie) bool {
+       var a *DWAttr
+
+       switch die.abbrev {
+       case DW_ABRV_FUNCTION,
+               DW_ABRV_VARIABLE:
+               a = getattr(die, DW_AT_external)
+               return a != nil && a.value != 0
+       }
+
+       return false
+}
+
+func ispubtype(die *DWDie) bool {
+       return die.abbrev >= DW_ABRV_NULLTYPE
+}
+
+func writepub(ispub func(*DWDie) bool) int64 {
+       var compunit *DWDie
+       var die *DWDie
+       var dwa *DWAttr
+       var unitstart int64
+       var unitend int64
+       var sectionstart int64
+       var here int64
+
+       sectionstart = Cpos()
+
+       for compunit = dwroot.child; compunit != nil; compunit = compunit.link {
+               unitstart = compunit.offs - COMPUNITHEADERSIZE
+               if compunit.link != nil {
+                       unitend = compunit.link.offs - COMPUNITHEADERSIZE
+               } else {
+                       unitend = infoo + infosize
+               }
+
+               // Write .debug_pubnames/types  Header (sec 6.1.1)
+               Thearch.Lput(0)                           // unit_length (*), will be filled in later.
+               Thearch.Wput(2)                           // dwarf version (appendix F)
+               Thearch.Lput(uint32(unitstart))           // debug_info_offset (of the Comp unit Header)
+               Thearch.Lput(uint32(unitend - unitstart)) // debug_info_length
+
+               for die = compunit.child; die != nil; die = die.link {
+                       if !ispub(die) {
+                               continue
+                       }
+                       Thearch.Lput(uint32(die.offs - unitstart))
+                       dwa = getattr(die, DW_AT_name)
+                       strnput(dwa.data.(string), int(dwa.value+1))
+               }
+
+               Thearch.Lput(0)
+
+               here = Cpos()
+               Cseek(sectionstart)
+               Thearch.Lput(uint32(here - sectionstart - 4)) // exclude the length field.
+               Cseek(here)
+       }
+
+       return sectionstart
+}
+
+/*
+ *  emit .debug_aranges.  _info must have been written before,
+ *  because we need die->offs of dw_globals.
+ */
+func writearanges() int64 {
+       var compunit *DWDie
+       var b *DWAttr
+       var e *DWAttr
+       var headersize int
+       var sectionstart int64
+       var value int64
+
+       sectionstart = Cpos()
+       headersize = int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize))) // don't count unit_length field itself
+
+       for compunit = dwroot.child; compunit != nil; compunit = compunit.link {
+               b = getattr(compunit, DW_AT_low_pc)
+               if b == nil {
+                       continue
+               }
+               e = getattr(compunit, DW_AT_high_pc)
+               if e == nil {
+                       continue
+               }
+
+               // Write .debug_aranges  Header + entry  (sec 6.1.2)
+               Thearch.Lput(uint32(headersize) + 4*uint32(Thearch.Ptrsize) - 4) // unit_length (*)
+               Thearch.Wput(2)                                                  // dwarf version (appendix F)
+
+               value = compunit.offs - COMPUNITHEADERSIZE // debug_info_offset
+               if Linkmode == LinkExternal {
+                       adddwarfrel(arangessec, infosym, sectionstart, 4, value)
+               } else {
+                       Thearch.Lput(uint32(value))
+               }
+
+               Cput(uint8(Thearch.Ptrsize))        // address_size
+               Cput(0)                             // segment_size
+               strnput("", headersize-(4+2+4+1+1)) // align to thearch.ptrsize
+
+               if Linkmode == LinkExternal {
+                       adddwarfrel(arangessec, b.data.(*LSym), sectionstart, Thearch.Ptrsize, b.value-(b.data.(*LSym)).Value)
+               } else {
+                       addrput(b.value)
+               }
+
+               addrput(e.value - b.value)
+               addrput(0)
+               addrput(0)
+       }
+
+       Cflush()
+       return sectionstart
+}
+
+func writegdbscript() int64 {
+       var sectionstart int64
+
+       sectionstart = Cpos()
+
+       if gdbscript != "" {
+               Cput(1) // magic 1 byte?
+               strnput(gdbscript, len(gdbscript)+1)
+               Cflush()
+       }
+
+       return sectionstart
+}
+
+func align(size int64) {
+       if HEADTYPE == Hwindows { // Only Windows PE need section align.
+               strnput("", int(Rnd(size, PEFILEALIGN)-size))
+       }
+}
+
+func writedwarfreloc(s *LSym) int64 {
+       var i int
+       var ri int
+       var start int64
+       var r *Reloc
+
+       start = Cpos()
+       for ri = 0; ri < len(s.R); ri++ {
+               r = &s.R[ri]
+               if Iself {
+                       i = Thearch.Elfreloc1(r, int64(r.Off))
+               } else if HEADTYPE == Hdarwin {
+                       i = Thearch.Machoreloc1(r, int64(r.Off))
+               } else {
+                       i = -1
+               }
+               if i < 0 {
+                       Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+               }
+       }
+
+       return start
+}
+
+/*
+ * This is the main entry point for generating dwarf.  After emitting
+ * the mandatory debug_abbrev section, it calls writelines() to set up
+ * the per-compilation unit part of the DIE tree, while simultaneously
+ * emitting the debug_line section.  When the final tree contains
+ * forward references, it will write the debug_info section in 2
+ * passes.
+ *
+ */
+func Dwarfemitdebugsections() {
+       var infoe int64
+       var die *DWDie
+
+       if Debug['w'] != 0 { // disable dwarf
+               return
+       }
+
+       if Linkmode == LinkExternal && !Iself {
+               return
+       }
+
+       // For diagnostic messages.
+       newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
+
+       mkindex(&dwroot)
+       mkindex(&dwtypes)
+       mkindex(&dwglobals)
+
+       // Some types that must exist to define other ones.
+       newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>")
+
+       newdie(&dwtypes, DW_ABRV_NULLTYPE, "void")
+       newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer")
+
+       die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr") // needed for array size
+       newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0)
+       newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, int64(Thearch.Ptrsize), 0)
+       newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, obj.KindUintptr, 0)
+
+       // Needed by the prettyprinter code for interface inspection.
+       defgotype(lookup_or_diag("type.runtime._type"))
+
+       defgotype(lookup_or_diag("type.runtime.interfacetype"))
+       defgotype(lookup_or_diag("type.runtime.itab"))
+
+       genasmsym(defdwsymb)
+
+       writeabbrev()
+       align(abbrevsize)
+       writelines()
+       align(linesize)
+       writeframes()
+       align(framesize)
+
+       synthesizestringtypes(dwtypes.child)
+       synthesizeslicetypes(dwtypes.child)
+       synthesizemaptypes(dwtypes.child)
+       synthesizechantypes(dwtypes.child)
+
+       reversetree(&dwroot.child)
+       reversetree(&dwtypes.child)
+       reversetree(&dwglobals.child)
+
+       movetomodule(&dwtypes)
+       movetomodule(&dwglobals)
+
+       infoo = Cpos()
+       writeinfo()
+       infoe = Cpos()
+       pubnameso = infoe
+       pubtypeso = infoe
+       arangeso = infoe
+       gdbscripto = infoe
+
+       if fwdcount > 0 {
+               if Debug['v'] != 0 {
+                       fmt.Fprintf(&Bso, "%5.2f dwarf pass 2.\n", obj.Cputime())
+               }
+               Cseek(infoo)
+               writeinfo()
+               if fwdcount > 0 {
+                       Diag("dwarf: unresolved references after first dwarf info pass")
+                       Errorexit()
+               }
+
+               if infoe != Cpos() {
+                       Diag("dwarf: inconsistent second dwarf info pass")
+                       Errorexit()
+               }
+       }
+
+       infosize = infoe - infoo
+       align(infosize)
+
+       pubnameso = writepub(ispubname)
+       pubnamessize = Cpos() - pubnameso
+       align(pubnamessize)
+
+       pubtypeso = writepub(ispubtype)
+       pubtypessize = Cpos() - pubtypeso
+       align(pubtypessize)
+
+       arangeso = writearanges()
+       arangessize = Cpos() - arangeso
+       align(arangessize)
+
+       gdbscripto = writegdbscript()
+       gdbscriptsize = Cpos() - gdbscripto
+       align(gdbscriptsize)
+
+       for Cpos()&7 != 0 {
+               Cput(0)
+       }
+       inforeloco = writedwarfreloc(infosec)
+       inforelocsize = Cpos() - inforeloco
+       align(inforelocsize)
+
+       arangesreloco = writedwarfreloc(arangessec)
+       arangesrelocsize = Cpos() - arangesreloco
+       align(arangesrelocsize)
+
+       linereloco = writedwarfreloc(linesec)
+       linerelocsize = Cpos() - linereloco
+       align(linerelocsize)
+
+       framereloco = writedwarfreloc(framesec)
+       framerelocsize = Cpos() - framereloco
+       align(framerelocsize)
+}
+
+/*
+ *  Elf.
+ */
+const (
+       ElfStrDebugAbbrev = iota
+       ElfStrDebugAranges
+       ElfStrDebugFrame
+       ElfStrDebugInfo
+       ElfStrDebugLine
+       ElfStrDebugLoc
+       ElfStrDebugMacinfo
+       ElfStrDebugPubNames
+       ElfStrDebugPubTypes
+       ElfStrDebugRanges
+       ElfStrDebugStr
+       ElfStrGDBScripts
+       ElfStrRelDebugInfo
+       ElfStrRelDebugAranges
+       ElfStrRelDebugLine
+       ElfStrRelDebugFrame
+       NElfStrDbg
+)
+
+var elfstrdbg [NElfStrDbg]int64
+
+func dwarfaddshstrings(shstrtab *LSym) {
+       if Debug['w'] != 0 { // disable dwarf
+               return
+       }
+
+       elfstrdbg[ElfStrDebugAbbrev] = Addstring(shstrtab, ".debug_abbrev")
+       elfstrdbg[ElfStrDebugAranges] = Addstring(shstrtab, ".debug_aranges")
+       elfstrdbg[ElfStrDebugFrame] = Addstring(shstrtab, ".debug_frame")
+       elfstrdbg[ElfStrDebugInfo] = Addstring(shstrtab, ".debug_info")
+       elfstrdbg[ElfStrDebugLine] = Addstring(shstrtab, ".debug_line")
+       elfstrdbg[ElfStrDebugLoc] = Addstring(shstrtab, ".debug_loc")
+       elfstrdbg[ElfStrDebugMacinfo] = Addstring(shstrtab, ".debug_macinfo")
+       elfstrdbg[ElfStrDebugPubNames] = Addstring(shstrtab, ".debug_pubnames")
+       elfstrdbg[ElfStrDebugPubTypes] = Addstring(shstrtab, ".debug_pubtypes")
+       elfstrdbg[ElfStrDebugRanges] = Addstring(shstrtab, ".debug_ranges")
+       elfstrdbg[ElfStrDebugStr] = Addstring(shstrtab, ".debug_str")
+       elfstrdbg[ElfStrGDBScripts] = Addstring(shstrtab, ".debug_gdb_scripts")
+       if Linkmode == LinkExternal {
+               if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+                       elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rela.debug_info")
+                       elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rela.debug_aranges")
+                       elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rela.debug_line")
+                       elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rela.debug_frame")
+               } else {
+                       elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rel.debug_info")
+                       elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rel.debug_aranges")
+                       elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rel.debug_line")
+                       elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rel.debug_frame")
+               }
+
+               infosym = Linklookup(Ctxt, ".debug_info", 0)
+               infosym.Hide = 1
+
+               abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0)
+               abbrevsym.Hide = 1
+
+               linesym = Linklookup(Ctxt, ".debug_line", 0)
+               linesym.Hide = 1
+
+               framesym = Linklookup(Ctxt, ".debug_frame", 0)
+               framesym.Hide = 1
+       }
+}
+
+// Add section symbols for DWARF debug info.  This is called before
+// dwarfaddelfheaders.
+func dwarfaddelfsectionsyms() {
+       if infosym != nil {
+               infosympos = Cpos()
+               putelfsectionsym(infosym, 0)
+       }
+
+       if abbrevsym != nil {
+               abbrevsympos = Cpos()
+               putelfsectionsym(abbrevsym, 0)
+       }
+
+       if linesym != nil {
+               linesympos = Cpos()
+               putelfsectionsym(linesym, 0)
+       }
+
+       if framesym != nil {
+               framesympos = Cpos()
+               putelfsectionsym(framesym, 0)
+       }
+}
+
+func dwarfaddelfrelocheader(elfstr int, shdata *ElfShdr, off int64, size int64) {
+       var sh *ElfShdr
+
+       sh = newElfShdr(elfstrdbg[elfstr])
+       if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+               sh.type_ = SHT_RELA
+       } else {
+               sh.type_ = SHT_REL
+       }
+
+       sh.entsize = uint64(Thearch.Ptrsize) * 2
+       if sh.type_ == SHT_RELA {
+               sh.entsize += uint64(Thearch.Ptrsize)
+       }
+       sh.link = uint32(elfshname(".symtab").shnum)
+       sh.info = uint32(shdata.shnum)
+       sh.off = uint64(off)
+       sh.size = uint64(size)
+       sh.addralign = uint64(Thearch.Ptrsize)
+}
+
+func dwarfaddelfheaders() {
+       var sh *ElfShdr
+       var shinfo *ElfShdr
+       var sharanges *ElfShdr
+       var shline *ElfShdr
+       var shframe *ElfShdr
+
+       if Debug['w'] != 0 { // disable dwarf
+               return
+       }
+
+       sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev])
+       sh.type_ = SHT_PROGBITS
+       sh.off = uint64(abbrevo)
+       sh.size = uint64(abbrevsize)
+       sh.addralign = 1
+       if abbrevsympos > 0 {
+               putelfsymshndx(abbrevsympos, sh.shnum)
+       }
+
+       sh = newElfShdr(elfstrdbg[ElfStrDebugLine])
+       sh.type_ = SHT_PROGBITS
+       sh.off = uint64(lineo)
+       sh.size = uint64(linesize)
+       sh.addralign = 1
+       if linesympos > 0 {
+               putelfsymshndx(linesympos, sh.shnum)
+       }
+       shline = sh
+
+       sh = newElfShdr(elfstrdbg[ElfStrDebugFrame])
+       sh.type_ = SHT_PROGBITS
+       sh.off = uint64(frameo)
+       sh.size = uint64(framesize)
+       sh.addralign = 1
+       if framesympos > 0 {
+               putelfsymshndx(framesympos, sh.shnum)
+       }
+       shframe = sh
+
+       sh = newElfShdr(elfstrdbg[ElfStrDebugInfo])
+       sh.type_ = SHT_PROGBITS
+       sh.off = uint64(infoo)
+       sh.size = uint64(infosize)
+       sh.addralign = 1
+       if infosympos > 0 {
+               putelfsymshndx(infosympos, sh.shnum)
+       }
+       shinfo = sh
+
+       if pubnamessize > 0 {
+               sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames])
+               sh.type_ = SHT_PROGBITS
+               sh.off = uint64(pubnameso)
+               sh.size = uint64(pubnamessize)
+               sh.addralign = 1
+       }
+
+       if pubtypessize > 0 {
+               sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes])
+               sh.type_ = SHT_PROGBITS
+               sh.off = uint64(pubtypeso)
+               sh.size = uint64(pubtypessize)
+               sh.addralign = 1
+       }
+
+       sharanges = nil
+       if arangessize != 0 {
+               sh = newElfShdr(elfstrdbg[ElfStrDebugAranges])
+               sh.type_ = SHT_PROGBITS
+               sh.off = uint64(arangeso)
+               sh.size = uint64(arangessize)
+               sh.addralign = 1
+               sharanges = sh
+       }
+
+       if gdbscriptsize != 0 {
+               sh = newElfShdr(elfstrdbg[ElfStrGDBScripts])
+               sh.type_ = SHT_PROGBITS
+               sh.off = uint64(gdbscripto)
+               sh.size = uint64(gdbscriptsize)
+               sh.addralign = 1
+       }
+
+       if inforelocsize != 0 {
+               dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize)
+       }
+
+       if arangesrelocsize != 0 {
+               dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize)
+       }
+
+       if linerelocsize != 0 {
+               dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize)
+       }
+
+       if framerelocsize != 0 {
+               dwarfaddelfrelocheader(ElfStrRelDebugFrame, shframe, framereloco, framerelocsize)
+       }
+}
+
+/*
+ * Macho
+ */
+func dwarfaddmachoheaders() {
+       var msect *MachoSect
+       var ms *MachoSeg
+       var fakestart int64
+       var nsect int
+
+       if Debug['w'] != 0 { // disable dwarf
+               return
+       }
+
+       // Zero vsize segments won't be loaded in memory, even so they
+       // have to be page aligned in the file.
+       fakestart = abbrevo &^ 0xfff
+
+       nsect = 4
+       if pubnamessize > 0 {
+               nsect++
+       }
+       if pubtypessize > 0 {
+               nsect++
+       }
+       if arangessize > 0 {
+               nsect++
+       }
+       if gdbscriptsize > 0 {
+               nsect++
+       }
+
+       ms = newMachoSeg("__DWARF", nsect)
+       ms.fileoffset = uint64(fakestart)
+       ms.filesize = uint64(abbrevo) - uint64(fakestart)
+       ms.vaddr = ms.fileoffset + Segdata.Vaddr - Segdata.Fileoff
+
+       msect = newMachoSect(ms, "__debug_abbrev", "__DWARF")
+       msect.off = uint32(abbrevo)
+       msect.size = uint64(abbrevsize)
+       msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
+       ms.filesize += msect.size
+
+       msect = newMachoSect(ms, "__debug_line", "__DWARF")
+       msect.off = uint32(lineo)
+       msect.size = uint64(linesize)
+       msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
+       ms.filesize += msect.size
+
+       msect = newMachoSect(ms, "__debug_frame", "__DWARF")
+       msect.off = uint32(frameo)
+       msect.size = uint64(framesize)
+       msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
+       ms.filesize += msect.size
+
+       msect = newMachoSect(ms, "__debug_info", "__DWARF")
+       msect.off = uint32(infoo)
+       msect.size = uint64(infosize)
+       msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
+       ms.filesize += msect.size
+
+       if pubnamessize > 0 {
+               msect = newMachoSect(ms, "__debug_pubnames", "__DWARF")
+               msect.off = uint32(pubnameso)
+               msect.size = uint64(pubnamessize)
+               msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
+               ms.filesize += msect.size
+       }
+
+       if pubtypessize > 0 {
+               msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF")
+               msect.off = uint32(pubtypeso)
+               msect.size = uint64(pubtypessize)
+               msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
+               ms.filesize += msect.size
+       }
+
+       if arangessize > 0 {
+               msect = newMachoSect(ms, "__debug_aranges", "__DWARF")
+               msect.off = uint32(arangeso)
+               msect.size = uint64(arangessize)
+               msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
+               ms.filesize += msect.size
+       }
+
+       // TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
+       if gdbscriptsize > 0 {
+               msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF")
+               msect.off = uint32(gdbscripto)
+               msect.size = uint64(gdbscriptsize)
+               msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
+               ms.filesize += msect.size
+       }
+}
+
+/*
+ * Windows PE
+ */
+func dwarfaddpeheaders() {
+       if Debug['w'] != 0 { // disable dwarf
+               return
+       }
+
+       newPEDWARFSection(".debug_abbrev", abbrevsize)
+       newPEDWARFSection(".debug_line", linesize)
+       newPEDWARFSection(".debug_frame", framesize)
+       newPEDWARFSection(".debug_info", infosize)
+       newPEDWARFSection(".debug_pubnames", pubnamessize)
+       newPEDWARFSection(".debug_pubtypes", pubtypessize)
+       newPEDWARFSection(".debug_aranges", arangessize)
+       newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize)
+}
diff --git a/src/cmd/internal/ld/dwarf_defs.go b/src/cmd/internal/ld/dwarf_defs.go
new file mode 100644 (file)
index 0000000..5be8389
--- /dev/null
@@ -0,0 +1,500 @@
+// Copyright 2010 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 ld
+
+// TODO/NICETOHAVE:
+//   - eliminate DW_CLS_ if not used
+//   - package info in compilation units
+//   - assign global variables and types to their packages
+//   - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
+//     ptype struct '[]uint8' and qualifiers need to be quoted away
+//   - lexical scoping is lost, so gdb gets confused as to which 'obj.i' you mean.
+//   - file:line info for variables
+//   - make strings a typedef so prettyprinters can see the underlying string type
+//
+// Copyright 2010 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.
+
+/*
+ * Emit debug_abbrevs, debug_info and debug_line sections to current
+ * offset in cout.
+ */
+
+/*
+ * Add the dwarf section names to the ELF
+ * s[ection]h[eader]str[ing]tab.  Prerequisite for
+ * dwarfaddelfheaders().
+ */
+
+/*
+ * Add section headers pointing to the sections emitted in
+ * dwarfemitdebugsections.
+ */
+// Copyright 2010 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.
+
+// Cut, pasted, tr-and-awk'ed from tables in
+// http://dwarfstd.org/doc/Dwarf3.pdf
+
+// Table 18
+const (
+       DW_TAG_array_type               = 0x01
+       DW_TAG_class_type               = 0x02
+       DW_TAG_entry_point              = 0x03
+       DW_TAG_enumeration_type         = 0x04
+       DW_TAG_formal_parameter         = 0x05
+       DW_TAG_imported_declaration     = 0x08
+       DW_TAG_label                    = 0x0a
+       DW_TAG_lexical_block            = 0x0b
+       DW_TAG_member                   = 0x0d
+       DW_TAG_pointer_type             = 0x0f
+       DW_TAG_reference_type           = 0x10
+       DW_TAG_compile_unit             = 0x11
+       DW_TAG_string_type              = 0x12
+       DW_TAG_structure_type           = 0x13
+       DW_TAG_subroutine_type          = 0x15
+       DW_TAG_typedef                  = 0x16
+       DW_TAG_union_type               = 0x17
+       DW_TAG_unspecified_parameters   = 0x18
+       DW_TAG_variant                  = 0x19
+       DW_TAG_common_block             = 0x1a
+       DW_TAG_common_inclusion         = 0x1b
+       DW_TAG_inheritance              = 0x1c
+       DW_TAG_inlined_subroutine       = 0x1d
+       DW_TAG_module                   = 0x1e
+       DW_TAG_ptr_to_member_type       = 0x1f
+       DW_TAG_set_type                 = 0x20
+       DW_TAG_subrange_type            = 0x21
+       DW_TAG_with_stmt                = 0x22
+       DW_TAG_access_declaration       = 0x23
+       DW_TAG_base_type                = 0x24
+       DW_TAG_catch_block              = 0x25
+       DW_TAG_const_type               = 0x26
+       DW_TAG_constant                 = 0x27
+       DW_TAG_enumerator               = 0x28
+       DW_TAG_file_type                = 0x29
+       DW_TAG_friend                   = 0x2a
+       DW_TAG_namelist                 = 0x2b
+       DW_TAG_namelist_item            = 0x2c
+       DW_TAG_packed_type              = 0x2d
+       DW_TAG_subprogram               = 0x2e
+       DW_TAG_template_type_parameter  = 0x2f
+       DW_TAG_template_value_parameter = 0x30
+       DW_TAG_thrown_type              = 0x31
+       DW_TAG_try_block                = 0x32
+       DW_TAG_variant_part             = 0x33
+       DW_TAG_variable                 = 0x34
+       DW_TAG_volatile_type            = 0x35
+       DW_TAG_dwarf_procedure          = 0x36
+       DW_TAG_restrict_type            = 0x37
+       DW_TAG_interface_type           = 0x38
+       DW_TAG_namespace                = 0x39
+       DW_TAG_imported_module          = 0x3a
+       DW_TAG_unspecified_type         = 0x3b
+       DW_TAG_partial_unit             = 0x3c
+       DW_TAG_imported_unit            = 0x3d
+       DW_TAG_condition                = 0x3f
+       DW_TAG_shared_type              = 0x40
+       DW_TAG_type_unit                = 0x41
+       DW_TAG_rvalue_reference_type    = 0x42
+       DW_TAG_template_alias           = 0x43
+       DW_TAG_lo_user                  = 0x4080
+       DW_TAG_hi_user                  = 0xffff
+)
+
+// Table 19
+const (
+       DW_CHILDREN_no  = 0x00
+       DW_CHILDREN_yes = 0x01
+)
+
+// Not from the spec, but logicaly belongs here
+const (
+       DW_CLS_ADDRESS = 0x01 + iota
+       DW_CLS_BLOCK
+       DW_CLS_CONSTANT
+       DW_CLS_FLAG
+       DW_CLS_PTR
+       DW_CLS_REFERENCE
+       DW_CLS_ADDRLOC
+       DW_CLS_STRING
+)
+
+// Table 20
+const (
+       DW_AT_sibling              = 0x01
+       DW_AT_location             = 0x02
+       DW_AT_name                 = 0x03
+       DW_AT_ordering             = 0x09
+       DW_AT_byte_size            = 0x0b
+       DW_AT_bit_offset           = 0x0c
+       DW_AT_bit_size             = 0x0d
+       DW_AT_stmt_list            = 0x10
+       DW_AT_low_pc               = 0x11
+       DW_AT_high_pc              = 0x12
+       DW_AT_language             = 0x13
+       DW_AT_discr                = 0x15
+       DW_AT_discr_value          = 0x16
+       DW_AT_visibility           = 0x17
+       DW_AT_import               = 0x18
+       DW_AT_string_length        = 0x19
+       DW_AT_common_reference     = 0x1a
+       DW_AT_comp_dir             = 0x1b
+       DW_AT_const_value          = 0x1c
+       DW_AT_containing_type      = 0x1d
+       DW_AT_default_value        = 0x1e
+       DW_AT_inline               = 0x20
+       DW_AT_is_optional          = 0x21
+       DW_AT_lower_bound          = 0x22
+       DW_AT_producer             = 0x25
+       DW_AT_prototyped           = 0x27
+       DW_AT_return_addr          = 0x2a
+       DW_AT_start_scope          = 0x2c
+       DW_AT_bit_stride           = 0x2e
+       DW_AT_upper_bound          = 0x2f
+       DW_AT_abstract_origin      = 0x31
+       DW_AT_accessibility        = 0x32
+       DW_AT_address_class        = 0x33
+       DW_AT_artificial           = 0x34
+       DW_AT_base_types           = 0x35
+       DW_AT_calling_convention   = 0x36
+       DW_AT_count                = 0x37
+       DW_AT_data_member_location = 0x38
+       DW_AT_decl_column          = 0x39
+       DW_AT_decl_file            = 0x3a
+       DW_AT_decl_line            = 0x3b
+       DW_AT_declaration          = 0x3c
+       DW_AT_discr_list           = 0x3d
+       DW_AT_encoding             = 0x3e
+       DW_AT_external             = 0x3f
+       DW_AT_frame_base           = 0x40
+       DW_AT_friend               = 0x41
+       DW_AT_identifier_case      = 0x42
+       DW_AT_macro_info           = 0x43
+       DW_AT_namelist_item        = 0x44
+       DW_AT_priority             = 0x45
+       DW_AT_segment              = 0x46
+       DW_AT_specification        = 0x47
+       DW_AT_static_link          = 0x48
+       DW_AT_type                 = 0x49
+       DW_AT_use_location         = 0x4a
+       DW_AT_variable_parameter   = 0x4b
+       DW_AT_virtuality           = 0x4c
+       DW_AT_vtable_elem_location = 0x4d
+       DW_AT_allocated            = 0x4e
+       DW_AT_associated           = 0x4f
+       DW_AT_data_location        = 0x50
+       DW_AT_byte_stride          = 0x51
+       DW_AT_entry_pc             = 0x52
+       DW_AT_use_UTF8             = 0x53
+       DW_AT_extension            = 0x54
+       DW_AT_ranges               = 0x55
+       DW_AT_trampoline           = 0x56
+       DW_AT_call_column          = 0x57
+       DW_AT_call_file            = 0x58
+       DW_AT_call_line            = 0x59
+       DW_AT_description          = 0x5a
+       DW_AT_binary_scale         = 0x5b
+       DW_AT_decimal_scale        = 0x5c
+       DW_AT_small                = 0x5d
+       DW_AT_decimal_sign         = 0x5e
+       DW_AT_digit_count          = 0x5f
+       DW_AT_picture_string       = 0x60
+       DW_AT_mutable              = 0x61
+       DW_AT_threads_scaled       = 0x62
+       DW_AT_explicit             = 0x63
+       DW_AT_object_pointer       = 0x64
+       DW_AT_endianity            = 0x65
+       DW_AT_elemental            = 0x66
+       DW_AT_pure                 = 0x67
+       DW_AT_recursive            = 0x68
+       DW_AT_lo_user              = 0x2000
+       DW_AT_hi_user              = 0x3fff
+)
+
+// Table 21
+const (
+       DW_FORM_addr      = 0x01
+       DW_FORM_block2    = 0x03
+       DW_FORM_block4    = 0x04
+       DW_FORM_data2     = 0x05
+       DW_FORM_data4     = 0x06
+       DW_FORM_data8     = 0x07
+       DW_FORM_string    = 0x08
+       DW_FORM_block     = 0x09
+       DW_FORM_block1    = 0x0a
+       DW_FORM_data1     = 0x0b
+       DW_FORM_flag      = 0x0c
+       DW_FORM_sdata     = 0x0d
+       DW_FORM_strp      = 0x0e
+       DW_FORM_udata     = 0x0f
+       DW_FORM_ref_addr  = 0x10
+       DW_FORM_ref1      = 0x11
+       DW_FORM_ref2      = 0x12
+       DW_FORM_ref4      = 0x13
+       DW_FORM_ref8      = 0x14
+       DW_FORM_ref_udata = 0x15
+       DW_FORM_indirect  = 0x16
+)
+
+// Table 24 (#operands, notes)
+const (
+       DW_OP_addr                = 0x03
+       DW_OP_deref               = 0x06
+       DW_OP_const1u             = 0x08
+       DW_OP_const1s             = 0x09
+       DW_OP_const2u             = 0x0a
+       DW_OP_const2s             = 0x0b
+       DW_OP_const4u             = 0x0c
+       DW_OP_const4s             = 0x0d
+       DW_OP_const8u             = 0x0e
+       DW_OP_const8s             = 0x0f
+       DW_OP_constu              = 0x10
+       DW_OP_consts              = 0x11
+       DW_OP_dup                 = 0x12
+       DW_OP_drop                = 0x13
+       DW_OP_over                = 0x14
+       DW_OP_pick                = 0x15
+       DW_OP_swap                = 0x16
+       DW_OP_rot                 = 0x17
+       DW_OP_xderef              = 0x18
+       DW_OP_abs                 = 0x19
+       DW_OP_and                 = 0x1a
+       DW_OP_div                 = 0x1b
+       DW_OP_minus               = 0x1c
+       DW_OP_mod                 = 0x1d
+       DW_OP_mul                 = 0x1e
+       DW_OP_neg                 = 0x1f
+       DW_OP_not                 = 0x20
+       DW_OP_or                  = 0x21
+       DW_OP_plus                = 0x22
+       DW_OP_plus_uconst         = 0x23
+       DW_OP_shl                 = 0x24
+       DW_OP_shr                 = 0x25
+       DW_OP_shra                = 0x26
+       DW_OP_xor                 = 0x27
+       DW_OP_skip                = 0x2f
+       DW_OP_bra                 = 0x28
+       DW_OP_eq                  = 0x29
+       DW_OP_ge                  = 0x2a
+       DW_OP_gt                  = 0x2b
+       DW_OP_le                  = 0x2c
+       DW_OP_lt                  = 0x2d
+       DW_OP_ne                  = 0x2e
+       DW_OP_lit0                = 0x30
+       DW_OP_lit31               = 0x4f
+       DW_OP_reg0                = 0x50
+       DW_OP_reg31               = 0x6f
+       DW_OP_breg0               = 0x70
+       DW_OP_breg31              = 0x8f
+       DW_OP_regx                = 0x90
+       DW_OP_fbreg               = 0x91
+       DW_OP_bregx               = 0x92
+       DW_OP_piece               = 0x93
+       DW_OP_deref_size          = 0x94
+       DW_OP_xderef_size         = 0x95
+       DW_OP_nop                 = 0x96
+       DW_OP_push_object_address = 0x97
+       DW_OP_call2               = 0x98
+       DW_OP_call4               = 0x99
+       DW_OP_call_ref            = 0x9a
+       DW_OP_form_tls_address    = 0x9b
+       DW_OP_call_frame_cfa      = 0x9c
+       DW_OP_bit_piece           = 0x9d
+       DW_OP_lo_user             = 0xe0
+       DW_OP_hi_user             = 0xff
+)
+
+// Table 25
+const (
+       DW_ATE_address         = 0x01
+       DW_ATE_boolean         = 0x02
+       DW_ATE_complex_float   = 0x03
+       DW_ATE_float           = 0x04
+       DW_ATE_signed          = 0x05
+       DW_ATE_signed_char     = 0x06
+       DW_ATE_unsigned        = 0x07
+       DW_ATE_unsigned_char   = 0x08
+       DW_ATE_imaginary_float = 0x09
+       DW_ATE_packed_decimal  = 0x0a
+       DW_ATE_numeric_string  = 0x0b
+       DW_ATE_edited          = 0x0c
+       DW_ATE_signed_fixed    = 0x0d
+       DW_ATE_unsigned_fixed  = 0x0e
+       DW_ATE_decimal_float   = 0x0f
+       DW_ATE_lo_user         = 0x80
+       DW_ATE_hi_user         = 0xff
+)
+
+// Table 26
+const (
+       DW_DS_unsigned           = 0x01
+       DW_DS_leading_overpunch  = 0x02
+       DW_DS_trailing_overpunch = 0x03
+       DW_DS_leading_separate   = 0x04
+       DW_DS_trailing_separate  = 0x05
+)
+
+// Table 27
+const (
+       DW_END_default = 0x00
+       DW_END_big     = 0x01
+       DW_END_little  = 0x02
+       DW_END_lo_user = 0x40
+       DW_END_hi_user = 0xff
+)
+
+// Table 28
+const (
+       DW_ACCESS_public    = 0x01
+       DW_ACCESS_protected = 0x02
+       DW_ACCESS_private   = 0x03
+)
+
+// Table 29
+const (
+       DW_VIS_local     = 0x01
+       DW_VIS_exported  = 0x02
+       DW_VIS_qualified = 0x03
+)
+
+// Table 30
+const (
+       DW_VIRTUALITY_none         = 0x00
+       DW_VIRTUALITY_virtual      = 0x01
+       DW_VIRTUALITY_pure_virtual = 0x02
+)
+
+// Table 31
+const (
+       DW_LANG_C89            = 0x0001
+       DW_LANG_C              = 0x0002
+       DW_LANG_Ada83          = 0x0003
+       DW_LANG_C_plus_plus    = 0x0004
+       DW_LANG_Cobol74        = 0x0005
+       DW_LANG_Cobol85        = 0x0006
+       DW_LANG_Fortran77      = 0x0007
+       DW_LANG_Fortran90      = 0x0008
+       DW_LANG_Pascal83       = 0x0009
+       DW_LANG_Modula2        = 0x000a
+       DW_LANG_Java           = 0x000b
+       DW_LANG_C99            = 0x000c
+       DW_LANG_Ada95          = 0x000d
+       DW_LANG_Fortran95      = 0x000e
+       DW_LANG_PLI            = 0x000f
+       DW_LANG_ObjC           = 0x0010
+       DW_LANG_ObjC_plus_plus = 0x0011
+       DW_LANG_UPC            = 0x0012
+       DW_LANG_D              = 0x0013
+       DW_LANG_Python         = 0x0014
+       DW_LANG_Go             = 0x0016
+       DW_LANG_lo_user        = 0x8000
+       DW_LANG_hi_user        = 0xffff
+)
+
+// Table 32
+const (
+       DW_ID_case_sensitive   = 0x00
+       DW_ID_up_case          = 0x01
+       DW_ID_down_case        = 0x02
+       DW_ID_case_insensitive = 0x03
+)
+
+// Table 33
+const (
+       DW_CC_normal  = 0x01
+       DW_CC_program = 0x02
+       DW_CC_nocall  = 0x03
+       DW_CC_lo_user = 0x40
+       DW_CC_hi_user = 0xff
+)
+
+// Table 34
+const (
+       DW_INL_not_inlined          = 0x00
+       DW_INL_inlined              = 0x01
+       DW_INL_declared_not_inlined = 0x02
+       DW_INL_declared_inlined     = 0x03
+)
+
+// Table 35
+const (
+       DW_ORD_row_major = 0x00
+       DW_ORD_col_major = 0x01
+)
+
+// Table 36
+const (
+       DW_DSC_label = 0x00
+       DW_DSC_range = 0x01
+)
+
+// Table 37
+const (
+       DW_LNS_copy               = 0x01
+       DW_LNS_advance_pc         = 0x02
+       DW_LNS_advance_line       = 0x03
+       DW_LNS_set_file           = 0x04
+       DW_LNS_set_column         = 0x05
+       DW_LNS_negate_stmt        = 0x06
+       DW_LNS_set_basic_block    = 0x07
+       DW_LNS_const_add_pc       = 0x08
+       DW_LNS_fixed_advance_pc   = 0x09
+       DW_LNS_set_prologue_end   = 0x0a
+       DW_LNS_set_epilogue_begin = 0x0b
+       DW_LNS_set_isa            = 0x0c
+)
+
+// Table 38
+const (
+       DW_LNE_end_sequence = 0x01
+       DW_LNE_set_address  = 0x02
+       DW_LNE_define_file  = 0x03
+       DW_LNE_lo_user      = 0x80
+       DW_LNE_hi_user      = 0xff
+)
+
+// Table 39
+const (
+       DW_MACINFO_define     = 0x01
+       DW_MACINFO_undef      = 0x02
+       DW_MACINFO_start_file = 0x03
+       DW_MACINFO_end_file   = 0x04
+       DW_MACINFO_vendor_ext = 0xff
+)
+
+// Table 40.
+const (
+       DW_CFA_nop                = 0x00
+       DW_CFA_set_loc            = 0x01
+       DW_CFA_advance_loc1       = 0x02
+       DW_CFA_advance_loc2       = 0x03
+       DW_CFA_advance_loc4       = 0x04
+       DW_CFA_offset_extended    = 0x05
+       DW_CFA_restore_extended   = 0x06
+       DW_CFA_undefined          = 0x07
+       DW_CFA_same_value         = 0x08
+       DW_CFA_register           = 0x09
+       DW_CFA_remember_state     = 0x0a
+       DW_CFA_restore_state      = 0x0b
+       DW_CFA_def_cfa            = 0x0c
+       DW_CFA_def_cfa_register   = 0x0d
+       DW_CFA_def_cfa_offset     = 0x0e
+       DW_CFA_def_cfa_expression = 0x0f
+       DW_CFA_expression         = 0x10
+       DW_CFA_offset_extended_sf = 0x11
+       DW_CFA_def_cfa_sf         = 0x12
+       DW_CFA_def_cfa_offset_sf  = 0x13
+       DW_CFA_val_offset         = 0x14
+       DW_CFA_val_offset_sf      = 0x15
+       DW_CFA_val_expression     = 0x16
+       DW_CFA_lo_user            = 0x1c
+       DW_CFA_hi_user            = 0x3f
+       DW_CFA_advance_loc        = 0x1 << 6
+       DW_CFA_offset             = 0x2 << 6
+       DW_CFA_restore            = 0x3 << 6
+)
diff --git a/src/cmd/internal/ld/elf.go b/src/cmd/internal/ld/elf.go
new file mode 100644 (file)
index 0000000..ca95fe0
--- /dev/null
@@ -0,0 +1,2448 @@
+// Copyright 2009 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 ld
+
+import (
+       "fmt"
+       "os"
+)
+
+/*
+ * Derived from:
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
+ * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
+ * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
+ * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
+ * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
+ * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
+ *
+ * Copyright (c) 1996-1998 John D. Polstra.  All rights reserved.
+ * Copyright (c) 2001 David E. O'Brien
+ * Portions Copyright 2009 The Go Authors.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * ELF definitions that are independent of architecture or word size.
+ */
+
+/*
+ * Note header.  The ".note" section contains an array of notes.  Each
+ * begins with this header, aligned to a word boundary.  Immediately
+ * following the note header is n_namesz bytes of name, padded to the
+ * next word boundary.  Then comes n_descsz bytes of descriptor, again
+ * padded to a word boundary.  The values of n_namesz and n_descsz do
+ * not include the padding.
+ */
+type Elf_Note struct {
+       n_namesz uint32
+       n_descsz uint32
+       n_type   uint32
+}
+
+const (
+       EI_MAG0              = 0
+       EI_MAG1              = 1
+       EI_MAG2              = 2
+       EI_MAG3              = 3
+       EI_CLASS             = 4
+       EI_DATA              = 5
+       EI_VERSION           = 6
+       EI_OSABI             = 7
+       EI_ABIVERSION        = 8
+       OLD_EI_BRAND         = 8
+       EI_PAD               = 9
+       EI_NIDENT            = 16
+       ELFMAG0              = 0x7f
+       ELFMAG1              = 'E'
+       ELFMAG2              = 'L'
+       ELFMAG3              = 'F'
+       SELFMAG              = 4
+       EV_NONE              = 0
+       EV_CURRENT           = 1
+       ELFCLASSNONE         = 0
+       ELFCLASS32           = 1
+       ELFCLASS64           = 2
+       ELFDATANONE          = 0
+       ELFDATA2LSB          = 1
+       ELFDATA2MSB          = 2
+       ELFOSABI_NONE        = 0
+       ELFOSABI_HPUX        = 1
+       ELFOSABI_NETBSD      = 2
+       ELFOSABI_LINUX       = 3
+       ELFOSABI_HURD        = 4
+       ELFOSABI_86OPEN      = 5
+       ELFOSABI_SOLARIS     = 6
+       ELFOSABI_AIX         = 7
+       ELFOSABI_IRIX        = 8
+       ELFOSABI_FREEBSD     = 9
+       ELFOSABI_TRU64       = 10
+       ELFOSABI_MODESTO     = 11
+       ELFOSABI_OPENBSD     = 12
+       ELFOSABI_OPENVMS     = 13
+       ELFOSABI_NSK         = 14
+       ELFOSABI_ARM         = 97
+       ELFOSABI_STANDALONE  = 255
+       ELFOSABI_SYSV        = ELFOSABI_NONE
+       ELFOSABI_MONTEREY    = ELFOSABI_AIX
+       ET_NONE              = 0
+       ET_REL               = 1
+       ET_EXEC              = 2
+       ET_DYN               = 3
+       ET_CORE              = 4
+       ET_LOOS              = 0xfe00
+       ET_HIOS              = 0xfeff
+       ET_LOPROC            = 0xff00
+       ET_HIPROC            = 0xffff
+       EM_NONE              = 0
+       EM_M32               = 1
+       EM_SPARC             = 2
+       EM_386               = 3
+       EM_68K               = 4
+       EM_88K               = 5
+       EM_860               = 7
+       EM_MIPS              = 8
+       EM_S370              = 9
+       EM_MIPS_RS3_LE       = 10
+       EM_PARISC            = 15
+       EM_VPP500            = 17
+       EM_SPARC32PLUS       = 18
+       EM_960               = 19
+       EM_PPC               = 20
+       EM_PPC64             = 21
+       EM_S390              = 22
+       EM_V800              = 36
+       EM_FR20              = 37
+       EM_RH32              = 38
+       EM_RCE               = 39
+       EM_ARM               = 40
+       EM_SH                = 42
+       EM_SPARCV9           = 43
+       EM_TRICORE           = 44
+       EM_ARC               = 45
+       EM_H8_300            = 46
+       EM_H8_300H           = 47
+       EM_H8S               = 48
+       EM_H8_500            = 49
+       EM_IA_64             = 50
+       EM_MIPS_X            = 51
+       EM_COLDFIRE          = 52
+       EM_68HC12            = 53
+       EM_MMA               = 54
+       EM_PCP               = 55
+       EM_NCPU              = 56
+       EM_NDR1              = 57
+       EM_STARCORE          = 58
+       EM_ME16              = 59
+       EM_ST100             = 60
+       EM_TINYJ             = 61
+       EM_X86_64            = 62
+       EM_486               = 6
+       EM_MIPS_RS4_BE       = 10
+       EM_ALPHA_STD         = 41
+       EM_ALPHA             = 0x9026
+       SHN_UNDEF            = 0
+       SHN_LORESERVE        = 0xff00
+       SHN_LOPROC           = 0xff00
+       SHN_HIPROC           = 0xff1f
+       SHN_LOOS             = 0xff20
+       SHN_HIOS             = 0xff3f
+       SHN_ABS              = 0xfff1
+       SHN_COMMON           = 0xfff2
+       SHN_XINDEX           = 0xffff
+       SHN_HIRESERVE        = 0xffff
+       SHT_NULL             = 0
+       SHT_PROGBITS         = 1
+       SHT_SYMTAB           = 2
+       SHT_STRTAB           = 3
+       SHT_RELA             = 4
+       SHT_HASH             = 5
+       SHT_DYNAMIC          = 6
+       SHT_NOTE             = 7
+       SHT_NOBITS           = 8
+       SHT_REL              = 9
+       SHT_SHLIB            = 10
+       SHT_DYNSYM           = 11
+       SHT_INIT_ARRAY       = 14
+       SHT_FINI_ARRAY       = 15
+       SHT_PREINIT_ARRAY    = 16
+       SHT_GROUP            = 17
+       SHT_SYMTAB_SHNDX     = 18
+       SHT_LOOS             = 0x60000000
+       SHT_HIOS             = 0x6fffffff
+       SHT_GNU_VERDEF       = 0x6ffffffd
+       SHT_GNU_VERNEED      = 0x6ffffffe
+       SHT_GNU_VERSYM       = 0x6fffffff
+       SHT_LOPROC           = 0x70000000
+       SHT_HIPROC           = 0x7fffffff
+       SHT_LOUSER           = 0x80000000
+       SHT_HIUSER           = 0xffffffff
+       SHF_WRITE            = 0x1
+       SHF_ALLOC            = 0x2
+       SHF_EXECINSTR        = 0x4
+       SHF_MERGE            = 0x10
+       SHF_STRINGS          = 0x20
+       SHF_INFO_LINK        = 0x40
+       SHF_LINK_ORDER       = 0x80
+       SHF_OS_NONCONFORMING = 0x100
+       SHF_GROUP            = 0x200
+       SHF_TLS              = 0x400
+       SHF_MASKOS           = 0x0ff00000
+       SHF_MASKPROC         = 0xf0000000
+       PT_NULL              = 0
+       PT_LOAD              = 1
+       PT_DYNAMIC           = 2
+       PT_INTERP            = 3
+       PT_NOTE              = 4
+       PT_SHLIB             = 5
+       PT_PHDR              = 6
+       PT_TLS               = 7
+       PT_LOOS              = 0x60000000
+       PT_HIOS              = 0x6fffffff
+       PT_LOPROC            = 0x70000000
+       PT_HIPROC            = 0x7fffffff
+       PT_GNU_STACK         = 0x6474e551
+       PT_PAX_FLAGS         = 0x65041580
+       PF_X                 = 0x1
+       PF_W                 = 0x2
+       PF_R                 = 0x4
+       PF_MASKOS            = 0x0ff00000
+       PF_MASKPROC          = 0xf0000000
+       DT_NULL              = 0
+       DT_NEEDED            = 1
+       DT_PLTRELSZ          = 2
+       DT_PLTGOT            = 3
+       DT_HASH              = 4
+       DT_STRTAB            = 5
+       DT_SYMTAB            = 6
+       DT_RELA              = 7
+       DT_RELASZ            = 8
+       DT_RELAENT           = 9
+       DT_STRSZ             = 10
+       DT_SYMENT            = 11
+       DT_INIT              = 12
+       DT_FINI              = 13
+       DT_SONAME            = 14
+       DT_RPATH             = 15
+       DT_SYMBOLIC          = 16
+       DT_REL               = 17
+       DT_RELSZ             = 18
+       DT_RELENT            = 19
+       DT_PLTREL            = 20
+       DT_DEBUG             = 21
+       DT_TEXTREL           = 22
+       DT_JMPREL            = 23
+       DT_BIND_NOW          = 24
+       DT_INIT_ARRAY        = 25
+       DT_FINI_ARRAY        = 26
+       DT_INIT_ARRAYSZ      = 27
+       DT_FINI_ARRAYSZ      = 28
+       DT_RUNPATH           = 29
+       DT_FLAGS             = 30
+       DT_ENCODING          = 32
+       DT_PREINIT_ARRAY     = 32
+       DT_PREINIT_ARRAYSZ   = 33
+       DT_LOOS              = 0x6000000d
+       DT_HIOS              = 0x6ffff000
+       DT_LOPROC            = 0x70000000
+       DT_HIPROC            = 0x7fffffff
+       DT_VERNEED           = 0x6ffffffe
+       DT_VERNEEDNUM        = 0x6fffffff
+       DT_VERSYM            = 0x6ffffff0
+       DT_PPC64_GLINK       = DT_LOPROC + 0
+       DT_PPC64_OPT         = DT_LOPROC + 3
+       DF_ORIGIN            = 0x0001
+       DF_SYMBOLIC          = 0x0002
+       DF_TEXTREL           = 0x0004
+       DF_BIND_NOW          = 0x0008
+       DF_STATIC_TLS        = 0x0010
+       NT_PRSTATUS          = 1
+       NT_FPREGSET          = 2
+       NT_PRPSINFO          = 3
+       STB_LOCAL            = 0
+       STB_GLOBAL           = 1
+       STB_WEAK             = 2
+       STB_LOOS             = 10
+       STB_HIOS             = 12
+       STB_LOPROC           = 13
+       STB_HIPROC           = 15
+       STT_NOTYPE           = 0
+       STT_OBJECT           = 1
+       STT_FUNC             = 2
+       STT_SECTION          = 3
+       STT_FILE             = 4
+       STT_COMMON           = 5
+       STT_TLS              = 6
+       STT_LOOS             = 10
+       STT_HIOS             = 12
+       STT_LOPROC           = 13
+       STT_HIPROC           = 15
+       STV_DEFAULT          = 0x0
+       STV_INTERNAL         = 0x1
+       STV_HIDDEN           = 0x2
+       STV_PROTECTED        = 0x3
+       STN_UNDEF            = 0
+)
+
+/* For accessing the fields of r_info. */
+
+/* For constructing r_info from field values. */
+
+/*
+ * Relocation types.
+ */
+const (
+       R_X86_64_NONE          = 0
+       R_X86_64_64            = 1
+       R_X86_64_PC32          = 2
+       R_X86_64_GOT32         = 3
+       R_X86_64_PLT32         = 4
+       R_X86_64_COPY          = 5
+       R_X86_64_GLOB_DAT      = 6
+       R_X86_64_JMP_SLOT      = 7
+       R_X86_64_RELATIVE      = 8
+       R_X86_64_GOTPCREL      = 9
+       R_X86_64_32            = 10
+       R_X86_64_32S           = 11
+       R_X86_64_16            = 12
+       R_X86_64_PC16          = 13
+       R_X86_64_8             = 14
+       R_X86_64_PC8           = 15
+       R_X86_64_DTPMOD64      = 16
+       R_X86_64_DTPOFF64      = 17
+       R_X86_64_TPOFF64       = 18
+       R_X86_64_TLSGD         = 19
+       R_X86_64_TLSLD         = 20
+       R_X86_64_DTPOFF32      = 21
+       R_X86_64_GOTTPOFF      = 22
+       R_X86_64_TPOFF32       = 23
+       R_X86_64_COUNT         = 24
+       R_ALPHA_NONE           = 0
+       R_ALPHA_REFLONG        = 1
+       R_ALPHA_REFQUAD        = 2
+       R_ALPHA_GPREL32        = 3
+       R_ALPHA_LITERAL        = 4
+       R_ALPHA_LITUSE         = 5
+       R_ALPHA_GPDISP         = 6
+       R_ALPHA_BRADDR         = 7
+       R_ALPHA_HINT           = 8
+       R_ALPHA_SREL16         = 9
+       R_ALPHA_SREL32         = 10
+       R_ALPHA_SREL64         = 11
+       R_ALPHA_OP_PUSH        = 12
+       R_ALPHA_OP_STORE       = 13
+       R_ALPHA_OP_PSUB        = 14
+       R_ALPHA_OP_PRSHIFT     = 15
+       R_ALPHA_GPVALUE        = 16
+       R_ALPHA_GPRELHIGH      = 17
+       R_ALPHA_GPRELLOW       = 18
+       R_ALPHA_IMMED_GP_16    = 19
+       R_ALPHA_IMMED_GP_HI32  = 20
+       R_ALPHA_IMMED_SCN_HI32 = 21
+       R_ALPHA_IMMED_BR_HI32  = 22
+       R_ALPHA_IMMED_LO32     = 23
+       R_ALPHA_COPY           = 24
+       R_ALPHA_GLOB_DAT       = 25
+       R_ALPHA_JMP_SLOT       = 26
+       R_ALPHA_RELATIVE       = 27
+       R_ALPHA_COUNT          = 28
+       R_ARM_NONE             = 0
+       R_ARM_PC24             = 1
+       R_ARM_ABS32            = 2
+       R_ARM_REL32            = 3
+       R_ARM_PC13             = 4
+       R_ARM_ABS16            = 5
+       R_ARM_ABS12            = 6
+       R_ARM_THM_ABS5         = 7
+       R_ARM_ABS8             = 8
+       R_ARM_SBREL32          = 9
+       R_ARM_THM_PC22         = 10
+       R_ARM_THM_PC8          = 11
+       R_ARM_AMP_VCALL9       = 12
+       R_ARM_SWI24            = 13
+       R_ARM_THM_SWI8         = 14
+       R_ARM_XPC25            = 15
+       R_ARM_THM_XPC22        = 16
+       R_ARM_COPY             = 20
+       R_ARM_GLOB_DAT         = 21
+       R_ARM_JUMP_SLOT        = 22
+       R_ARM_RELATIVE         = 23
+       R_ARM_GOTOFF           = 24
+       R_ARM_GOTPC            = 25
+       R_ARM_GOT32            = 26
+       R_ARM_PLT32            = 27
+       R_ARM_CALL             = 28
+       R_ARM_JUMP24           = 29
+       R_ARM_V4BX             = 40
+       R_ARM_GOT_PREL         = 96
+       R_ARM_GNU_VTENTRY      = 100
+       R_ARM_GNU_VTINHERIT    = 101
+       R_ARM_TLS_IE32         = 107
+       R_ARM_TLS_LE32         = 108
+       R_ARM_RSBREL32         = 250
+       R_ARM_THM_RPC22        = 251
+       R_ARM_RREL32           = 252
+       R_ARM_RABS32           = 253
+       R_ARM_RPC24            = 254
+       R_ARM_RBASE            = 255
+       R_ARM_COUNT            = 38
+       R_386_NONE             = 0
+       R_386_32               = 1
+       R_386_PC32             = 2
+       R_386_GOT32            = 3
+       R_386_PLT32            = 4
+       R_386_COPY             = 5
+       R_386_GLOB_DAT         = 6
+       R_386_JMP_SLOT         = 7
+       R_386_RELATIVE         = 8
+       R_386_GOTOFF           = 9
+       R_386_GOTPC            = 10
+       R_386_TLS_TPOFF        = 14
+       R_386_TLS_IE           = 15
+       R_386_TLS_GOTIE        = 16
+       R_386_TLS_LE           = 17
+       R_386_TLS_GD           = 18
+       R_386_TLS_LDM          = 19
+       R_386_TLS_GD_32        = 24
+       R_386_TLS_GD_PUSH      = 25
+       R_386_TLS_GD_CALL      = 26
+       R_386_TLS_GD_POP       = 27
+       R_386_TLS_LDM_32       = 28
+       R_386_TLS_LDM_PUSH     = 29
+       R_386_TLS_LDM_CALL     = 30
+       R_386_TLS_LDM_POP      = 31
+       R_386_TLS_LDO_32       = 32
+       R_386_TLS_IE_32        = 33
+       R_386_TLS_LE_32        = 34
+       R_386_TLS_DTPMOD32     = 35
+       R_386_TLS_DTPOFF32     = 36
+       R_386_TLS_TPOFF32      = 37
+       R_386_COUNT            = 38
+       R_PPC_NONE             = 0
+       R_PPC_ADDR32           = 1
+       R_PPC_ADDR24           = 2
+       R_PPC_ADDR16           = 3
+       R_PPC_ADDR16_LO        = 4
+       R_PPC_ADDR16_HI        = 5
+       R_PPC_ADDR16_HA        = 6
+       R_PPC_ADDR14           = 7
+       R_PPC_ADDR14_BRTAKEN   = 8
+       R_PPC_ADDR14_BRNTAKEN  = 9
+       R_PPC_REL24            = 10
+       R_PPC_REL14            = 11
+       R_PPC_REL14_BRTAKEN    = 12
+       R_PPC_REL14_BRNTAKEN   = 13
+       R_PPC_GOT16            = 14
+       R_PPC_GOT16_LO         = 15
+       R_PPC_GOT16_HI         = 16
+       R_PPC_GOT16_HA         = 17
+       R_PPC_PLTREL24         = 18
+       R_PPC_COPY             = 19
+       R_PPC_GLOB_DAT         = 20
+       R_PPC_JMP_SLOT         = 21
+       R_PPC_RELATIVE         = 22
+       R_PPC_LOCAL24PC        = 23
+       R_PPC_UADDR32          = 24
+       R_PPC_UADDR16          = 25
+       R_PPC_REL32            = 26
+       R_PPC_PLT32            = 27
+       R_PPC_PLTREL32         = 28
+       R_PPC_PLT16_LO         = 29
+       R_PPC_PLT16_HI         = 30
+       R_PPC_PLT16_HA         = 31
+       R_PPC_SDAREL16         = 32
+       R_PPC_SECTOFF          = 33
+       R_PPC_SECTOFF_LO       = 34
+       R_PPC_SECTOFF_HI       = 35
+       R_PPC_SECTOFF_HA       = 36
+       R_PPC_COUNT            = 37
+       R_PPC_TLS              = 67
+       R_PPC_DTPMOD32         = 68
+       R_PPC_TPREL16          = 69
+       R_PPC_TPREL16_LO       = 70
+       R_PPC_TPREL16_HI       = 71
+       R_PPC_TPREL16_HA       = 72
+       R_PPC_TPREL32          = 73
+       R_PPC_DTPREL16         = 74
+       R_PPC_DTPREL16_LO      = 75
+       R_PPC_DTPREL16_HI      = 76
+       R_PPC_DTPREL16_HA      = 77
+       R_PPC_DTPREL32         = 78
+       R_PPC_GOT_TLSGD16      = 79
+       R_PPC_GOT_TLSGD16_LO   = 80
+       R_PPC_GOT_TLSGD16_HI   = 81
+       R_PPC_GOT_TLSGD16_HA   = 82
+       R_PPC_GOT_TLSLD16      = 83
+       R_PPC_GOT_TLSLD16_LO   = 84
+       R_PPC_GOT_TLSLD16_HI   = 85
+       R_PPC_GOT_TLSLD16_HA   = 86
+       R_PPC_GOT_TPREL16      = 87
+       R_PPC_GOT_TPREL16_LO   = 88
+       R_PPC_GOT_TPREL16_HI   = 89
+       R_PPC_GOT_TPREL16_HA   = 90
+       R_PPC_EMB_NADDR32      = 101
+       R_PPC_EMB_NADDR16      = 102
+       R_PPC_EMB_NADDR16_LO   = 103
+       R_PPC_EMB_NADDR16_HI   = 104
+       R_PPC_EMB_NADDR16_HA   = 105
+       R_PPC_EMB_SDAI16       = 106
+       R_PPC_EMB_SDA2I16      = 107
+       R_PPC_EMB_SDA2REL      = 108
+       R_PPC_EMB_SDA21        = 109
+       R_PPC_EMB_MRKREF       = 110
+       R_PPC_EMB_RELSEC16     = 111
+       R_PPC_EMB_RELST_LO     = 112
+       R_PPC_EMB_RELST_HI     = 113
+       R_PPC_EMB_RELST_HA     = 114
+       R_PPC_EMB_BIT_FLD      = 115
+       R_PPC_EMB_RELSDA       = 116
+       R_PPC_EMB_COUNT        = R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1
+       R_PPC64_REL24          = R_PPC_REL24
+       R_PPC64_JMP_SLOT       = R_PPC_JMP_SLOT
+       R_PPC64_ADDR64         = 38
+       R_PPC64_TOC16          = 47
+       R_PPC64_TOC16_LO       = 48
+       R_PPC64_TOC16_HI       = 49
+       R_PPC64_TOC16_HA       = 50
+       R_PPC64_TOC16_DS       = 63
+       R_PPC64_TOC16_LO_DS    = 64
+       R_PPC64_REL16_LO       = 250
+       R_PPC64_REL16_HI       = 251
+       R_PPC64_REL16_HA       = 252
+       R_SPARC_NONE           = 0
+       R_SPARC_8              = 1
+       R_SPARC_16             = 2
+       R_SPARC_32             = 3
+       R_SPARC_DISP8          = 4
+       R_SPARC_DISP16         = 5
+       R_SPARC_DISP32         = 6
+       R_SPARC_WDISP30        = 7
+       R_SPARC_WDISP22        = 8
+       R_SPARC_HI22           = 9
+       R_SPARC_22             = 10
+       R_SPARC_13             = 11
+       R_SPARC_LO10           = 12
+       R_SPARC_GOT10          = 13
+       R_SPARC_GOT13          = 14
+       R_SPARC_GOT22          = 15
+       R_SPARC_PC10           = 16
+       R_SPARC_PC22           = 17
+       R_SPARC_WPLT30         = 18
+       R_SPARC_COPY           = 19
+       R_SPARC_GLOB_DAT       = 20
+       R_SPARC_JMP_SLOT       = 21
+       R_SPARC_RELATIVE       = 22
+       R_SPARC_UA32           = 23
+       R_SPARC_PLT32          = 24
+       R_SPARC_HIPLT22        = 25
+       R_SPARC_LOPLT10        = 26
+       R_SPARC_PCPLT32        = 27
+       R_SPARC_PCPLT22        = 28
+       R_SPARC_PCPLT10        = 29
+       R_SPARC_10             = 30
+       R_SPARC_11             = 31
+       R_SPARC_64             = 32
+       R_SPARC_OLO10          = 33
+       R_SPARC_HH22           = 34
+       R_SPARC_HM10           = 35
+       R_SPARC_LM22           = 36
+       R_SPARC_PC_HH22        = 37
+       R_SPARC_PC_HM10        = 38
+       R_SPARC_PC_LM22        = 39
+       R_SPARC_WDISP16        = 40
+       R_SPARC_WDISP19        = 41
+       R_SPARC_GLOB_JMP       = 42
+       R_SPARC_7              = 43
+       R_SPARC_5              = 44
+       R_SPARC_6              = 45
+       R_SPARC_DISP64         = 46
+       R_SPARC_PLT64          = 47
+       R_SPARC_HIX22          = 48
+       R_SPARC_LOX10          = 49
+       R_SPARC_H44            = 50
+       R_SPARC_M44            = 51
+       R_SPARC_L44            = 52
+       R_SPARC_REGISTER       = 53
+       R_SPARC_UA64           = 54
+       R_SPARC_UA16           = 55
+       ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
+)
+
+/*
+ * Symbol table entries.
+ */
+
+/* For accessing the fields of st_info. */
+
+/* For constructing st_info from field values. */
+
+/* For accessing the fields of st_other. */
+
+/*
+ * ELF header.
+ */
+type ElfEhdr struct {
+       ident     [EI_NIDENT]uint8
+       type_     uint16
+       machine   uint16
+       version   uint32
+       entry     uint64
+       phoff     uint64
+       shoff     uint64
+       flags     uint32
+       ehsize    uint16
+       phentsize uint16
+       phnum     uint16
+       shentsize uint16
+       shnum     uint16
+       shstrndx  uint16
+}
+
+/*
+ * Section header.
+ */
+type ElfShdr struct {
+       name      uint32
+       type_     uint32
+       flags     uint64
+       addr      uint64
+       off       uint64
+       size      uint64
+       link      uint32
+       info      uint32
+       addralign uint64
+       entsize   uint64
+       shnum     int
+       secsym    *LSym
+}
+
+/*
+ * Program header.
+ */
+type ElfPhdr struct {
+       type_  uint32
+       flags  uint32
+       off    uint64
+       vaddr  uint64
+       paddr  uint64
+       filesz uint64
+       memsz  uint64
+       align  uint64
+}
+
+/* For accessing the fields of r_info. */
+
+/* For constructing r_info from field values. */
+
+/*
+ * Symbol table entries.
+ */
+
+/* For accessing the fields of st_info. */
+
+/* For constructing st_info from field values. */
+
+/* For accessing the fields of st_other. */
+
+/*
+ * Go linker interface
+ */
+const (
+       ELF64HDRSIZE  = 64
+       ELF64PHDRSIZE = 56
+       ELF64SHDRSIZE = 64
+       ELF64RELSIZE  = 16
+       ELF64RELASIZE = 24
+       ELF64SYMSIZE  = 24
+       ELF32HDRSIZE  = 52
+       ELF32PHDRSIZE = 32
+       ELF32SHDRSIZE = 40
+       ELF32SYMSIZE  = 16
+       ELF32RELSIZE  = 8
+)
+
+/*
+ * The interface uses the 64-bit structures always,
+ * to avoid code duplication.  The writers know how to
+ * marshal a 32-bit representation from the 64-bit structure.
+ */
+
+var numelfphdr int
+
+var numelfshdr int
+
+var elfstrsize int
+
+var Elfstrdat []byte
+
+/*
+ * Total amount of space to reserve at the start of the file
+ * for Header, PHeaders, SHeaders, and interp.
+ * May waste some.
+ * On FreeBSD, cannot be larger than a page.
+ */
+const (
+       ELFRESERVE = 3072
+)
+
+/*
+ * We use the 64-bit data structures on both 32- and 64-bit machines
+ * in order to write the code just once.  The 64-bit data structure is
+ * written in the 32-bit format on the 32-bit machines.
+ */
+const (
+       NSECT = 48
+)
+
+var Iself bool
+
+var Nelfsym int = 1
+
+var elf64 int
+
+var ehdr ElfEhdr
+
+var phdr [NSECT]*ElfPhdr
+
+var shdr [NSECT]*ElfShdr
+
+var interp string
+
+type Elfstring struct {
+       s   string
+       off int
+}
+
+var elfstr [100]Elfstring
+
+var nelfstr int
+
+var buildinfo []byte
+
+/*
+ Initialize the global variable that describes the ELF header. It will be updated as
+ we write section and prog headers.
+*/
+func Elfinit() {
+       Iself = true
+
+       switch Thearch.Thechar {
+       // 64-bit architectures
+       case '9':
+               if Ctxt.Arch.Endian == BigEndian {
+                       ehdr.flags = 1 /* Version 1 ABI */
+               } else {
+                       ehdr.flags = 2 /* Version 2 ABI */
+               }
+               fallthrough
+
+               // fallthrough
+       case '6':
+               elf64 = 1
+
+               ehdr.phoff = ELF64HDRSIZE      /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
+               ehdr.shoff = ELF64HDRSIZE      /* Will move as we add PHeaders */
+               ehdr.ehsize = ELF64HDRSIZE     /* Must be ELF64HDRSIZE */
+               ehdr.phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
+               ehdr.shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */
+
+               // we use EABI on both linux/arm and freebsd/arm.
+       // 32-bit architectures
+       case '5':
+               if HEADTYPE == Hlinux || HEADTYPE == Hfreebsd {
+                       ehdr.flags = 0x5000002 // has entry point, Version5 EABI
+               }
+               fallthrough
+
+               // fallthrough
+       default:
+               ehdr.phoff = ELF32HDRSIZE
+               /* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
+               ehdr.shoff = ELF32HDRSIZE      /* Will move as we add PHeaders */
+               ehdr.ehsize = ELF32HDRSIZE     /* Must be ELF32HDRSIZE */
+               ehdr.phentsize = ELF32PHDRSIZE /* Must be ELF32PHDRSIZE */
+               ehdr.shentsize = ELF32SHDRSIZE /* Must be ELF32SHDRSIZE */
+       }
+}
+
+func elf64phdr(e *ElfPhdr) {
+       Thearch.Lput(e.type_)
+       Thearch.Lput(e.flags)
+       Thearch.Vput(e.off)
+       Thearch.Vput(e.vaddr)
+       Thearch.Vput(e.paddr)
+       Thearch.Vput(e.filesz)
+       Thearch.Vput(e.memsz)
+       Thearch.Vput(e.align)
+}
+
+func elf32phdr(e *ElfPhdr) {
+       var frag int
+
+       if e.type_ == PT_LOAD {
+               // Correct ELF loaders will do this implicitly,
+               // but buggy ELF loaders like the one in some
+               // versions of QEMU won't.
+               frag = int(e.vaddr & (e.align - 1))
+
+               e.off -= uint64(frag)
+               e.vaddr -= uint64(frag)
+               e.paddr -= uint64(frag)
+               e.filesz += uint64(frag)
+               e.memsz += uint64(frag)
+       }
+
+       Thearch.Lput(e.type_)
+       Thearch.Lput(uint32(e.off))
+       Thearch.Lput(uint32(e.vaddr))
+       Thearch.Lput(uint32(e.paddr))
+       Thearch.Lput(uint32(e.filesz))
+       Thearch.Lput(uint32(e.memsz))
+       Thearch.Lput(e.flags)
+       Thearch.Lput(uint32(e.align))
+}
+
+func elf64shdr(e *ElfShdr) {
+       Thearch.Lput(e.name)
+       Thearch.Lput(e.type_)
+       Thearch.Vput(e.flags)
+       Thearch.Vput(e.addr)
+       Thearch.Vput(e.off)
+       Thearch.Vput(e.size)
+       Thearch.Lput(e.link)
+       Thearch.Lput(e.info)
+       Thearch.Vput(e.addralign)
+       Thearch.Vput(e.entsize)
+}
+
+func elf32shdr(e *ElfShdr) {
+       Thearch.Lput(e.name)
+       Thearch.Lput(e.type_)
+       Thearch.Lput(uint32(e.flags))
+       Thearch.Lput(uint32(e.addr))
+       Thearch.Lput(uint32(e.off))
+       Thearch.Lput(uint32(e.size))
+       Thearch.Lput(e.link)
+       Thearch.Lput(e.info)
+       Thearch.Lput(uint32(e.addralign))
+       Thearch.Lput(uint32(e.entsize))
+}
+
+func elfwriteshdrs() uint32 {
+       var i int
+
+       if elf64 != 0 {
+               for i = 0; i < int(ehdr.shnum); i++ {
+                       elf64shdr(shdr[i])
+               }
+               return uint32(ehdr.shnum) * ELF64SHDRSIZE
+       }
+
+       for i = 0; i < int(ehdr.shnum); i++ {
+               elf32shdr(shdr[i])
+       }
+       return uint32(ehdr.shnum) * ELF32SHDRSIZE
+}
+
+func elfsetstring(s string, off int) {
+       if nelfstr >= len(elfstr) {
+               Diag("too many elf strings")
+               Errorexit()
+       }
+
+       elfstr[nelfstr].s = s
+       elfstr[nelfstr].off = off
+       nelfstr++
+}
+
+func elfwritephdrs() uint32 {
+       var i int
+
+       if elf64 != 0 {
+               for i = 0; i < int(ehdr.phnum); i++ {
+                       elf64phdr(phdr[i])
+               }
+               return uint32(ehdr.phnum) * ELF64PHDRSIZE
+       }
+
+       for i = 0; i < int(ehdr.phnum); i++ {
+               elf32phdr(phdr[i])
+       }
+       return uint32(ehdr.phnum) * ELF32PHDRSIZE
+}
+
+func newElfPhdr() *ElfPhdr {
+       var e *ElfPhdr
+
+       e = new(ElfPhdr)
+       if ehdr.phnum >= NSECT {
+               Diag("too many phdrs")
+       } else {
+               phdr[ehdr.phnum] = e
+               ehdr.phnum++
+       }
+       if elf64 != 0 {
+               ehdr.shoff += ELF64PHDRSIZE
+       } else {
+               ehdr.shoff += ELF32PHDRSIZE
+       }
+       return e
+}
+
+func newElfShdr(name int64) *ElfShdr {
+       var e *ElfShdr
+
+       e = new(ElfShdr)
+       e.name = uint32(name)
+       e.shnum = int(ehdr.shnum)
+       if ehdr.shnum >= NSECT {
+               Diag("too many shdrs")
+       } else {
+               shdr[ehdr.shnum] = e
+               ehdr.shnum++
+       }
+
+       return e
+}
+
+func getElfEhdr() *ElfEhdr {
+       return &ehdr
+}
+
+func elf64writehdr() uint32 {
+       var i int
+
+       for i = 0; i < EI_NIDENT; i++ {
+               Cput(ehdr.ident[i])
+       }
+       Thearch.Wput(ehdr.type_)
+       Thearch.Wput(ehdr.machine)
+       Thearch.Lput(ehdr.version)
+       Thearch.Vput(ehdr.entry)
+       Thearch.Vput(ehdr.phoff)
+       Thearch.Vput(ehdr.shoff)
+       Thearch.Lput(ehdr.flags)
+       Thearch.Wput(ehdr.ehsize)
+       Thearch.Wput(ehdr.phentsize)
+       Thearch.Wput(ehdr.phnum)
+       Thearch.Wput(ehdr.shentsize)
+       Thearch.Wput(ehdr.shnum)
+       Thearch.Wput(ehdr.shstrndx)
+       return ELF64HDRSIZE
+}
+
+func elf32writehdr() uint32 {
+       var i int
+
+       for i = 0; i < EI_NIDENT; i++ {
+               Cput(ehdr.ident[i])
+       }
+       Thearch.Wput(ehdr.type_)
+       Thearch.Wput(ehdr.machine)
+       Thearch.Lput(ehdr.version)
+       Thearch.Lput(uint32(ehdr.entry))
+       Thearch.Lput(uint32(ehdr.phoff))
+       Thearch.Lput(uint32(ehdr.shoff))
+       Thearch.Lput(ehdr.flags)
+       Thearch.Wput(ehdr.ehsize)
+       Thearch.Wput(ehdr.phentsize)
+       Thearch.Wput(ehdr.phnum)
+       Thearch.Wput(ehdr.shentsize)
+       Thearch.Wput(ehdr.shnum)
+       Thearch.Wput(ehdr.shstrndx)
+       return ELF32HDRSIZE
+}
+
+func elfwritehdr() uint32 {
+       if elf64 != 0 {
+               return elf64writehdr()
+       }
+       return elf32writehdr()
+}
+
+/* Taken directly from the definition document for ELF64 */
+func elfhash(name []byte) uint32 {
+       var h uint32 = 0
+       var g uint32
+       for len(name) != 0 {
+               h = (h << 4) + uint32(name[0])
+               name = name[1:]
+               g = h & 0xf0000000
+               if g != 0 {
+                       h ^= g >> 24
+               }
+               h &= 0x0fffffff
+       }
+
+       return h
+}
+
+func Elfwritedynent(s *LSym, tag int, val uint64) {
+       if elf64 != 0 {
+               Adduint64(Ctxt, s, uint64(tag))
+               Adduint64(Ctxt, s, val)
+       } else {
+               Adduint32(Ctxt, s, uint32(tag))
+               Adduint32(Ctxt, s, uint32(val))
+       }
+}
+
+func elfwritedynentsym(s *LSym, tag int, t *LSym) {
+       Elfwritedynentsymplus(s, tag, t, 0)
+}
+
+func Elfwritedynentsymplus(s *LSym, tag int, t *LSym, add int64) {
+       if elf64 != 0 {
+               Adduint64(Ctxt, s, uint64(tag))
+       } else {
+               Adduint32(Ctxt, s, uint32(tag))
+       }
+       Addaddrplus(Ctxt, s, t, add)
+}
+
+func elfwritedynentsymsize(s *LSym, tag int, t *LSym) {
+       if elf64 != 0 {
+               Adduint64(Ctxt, s, uint64(tag))
+       } else {
+               Adduint32(Ctxt, s, uint32(tag))
+       }
+       addsize(Ctxt, s, t)
+}
+
+func elfinterp(sh *ElfShdr, startva uint64, resoff uint64, p string) int {
+       var n int
+
+       interp = p
+       n = len(interp) + 1
+       sh.addr = startva + resoff - uint64(n)
+       sh.off = resoff - uint64(n)
+       sh.size = uint64(n)
+
+       return n
+}
+
+func elfwriteinterp() int {
+       var sh *ElfShdr
+
+       sh = elfshname(".interp")
+       Cseek(int64(sh.off))
+       coutbuf.w.WriteString(interp)
+       Cput(0)
+       return int(sh.size)
+}
+
+func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int {
+       var n uint64
+
+       n = 3*4 + uint64(sz) + resoff%4
+
+       sh.type_ = SHT_NOTE
+       sh.flags = SHF_ALLOC
+       sh.addralign = 4
+       sh.addr = startva + resoff - n
+       sh.off = resoff - n
+       sh.size = n - resoff%4
+
+       return int(n)
+}
+
+func elfwritenotehdr(str string, namesz uint32, descsz uint32, tag uint32) *ElfShdr {
+       var sh *ElfShdr
+
+       sh = elfshname(str)
+
+       // Write Elf_Note header.
+       Cseek(int64(sh.off))
+
+       Thearch.Lput(namesz)
+       Thearch.Lput(descsz)
+       Thearch.Lput(tag)
+
+       return sh
+}
+
+// NetBSD Signature (as per sys/exec_elf.h)
+const (
+       ELF_NOTE_NETBSD_NAMESZ  = 7
+       ELF_NOTE_NETBSD_DESCSZ  = 4
+       ELF_NOTE_NETBSD_TAG     = 1
+       ELF_NOTE_NETBSD_VERSION = 599000000
+)
+
+var ELF_NOTE_NETBSD_NAME = []byte("NetBSD\x00")
+
+func elfnetbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
+       var n int
+
+       n = int(Rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + Rnd(ELF_NOTE_NETBSD_DESCSZ, 4))
+       return elfnote(sh, startva, resoff, n)
+}
+
+func elfwritenetbsdsig() int {
+       var sh *ElfShdr
+
+       // Write Elf_Note header.
+       sh = elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG)
+
+       if sh == nil {
+               return 0
+       }
+
+       // Followed by NetBSD string and version.
+       Cwrite(ELF_NOTE_NETBSD_NAME)
+       Cput(0)
+
+       Thearch.Lput(ELF_NOTE_NETBSD_VERSION)
+
+       return int(sh.size)
+}
+
+// OpenBSD Signature
+const (
+       ELF_NOTE_OPENBSD_NAMESZ  = 8
+       ELF_NOTE_OPENBSD_DESCSZ  = 4
+       ELF_NOTE_OPENBSD_TAG     = 1
+       ELF_NOTE_OPENBSD_VERSION = 0
+)
+
+var ELF_NOTE_OPENBSD_NAME = []byte("OpenBSD\x00")
+
+func elfopenbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
+       var n int
+
+       n = ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ
+       return elfnote(sh, startva, resoff, n)
+}
+
+func elfwriteopenbsdsig() int {
+       var sh *ElfShdr
+
+       // Write Elf_Note header.
+       sh = elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG)
+
+       if sh == nil {
+               return 0
+       }
+
+       // Followed by OpenBSD string and version.
+       Cwrite(ELF_NOTE_OPENBSD_NAME)
+
+       Thearch.Lput(ELF_NOTE_OPENBSD_VERSION)
+
+       return int(sh.size)
+}
+
+func addbuildinfo(val string) {
+       var ov string
+       var i int
+       var b int
+       var j int
+
+       if val[0] != '0' || val[1] != 'x' {
+               fmt.Fprintf(os.Stderr, "%s: -B argument must start with 0x: %s\n", os.Args[0], val)
+               Exit(2)
+       }
+
+       ov = val
+       val = val[2:]
+       i = 0
+       for val != "" {
+               if len(val) == 1 {
+                       fmt.Fprintf(os.Stderr, "%s: -B argument must have even number of digits: %s\n", os.Args[0], ov)
+                       Exit(2)
+               }
+
+               b = 0
+               for j = 0; j < 2; (func() { j++; val = val[1:] })() {
+                       b *= 16
+                       if val[0] >= '0' && val[0] <= '9' {
+                               b += int(val[0]) - '0'
+                       } else if val[0] >= 'a' && val[0] <= 'f' {
+                               b += int(val[0]) - 'a' + 10
+                       } else if val[0] >= 'A' && val[0] <= 'F' {
+                               b += int(val[0]) - 'A' + 10
+                       } else {
+                               fmt.Fprintf(os.Stderr, "%s: -B argument contains invalid hex digit %c: %s\n", os.Args[0], val[0], ov)
+                               Exit(2)
+                       }
+               }
+
+               const maxLen = 32
+               if i >= maxLen {
+                       fmt.Fprintf(os.Stderr, "%s: -B option too long (max %d digits): %s\n", os.Args[0], maxLen, ov)
+                       Exit(2)
+               }
+
+               buildinfo = append(buildinfo, uint8(b))
+               i++
+       }
+
+       buildinfo = buildinfo[:i]
+}
+
+// Build info note
+const (
+       ELF_NOTE_BUILDINFO_NAMESZ = 4
+       ELF_NOTE_BUILDINFO_TAG    = 3
+)
+
+var ELF_NOTE_BUILDINFO_NAME = []byte("GNU\x00")
+
+func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int {
+       var n int
+
+       n = int(ELF_NOTE_BUILDINFO_NAMESZ + Rnd(int64(len(buildinfo)), 4))
+       return elfnote(sh, startva, resoff, n)
+}
+
+func elfwritebuildinfo() int {
+       var sh *ElfShdr
+
+       sh = elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG)
+       if sh == nil {
+               return 0
+       }
+
+       Cwrite(ELF_NOTE_BUILDINFO_NAME)
+       Cwrite(buildinfo)
+       var zero = make([]byte, 4)
+       Cwrite(zero[:int(Rnd(int64(len(buildinfo)), 4)-int64(len(buildinfo)))])
+
+       return int(sh.size)
+}
+
+var elfverneed int
+
+type Elfaux struct {
+       next *Elfaux
+       num  int
+       vers string
+}
+
+type Elflib struct {
+       next *Elflib
+       aux  *Elfaux
+       file string
+}
+
+func addelflib(list **Elflib, file string, vers string) *Elfaux {
+       var lib *Elflib
+       var aux *Elfaux
+
+       for lib = *list; lib != nil; lib = lib.next {
+               if lib.file == file {
+                       goto havelib
+               }
+       }
+       lib = new(Elflib)
+       lib.next = *list
+       lib.file = file
+       *list = lib
+
+havelib:
+       for aux = lib.aux; aux != nil; aux = aux.next {
+               if aux.vers == vers {
+                       goto haveaux
+               }
+       }
+       aux = new(Elfaux)
+       aux.next = lib.aux
+       aux.vers = vers
+       lib.aux = aux
+
+haveaux:
+       return aux
+}
+
+func elfdynhash() {
+       var s *LSym
+       var sy *LSym
+       var dynstr *LSym
+       var i int
+       var j int
+       var nbucket int
+       var b int
+       var nfile int
+       var hc uint32
+       var chain []uint32
+       var buckets []uint32
+       var nsym int
+       var name string
+       var need []*Elfaux
+       var needlib *Elflib
+       var l *Elflib
+       var x *Elfaux
+
+       if !Iself {
+               return
+       }
+
+       nsym = Nelfsym
+       s = Linklookup(Ctxt, ".hash", 0)
+       s.Type = SELFROSECT
+       s.Reachable = true
+
+       i = nsym
+       nbucket = 1
+       for i > 0 {
+               nbucket++
+               i >>= 1
+       }
+
+       needlib = nil
+       need = make([]*Elfaux, nsym)
+       chain = make([]uint32, nsym)
+       buckets = make([]uint32, nbucket)
+       if need == nil || chain == nil || buckets == nil {
+               Ctxt.Cursym = nil
+               Diag("out of memory")
+               Errorexit()
+       }
+
+       for i = 0; i < nsym; i++ {
+               need[i] = nil
+       }
+       for i = 0; i < nsym; i++ {
+               chain[i] = 0
+       }
+       for i = 0; i < nbucket; i++ {
+               buckets[i] = 0
+       }
+       for sy = Ctxt.Allsym; sy != nil; sy = sy.Allsym {
+               if sy.Dynid <= 0 {
+                       continue
+               }
+
+               if sy.Dynimpvers != "" {
+                       need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib, sy.Dynimpvers)
+               }
+
+               name = sy.Extname
+               hc = elfhash([]byte(name))
+
+               b = int(hc % uint32(nbucket))
+               chain[sy.Dynid] = buckets[b]
+               buckets[b] = uint32(sy.Dynid)
+       }
+
+       Adduint32(Ctxt, s, uint32(nbucket))
+       Adduint32(Ctxt, s, uint32(nsym))
+       for i = 0; i < nbucket; i++ {
+               Adduint32(Ctxt, s, buckets[i])
+       }
+       for i = 0; i < nsym; i++ {
+               Adduint32(Ctxt, s, chain[i])
+       }
+
+       // version symbols
+       dynstr = Linklookup(Ctxt, ".dynstr", 0)
+
+       s = Linklookup(Ctxt, ".gnu.version_r", 0)
+       i = 2
+       nfile = 0
+       for l = needlib; l != nil; l = l.next {
+               nfile++
+
+               // header
+               Adduint16(Ctxt, s, 1) // table version
+               j = 0
+               for x = l.aux; x != nil; x = x.next {
+                       j++
+               }
+               Adduint16(Ctxt, s, uint16(j))                         // aux count
+               Adduint32(Ctxt, s, uint32(Addstring(dynstr, l.file))) // file string offset
+               Adduint32(Ctxt, s, 16)                                // offset from header to first aux
+               if l.next != nil {
+                       Adduint32(Ctxt, s, 16+uint32(j)*16) // offset from this header to next
+               } else {
+                       Adduint32(Ctxt, s, 0)
+               }
+
+               for x = l.aux; x != nil; x = x.next {
+                       x.num = i
+                       i++
+
+                       // aux struct
+                       Adduint32(Ctxt, s, elfhash([]byte(x.vers)))           // hash
+                       Adduint16(Ctxt, s, 0)                                 // flags
+                       Adduint16(Ctxt, s, uint16(x.num))                     // other - index we refer to this by
+                       Adduint32(Ctxt, s, uint32(Addstring(dynstr, x.vers))) // version string offset
+                       if x.next != nil {
+                               Adduint32(Ctxt, s, 16) // offset from this aux to next
+                       } else {
+                               Adduint32(Ctxt, s, 0)
+                       }
+               }
+       }
+
+       // version references
+       s = Linklookup(Ctxt, ".gnu.version", 0)
+
+       for i = 0; i < nsym; i++ {
+               if i == 0 {
+                       Adduint16(Ctxt, s, 0) // first entry - no symbol
+               } else if need[i] == nil {
+                       Adduint16(Ctxt, s, 1) // global
+               } else {
+                       Adduint16(Ctxt, s, uint16(need[i].num))
+               }
+       }
+
+       s = Linklookup(Ctxt, ".dynamic", 0)
+       elfverneed = nfile
+       if elfverneed != 0 {
+               elfwritedynentsym(s, DT_VERNEED, Linklookup(Ctxt, ".gnu.version_r", 0))
+               Elfwritedynent(s, DT_VERNEEDNUM, uint64(nfile))
+               elfwritedynentsym(s, DT_VERSYM, Linklookup(Ctxt, ".gnu.version", 0))
+       }
+
+       if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+               sy = Linklookup(Ctxt, ".rela.plt", 0)
+               if sy.Size > 0 {
+                       Elfwritedynent(s, DT_PLTREL, DT_RELA)
+                       elfwritedynentsymsize(s, DT_PLTRELSZ, sy)
+                       elfwritedynentsym(s, DT_JMPREL, sy)
+               }
+       } else {
+               sy = Linklookup(Ctxt, ".rel.plt", 0)
+               if sy.Size > 0 {
+                       Elfwritedynent(s, DT_PLTREL, DT_REL)
+                       elfwritedynentsymsize(s, DT_PLTRELSZ, sy)
+                       elfwritedynentsym(s, DT_JMPREL, sy)
+               }
+       }
+
+       Elfwritedynent(s, DT_NULL, 0)
+}
+
+func elfphload(seg *Segment) *ElfPhdr {
+       var ph *ElfPhdr
+
+       ph = newElfPhdr()
+       ph.type_ = PT_LOAD
+       if seg.Rwx&4 != 0 {
+               ph.flags |= PF_R
+       }
+       if seg.Rwx&2 != 0 {
+               ph.flags |= PF_W
+       }
+       if seg.Rwx&1 != 0 {
+               ph.flags |= PF_X
+       }
+       ph.vaddr = seg.Vaddr
+       ph.paddr = seg.Vaddr
+       ph.memsz = seg.Length
+       ph.off = seg.Fileoff
+       ph.filesz = seg.Filelen
+       ph.align = uint64(INITRND)
+
+       return ph
+}
+
+func elfshname(name string) *ElfShdr {
+       var i int
+       var off int
+       var sh *ElfShdr
+
+       for i = 0; i < nelfstr; i++ {
+               if name == elfstr[i].s {
+                       off = elfstr[i].off
+                       goto found
+               }
+       }
+
+       Diag("cannot find elf name %s", name)
+       Errorexit()
+       return nil
+
+found:
+       for i = 0; i < int(ehdr.shnum); i++ {
+               sh = shdr[i]
+               if sh.name == uint32(off) {
+                       return sh
+               }
+       }
+
+       sh = newElfShdr(int64(off))
+       return sh
+}
+
+func elfshalloc(sect *Section) *ElfShdr {
+       var sh *ElfShdr
+
+       sh = elfshname(sect.Name)
+       sect.Elfsect = sh
+       return sh
+}
+
+func elfshbits(sect *Section) *ElfShdr {
+       var sh *ElfShdr
+
+       sh = elfshalloc(sect)
+       if sh.type_ > 0 {
+               return sh
+       }
+
+       if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
+               sh.type_ = SHT_PROGBITS
+       } else {
+               sh.type_ = SHT_NOBITS
+       }
+       sh.flags = SHF_ALLOC
+       if sect.Rwx&1 != 0 {
+               sh.flags |= SHF_EXECINSTR
+       }
+       if sect.Rwx&2 != 0 {
+               sh.flags |= SHF_WRITE
+       }
+       if sect.Name == ".tbss" {
+               if goos != "android" {
+                       sh.flags |= SHF_TLS // no TLS on android
+               }
+               sh.type_ = SHT_NOBITS
+       }
+
+       if Linkmode != LinkExternal {
+               sh.addr = sect.Vaddr
+       }
+       sh.addralign = uint64(sect.Align)
+       sh.size = sect.Length
+       sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
+
+       return sh
+}
+
+func elfshreloc(sect *Section) *ElfShdr {
+       var typ int
+       var sh *ElfShdr
+       var prefix string
+       var buf string
+
+       // If main section is SHT_NOBITS, nothing to relocate.
+       // Also nothing to relocate in .shstrtab.
+       if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
+               return nil
+       }
+       if sect.Name == ".shstrtab" || sect.Name == ".tbss" {
+               return nil
+       }
+
+       if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+               prefix = ".rela"
+               typ = SHT_RELA
+       } else {
+               prefix = ".rel"
+               typ = SHT_REL
+       }
+
+       buf = fmt.Sprintf("%s%s", prefix, sect.Name)
+       sh = elfshname(buf)
+       sh.type_ = uint32(typ)
+       sh.entsize = uint64(Thearch.Regsize) * 2
+       if typ == SHT_RELA {
+               sh.entsize += uint64(Thearch.Regsize)
+       }
+       sh.link = uint32(elfshname(".symtab").shnum)
+       sh.info = uint32((sect.Elfsect.(*ElfShdr)).shnum)
+       sh.off = sect.Reloff
+       sh.size = sect.Rellen
+       sh.addralign = uint64(Thearch.Regsize)
+       return sh
+}
+
+func elfrelocsect(sect *Section, first *LSym) {
+       var ri int
+       var sym *LSym
+       var eaddr int32
+       var r *Reloc
+
+       // If main section is SHT_NOBITS, nothing to relocate.
+       // Also nothing to relocate in .shstrtab.
+       if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
+               return
+       }
+       if sect.Name == ".shstrtab" {
+               return
+       }
+
+       sect.Reloff = uint64(Cpos())
+       for sym = first; sym != nil; sym = sym.Next {
+               if !sym.Reachable {
+                       continue
+               }
+               if uint64(sym.Value) >= sect.Vaddr {
+                       break
+               }
+       }
+
+       eaddr = int32(sect.Vaddr + sect.Length)
+       for ; sym != nil; sym = sym.Next {
+               if !sym.Reachable {
+                       continue
+               }
+               if sym.Value >= int64(eaddr) {
+                       break
+               }
+               Ctxt.Cursym = sym
+
+               for ri = 0; ri < len(sym.R); ri++ {
+                       r = &sym.R[ri]
+                       if r.Done != 0 {
+                               continue
+                       }
+                       if r.Xsym == nil {
+                               Diag("missing xsym in relocation")
+                               continue
+                       }
+
+                       if r.Xsym.Elfsym == 0 {
+                               Diag("reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
+                       }
+                       if Thearch.Elfreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
+                               Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+                       }
+               }
+       }
+
+       sect.Rellen = uint64(Cpos()) - sect.Reloff
+}
+
+func Elfemitreloc() {
+       var sect *Section
+
+       for Cpos()&7 != 0 {
+               Cput(0)
+       }
+
+       elfrelocsect(Segtext.Sect, Ctxt.Textp)
+       for sect = Segtext.Sect.Next; sect != nil; sect = sect.Next {
+               elfrelocsect(sect, datap)
+       }
+       for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+               elfrelocsect(sect, datap)
+       }
+       for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+               elfrelocsect(sect, datap)
+       }
+}
+
+func doelf() {
+       var s *LSym
+       var shstrtab *LSym
+       var dynstr *LSym
+
+       if !Iself {
+               return
+       }
+
+       /* predefine strings we need for section headers */
+       shstrtab = Linklookup(Ctxt, ".shstrtab", 0)
+
+       shstrtab.Type = SELFROSECT
+       shstrtab.Reachable = true
+
+       Addstring(shstrtab, "")
+       Addstring(shstrtab, ".text")
+       Addstring(shstrtab, ".noptrdata")
+       Addstring(shstrtab, ".data")
+       Addstring(shstrtab, ".bss")
+       Addstring(shstrtab, ".noptrbss")
+
+       // generate .tbss section (except for OpenBSD where it's not supported)
+       // for dynamic internal linker or external linking, so that various
+       // binutils could correctly calculate PT_TLS size.
+       // see http://golang.org/issue/5200.
+       if HEADTYPE != Hopenbsd {
+               if Debug['d'] == 0 || Linkmode == LinkExternal {
+                       Addstring(shstrtab, ".tbss")
+               }
+       }
+       if HEADTYPE == Hnetbsd {
+               Addstring(shstrtab, ".note.netbsd.ident")
+       }
+       if HEADTYPE == Hopenbsd {
+               Addstring(shstrtab, ".note.openbsd.ident")
+       }
+       if len(buildinfo) > 0 {
+               Addstring(shstrtab, ".note.gnu.build-id")
+       }
+       Addstring(shstrtab, ".elfdata")
+       Addstring(shstrtab, ".rodata")
+       Addstring(shstrtab, ".typelink")
+       Addstring(shstrtab, ".gosymtab")
+       Addstring(shstrtab, ".gopclntab")
+
+       if Linkmode == LinkExternal {
+               debug_s = Debug['s']
+               Debug['s'] = 0
+               Debug['d'] = 1
+
+               if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+                       Addstring(shstrtab, ".rela.text")
+                       Addstring(shstrtab, ".rela.rodata")
+                       Addstring(shstrtab, ".rela.typelink")
+                       Addstring(shstrtab, ".rela.gosymtab")
+                       Addstring(shstrtab, ".rela.gopclntab")
+                       Addstring(shstrtab, ".rela.noptrdata")
+                       Addstring(shstrtab, ".rela.data")
+               } else {
+                       Addstring(shstrtab, ".rel.text")
+                       Addstring(shstrtab, ".rel.rodata")
+                       Addstring(shstrtab, ".rel.typelink")
+                       Addstring(shstrtab, ".rel.gosymtab")
+                       Addstring(shstrtab, ".rel.gopclntab")
+                       Addstring(shstrtab, ".rel.noptrdata")
+                       Addstring(shstrtab, ".rel.data")
+               }
+
+               // add a .note.GNU-stack section to mark the stack as non-executable
+               Addstring(shstrtab, ".note.GNU-stack")
+       }
+
+       if Flag_shared != 0 {
+               Addstring(shstrtab, ".init_array")
+               if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+                       Addstring(shstrtab, ".rela.init_array")
+               } else {
+                       Addstring(shstrtab, ".rel.init_array")
+               }
+       }
+
+       if Debug['s'] == 0 {
+               Addstring(shstrtab, ".symtab")
+               Addstring(shstrtab, ".strtab")
+               dwarfaddshstrings(shstrtab)
+       }
+
+       Addstring(shstrtab, ".shstrtab")
+
+       if Debug['d'] == 0 {
+               Addstring(shstrtab, ".interp")
+               Addstring(shstrtab, ".hash")
+               Addstring(shstrtab, ".got")
+               if Thearch.Thechar == '9' {
+                       Addstring(shstrtab, ".glink")
+               }
+               Addstring(shstrtab, ".got.plt")
+               Addstring(shstrtab, ".dynamic")
+               Addstring(shstrtab, ".dynsym")
+               Addstring(shstrtab, ".dynstr")
+               if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+                       Addstring(shstrtab, ".rela")
+                       Addstring(shstrtab, ".rela.plt")
+               } else {
+                       Addstring(shstrtab, ".rel")
+                       Addstring(shstrtab, ".rel.plt")
+               }
+
+               Addstring(shstrtab, ".plt")
+               Addstring(shstrtab, ".gnu.version")
+               Addstring(shstrtab, ".gnu.version_r")
+
+               /* dynamic symbol table - first entry all zeros */
+               s = Linklookup(Ctxt, ".dynsym", 0)
+
+               s.Type = SELFROSECT
+               s.Reachable = true
+               if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+                       s.Size += ELF64SYMSIZE
+               } else {
+                       s.Size += ELF32SYMSIZE
+               }
+
+               /* dynamic string table */
+               s = Linklookup(Ctxt, ".dynstr", 0)
+
+               s.Type = SELFROSECT
+               s.Reachable = true
+               if s.Size == 0 {
+                       Addstring(s, "")
+               }
+               dynstr = s
+
+               /* relocation table */
+               if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+                       s = Linklookup(Ctxt, ".rela", 0)
+               } else {
+                       s = Linklookup(Ctxt, ".rel", 0)
+               }
+               s.Reachable = true
+               s.Type = SELFROSECT
+
+               /* global offset table */
+               s = Linklookup(Ctxt, ".got", 0)
+
+               s.Reachable = true
+               s.Type = SELFGOT // writable
+
+               /* ppc64 glink resolver */
+               if Thearch.Thechar == '9' {
+                       s = Linklookup(Ctxt, ".glink", 0)
+                       s.Reachable = true
+                       s.Type = SELFRXSECT
+               }
+
+               /* hash */
+               s = Linklookup(Ctxt, ".hash", 0)
+
+               s.Reachable = true
+               s.Type = SELFROSECT
+
+               s = Linklookup(Ctxt, ".got.plt", 0)
+               s.Reachable = true
+               s.Type = SELFSECT // writable
+
+               s = Linklookup(Ctxt, ".plt", 0)
+
+               s.Reachable = true
+               if Thearch.Thechar == '9' {
+                       // In the ppc64 ABI, .plt is a data section
+                       // written by the dynamic linker.
+                       s.Type = SELFSECT
+               } else {
+                       s.Type = SELFRXSECT
+               }
+
+               Thearch.Elfsetupplt()
+
+               if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+                       s = Linklookup(Ctxt, ".rela.plt", 0)
+               } else {
+                       s = Linklookup(Ctxt, ".rel.plt", 0)
+               }
+               s.Reachable = true
+               s.Type = SELFROSECT
+
+               s = Linklookup(Ctxt, ".gnu.version", 0)
+               s.Reachable = true
+               s.Type = SELFROSECT
+
+               s = Linklookup(Ctxt, ".gnu.version_r", 0)
+               s.Reachable = true
+               s.Type = SELFROSECT
+
+               /* define dynamic elf table */
+               s = Linklookup(Ctxt, ".dynamic", 0)
+
+               s.Reachable = true
+               s.Type = SELFSECT // writable
+
+               /*
+                * .dynamic table
+                */
+               elfwritedynentsym(s, DT_HASH, Linklookup(Ctxt, ".hash", 0))
+
+               elfwritedynentsym(s, DT_SYMTAB, Linklookup(Ctxt, ".dynsym", 0))
+               if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+                       Elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE)
+               } else {
+                       Elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE)
+               }
+               elfwritedynentsym(s, DT_STRTAB, Linklookup(Ctxt, ".dynstr", 0))
+               elfwritedynentsymsize(s, DT_STRSZ, Linklookup(Ctxt, ".dynstr", 0))
+               if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+                       elfwritedynentsym(s, DT_RELA, Linklookup(Ctxt, ".rela", 0))
+                       elfwritedynentsymsize(s, DT_RELASZ, Linklookup(Ctxt, ".rela", 0))
+                       Elfwritedynent(s, DT_RELAENT, ELF64RELASIZE)
+               } else {
+                       elfwritedynentsym(s, DT_REL, Linklookup(Ctxt, ".rel", 0))
+                       elfwritedynentsymsize(s, DT_RELSZ, Linklookup(Ctxt, ".rel", 0))
+                       Elfwritedynent(s, DT_RELENT, ELF32RELSIZE)
+               }
+
+               if rpath != "" {
+                       Elfwritedynent(s, DT_RUNPATH, uint64(Addstring(dynstr, rpath)))
+               }
+
+               if Thearch.Thechar == '9' {
+                       elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".plt", 0))
+               } else {
+                       elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got.plt", 0))
+               }
+
+               if Thearch.Thechar == '9' {
+                       Elfwritedynent(s, DT_PPC64_OPT, 0)
+               }
+
+               // Solaris dynamic linker can't handle an empty .rela.plt if
+               // DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
+               // DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
+               // size of .rel(a).plt section.
+               Elfwritedynent(s, DT_DEBUG, 0)
+       }
+}
+
+// Do not write DT_NULL.  elfdynhash will finish it.
+func shsym(sh *ElfShdr, s *LSym) {
+       var addr int64
+       addr = Symaddr(s)
+       if sh.flags&SHF_ALLOC != 0 {
+               sh.addr = uint64(addr)
+       }
+       sh.off = uint64(datoff(addr))
+       sh.size = uint64(s.Size)
+}
+
+func phsh(ph *ElfPhdr, sh *ElfShdr) {
+       ph.vaddr = sh.addr
+       ph.paddr = ph.vaddr
+       ph.off = sh.off
+       ph.filesz = sh.size
+       ph.memsz = sh.size
+       ph.align = sh.addralign
+}
+
+func Asmbelfsetup() {
+       var sect *Section
+
+       /* This null SHdr must appear before all others */
+       elfshname("")
+
+       for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+               elfshalloc(sect)
+       }
+       for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+               elfshalloc(sect)
+       }
+       for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+               elfshalloc(sect)
+       }
+}
+
+func Asmbelf(symo int64) {
+       var a int64
+       var o int64
+       var startva int64
+       var resoff int64
+       var eh *ElfEhdr
+       var ph *ElfPhdr
+       var pph *ElfPhdr
+       var pnote *ElfPhdr
+       var sh *ElfShdr
+       var sect *Section
+
+       eh = getElfEhdr()
+       switch Thearch.Thechar {
+       default:
+               Diag("unknown architecture in asmbelf")
+               Errorexit()
+               fallthrough
+
+       case '5':
+               eh.machine = EM_ARM
+
+       case '6':
+               eh.machine = EM_X86_64
+
+       case '8':
+               eh.machine = EM_386
+
+       case '9':
+               eh.machine = EM_PPC64
+       }
+
+       startva = INITTEXT - int64(HEADR)
+       resoff = ELFRESERVE
+
+       pph = nil
+       if Linkmode == LinkExternal {
+               /* skip program headers */
+               eh.phoff = 0
+
+               eh.phentsize = 0
+               goto elfobj
+       }
+
+       /* program header info */
+       pph = newElfPhdr()
+
+       pph.type_ = PT_PHDR
+       pph.flags = PF_R
+       pph.off = uint64(eh.ehsize)
+       pph.vaddr = uint64(INITTEXT) - uint64(HEADR) + pph.off
+       pph.paddr = uint64(INITTEXT) - uint64(HEADR) + pph.off
+       pph.align = uint64(INITRND)
+
+       /*
+        * PHDR must be in a loaded segment. Adjust the text
+        * segment boundaries downwards to include it.
+        * Except on NaCl where it must not be loaded.
+        */
+       if HEADTYPE != Hnacl {
+               o = int64(Segtext.Vaddr - pph.vaddr)
+               Segtext.Vaddr -= uint64(o)
+               Segtext.Length += uint64(o)
+               o = int64(Segtext.Fileoff - pph.off)
+               Segtext.Fileoff -= uint64(o)
+               Segtext.Filelen += uint64(o)
+       }
+
+       if Debug['d'] == 0 {
+               /* interpreter */
+               sh = elfshname(".interp")
+
+               sh.type_ = SHT_PROGBITS
+               sh.flags = SHF_ALLOC
+               sh.addralign = 1
+               if interpreter == "" {
+                       switch HEADTYPE {
+                       case Hlinux:
+                               interpreter = Thearch.Linuxdynld
+
+                       case Hfreebsd:
+                               interpreter = Thearch.Freebsddynld
+
+                       case Hnetbsd:
+                               interpreter = Thearch.Netbsddynld
+
+                       case Hopenbsd:
+                               interpreter = Thearch.Openbsddynld
+
+                       case Hdragonfly:
+                               interpreter = Thearch.Dragonflydynld
+
+                       case Hsolaris:
+                               interpreter = Thearch.Solarisdynld
+                       }
+               }
+
+               resoff -= int64(elfinterp(sh, uint64(startva), uint64(resoff), interpreter))
+
+               ph = newElfPhdr()
+               ph.type_ = PT_INTERP
+               ph.flags = PF_R
+               phsh(ph, sh)
+       }
+
+       pnote = nil
+       if HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd {
+               sh = nil
+               switch HEADTYPE {
+               case Hnetbsd:
+                       sh = elfshname(".note.netbsd.ident")
+                       resoff -= int64(elfnetbsdsig(sh, uint64(startva), uint64(resoff)))
+
+               case Hopenbsd:
+                       sh = elfshname(".note.openbsd.ident")
+                       resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
+               }
+
+               pnote = newElfPhdr()
+               pnote.type_ = PT_NOTE
+               pnote.flags = PF_R
+               phsh(pnote, sh)
+       }
+
+       if len(buildinfo) > 0 {
+               sh = elfshname(".note.gnu.build-id")
+               resoff -= int64(elfbuildinfo(sh, uint64(startva), uint64(resoff)))
+
+               if pnote == nil {
+                       pnote = newElfPhdr()
+                       pnote.type_ = PT_NOTE
+                       pnote.flags = PF_R
+               }
+
+               phsh(pnote, sh)
+       }
+
+       // Additions to the reserved area must be above this line.
+
+       elfphload(&Segtext)
+       if Segrodata.Sect != nil {
+               elfphload(&Segrodata)
+       }
+       elfphload(&Segdata)
+
+       /* Dynamic linking sections */
+       if Debug['d'] == 0 {
+               sh = elfshname(".dynsym")
+               sh.type_ = SHT_DYNSYM
+               sh.flags = SHF_ALLOC
+               if elf64 != 0 {
+                       sh.entsize = ELF64SYMSIZE
+               } else {
+                       sh.entsize = ELF32SYMSIZE
+               }
+               sh.addralign = uint64(Thearch.Regsize)
+               sh.link = uint32(elfshname(".dynstr").shnum)
+
+               // sh->info = index of first non-local symbol (number of local symbols)
+               shsym(sh, Linklookup(Ctxt, ".dynsym", 0))
+
+               sh = elfshname(".dynstr")
+               sh.type_ = SHT_STRTAB
+               sh.flags = SHF_ALLOC
+               sh.addralign = 1
+               shsym(sh, Linklookup(Ctxt, ".dynstr", 0))
+
+               if elfverneed != 0 {
+                       sh = elfshname(".gnu.version")
+                       sh.type_ = SHT_GNU_VERSYM
+                       sh.flags = SHF_ALLOC
+                       sh.addralign = 2
+                       sh.link = uint32(elfshname(".dynsym").shnum)
+                       sh.entsize = 2
+                       shsym(sh, Linklookup(Ctxt, ".gnu.version", 0))
+
+                       sh = elfshname(".gnu.version_r")
+                       sh.type_ = SHT_GNU_VERNEED
+                       sh.flags = SHF_ALLOC
+                       sh.addralign = uint64(Thearch.Regsize)
+                       sh.info = uint32(elfverneed)
+                       sh.link = uint32(elfshname(".dynstr").shnum)
+                       shsym(sh, Linklookup(Ctxt, ".gnu.version_r", 0))
+               }
+
+               switch eh.machine {
+               case EM_X86_64,
+                       EM_PPC64:
+                       sh = elfshname(".rela.plt")
+                       sh.type_ = SHT_RELA
+                       sh.flags = SHF_ALLOC
+                       sh.entsize = ELF64RELASIZE
+                       sh.addralign = uint64(Thearch.Regsize)
+                       sh.link = uint32(elfshname(".dynsym").shnum)
+                       sh.info = uint32(elfshname(".plt").shnum)
+                       shsym(sh, Linklookup(Ctxt, ".rela.plt", 0))
+
+                       sh = elfshname(".rela")
+                       sh.type_ = SHT_RELA
+                       sh.flags = SHF_ALLOC
+                       sh.entsize = ELF64RELASIZE
+                       sh.addralign = 8
+                       sh.link = uint32(elfshname(".dynsym").shnum)
+                       shsym(sh, Linklookup(Ctxt, ".rela", 0))
+
+               default:
+                       sh = elfshname(".rel.plt")
+                       sh.type_ = SHT_REL
+                       sh.flags = SHF_ALLOC
+                       sh.entsize = ELF32RELSIZE
+                       sh.addralign = 4
+                       sh.link = uint32(elfshname(".dynsym").shnum)
+                       shsym(sh, Linklookup(Ctxt, ".rel.plt", 0))
+
+                       sh = elfshname(".rel")
+                       sh.type_ = SHT_REL
+                       sh.flags = SHF_ALLOC
+                       sh.entsize = ELF32RELSIZE
+                       sh.addralign = 4
+                       sh.link = uint32(elfshname(".dynsym").shnum)
+                       shsym(sh, Linklookup(Ctxt, ".rel", 0))
+               }
+
+               if eh.machine == EM_PPC64 {
+                       sh = elfshname(".glink")
+                       sh.type_ = SHT_PROGBITS
+                       sh.flags = SHF_ALLOC + SHF_EXECINSTR
+                       sh.addralign = 4
+                       shsym(sh, Linklookup(Ctxt, ".glink", 0))
+               }
+
+               sh = elfshname(".plt")
+               sh.type_ = SHT_PROGBITS
+               sh.flags = SHF_ALLOC + SHF_EXECINSTR
+               if eh.machine == EM_X86_64 {
+                       sh.entsize = 16
+               } else if eh.machine == EM_PPC64 {
+                       // On ppc64, this is just a table of addresses
+                       // filled by the dynamic linker
+                       sh.type_ = SHT_NOBITS
+
+                       sh.flags = SHF_ALLOC + SHF_WRITE
+                       sh.entsize = 8
+               } else {
+                       sh.entsize = 4
+               }
+               sh.addralign = sh.entsize
+               shsym(sh, Linklookup(Ctxt, ".plt", 0))
+
+               // On ppc64, .got comes from the input files, so don't
+               // create it here, and .got.plt is not used.
+               if eh.machine != EM_PPC64 {
+                       sh = elfshname(".got")
+                       sh.type_ = SHT_PROGBITS
+                       sh.flags = SHF_ALLOC + SHF_WRITE
+                       sh.entsize = uint64(Thearch.Regsize)
+                       sh.addralign = uint64(Thearch.Regsize)
+                       shsym(sh, Linklookup(Ctxt, ".got", 0))
+
+                       sh = elfshname(".got.plt")
+                       sh.type_ = SHT_PROGBITS
+                       sh.flags = SHF_ALLOC + SHF_WRITE
+                       sh.entsize = uint64(Thearch.Regsize)
+                       sh.addralign = uint64(Thearch.Regsize)
+                       shsym(sh, Linklookup(Ctxt, ".got.plt", 0))
+               }
+
+               sh = elfshname(".hash")
+               sh.type_ = SHT_HASH
+               sh.flags = SHF_ALLOC
+               sh.entsize = 4
+               sh.addralign = uint64(Thearch.Regsize)
+               sh.link = uint32(elfshname(".dynsym").shnum)
+               shsym(sh, Linklookup(Ctxt, ".hash", 0))
+
+               /* sh and PT_DYNAMIC for .dynamic section */
+               sh = elfshname(".dynamic")
+
+               sh.type_ = SHT_DYNAMIC
+               sh.flags = SHF_ALLOC + SHF_WRITE
+               sh.entsize = 2 * uint64(Thearch.Regsize)
+               sh.addralign = uint64(Thearch.Regsize)
+               sh.link = uint32(elfshname(".dynstr").shnum)
+               shsym(sh, Linklookup(Ctxt, ".dynamic", 0))
+               ph = newElfPhdr()
+               ph.type_ = PT_DYNAMIC
+               ph.flags = PF_R + PF_W
+               phsh(ph, sh)
+
+               /*
+                * Thread-local storage segment (really just size).
+                */
+               // Do not emit PT_TLS for OpenBSD since ld.so(1) does
+               // not currently support it. This is handled
+               // appropriately in runtime/cgo.
+               if Ctxt.Tlsoffset != 0 && HEADTYPE != Hopenbsd {
+                       ph = newElfPhdr()
+                       ph.type_ = PT_TLS
+                       ph.flags = PF_R
+                       ph.memsz = uint64(-Ctxt.Tlsoffset)
+                       ph.align = uint64(Thearch.Regsize)
+               }
+       }
+
+       if HEADTYPE == Hlinux {
+               ph = newElfPhdr()
+               ph.type_ = PT_GNU_STACK
+               ph.flags = PF_W + PF_R
+               ph.align = uint64(Thearch.Regsize)
+
+               ph = newElfPhdr()
+               ph.type_ = PT_PAX_FLAGS
+               ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
+               ph.align = uint64(Thearch.Regsize)
+       }
+
+elfobj:
+       sh = elfshname(".shstrtab")
+       sh.type_ = SHT_STRTAB
+       sh.addralign = 1
+       shsym(sh, Linklookup(Ctxt, ".shstrtab", 0))
+       eh.shstrndx = uint16(sh.shnum)
+
+       // put these sections early in the list
+       if Debug['s'] == 0 {
+               elfshname(".symtab")
+               elfshname(".strtab")
+       }
+
+       for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+               elfshbits(sect)
+       }
+       for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+               elfshbits(sect)
+       }
+       for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+               elfshbits(sect)
+       }
+
+       if Linkmode == LinkExternal {
+               for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+                       elfshreloc(sect)
+               }
+               for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+                       elfshreloc(sect)
+               }
+               for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+                       elfshreloc(sect)
+               }
+
+               // add a .note.GNU-stack section to mark the stack as non-executable
+               sh = elfshname(".note.GNU-stack")
+
+               sh.type_ = SHT_PROGBITS
+               sh.addralign = 1
+               sh.flags = 0
+       }
+
+       // generate .tbss section for dynamic internal linking (except for OpenBSD)
+       // external linking generates .tbss in data.c
+       if Linkmode == LinkInternal && Debug['d'] == 0 && HEADTYPE != Hopenbsd {
+               sh = elfshname(".tbss")
+               sh.type_ = SHT_NOBITS
+               sh.addralign = uint64(Thearch.Regsize)
+               sh.size = uint64(-Ctxt.Tlsoffset)
+               sh.flags = SHF_ALLOC | SHF_TLS | SHF_WRITE
+       }
+
+       if Debug['s'] == 0 {
+               sh = elfshname(".symtab")
+               sh.type_ = SHT_SYMTAB
+               sh.off = uint64(symo)
+               sh.size = uint64(Symsize)
+               sh.addralign = uint64(Thearch.Regsize)
+               sh.entsize = 8 + 2*uint64(Thearch.Regsize)
+               sh.link = uint32(elfshname(".strtab").shnum)
+               sh.info = uint32(elfglobalsymndx)
+
+               sh = elfshname(".strtab")
+               sh.type_ = SHT_STRTAB
+               sh.off = uint64(symo) + uint64(Symsize)
+               sh.size = uint64(len(Elfstrdat))
+               sh.addralign = 1
+
+               dwarfaddelfheaders()
+       }
+
+       /* Main header */
+       eh.ident[EI_MAG0] = '\177'
+
+       eh.ident[EI_MAG1] = 'E'
+       eh.ident[EI_MAG2] = 'L'
+       eh.ident[EI_MAG3] = 'F'
+       if HEADTYPE == Hfreebsd {
+               eh.ident[EI_OSABI] = ELFOSABI_FREEBSD
+       } else if HEADTYPE == Hnetbsd {
+               eh.ident[EI_OSABI] = ELFOSABI_NETBSD
+       } else if HEADTYPE == Hopenbsd {
+               eh.ident[EI_OSABI] = ELFOSABI_OPENBSD
+       } else if HEADTYPE == Hdragonfly {
+               eh.ident[EI_OSABI] = ELFOSABI_NONE
+       }
+       if elf64 != 0 {
+               eh.ident[EI_CLASS] = ELFCLASS64
+       } else {
+               eh.ident[EI_CLASS] = ELFCLASS32
+       }
+       if Ctxt.Arch.Endian == BigEndian {
+               eh.ident[EI_DATA] = ELFDATA2MSB
+       } else {
+               eh.ident[EI_DATA] = ELFDATA2LSB
+       }
+       eh.ident[EI_VERSION] = EV_CURRENT
+
+       if Linkmode == LinkExternal {
+               eh.type_ = ET_REL
+       } else {
+               eh.type_ = ET_EXEC
+       }
+
+       if Linkmode != LinkExternal {
+               eh.entry = uint64(Entryvalue())
+       }
+
+       eh.version = EV_CURRENT
+
+       if pph != nil {
+               pph.filesz = uint64(eh.phnum) * uint64(eh.phentsize)
+               pph.memsz = pph.filesz
+       }
+
+       Cseek(0)
+       a = 0
+       a += int64(elfwritehdr())
+       a += int64(elfwritephdrs())
+       a += int64(elfwriteshdrs())
+       if Debug['d'] == 0 {
+               a += int64(elfwriteinterp())
+       }
+       if Linkmode != LinkExternal {
+               if HEADTYPE == Hnetbsd {
+                       a += int64(elfwritenetbsdsig())
+               }
+               if HEADTYPE == Hopenbsd {
+                       a += int64(elfwriteopenbsdsig())
+               }
+               if len(buildinfo) > 0 {
+                       a += int64(elfwritebuildinfo())
+               }
+       }
+
+       if a > ELFRESERVE {
+               Diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE)
+       }
+}
+
+func ELF32_R_SYM(info uint32) uint32 {
+       return info >> 8
+}
+
+func ELF32_R_TYPE(info uint32) uint32 {
+       return uint32(uint8(info))
+}
+
+func ELF32_R_INFO(sym uint32, type_ uint32) uint32 {
+       return sym<<8 | type_
+}
+
+func ELF32_ST_BIND(info uint8) uint8 {
+       return info >> 4
+}
+
+func ELF32_ST_TYPE(info uint8) uint8 {
+       return info & 0xf
+}
+
+func ELF32_ST_INFO(bind uint8, type_ uint8) uint8 {
+       return bind<<4 | type_&0xf
+}
+
+func ELF32_ST_VISIBILITY(oth uint8) uint8 {
+       return oth & 3
+}
+
+func ELF64_R_SYM(info uint64) uint32 {
+       return uint32(info >> 32)
+}
+
+func ELF64_R_TYPE(info uint64) uint32 {
+       return uint32(info)
+}
+
+func ELF64_R_INFO(sym uint32, type_ uint32) uint64 {
+       return uint64(sym)<<32 | uint64(type_)
+}
+
+func ELF64_ST_BIND(info uint8) uint8 {
+       return info >> 4
+}
+
+func ELF64_ST_TYPE(info uint8) uint8 {
+       return info & 0xf
+}
+
+func ELF64_ST_INFO(bind uint8, type_ uint8) uint8 {
+       return bind<<4 | type_&0xf
+}
+
+func ELF64_ST_VISIBILITY(oth uint8) uint8 {
+       return oth & 3
+}
diff --git a/src/cmd/internal/ld/fmt.go b/src/cmd/internal/ld/fmt.go
new file mode 100644 (file)
index 0000000..86096e6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+package ld
+
+// (The comments in this file were copied from the manpage files rune.3,
+// isalpharune.3, and runestrcat.3. Some formatting changes were also made
+// to conform to Google style. /JRM 11/11/05)
+
+type Fmt struct {
+       runes     uint8
+       start     interface{}
+       to        interface{}
+       stop      interface{}
+       flush     func(*Fmt) int
+       farg      interface{}
+       nfmt      int
+       args      []interface{}
+       r         uint
+       width     int
+       prec      int
+       flags     uint32
+       decimal   string
+       thousands string
+       grouping  string
+}
+
+const (
+       FmtWidth    = 1
+       FmtLeft     = FmtWidth << 1
+       FmtPrec     = FmtLeft << 1
+       FmtSharp    = FmtPrec << 1
+       FmtSpace    = FmtSharp << 1
+       FmtSign     = FmtSpace << 1
+       FmtApost    = FmtSign << 1
+       FmtZero     = FmtApost << 1
+       FmtUnsigned = FmtZero << 1
+       FmtShort    = FmtUnsigned << 1
+       FmtLong     = FmtShort << 1
+       FmtVLong    = FmtLong << 1
+       FmtComma    = FmtVLong << 1
+       FmtByte     = FmtComma << 1
+       FmtLDouble  = FmtByte << 1
+       FmtFlag     = FmtLDouble << 1
+)
+
+var fmtdoquote func(int) int
+
+/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
diff --git a/src/cmd/internal/ld/go.go b/src/cmd/internal/ld/go.go
new file mode 100644 (file)
index 0000000..cd85c8b
--- /dev/null
@@ -0,0 +1,929 @@
+// Copyright 2009 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 ld
+
+import (
+       "bytes"
+       "cmd/internal/obj"
+       "fmt"
+       "os"
+       "strings"
+       "unicode/utf8"
+)
+
+// go-specific code shared across loaders (5l, 6l, 8l).
+
+// replace all "". with pkg.
+func expandpkg(t0 string, pkg string) string {
+       return strings.Replace(t0, `"".`, pkg+".", -1)
+}
+
+// Copyright 2009 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.
+
+// go-specific code shared across loaders (5l, 6l, 8l).
+
+// accumulate all type information from .6 files.
+// check for inconsistencies.
+
+// TODO:
+//     generate debugging section in binary.
+//     once the dust settles, try to move some code to
+//             libmach, so that other linkers and ar can share.
+
+/*
+ *     package import data
+ */
+type Import struct {
+       hash   *Import
+       prefix string
+       name   string
+       def    string
+       file   string
+}
+
+const (
+       NIHASH = 1024
+)
+
+var ihash [NIHASH]*Import
+
+var nimport int
+
+func hashstr(name string) int {
+       var h uint32
+       var cp string
+
+       h = 0
+       for cp = name; cp != ""; cp = cp[1:] {
+               h = h*1119 + uint32(cp[0])
+       }
+       h &= 0xffffff
+       return int(h)
+}
+
+func ilookup(name string) *Import {
+       var h int
+       var x *Import
+
+       h = hashstr(name) % NIHASH
+       for x = ihash[h]; x != nil; x = x.hash {
+               if x.name[0] == name[0] && x.name == name {
+                       return x
+               }
+       }
+       x = new(Import)
+       x.name = name
+       x.hash = ihash[h]
+       ihash[h] = x
+       nimport++
+       return x
+}
+
+func ldpkg(f *Biobuf, pkg string, length int64, filename string, whence int) {
+       var bdata []byte
+       var data string
+       var p0, p1 int
+       var name string
+
+       if Debug['g'] != 0 {
+               return
+       }
+
+       if int64(int(length)) != length {
+               fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
+               if Debug['u'] != 0 {
+                       Errorexit()
+               }
+               return
+       }
+
+       bdata = make([]byte, length)
+       if int64(Bread(f, bdata)) != length {
+               fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
+               if Debug['u'] != 0 {
+                       Errorexit()
+               }
+               return
+       }
+       data = string(bdata)
+
+       // first \n$$ marks beginning of exports - skip rest of line
+       p0 = strings.Index(data, "\n$$")
+       if p0 < 0 {
+               if Debug['u'] != 0 && whence != ArchiveObj {
+                       fmt.Fprintf(os.Stderr, "%s: cannot find export data in %s\n", os.Args[0], filename)
+                       Errorexit()
+               }
+               return
+       }
+
+       p0 += 3
+       for p0 < len(data) && data[0] != '\n' {
+               p0++
+       }
+
+       // second marks end of exports / beginning of local data
+       p1 = strings.Index(data[p0:], "\n$$")
+       if p1 < 0 {
+               fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename)
+               if Debug['u'] != 0 {
+                       Errorexit()
+               }
+               return
+       }
+       p1 += p0
+
+       for p0 < p1 && (data[p0] == ' ' || data[0] == '\t' || data[0] == '\n') {
+               p0++
+       }
+       if p0 < p1 {
+               if !strings.HasPrefix(data[p0:], "package ") {
+                       fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:])
+                       if Debug['u'] != 0 {
+                               Errorexit()
+                       }
+                       return
+               }
+
+               p0 += 8
+               for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
+                       p0++
+               }
+               name = data[p0:]
+               for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' {
+                       p0++
+               }
+               if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) {
+                       fmt.Fprintf(os.Stderr, "%s: load of unsafe package %s\n", os.Args[0], filename)
+                       nerrors++
+                       Errorexit()
+               }
+
+               name = name[:p1-p0]
+               if p0 < p1 {
+                       if data[p0] == '\n' {
+                               p0++
+                       } else {
+                               p0++
+                               for p0 < p1 && data[p0] != '\n' {
+                                       p0++
+                               }
+                       }
+               }
+
+               if pkg == "main" && name != "main" {
+                       fmt.Fprintf(os.Stderr, "%s: %s: not package main (package %s)\n", os.Args[0], filename, name)
+                       nerrors++
+                       Errorexit()
+               }
+
+               loadpkgdata(filename, pkg, data[p0:p1])
+       }
+
+       // __.PKGDEF has no cgo section - those are in the C compiler-generated object files.
+       if whence == Pkgdef {
+               return
+       }
+
+       // look for cgo section
+       p0 = strings.Index(data[p1:], "\n$$  // cgo")
+       if p0 >= 0 {
+               p0 += p1
+               i := strings.IndexByte(data[p0+1:], '\n')
+               if i < 0 {
+                       fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
+                       if Debug['u'] != 0 {
+                               Errorexit()
+                       }
+                       return
+               }
+               p0 += 1 + i
+
+               p1 = strings.Index(data[p0:], "\n$$")
+               if p1 < 0 {
+                       p1 = strings.Index(data[p0:], "\n!\n")
+               }
+               if p1 < 0 {
+                       fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
+                       if Debug['u'] != 0 {
+                               Errorexit()
+                       }
+                       return
+               }
+               p1 += p0
+
+               loadcgo(filename, pkg, data[p0:p1])
+       }
+}
+
+func loadpkgdata(file string, pkg string, data string) {
+       var p string
+       var prefix string
+       var name string
+       var def string
+       var x *Import
+
+       file = file
+       p = data
+       for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 {
+               x = ilookup(name)
+               if x.prefix == "" {
+                       x.prefix = prefix
+                       x.def = def
+                       x.file = file
+               } else if x.prefix != prefix {
+                       fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
+                       fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", x.file, x.prefix, name)
+                       fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", file, prefix, name)
+                       nerrors++
+               } else if x.def != def {
+                       fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
+                       fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", x.file, x.prefix, name, x.def)
+                       fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", file, prefix, name, def)
+                       nerrors++
+               }
+       }
+}
+
+func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int {
+       var p string
+       var prefix string
+       var name string
+       var def string
+       var meth string
+       var inquote bool
+
+       // skip white space
+       p = *pp
+
+loop:
+       for len(p) > 0 && (p[0] == ' ' || p[0] == '\t' || p[0] == '\n') {
+               p = p[1:]
+       }
+       if len(p) == 0 || strings.HasPrefix(p, "$$\n") {
+               return 0
+       }
+
+       // prefix: (var|type|func|const)
+       prefix = p
+
+       if len(p) < 7 {
+               return -1
+       }
+       if strings.HasPrefix(p, "var ") {
+               p = p[4:]
+       } else if strings.HasPrefix(p, "type ") {
+               p = p[5:]
+       } else if strings.HasPrefix(p, "func ") {
+               p = p[5:]
+       } else if strings.HasPrefix(p, "const ") {
+               p = p[6:]
+       } else if strings.HasPrefix(p, "import ") {
+               p = p[7:]
+               for len(p) > 0 && p[0] != ' ' {
+                       p = p[1:]
+               }
+               p = p[1:]
+               name := p
+               for len(p) > 0 && p[0] != '\n' {
+                       p = p[1:]
+               }
+               if len(p) == 0 {
+                       fmt.Fprintf(os.Stderr, "%s: %s: confused in import line\n", os.Args[0], file)
+                       nerrors++
+                       return -1
+               }
+               name = name[:len(name)-len(p)]
+               p = p[1:]
+               imported(pkg, name)
+               goto loop
+       } else {
+               fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix)
+               nerrors++
+               return -1
+       }
+
+       prefix = prefix[:len(prefix)-len(p)-1]
+
+       // name: a.b followed by space
+       name = p
+
+       inquote = false
+       for len(p) > 0 {
+               if p[0] == ' ' && !inquote {
+                       break
+               }
+
+               if p[0] == '\\' {
+                       p = p[1:]
+               } else if p[0] == '"' {
+                       inquote = !inquote
+               }
+
+               p = p[1:]
+       }
+
+       if len(p) == 0 {
+               return -1
+       }
+       name = name[:len(name)-len(p)]
+       p = p[1:]
+
+       // def: free form to new line
+       def = p
+
+       for len(p) > 0 && p[0] != '\n' {
+               p = p[1:]
+       }
+       if len(p) == 0 {
+               return -1
+       }
+       def = def[:len(def)-len(p)]
+       var defbuf *bytes.Buffer
+       p = p[1:]
+
+       // include methods on successive lines in def of named type
+       for parsemethod(&p, &meth) > 0 {
+               if defbuf == nil {
+                       defbuf = new(bytes.Buffer)
+                       defbuf.WriteString(def)
+               }
+               defbuf.WriteString("\n\t")
+               defbuf.WriteString(meth)
+       }
+       if defbuf != nil {
+               def = defbuf.String()
+       }
+
+       name = expandpkg(name, pkg)
+       def = expandpkg(def, pkg)
+
+       // done
+       *pp = p
+
+       *prefixp = prefix
+       *namep = name
+       *defp = def
+       return 1
+}
+
+func parsemethod(pp *string, methp *string) int {
+       var p string
+
+       // skip white space
+       p = *pp
+
+       for len(p) > 0 && (p[0] == ' ' || p[0] == '\t') {
+               p = p[1:]
+       }
+       if len(p) == 0 {
+               return 0
+       }
+
+       // might be a comment about the method
+       if strings.HasPrefix(p, "//") {
+               goto useline
+       }
+
+       // if it says "func (", it's a method
+       if strings.HasPrefix(p, "func (") {
+               goto useline
+       }
+       return 0
+
+       // definition to end of line
+useline:
+       *methp = p
+
+       for len(p) > 0 && p[0] != '\n' {
+               p = p[1:]
+       }
+       if len(p) == 0 {
+               fmt.Fprintf(os.Stderr, "%s: lost end of line in method definition\n", os.Args[0])
+               *pp = ""
+               return -1
+       }
+
+       *methp = (*methp)[:len(*methp)-len(p)]
+       *pp = p[1:]
+       return 1
+}
+
+func loadcgo(file string, pkg string, p string) {
+       var next string
+       var p0 string
+       var q string
+       var f []string
+       var local string
+       var remote string
+       var lib string
+       var s *LSym
+
+       p0 = ""
+       for ; p != ""; p = next {
+               if i := strings.Index(p, "\n"); i >= 0 {
+                       p, next = p[:i], p[i+1:]
+               } else {
+                       next = ""
+               }
+
+               p0 = p // save for error message
+               f = tokenize(p)
+               if len(f) == 0 {
+                       continue
+               }
+
+               if f[0] == "cgo_import_dynamic" {
+                       if len(f) < 2 || len(f) > 4 {
+                               goto err
+                       }
+
+                       local = f[1]
+                       remote = local
+                       if len(f) > 2 {
+                               remote = f[2]
+                       }
+                       lib = ""
+                       if len(f) > 3 {
+                               lib = f[3]
+                       }
+
+                       if Debug['d'] != 0 {
+                               fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
+                               nerrors++
+                               return
+                       }
+
+                       if local == "_" && remote == "_" {
+                               // allow #pragma dynimport _ _ "foo.so"
+                               // to force a link of foo.so.
+                               havedynamic = 1
+
+                               Thearch.Adddynlib(lib)
+                               continue
+                       }
+
+                       local = expandpkg(local, pkg)
+                       q = ""
+                       if i := strings.Index(remote, "#"); i >= 0 {
+                               remote, q = remote[:i], remote[i+1:]
+                       }
+                       s = Linklookup(Ctxt, local, 0)
+                       if local != f[1] {
+                       }
+                       if s.Type == 0 || s.Type == SXREF || s.Type == SHOSTOBJ {
+                               s.Dynimplib = lib
+                               s.Extname = remote
+                               s.Dynimpvers = q
+                               if s.Type != SHOSTOBJ {
+                                       s.Type = SDYNIMPORT
+                               }
+                               havedynamic = 1
+                       }
+
+                       continue
+               }
+
+               if f[0] == "cgo_import_static" {
+                       if len(f) != 2 {
+                               goto err
+                       }
+                       local = f[1]
+                       s = Linklookup(Ctxt, local, 0)
+                       s.Type = SHOSTOBJ
+                       s.Size = 0
+                       continue
+               }
+
+               if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" {
+                       // TODO: Remove once we know Windows is okay.
+                       if f[0] == "cgo_export_static" && HEADTYPE == Hwindows {
+                               continue
+                       }
+
+                       if len(f) < 2 || len(f) > 3 {
+                               goto err
+                       }
+                       local = f[1]
+                       if len(f) > 2 {
+                               remote = f[2]
+                       } else {
+                               remote = local
+                       }
+                       local = expandpkg(local, pkg)
+                       s = Linklookup(Ctxt, local, 0)
+
+                       if Flag_shared != 0 && s == Linklookup(Ctxt, "main", 0) {
+                               continue
+                       }
+
+                       // export overrides import, for openbsd/cgo.
+                       // see issue 4878.
+                       if s.Dynimplib != "" {
+                               s.Dynimplib = ""
+                               s.Extname = ""
+                               s.Dynimpvers = ""
+                               s.Type = 0
+                       }
+
+                       if s.Cgoexport == 0 {
+                               s.Extname = remote
+                               dynexp = append(dynexp, s)
+                       } else if s.Extname != remote {
+                               fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote)
+                               nerrors++
+                               return
+                       }
+
+                       if f[0] == "cgo_export_static" {
+                               s.Cgoexport |= CgoExportStatic
+                       } else {
+                               s.Cgoexport |= CgoExportDynamic
+                       }
+                       if local != f[1] {
+                       }
+                       continue
+               }
+
+               if f[0] == "cgo_dynamic_linker" {
+                       if len(f) != 2 {
+                               goto err
+                       }
+
+                       if Debug['I'] == 0 {
+                               if interpreter != "" && interpreter != f[1] {
+                                       fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
+                                       nerrors++
+                                       return
+                               }
+
+                               interpreter = f[1]
+                       }
+
+                       continue
+               }
+
+               if f[0] == "cgo_ldflag" {
+                       if len(f) != 2 {
+                               goto err
+                       }
+                       ldflag = append(ldflag, f[1])
+                       continue
+               }
+       }
+
+       return
+
+err:
+       fmt.Fprintf(os.Stderr, "%s: %s: invalid dynimport line: %s\n", os.Args[0], file, p0)
+       nerrors++
+}
+
+var markq *LSym
+
+var emarkq *LSym
+
+func mark1(s *LSym, parent *LSym) {
+       if s == nil || s.Reachable {
+               return
+       }
+       if strings.HasPrefix(s.Name, "go.weak.") {
+               return
+       }
+       s.Reachable = true
+       s.Reachparent = parent
+       if markq == nil {
+               markq = s
+       } else {
+               emarkq.Queue = s
+       }
+       emarkq = s
+}
+
+func mark(s *LSym) {
+       mark1(s, nil)
+}
+
+func markflood() {
+       var a *Auto
+       var s *LSym
+       var i int
+
+       for s = markq; s != nil; s = s.Queue {
+               if s.Type == STEXT {
+                       if Debug['v'] > 1 {
+                               fmt.Fprintf(&Bso, "marktext %s\n", s.Name)
+                       }
+                       for a = s.Autom; a != nil; a = a.Link {
+                               mark1(a.Gotype, s)
+                       }
+               }
+
+               for i = 0; i < len(s.R); i++ {
+                       mark1(s.R[i].Sym, s)
+               }
+               if s.Pcln != nil {
+                       for i = 0; i < s.Pcln.Nfuncdata; i++ {
+                               mark1(s.Pcln.Funcdata[i], s)
+                       }
+               }
+
+               mark1(s.Gotype, s)
+               mark1(s.Sub, s)
+               mark1(s.Outer, s)
+       }
+}
+
+var markextra = []string{
+       "runtime.morestack",
+       "runtime.morestackx",
+       "runtime.morestack00",
+       "runtime.morestack10",
+       "runtime.morestack01",
+       "runtime.morestack11",
+       "runtime.morestack8",
+       "runtime.morestack16",
+       "runtime.morestack24",
+       "runtime.morestack32",
+       "runtime.morestack40",
+       "runtime.morestack48",
+       // on arm, lock in the div/mod helpers too
+       "_div",
+       "_divu",
+       "_mod",
+       "_modu",
+}
+
+func deadcode() {
+       var i int
+       var s *LSym
+       var last *LSym
+       var p *LSym
+       var fmt_ string
+
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime())
+       }
+
+       mark(Linklookup(Ctxt, INITENTRY, 0))
+       for i = 0; i < len(markextra); i++ {
+               mark(Linklookup(Ctxt, markextra[i], 0))
+       }
+
+       for i = 0; i < len(dynexp); i++ {
+               mark(dynexp[i])
+       }
+
+       markflood()
+
+       // keep each beginning with 'typelink.' if the symbol it points at is being kept.
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if strings.HasPrefix(s.Name, "go.typelink.") {
+                       s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable
+               }
+       }
+
+       // remove dead text but keep file information (z symbols).
+       last = nil
+
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               if !s.Reachable {
+                       continue
+               }
+
+               // NOTE: Removing s from old textp and adding to new, shorter textp.
+               if last == nil {
+                       Ctxt.Textp = s
+               } else {
+                       last.Next = s
+               }
+               last = s
+       }
+
+       if last == nil {
+               Ctxt.Textp = nil
+       } else {
+               last.Next = nil
+       }
+
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if strings.HasPrefix(s.Name, "go.weak.") {
+                       s.Special = 1 // do not lay out in data segment
+                       s.Reachable = true
+                       s.Hide = 1
+               }
+       }
+
+       // record field tracking references
+       fmt_ = ""
+
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if strings.HasPrefix(s.Name, "go.track.") {
+                       s.Special = 1 // do not lay out in data segment
+                       s.Hide = 1
+                       if s.Reachable {
+                               fmt_ += fmt.Sprintf("%s", s.Name[9:])
+                               for p = s.Reachparent; p != nil; p = p.Reachparent {
+                                       fmt_ += fmt.Sprintf("\t%s", p.Name)
+                               }
+                               fmt_ += fmt.Sprintf("\n")
+                       }
+
+                       s.Type = SCONST
+                       s.Value = 0
+               }
+       }
+
+       if tracksym == "" {
+               return
+       }
+       s = Linklookup(Ctxt, tracksym, 0)
+       if !s.Reachable {
+               return
+       }
+       addstrdata(tracksym, fmt_)
+}
+
+func doweak() {
+       var s *LSym
+       var t *LSym
+
+       // resolve weak references only if
+       // target symbol will be in binary anyway.
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if strings.HasPrefix(s.Name, "go.weak.") {
+                       t = Linkrlookup(Ctxt, s.Name[8:], int(s.Version))
+                       if t != nil && t.Type != 0 && t.Reachable {
+                               s.Value = t.Value
+                               s.Type = t.Type
+                               s.Outer = t
+                       } else {
+                               s.Type = SCONST
+                               s.Value = 0
+                       }
+
+                       continue
+               }
+       }
+}
+
+func addexport() {
+       var i int
+
+       if HEADTYPE == Hdarwin {
+               return
+       }
+
+       for i = 0; i < len(dynexp); i++ {
+               Thearch.Adddynsym(Ctxt, dynexp[i])
+       }
+}
+
+/* %Z from gc, for quoting import paths */
+func Zconv(s string, flag int) string {
+       // NOTE: Keep in sync with gc Zconv.
+       var n int
+       var fp string
+       for i := 0; i < len(s); i += n {
+               var r rune
+               r, n = utf8.DecodeRuneInString(s[i:])
+               switch r {
+               case utf8.RuneError:
+                       if n == 1 {
+                               fp += fmt.Sprintf("\\x%02x", s[i])
+                               break
+                       }
+                       fallthrough
+
+                       // fall through
+               default:
+                       if r < ' ' {
+                               fp += fmt.Sprintf("\\x%02x", r)
+                               break
+                       }
+
+                       fp += string(r)
+
+               case '\t':
+                       fp += "\\t"
+
+               case '\n':
+                       fp += "\\n"
+
+               case '"',
+                       '\\':
+                       fp += `\` + string(r)
+
+               case 0xFEFF: // BOM, basically disallowed in source code
+                       fp += "\\uFEFF"
+               }
+       }
+
+       return fp
+}
+
+type Pkg struct {
+       mark    uint8
+       checked uint8
+       next    *Pkg
+       path_   string
+       impby   []*Pkg
+       all     *Pkg
+}
+
+var phash [1024]*Pkg
+
+var pkgall *Pkg
+
+func getpkg(path_ string) *Pkg {
+       var p *Pkg
+       var h int
+
+       h = hashstr(path_) % len(phash)
+       for p = phash[h]; p != nil; p = p.next {
+               if p.path_ == path_ {
+                       return p
+               }
+       }
+       p = new(Pkg)
+       p.path_ = path_
+       p.next = phash[h]
+       phash[h] = p
+       p.all = pkgall
+       pkgall = p
+       return p
+}
+
+func imported(pkg string, import_ string) {
+       var p *Pkg
+       var i *Pkg
+
+       // everyone imports runtime, even runtime.
+       if import_ == "\"runtime\"" {
+               return
+       }
+
+       pkg = fmt.Sprintf("\"%v\"", Zconv(pkg, 0)) // turn pkg path into quoted form, freed below
+       p = getpkg(pkg)
+       i = getpkg(import_)
+       i.impby = append(i.impby, p)
+}
+
+func cycle(p *Pkg) *Pkg {
+       var i int
+       var bad *Pkg
+
+       if p.checked != 0 {
+               return nil
+       }
+
+       if p.mark != 0 {
+               nerrors++
+               fmt.Printf("import cycle:\n")
+               fmt.Printf("\t%s\n", p.path_)
+               return p
+       }
+
+       p.mark = 1
+       for i = 0; i < len(p.impby); i++ {
+               bad = cycle(p.impby[i])
+               if bad != nil {
+                       p.mark = 0
+                       p.checked = 1
+                       fmt.Printf("\timports %s\n", p.path_)
+                       if bad == p {
+                               return nil
+                       }
+                       return bad
+               }
+       }
+
+       p.checked = 1
+       p.mark = 0
+       return nil
+}
+
+func importcycles() {
+       var p *Pkg
+
+       for p = pkgall; p != nil; p = p.all {
+               cycle(p)
+       }
+}
+
+func setlinkmode(arg string) {
+       if arg == "internal" {
+               Linkmode = LinkInternal
+       } else if arg == "external" {
+               Linkmode = LinkExternal
+       } else if arg == "auto" {
+               Linkmode = LinkAuto
+       } else {
+               fmt.Fprintf(os.Stderr, "unknown link mode -linkmode %s\n", arg)
+               Errorexit()
+       }
+}
diff --git a/src/cmd/internal/ld/ld.go b/src/cmd/internal/ld/ld.go
new file mode 100644 (file)
index 0000000..99f2fab
--- /dev/null
@@ -0,0 +1,123 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "os"
+       "path"
+       "strconv"
+       "strings"
+)
+
+func addlib(ctxt *Link, src string, obj string, pathname string) {
+       name := path.Clean(pathname)
+
+       // runtime.a -> runtime, runtime.6 -> runtime
+       pkg := name
+       if len(pkg) >= 2 && pkg[len(pkg)-2] == '.' {
+               pkg = pkg[:len(pkg)-2]
+       }
+
+       // already loaded?
+       for i := 0; i < len(ctxt.Library); i++ {
+               if ctxt.Library[i].Pkg == pkg {
+                       return
+               }
+       }
+
+       var pname string
+       if (ctxt.Windows == 0 && strings.HasPrefix(name, "/")) || (ctxt.Windows != 0 && len(name) >= 2 && name[1] == ':') {
+               pname = name
+       } else {
+               // try dot, -L "libdir", and then goroot.
+               for _, dir := range ctxt.Libdir {
+                       pname = dir + "/" + name
+                       if _, err := os.Stat(pname); err == nil {
+                               break
+                       }
+               }
+       }
+
+       pname = path.Clean(pname)
+
+       if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
+               fmt.Fprintf(ctxt.Bso, "%5.2f addlib: %s %s pulls in %s\n", elapsed(), obj, src, pname)
+       }
+
+       addlibpath(ctxt, src, obj, pname, pkg)
+}
+
+/*
+ * add library to library list.
+ *     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) {
+       var i int
+       var l *Library
+
+       for i = 0; i < len(ctxt.Library); i++ {
+               if file == ctxt.Library[i].File {
+                       return
+               }
+       }
+
+       if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
+               fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", obj.Cputime(), srcref, objref, file, pkg)
+       }
+
+       ctxt.Library = append(ctxt.Library, Library{})
+       l = &ctxt.Library[len(ctxt.Library)-1]
+       l.Objref = objref
+       l.Srcref = srcref
+       l.File = file
+       l.Pkg = pkg
+}
+
+var fnuxi8 [8]uint8
+
+var fnuxi4 [4]uint8
+
+var inuxi1 [1]uint8
+
+var inuxi2 [2]uint8
+
+var inuxi8 [8]uint8
+
+func atolwhex(s string) int64 {
+       n, _ := strconv.ParseInt(s, 0, 64)
+       return n
+}
diff --git a/src/cmd/internal/ld/ldelf.go b/src/cmd/internal/ld/ldelf.go
new file mode 100644 (file)
index 0000000..c50e995
--- /dev/null
@@ -0,0 +1,1004 @@
+package ld
+
+import (
+       "bytes"
+       "cmd/internal/obj"
+       "encoding/binary"
+       "fmt"
+       "log"
+       "sort"
+       "strings"
+)
+
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+       Copyright © 2004 Russ Cox.
+       Portions Copyright © 2008-2010 Google Inc.
+       Portions Copyright © 2010 The Go Authors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+const (
+       ElfClassNone = 0 + iota
+       ElfClass32
+       ElfClass64
+       ElfDataNone = 0 + iota - 3
+       ElfDataLsb
+       ElfDataMsb
+       ElfTypeNone = 0 + iota - 6
+       ElfTypeRelocatable
+       ElfTypeExecutable
+       ElfTypeSharedObject
+       ElfTypeCore
+       ElfMachNone = 0 + iota - 11
+       ElfMach32100
+       ElfMachSparc
+       ElfMach386
+       ElfMach68000
+       ElfMach88000
+       ElfMach486
+       ElfMach860
+       ElfMachMips
+       ElfMachS370
+       ElfMachMipsLe
+       ElfMachParisc = 15
+       ElfMachVpp500 = 17 + iota - 23
+       ElfMachSparc32Plus
+       ElfMach960
+       ElfMachPower
+       ElfMachPower64
+       ElfMachS390
+       ElfMachV800 = 36 + iota - 29
+       ElfMachFr20
+       ElfMachRh32
+       ElfMachRce
+       ElfMachArm
+       ElfMachAlpha
+       ElfMachSH
+       ElfMachSparc9
+       ElfMachAmd64  = 62
+       ElfAbiNone    = 0
+       ElfAbiSystemV = 0 + iota - 39
+       ElfAbiHPUX
+       ElfAbiNetBSD
+       ElfAbiLinux
+       ElfAbiSolaris = 6 + iota - 43
+       ElfAbiAix
+       ElfAbiIrix
+       ElfAbiFreeBSD
+       ElfAbiTru64
+       ElfAbiModesto
+       ElfAbiOpenBSD
+       ElfAbiARM      = 97
+       ElfAbiEmbedded = 255
+       ElfSectNone    = 0 + iota - 52
+       ElfSectProgbits
+       ElfSectSymtab
+       ElfSectStrtab
+       ElfSectRela
+       ElfSectHash
+       ElfSectDynamic
+       ElfSectNote
+       ElfSectNobits
+       ElfSectRel
+       ElfSectShlib
+       ElfSectDynsym
+       ElfSectFlagWrite = 0x1
+       ElfSectFlagAlloc = 0x2
+       ElfSectFlagExec  = 0x4
+       ElfSymBindLocal  = 0 + iota - 67
+       ElfSymBindGlobal
+       ElfSymBindWeak
+       ElfSymTypeNone = 0 + iota - 70
+       ElfSymTypeObject
+       ElfSymTypeFunc
+       ElfSymTypeSection
+       ElfSymTypeFile
+       ElfSymShnNone   = 0
+       ElfSymShnAbs    = 0xFFF1
+       ElfSymShnCommon = 0xFFF2
+       ElfProgNone     = 0 + iota - 78
+       ElfProgLoad
+       ElfProgDynamic
+       ElfProgInterp
+       ElfProgNote
+       ElfProgShlib
+       ElfProgPhdr
+       ElfProgFlagExec     = 0x1
+       ElfProgFlagWrite    = 0x2
+       ElfProgFlagRead     = 0x4
+       ElfNotePrStatus     = 1
+       ElfNotePrFpreg      = 2
+       ElfNotePrPsinfo     = 3
+       ElfNotePrTaskstruct = 4
+       ElfNotePrAuxv       = 6
+       ElfNotePrXfpreg     = 0x46e62b7f
+)
+
+type ElfHdrBytes struct {
+       Ident     [16]uint8
+       Type      [2]uint8
+       Machine   [2]uint8
+       Version   [4]uint8
+       Entry     [4]uint8
+       Phoff     [4]uint8
+       Shoff     [4]uint8
+       Flags     [4]uint8
+       Ehsize    [2]uint8
+       Phentsize [2]uint8
+       Phnum     [2]uint8
+       Shentsize [2]uint8
+       Shnum     [2]uint8
+       Shstrndx  [2]uint8
+}
+
+type ElfSectBytes struct {
+       Name    [4]uint8
+       Type    [4]uint8
+       Flags   [4]uint8
+       Addr    [4]uint8
+       Off     [4]uint8
+       Size    [4]uint8
+       Link    [4]uint8
+       Info    [4]uint8
+       Align   [4]uint8
+       Entsize [4]uint8
+}
+
+type ElfProgBytes struct {
+}
+
+type ElfSymBytes struct {
+       Name  [4]uint8
+       Value [4]uint8
+       Size  [4]uint8
+       Info  uint8
+       Other uint8
+       Shndx [2]uint8
+}
+
+type ElfHdrBytes64 struct {
+       Ident     [16]uint8
+       Type      [2]uint8
+       Machine   [2]uint8
+       Version   [4]uint8
+       Entry     [8]uint8
+       Phoff     [8]uint8
+       Shoff     [8]uint8
+       Flags     [4]uint8
+       Ehsize    [2]uint8
+       Phentsize [2]uint8
+       Phnum     [2]uint8
+       Shentsize [2]uint8
+       Shnum     [2]uint8
+       Shstrndx  [2]uint8
+}
+
+type ElfSectBytes64 struct {
+       Name    [4]uint8
+       Type    [4]uint8
+       Flags   [8]uint8
+       Addr    [8]uint8
+       Off     [8]uint8
+       Size    [8]uint8
+       Link    [4]uint8
+       Info    [4]uint8
+       Align   [8]uint8
+       Entsize [8]uint8
+}
+
+type ElfProgBytes64 struct {
+}
+
+type ElfSymBytes64 struct {
+       Name  [4]uint8
+       Info  uint8
+       Other uint8
+       Shndx [2]uint8
+       Value [8]uint8
+       Size  [8]uint8
+}
+
+type ElfSect struct {
+       name    string
+       nameoff uint32
+       type_   uint32
+       flags   uint64
+       addr    uint64
+       off     uint64
+       size    uint64
+       link    uint32
+       info    uint32
+       align   uint64
+       entsize uint64
+       base    []byte
+       sym     *LSym
+}
+
+type ElfObj struct {
+       f         *Biobuf
+       base      int64
+       length    int64
+       is64      int
+       name      string
+       e         binary.ByteOrder
+       sect      []ElfSect
+       nsect     uint
+       shstrtab  string
+       nsymtab   int
+       symtab    *ElfSect
+       symstr    *ElfSect
+       type_     uint32
+       machine   uint32
+       version   uint32
+       entry     uint64
+       phoff     uint64
+       shoff     uint64
+       flags     uint32
+       ehsize    uint32
+       phentsize uint32
+       phnum     uint32
+       shentsize uint32
+       shnum     uint32
+       shstrndx  uint32
+}
+
+type ElfSym struct {
+       name  string
+       value uint64
+       size  uint64
+       bind  uint8
+       type_ uint8
+       other uint8
+       shndx uint16
+       sym   *LSym
+}
+
+var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'}
+
+func valuecmp(a *LSym, b *LSym) int {
+       if a.Value < b.Value {
+               return -1
+       }
+       if a.Value > b.Value {
+               return +1
+       }
+       return 0
+}
+
+func ldelf(f *Biobuf, pkg string, length int64, pn string) {
+       var err error
+       var base int32
+       var add uint64
+       var info uint64
+       var name string
+       var i int
+       var j int
+       var rela int
+       var is64 int
+       var n int
+       var flag int
+       var hdrbuf [64]uint8
+       var p []byte
+       var hdr *ElfHdrBytes
+       var elfobj *ElfObj
+       var sect *ElfSect
+       var rsect *ElfSect
+       var sym ElfSym
+       var e binary.ByteOrder
+       var r []Reloc
+       var rp *Reloc
+       var s *LSym
+       var symbols []*LSym
+
+       symbols = nil
+
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
+       }
+
+       Ctxt.Version++
+       base = int32(Boffset(f))
+
+       if Bread(f, hdrbuf[:]) != len(hdrbuf) {
+               goto bad
+       }
+       hdr = new(ElfHdrBytes)
+       binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
+       if string(hdr.Ident[:4]) != "\x7FELF" {
+               goto bad
+       }
+       switch hdr.Ident[5] {
+       case ElfDataLsb:
+               e = binary.LittleEndian
+
+       case ElfDataMsb:
+               e = binary.BigEndian
+
+       default:
+               goto bad
+       }
+
+       // read header
+       elfobj = new(ElfObj)
+
+       elfobj.e = e
+       elfobj.f = f
+       elfobj.base = int64(base)
+       elfobj.length = length
+       elfobj.name = pn
+
+       is64 = 0
+       if hdr.Ident[4] == ElfClass64 {
+               var hdr *ElfHdrBytes64
+
+               is64 = 1
+               hdr = new(ElfHdrBytes64)
+               binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
+               elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
+               elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
+               elfobj.version = e.Uint32(hdr.Version[:])
+               elfobj.phoff = e.Uint64(hdr.Phoff[:])
+               elfobj.shoff = e.Uint64(hdr.Shoff[:])
+               elfobj.flags = e.Uint32(hdr.Flags[:])
+               elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
+               elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
+               elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
+               elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
+               elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
+               elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
+       } else {
+               elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
+               elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
+               elfobj.version = e.Uint32(hdr.Version[:])
+               elfobj.entry = uint64(e.Uint32(hdr.Entry[:]))
+               elfobj.phoff = uint64(e.Uint32(hdr.Phoff[:]))
+               elfobj.shoff = uint64(e.Uint32(hdr.Shoff[:]))
+               elfobj.flags = e.Uint32(hdr.Flags[:])
+               elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
+               elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
+               elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
+               elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
+               elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
+               elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
+       }
+
+       elfobj.is64 = is64
+
+       if uint32(hdr.Ident[6]) != elfobj.version {
+               goto bad
+       }
+
+       if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable {
+               Diag("%s: elf but not elf relocatable object", pn)
+               return
+       }
+
+       switch Thearch.Thechar {
+       default:
+               Diag("%s: elf %s unimplemented", pn, Thestring)
+               return
+
+       case '5':
+               if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
+                       Diag("%s: elf object but not arm", pn)
+                       return
+               }
+
+       case '6':
+               if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
+                       Diag("%s: elf object but not amd64", pn)
+                       return
+               }
+
+       case '8':
+               if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
+                       Diag("%s: elf object but not 386", pn)
+                       return
+               }
+
+       case '9':
+               if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
+                       Diag("%s: elf object but not ppc64", pn)
+                       return
+               }
+       }
+
+       // load section list into memory.
+       elfobj.sect = make([]ElfSect, elfobj.shnum)
+
+       elfobj.nsect = uint(elfobj.shnum)
+       for i = 0; uint(i) < elfobj.nsect; i++ {
+               if Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
+                       goto bad
+               }
+               sect = &elfobj.sect[i]
+               if is64 != 0 {
+                       var b ElfSectBytes64
+
+                       if err = binary.Read(f, e, &b); err != nil {
+                               goto bad
+                       }
+
+                       sect.nameoff = uint32(e.Uint32(b.Name[:]))
+                       sect.type_ = e.Uint32(b.Type[:])
+                       sect.flags = e.Uint64(b.Flags[:])
+                       sect.addr = e.Uint64(b.Addr[:])
+                       sect.off = e.Uint64(b.Off[:])
+                       sect.size = e.Uint64(b.Size[:])
+                       sect.link = e.Uint32(b.Link[:])
+                       sect.info = e.Uint32(b.Info[:])
+                       sect.align = e.Uint64(b.Align[:])
+                       sect.entsize = e.Uint64(b.Entsize[:])
+               } else {
+                       var b ElfSectBytes
+
+                       if err = binary.Read(f, e, &b); err != nil {
+                               goto bad
+                       }
+
+                       sect.nameoff = uint32(e.Uint32(b.Name[:]))
+                       sect.type_ = e.Uint32(b.Type[:])
+                       sect.flags = uint64(e.Uint32(b.Flags[:]))
+                       sect.addr = uint64(e.Uint32(b.Addr[:]))
+                       sect.off = uint64(e.Uint32(b.Off[:]))
+                       sect.size = uint64(e.Uint32(b.Size[:]))
+                       sect.link = e.Uint32(b.Link[:])
+                       sect.info = e.Uint32(b.Info[:])
+                       sect.align = uint64(e.Uint32(b.Align[:]))
+                       sect.entsize = uint64(e.Uint32(b.Entsize[:]))
+               }
+       }
+
+       // read section string table and translate names
+       if elfobj.shstrndx >= uint32(elfobj.nsect) {
+               err = fmt.Errorf("shstrndx out of range %d >= %d", elfobj.shstrndx, elfobj.nsect)
+               goto bad
+       }
+
+       sect = &elfobj.sect[elfobj.shstrndx]
+       if err = elfmap(elfobj, sect); err != nil {
+               goto bad
+       }
+       for i = 0; uint(i) < elfobj.nsect; i++ {
+               if elfobj.sect[i].nameoff != 0 {
+                       elfobj.sect[i].name = cstring(sect.base[elfobj.sect[i].nameoff:])
+               }
+       }
+
+       // load string table for symbols into memory.
+       elfobj.symtab = section(elfobj, ".symtab")
+
+       if elfobj.symtab == nil {
+               // our work is done here - no symbols means nothing can refer to this file
+               return
+       }
+
+       if elfobj.symtab.link <= 0 || elfobj.symtab.link >= uint32(elfobj.nsect) {
+               Diag("%s: elf object has symbol table with invalid string table link", pn)
+               return
+       }
+
+       elfobj.symstr = &elfobj.sect[elfobj.symtab.link]
+       if is64 != 0 {
+               elfobj.nsymtab = int(elfobj.symtab.size / ELF64SYMSIZE)
+       } else {
+               elfobj.nsymtab = int(elfobj.symtab.size / ELF32SYMSIZE)
+       }
+
+       if err = elfmap(elfobj, elfobj.symtab); err != nil {
+               goto bad
+       }
+       if err = elfmap(elfobj, elfobj.symstr); err != nil {
+               goto bad
+       }
+
+       // load text and data segments into memory.
+       // they are not as small as the section lists, but we'll need
+       // the memory anyway for the symbol images, so we might
+       // as well use one large chunk.
+
+       // create symbols for elfmapped sections
+       for i = 0; uint(i) < elfobj.nsect; i++ {
+               sect = &elfobj.sect[i]
+               if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 {
+                       continue
+               }
+               if sect.type_ != ElfSectNobits {
+                       if err = elfmap(elfobj, sect); err != nil {
+                               goto bad
+                       }
+               }
+
+               name = fmt.Sprintf("%s(%s)", pkg, sect.name)
+               s = Linklookup(Ctxt, name, Ctxt.Version)
+
+               switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
+               default:
+                       err = fmt.Errorf("unexpected flags for ELF section %s", sect.name)
+                       goto bad
+
+               case ElfSectFlagAlloc:
+                       s.Type = SRODATA
+
+               case ElfSectFlagAlloc + ElfSectFlagWrite:
+                       if sect.type_ == ElfSectNobits {
+                               s.Type = SNOPTRBSS
+                       } else {
+                               s.Type = SNOPTRDATA
+                       }
+
+               case ElfSectFlagAlloc + ElfSectFlagExec:
+                       s.Type = STEXT
+               }
+
+               if sect.name == ".got" || sect.name == ".toc" {
+                       s.Type = SELFGOT
+               }
+               if sect.type_ == ElfSectProgbits {
+                       s.P = sect.base
+                       s.P = s.P[:sect.size]
+               }
+
+               s.Size = int64(sect.size)
+               s.Align = int32(sect.align)
+               sect.sym = s
+       }
+
+       // enter sub-symbols into symbol table.
+       // symbol 0 is the null symbol.
+       symbols = make([]*LSym, elfobj.nsymtab)
+
+       if symbols == nil {
+               Diag("out of memory")
+               Errorexit()
+       }
+
+       for i = 1; i < elfobj.nsymtab; i++ {
+               if err = readelfsym(elfobj, i, &sym, 1); err != nil {
+                       goto bad
+               }
+               symbols[i] = sym.sym
+               if sym.type_ != ElfSymTypeFunc && sym.type_ != ElfSymTypeObject && sym.type_ != ElfSymTypeNone {
+                       continue
+               }
+               if sym.shndx == ElfSymShnCommon {
+                       s = sym.sym
+                       if uint64(s.Size) < sym.size {
+                               s.Size = int64(sym.size)
+                       }
+                       if s.Type == 0 || s.Type == SXREF {
+                               s.Type = SNOPTRBSS
+                       }
+                       continue
+               }
+
+               if uint(sym.shndx) >= elfobj.nsect || sym.shndx == 0 {
+                       continue
+               }
+
+               // even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols
+               if sym.sym == nil {
+                       continue
+               }
+               sect = &elfobj.sect[sym.shndx:][0]
+               if sect.sym == nil {
+                       if strings.HasPrefix(sym.name, ".Linfo_string") {
+                               continue
+                       }
+                       Diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type_)
+                       continue
+               }
+
+               s = sym.sym
+               if s.Outer != nil {
+                       if s.Dupok != 0 {
+                               continue
+                       }
+                       Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
+                       Errorexit()
+               }
+
+               s.Sub = sect.sym.Sub
+               sect.sym.Sub = s
+               s.Type = sect.sym.Type | s.Type&^SMASK | SSUB
+               if s.Cgoexport&CgoExportDynamic == 0 {
+                       s.Dynimplib = "" // satisfy dynimport
+               }
+               s.Value = int64(sym.value)
+               s.Size = int64(sym.size)
+               s.Outer = sect.sym
+               if sect.sym.Type == STEXT {
+                       if s.External != 0 && s.Dupok == 0 {
+                               Diag("%s: duplicate definition of %s", pn, s.Name)
+                       }
+                       s.External = 1
+               }
+
+               if elfobj.machine == ElfMachPower64 {
+                       flag = int(sym.other) >> 5
+                       if 2 <= flag && flag <= 6 {
+                               s.Localentry = 1 << uint(flag-2)
+                       } else if flag == 7 {
+                               Diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s.Name)
+                       }
+               }
+       }
+
+       // Sort outer lists by address, adding to textp.
+       // This keeps textp in increasing address order.
+       for i = 0; uint(i) < elfobj.nsect; i++ {
+               s = elfobj.sect[i].sym
+               if s == nil {
+                       continue
+               }
+               if s.Sub != nil {
+                       s.Sub = listsort(s.Sub, valuecmp, listsubp)
+               }
+               if s.Type == STEXT {
+                       if s.Onlist != 0 {
+                               log.Fatalf("symbol %s listed multiple times", s.Name)
+                       }
+                       s.Onlist = 1
+                       if Ctxt.Etextp != nil {
+                               Ctxt.Etextp.Next = s
+                       } else {
+                               Ctxt.Textp = s
+                       }
+                       Ctxt.Etextp = s
+                       for s = s.Sub; s != nil; s = s.Sub {
+                               if s.Onlist != 0 {
+                                       log.Fatalf("symbol %s listed multiple times", s.Name)
+                               }
+                               s.Onlist = 1
+                               Ctxt.Etextp.Next = s
+                               Ctxt.Etextp = s
+                       }
+               }
+       }
+
+       // load relocations
+       for i = 0; uint(i) < elfobj.nsect; i++ {
+               rsect = &elfobj.sect[i]
+               if rsect.type_ != ElfSectRela && rsect.type_ != ElfSectRel {
+                       continue
+               }
+               if rsect.info >= uint32(elfobj.nsect) || elfobj.sect[rsect.info].base == nil {
+                       continue
+               }
+               sect = &elfobj.sect[rsect.info]
+               if err = elfmap(elfobj, rsect); err != nil {
+                       goto bad
+               }
+               rela = 0
+               if rsect.type_ == ElfSectRela {
+                       rela = 1
+               }
+               n = int(rsect.size / uint64(4+4*is64) / uint64(2+rela))
+               r = make([]Reloc, n)
+               p = rsect.base
+               for j = 0; j < n; j++ {
+                       add = 0
+                       rp = &r[j]
+                       if is64 != 0 {
+                               // 64-bit rel/rela
+                               rp.Off = int32(e.Uint64(p))
+
+                               p = p[8:]
+                               info = e.Uint64(p)
+                               p = p[8:]
+                               if rela != 0 {
+                                       add = e.Uint64(p)
+                                       p = p[8:]
+                               }
+                       } else {
+                               // 32-bit rel/rela
+                               rp.Off = int32(e.Uint32(p))
+
+                               p = p[4:]
+                               info = uint64(e.Uint32(p))
+                               info = info>>8<<32 | info&0xff // convert to 64-bit info
+                               p = p[4:]
+                               if rela != 0 {
+                                       add = uint64(e.Uint32(p))
+                                       p = p[4:]
+                               }
+                       }
+
+                       if info&0xffffffff == 0 { // skip R_*_NONE relocation
+                               j--
+                               n--
+                               continue
+                       }
+
+                       if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol
+                               rp.Sym = nil
+                       } else {
+                               if err = readelfsym(elfobj, int(info>>32), &sym, 0); err != nil {
+                                       goto bad
+                               }
+                               sym.sym = symbols[info>>32]
+                               if sym.sym == nil {
+                                       err = fmt.Errorf("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), sym.name, sym.shndx, sym.type_)
+                                       goto bad
+                               }
+
+                               rp.Sym = sym.sym
+                       }
+
+                       rp.Type = int32(reltype(pn, int(uint32(info)), &rp.Siz))
+                       if rela != 0 {
+                               rp.Add = int64(add)
+                       } else {
+                               // load addend from image
+                               if rp.Siz == 4 {
+                                       rp.Add = int64(e.Uint32(sect.base[rp.Off:]))
+                               } else if rp.Siz == 8 {
+                                       rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
+                               } else {
+                                       Diag("invalid rela size %d", rp.Siz)
+                               }
+                       }
+
+                       if rp.Siz == 2 {
+                               rp.Add = int64(int16(rp.Add))
+                       }
+                       if rp.Siz == 4 {
+                               rp.Add = int64(int32(rp.Add))
+                       }
+               }
+
+               //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
+               sort.Sort(rbyoff(r[:n]))
+               // just in case
+
+               s = sect.sym
+               s.R = r
+               s.R = s.R[:n]
+       }
+
+       return
+
+bad:
+       Diag("%s: malformed elf file: %v", pn, err)
+}
+
+func section(elfobj *ElfObj, name string) *ElfSect {
+       var i int
+
+       for i = 0; uint(i) < elfobj.nsect; i++ {
+               if elfobj.sect[i].name != "" && name != "" && elfobj.sect[i].name == name {
+                       return &elfobj.sect[i]
+               }
+       }
+       return nil
+}
+
+func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
+       if sect.base != nil {
+               return nil
+       }
+
+       if sect.off+sect.size > uint64(elfobj.length) {
+               err = fmt.Errorf("elf section past end of file")
+               return err
+       }
+
+       sect.base = make([]byte, sect.size)
+       err = fmt.Errorf("short read")
+       if Bseek(elfobj.f, int64(uint64(elfobj.base)+sect.off), 0) < 0 || Bread(elfobj.f, sect.base) != len(sect.base) {
+               return err
+       }
+
+       return nil
+}
+
+func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
+       var s *LSym
+
+       if i >= elfobj.nsymtab || i < 0 {
+               err = fmt.Errorf("invalid elf symbol index")
+               return err
+       }
+
+       if i == 0 {
+               Diag("readym: read null symbol!")
+       }
+
+       if elfobj.is64 != 0 {
+               b := new(ElfSymBytes64)
+               binary.Read(bytes.NewReader(elfobj.symtab.base[i*ELF64SYMSIZE:(i+1)*ELF64SYMSIZE]), elfobj.e, b)
+               sym.name = cstring(elfobj.symstr.base[elfobj.e.Uint32(b.Name[:]):])
+               sym.value = elfobj.e.Uint64(b.Value[:])
+               sym.size = elfobj.e.Uint64(b.Size[:])
+               sym.shndx = elfobj.e.Uint16(b.Shndx[:])
+               sym.bind = b.Info >> 4
+               sym.type_ = b.Info & 0xf
+               sym.other = b.Other
+       } else {
+               b := new(ElfSymBytes)
+               binary.Read(bytes.NewReader(elfobj.symtab.base[i*ELF32SYMSIZE:(i+1)*ELF32SYMSIZE]), elfobj.e, b)
+               sym.name = cstring(elfobj.symstr.base[elfobj.e.Uint32(b.Name[:]):])
+               sym.value = uint64(elfobj.e.Uint32(b.Value[:]))
+               sym.size = uint64(elfobj.e.Uint32(b.Size[:]))
+               sym.shndx = elfobj.e.Uint16(b.Shndx[:])
+               sym.bind = b.Info >> 4
+               sym.type_ = b.Info & 0xf
+               sym.other = b.Other
+       }
+
+       s = nil
+       if sym.name == "_GLOBAL_OFFSET_TABLE_" {
+               sym.name = ".got"
+       }
+       if sym.name == ".TOC." {
+               // Magic symbol on ppc64.  Will be set to this object
+               // file's .got+0x8000.
+               sym.bind = ElfSymBindLocal
+       }
+
+       switch sym.type_ {
+       case ElfSymTypeSection:
+               s = elfobj.sect[sym.shndx].sym
+
+       case ElfSymTypeObject,
+               ElfSymTypeFunc,
+               ElfSymTypeNone:
+               switch sym.bind {
+               case ElfSymBindGlobal:
+                       if needSym != 0 {
+                               s = Linklookup(Ctxt, sym.name, 0)
+
+                               // for global scoped hidden symbols we should insert it into
+                               // symbol hash table, but mark them as hidden.
+                               // __i686.get_pc_thunk.bx is allowed to be duplicated, to
+                               // workaround that we set dupok.
+                               // TODO(minux): correctly handle __i686.get_pc_thunk.bx without
+                               // set dupok generally. See http://codereview.appspot.com/5823055/
+                               // comment #5 for details.
+                               if s != nil && sym.other == 2 {
+                                       s.Type |= SHIDDEN
+                                       s.Dupok = 1
+                               }
+                       }
+
+               case ElfSymBindLocal:
+                       if Thearch.Thechar == '5' && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) {
+                               // binutils for arm generate these elfmapping
+                               // symbols, ignore these
+                               break
+                       }
+
+                       if sym.name == ".TOC." {
+                               // We need to be able to look this up,
+                               // so put it in the hash table.
+                               if needSym != 0 {
+                                       s = Linklookup(Ctxt, sym.name, Ctxt.Version)
+                                       s.Type |= SHIDDEN
+                               }
+
+                               break
+                       }
+
+                       if needSym != 0 {
+                               // local names and hidden visiblity global names are unique
+                               // and should only reference by its index, not name, so we
+                               // don't bother to add them into hash table
+                               s = linknewsym(Ctxt, sym.name, Ctxt.Version)
+
+                               s.Type |= SHIDDEN
+                       }
+
+               case ElfSymBindWeak:
+                       if needSym != 0 {
+                               s = linknewsym(Ctxt, sym.name, 0)
+                               if sym.other == 2 {
+                                       s.Type |= SHIDDEN
+                               }
+                       }
+
+               default:
+                       err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.bind)
+                       return err
+               }
+       }
+
+       if s != nil && s.Type == 0 && sym.type_ != ElfSymTypeSection {
+               s.Type = SXREF
+       }
+       sym.sym = s
+
+       return nil
+}
+
+type rbyoff []Reloc
+
+func (x rbyoff) Len() int {
+       return len(x)
+}
+
+func (x rbyoff) Swap(i, j int) {
+       x[i], x[j] = x[j], x[i]
+}
+
+func (x rbyoff) Less(i, j int) bool {
+       var a *Reloc
+       var b *Reloc
+
+       a = &x[i]
+       b = &x[j]
+       if a.Off < b.Off {
+               return true
+       }
+       if a.Off > b.Off {
+               return false
+       }
+       return false
+}
+
+func reltype(pn string, elftype int, siz *uint8) int {
+       switch uint32(Thearch.Thechar) | uint32(elftype)<<24 {
+       default:
+               Diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
+               fallthrough
+
+       case '9' | R_PPC64_TOC16<<24,
+               '9' | R_PPC64_TOC16_LO<<24,
+               '9' | R_PPC64_TOC16_HI<<24,
+               '9' | R_PPC64_TOC16_HA<<24,
+               '9' | R_PPC64_TOC16_DS<<24,
+               '9' | R_PPC64_TOC16_LO_DS<<24,
+               '9' | R_PPC64_REL16_LO<<24,
+               '9' | R_PPC64_REL16_HI<<24,
+               '9' | R_PPC64_REL16_HA<<24:
+               *siz = 2
+
+       case '5' | R_ARM_ABS32<<24,
+               '5' | R_ARM_GOT32<<24,
+               '5' | R_ARM_PLT32<<24,
+               '5' | R_ARM_GOTOFF<<24,
+               '5' | R_ARM_GOTPC<<24,
+               '5' | R_ARM_THM_PC22<<24,
+               '5' | R_ARM_REL32<<24,
+               '5' | R_ARM_CALL<<24,
+               '5' | R_ARM_V4BX<<24,
+               '5' | R_ARM_GOT_PREL<<24,
+               '5' | R_ARM_PC24<<24,
+               '5' | R_ARM_JUMP24<<24,
+               '6' | R_X86_64_PC32<<24,
+               '6' | R_X86_64_PLT32<<24,
+               '6' | R_X86_64_GOTPCREL<<24,
+               '8' | R_386_32<<24,
+               '8' | R_386_PC32<<24,
+               '8' | R_386_GOT32<<24,
+               '8' | R_386_PLT32<<24,
+               '8' | R_386_GOTOFF<<24,
+               '8' | R_386_GOTPC<<24,
+               '9' | R_PPC64_REL24<<24:
+               *siz = 4
+
+       case '6' | R_X86_64_64<<24,
+               '9' | R_PPC64_ADDR64<<24:
+               *siz = 8
+       }
+
+       return 256 + elftype
+}
diff --git a/src/cmd/internal/ld/ldmacho.go b/src/cmd/internal/ld/ldmacho.go
new file mode 100644 (file)
index 0000000..e762318
--- /dev/null
@@ -0,0 +1,919 @@
+package ld
+
+import (
+       "encoding/binary"
+       "fmt"
+       "log"
+       "sort"
+)
+
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+       Copyright © 2004 Russ Cox.
+       Portions Copyright © 2008-2010 Google Inc.
+       Portions Copyright © 2010 The Go Authors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+const (
+       N_EXT  = 0x01
+       N_TYPE = 0x1e
+       N_STAB = 0xe0
+)
+
+type LdMachoObj struct {
+       f          *Biobuf
+       base       int64
+       length     int64
+       is64       bool
+       name       string
+       e          binary.ByteOrder
+       cputype    uint
+       subcputype uint
+       filetype   uint32
+       flags      uint32
+       cmd        []LdMachoCmd
+       ncmd       uint
+}
+
+type LdMachoCmd struct {
+       type_ int
+       off   uint32
+       size  uint32
+       seg   LdMachoSeg
+       sym   LdMachoSymtab
+       dsym  LdMachoDysymtab
+}
+
+type LdMachoSeg struct {
+       name     string
+       vmaddr   uint64
+       vmsize   uint64
+       fileoff  uint32
+       filesz   uint32
+       maxprot  uint32
+       initprot uint32
+       nsect    uint32
+       flags    uint32
+       sect     []LdMachoSect
+}
+
+type LdMachoSect struct {
+       name    string
+       segname string
+       addr    uint64
+       size    uint64
+       off     uint32
+       align   uint32
+       reloff  uint32
+       nreloc  uint32
+       flags   uint32
+       res1    uint32
+       res2    uint32
+       sym     *LSym
+       rel     []LdMachoRel
+}
+
+type LdMachoRel struct {
+       addr      uint32
+       symnum    uint32
+       pcrel     uint8
+       length    uint8
+       extrn     uint8
+       type_     uint8
+       scattered uint8
+       value     uint32
+}
+
+type LdMachoSymtab struct {
+       symoff  uint32
+       nsym    uint32
+       stroff  uint32
+       strsize uint32
+       str     []byte
+       sym     []LdMachoSym
+}
+
+type LdMachoSym struct {
+       name    string
+       type_   uint8
+       sectnum uint8
+       desc    uint16
+       kind    int8
+       value   uint64
+       sym     *LSym
+}
+
+type LdMachoDysymtab struct {
+       ilocalsym      uint32
+       nlocalsym      uint32
+       iextdefsym     uint32
+       nextdefsym     uint32
+       iundefsym      uint32
+       nundefsym      uint32
+       tocoff         uint32
+       ntoc           uint32
+       modtaboff      uint32
+       nmodtab        uint32
+       extrefsymoff   uint32
+       nextrefsyms    uint32
+       indirectsymoff uint32
+       nindirectsyms  uint32
+       extreloff      uint32
+       nextrel        uint32
+       locreloff      uint32
+       nlocrel        uint32
+       indir          []uint32
+}
+
+const (
+       LdMachoCpuVax         = 1
+       LdMachoCpu68000       = 6
+       LdMachoCpu386         = 7
+       LdMachoCpuAmd64       = 0x1000007
+       LdMachoCpuMips        = 8
+       LdMachoCpu98000       = 10
+       LdMachoCpuHppa        = 11
+       LdMachoCpuArm         = 12
+       LdMachoCpu88000       = 13
+       LdMachoCpuSparc       = 14
+       LdMachoCpu860         = 15
+       LdMachoCpuAlpha       = 16
+       LdMachoCpuPower       = 18
+       LdMachoCmdSegment     = 1
+       LdMachoCmdSymtab      = 2
+       LdMachoCmdSymseg      = 3
+       LdMachoCmdThread      = 4
+       LdMachoCmdDysymtab    = 11
+       LdMachoCmdSegment64   = 25
+       LdMachoFileObject     = 1
+       LdMachoFileExecutable = 2
+       LdMachoFileFvmlib     = 3
+       LdMachoFileCore       = 4
+       LdMachoFilePreload    = 5
+)
+
+func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int {
+       var e4 func([]byte) uint32
+       var e8 func([]byte) uint64
+       var s *LdMachoSect
+       var i int
+
+       e4 = m.e.Uint32
+       e8 = m.e.Uint64
+
+       c.type_ = int(type_)
+       c.size = uint32(sz)
+       switch type_ {
+       default:
+               return -1
+
+       case LdMachoCmdSegment:
+               if sz < 56 {
+                       return -1
+               }
+               c.seg.name = cstring(p[8:24])
+               c.seg.vmaddr = uint64(e4(p[24:]))
+               c.seg.vmsize = uint64(e4(p[28:]))
+               c.seg.fileoff = e4(p[32:])
+               c.seg.filesz = e4(p[36:])
+               c.seg.maxprot = e4(p[40:])
+               c.seg.initprot = e4(p[44:])
+               c.seg.nsect = e4(p[48:])
+               c.seg.flags = e4(p[52:])
+               c.seg.sect = make([]LdMachoSect, c.seg.nsect)
+               if uint32(sz) < 56+c.seg.nsect*68 {
+                       return -1
+               }
+               p = p[56:]
+               for i = 0; uint32(i) < c.seg.nsect; i++ {
+                       s = &c.seg.sect[i]
+                       s.name = cstring(p[0:16])
+                       s.segname = cstring(p[16:32])
+                       s.addr = uint64(e4(p[32:]))
+                       s.size = uint64(e4(p[36:]))
+                       s.off = e4(p[40:])
+                       s.align = e4(p[44:])
+                       s.reloff = e4(p[48:])
+                       s.nreloc = e4(p[52:])
+                       s.flags = e4(p[56:])
+                       s.res1 = e4(p[60:])
+                       s.res2 = e4(p[64:])
+                       p = p[68:]
+               }
+
+       case LdMachoCmdSegment64:
+               if sz < 72 {
+                       return -1
+               }
+               c.seg.name = cstring(p[8:24])
+               c.seg.vmaddr = e8(p[24:])
+               c.seg.vmsize = e8(p[32:])
+               c.seg.fileoff = uint32(e8(p[40:]))
+               c.seg.filesz = uint32(e8(p[48:]))
+               c.seg.maxprot = e4(p[56:])
+               c.seg.initprot = e4(p[60:])
+               c.seg.nsect = e4(p[64:])
+               c.seg.flags = e4(p[68:])
+               c.seg.sect = make([]LdMachoSect, c.seg.nsect)
+               if uint32(sz) < 72+c.seg.nsect*80 {
+                       return -1
+               }
+               p = p[72:]
+               for i = 0; uint32(i) < c.seg.nsect; i++ {
+                       s = &c.seg.sect[i]
+                       s.name = cstring(p[0:16])
+                       s.segname = cstring(p[16:32])
+                       s.addr = e8(p[32:])
+                       s.size = e8(p[40:])
+                       s.off = e4(p[48:])
+                       s.align = e4(p[52:])
+                       s.reloff = e4(p[56:])
+                       s.nreloc = e4(p[60:])
+                       s.flags = e4(p[64:])
+                       s.res1 = e4(p[68:])
+                       s.res2 = e4(p[72:])
+
+                       // p+76 is reserved
+                       p = p[80:]
+               }
+
+       case LdMachoCmdSymtab:
+               if sz < 24 {
+                       return -1
+               }
+               c.sym.symoff = e4(p[8:])
+               c.sym.nsym = e4(p[12:])
+               c.sym.stroff = e4(p[16:])
+               c.sym.strsize = e4(p[20:])
+
+       case LdMachoCmdDysymtab:
+               if sz < 80 {
+                       return -1
+               }
+               c.dsym.ilocalsym = e4(p[8:])
+               c.dsym.nlocalsym = e4(p[12:])
+               c.dsym.iextdefsym = e4(p[16:])
+               c.dsym.nextdefsym = e4(p[20:])
+               c.dsym.iundefsym = e4(p[24:])
+               c.dsym.nundefsym = e4(p[28:])
+               c.dsym.tocoff = e4(p[32:])
+               c.dsym.ntoc = e4(p[36:])
+               c.dsym.modtaboff = e4(p[40:])
+               c.dsym.nmodtab = e4(p[44:])
+               c.dsym.extrefsymoff = e4(p[48:])
+               c.dsym.nextrefsyms = e4(p[52:])
+               c.dsym.indirectsymoff = e4(p[56:])
+               c.dsym.nindirectsyms = e4(p[60:])
+               c.dsym.extreloff = e4(p[64:])
+               c.dsym.nextrel = e4(p[68:])
+               c.dsym.locreloff = e4(p[72:])
+               c.dsym.nlocrel = e4(p[76:])
+       }
+
+       return 0
+}
+
+func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
+       var rel []LdMachoRel
+       var r *LdMachoRel
+       var buf []byte
+       var p []byte
+       var i int
+       var n int
+       var v uint32
+
+       if sect.rel != nil || sect.nreloc == 0 {
+               return 0
+       }
+       rel = make([]LdMachoRel, sect.nreloc)
+       n = int(sect.nreloc * 8)
+       buf = make([]byte, n)
+       if Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || Bread(m.f, buf) != n {
+               return -1
+       }
+       for i = 0; uint32(i) < sect.nreloc; i++ {
+               r = &rel[i]
+               p = buf[i*8:]
+               r.addr = m.e.Uint32(p)
+
+               // TODO(rsc): Wrong interpretation for big-endian bitfields?
+               if r.addr&0x80000000 != 0 {
+                       // scatterbrained relocation
+                       r.scattered = 1
+
+                       v = r.addr >> 24
+                       r.addr &= 0xFFFFFF
+                       r.type_ = uint8(v & 0xF)
+                       v >>= 4
+                       r.length = 1 << (v & 3)
+                       v >>= 2
+                       r.pcrel = uint8(v & 1)
+                       r.value = m.e.Uint32(p[4:])
+               } else {
+                       v = m.e.Uint32(p[4:])
+                       r.symnum = v & 0xFFFFFF
+                       v >>= 24
+                       r.pcrel = uint8(v & 1)
+                       v >>= 1
+                       r.length = 1 << (v & 3)
+                       v >>= 2
+                       r.extrn = uint8(v & 1)
+                       v >>= 1
+                       r.type_ = uint8(v)
+               }
+       }
+
+       sect.rel = rel
+       return 0
+}
+
+func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int {
+       var p []byte
+       var i int
+       var n int
+
+       n = int(d.nindirectsyms)
+
+       p = make([]byte, n*4)
+       if Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || Bread(m.f, p) != len(p) {
+               return -1
+       }
+
+       d.indir = make([]uint32, n)
+       for i = 0; i < n; i++ {
+               d.indir[i] = m.e.Uint32(p[4*i:])
+       }
+       return 0
+}
+
+func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
+       var strbuf []byte
+       var symbuf []byte
+       var p []byte
+       var i int
+       var n int
+       var symsize int
+       var sym []LdMachoSym
+       var s *LdMachoSym
+       var v uint32
+
+       if symtab.sym != nil {
+               return 0
+       }
+
+       strbuf = make([]byte, symtab.strsize)
+       if Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || Bread(m.f, strbuf) != len(strbuf) {
+               return -1
+       }
+
+       symsize = 12
+       if m.is64 {
+               symsize = 16
+       }
+       n = int(symtab.nsym * uint32(symsize))
+       symbuf = make([]byte, n)
+       if Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || Bread(m.f, symbuf) != len(symbuf) {
+               return -1
+       }
+       sym = make([]LdMachoSym, symtab.nsym)
+       p = symbuf
+       for i = 0; uint32(i) < symtab.nsym; i++ {
+               s = &sym[i]
+               v = m.e.Uint32(p)
+               if v >= symtab.strsize {
+                       return -1
+               }
+               s.name = cstring(strbuf[v:])
+               s.type_ = uint8(p[4])
+               s.sectnum = uint8(p[5])
+               s.desc = m.e.Uint16(p[6:])
+               if m.is64 {
+                       s.value = m.e.Uint64(p[8:])
+               } else {
+                       s.value = uint64(m.e.Uint32(p[8:]))
+               }
+               p = p[symsize:]
+       }
+
+       symtab.str = strbuf
+       symtab.sym = sym
+       return 0
+}
+
+func ldmacho(f *Biobuf, pkg string, length int64, pn string) {
+       var err error
+       var i int
+       var j int
+       var is64 bool
+       var secaddr uint64
+       var hdr [7 * 4]uint8
+       var cmdp []byte
+       var tmp [4]uint8
+       var dat []byte
+       var ncmd uint32
+       var cmdsz uint32
+       var ty uint32
+       var sz uint32
+       var off uint32
+       var m *LdMachoObj
+       var e binary.ByteOrder
+       var base int64
+       var sect *LdMachoSect
+       var rel *LdMachoRel
+       var rpi int
+       var s *LSym
+       var s1 *LSym
+       var outer *LSym
+       var c *LdMachoCmd
+       var symtab *LdMachoSymtab
+       var dsymtab *LdMachoDysymtab
+       var sym *LdMachoSym
+       var r []Reloc
+       var rp *Reloc
+       var name string
+
+       Ctxt.Version++
+       base = Boffset(f)
+       if Bread(f, hdr[:]) != len(hdr) {
+               goto bad
+       }
+
+       if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
+               e = binary.BigEndian
+       } else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
+               e = binary.LittleEndian
+       } else {
+               err = fmt.Errorf("bad magic - not mach-o file")
+               goto bad
+       }
+
+       is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
+       ncmd = e.Uint32([]byte(hdr[4*4:]))
+       cmdsz = e.Uint32([]byte(hdr[5*4:]))
+       if ncmd > 0x10000 || cmdsz >= 0x01000000 {
+               err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
+               goto bad
+       }
+
+       if is64 {
+               Bread(f, tmp[:4]) // skip reserved word in header
+       }
+
+       m = new(LdMachoObj)
+
+       m.f = f
+       m.e = e
+       m.cputype = uint(e.Uint32([]byte(hdr[1*4:])))
+       m.subcputype = uint(e.Uint32([]byte(hdr[2*4:])))
+       m.filetype = e.Uint32([]byte(hdr[3*4:]))
+       m.ncmd = uint(ncmd)
+       m.flags = e.Uint32([]byte(hdr[6*4:]))
+       m.is64 = is64
+       m.base = base
+       m.length = length
+       m.name = pn
+
+       switch Thearch.Thechar {
+       default:
+               Diag("%s: mach-o %s unimplemented", pn, Thestring)
+               return
+
+       case '6':
+               if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
+                       Diag("%s: mach-o object but not amd64", pn)
+                       return
+               }
+
+       case '8':
+               if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
+                       Diag("%s: mach-o object but not 386", pn)
+                       return
+               }
+       }
+
+       m.cmd = make([]LdMachoCmd, ncmd)
+       off = uint32(len(hdr))
+       cmdp = make([]byte, cmdsz)
+       if Bread(f, cmdp) != len(cmdp) {
+               err = fmt.Errorf("reading cmds: %v", err)
+               goto bad
+       }
+
+       // read and parse load commands
+       c = nil
+
+       symtab = nil
+       dsymtab = nil
+
+       for i = 0; uint32(i) < ncmd; i++ {
+               ty = e.Uint32(cmdp)
+               sz = e.Uint32(cmdp[4:])
+               m.cmd[i].off = off
+               unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz))
+               cmdp = cmdp[sz:]
+               off += sz
+               if ty == LdMachoCmdSymtab {
+                       if symtab != nil {
+                               err = fmt.Errorf("multiple symbol tables")
+                               goto bad
+                       }
+
+                       symtab = &m.cmd[i].sym
+                       macholoadsym(m, symtab)
+               }
+
+               if ty == LdMachoCmdDysymtab {
+                       dsymtab = &m.cmd[i].dsym
+                       macholoaddsym(m, dsymtab)
+               }
+
+               if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
+                       if c != nil {
+                               err = fmt.Errorf("multiple load commands")
+                               goto bad
+                       }
+
+                       c = &m.cmd[i]
+               }
+       }
+
+       // load text and data segments into memory.
+       // they are not as small as the load commands, but we'll need
+       // the memory anyway for the symbol images, so we might
+       // as well use one large chunk.
+       if c == nil {
+               err = fmt.Errorf("no load command")
+               goto bad
+       }
+
+       if symtab == nil {
+               // our work is done here - no symbols means nothing can refer to this file
+               return
+       }
+
+       if int64(c.seg.fileoff+c.seg.filesz) >= length {
+               err = fmt.Errorf("load segment out of range")
+               goto bad
+       }
+
+       dat = make([]byte, c.seg.filesz)
+       if Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || Bread(f, dat) != len(dat) {
+               err = fmt.Errorf("cannot load object data: %v", err)
+               goto bad
+       }
+
+       for i = 0; uint32(i) < c.seg.nsect; i++ {
+               sect = &c.seg.sect[i]
+               if sect.segname != "__TEXT" && sect.segname != "__DATA" {
+                       continue
+               }
+               if sect.name == "__eh_frame" {
+                       continue
+               }
+               name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
+               s = Linklookup(Ctxt, name, Ctxt.Version)
+               if s.Type != 0 {
+                       err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name)
+                       goto bad
+               }
+
+               if sect.flags&0xff == 1 { // S_ZEROFILL
+                       s.P = make([]byte, sect.size)
+               } else {
+                       s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size]
+               }
+               s.Size = int64(len(s.P))
+
+               if sect.segname == "__TEXT" {
+                       if sect.name == "__text" {
+                               s.Type = STEXT
+                       } else {
+                               s.Type = SRODATA
+                       }
+               } else {
+                       if sect.name == "__bss" {
+                               s.Type = SNOPTRBSS
+                               s.P = s.P[:0]
+                       } else {
+                               s.Type = SNOPTRDATA
+                       }
+               }
+
+               sect.sym = s
+       }
+
+       // enter sub-symbols into symbol table.
+       // have to guess sizes from next symbol.
+       for i = 0; uint32(i) < symtab.nsym; i++ {
+               var v int
+               sym = &symtab.sym[i]
+               if sym.type_&N_STAB != 0 {
+                       continue
+               }
+
+               // TODO: check sym->type against outer->type.
+               name = sym.name
+
+               if name[0] == '_' && name[1] != '\x00' {
+                       name = name[1:]
+               }
+               v = 0
+               if sym.type_&N_EXT == 0 {
+                       v = Ctxt.Version
+               }
+               s = Linklookup(Ctxt, name, v)
+               if sym.type_&N_EXT == 0 {
+                       s.Dupok = 1
+               }
+               sym.sym = s
+               if sym.sectnum == 0 { // undefined
+                       continue
+               }
+               if uint32(sym.sectnum) > c.seg.nsect {
+                       err = fmt.Errorf("reference to invalid section %d", sym.sectnum)
+                       goto bad
+               }
+
+               sect = &c.seg.sect[sym.sectnum-1]
+               outer = sect.sym
+               if outer == nil {
+                       err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name)
+                       continue
+               }
+
+               if s.Outer != nil {
+                       if s.Dupok != 0 {
+                               continue
+                       }
+                       Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
+                       Errorexit()
+               }
+
+               s.Type = outer.Type | SSUB
+               s.Sub = outer.Sub
+               outer.Sub = s
+               s.Outer = outer
+               s.Value = int64(sym.value - sect.addr)
+               if s.Cgoexport&CgoExportDynamic == 0 {
+                       s.Dynimplib = "" // satisfy dynimport
+               }
+               if outer.Type == STEXT {
+                       if s.External != 0 && s.Dupok == 0 {
+                               Diag("%s: duplicate definition of %s", pn, s.Name)
+                       }
+                       s.External = 1
+               }
+
+               sym.sym = s
+       }
+
+       // Sort outer lists by address, adding to textp.
+       // This keeps textp in increasing address order.
+       for i = 0; uint32(i) < c.seg.nsect; i++ {
+               sect = &c.seg.sect[i]
+               s = sect.sym
+               if s == nil {
+                       continue
+               }
+               if s.Sub != nil {
+                       s.Sub = listsort(s.Sub, valuecmp, listsubp)
+
+                       // assign sizes, now that we know symbols in sorted order.
+                       for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
+                               if s1.Sub != nil {
+                                       s1.Size = s1.Sub.Value - s1.Value
+                               } else {
+                                       s1.Size = s.Value + s.Size - s1.Value
+                               }
+                       }
+               }
+
+               if s.Type == STEXT {
+                       if s.Onlist != 0 {
+                               log.Fatalf("symbol %s listed multiple times", s.Name)
+                       }
+                       s.Onlist = 1
+                       if Ctxt.Etextp != nil {
+                               Ctxt.Etextp.Next = s
+                       } else {
+                               Ctxt.Textp = s
+                       }
+                       Ctxt.Etextp = s
+                       for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
+                               if s1.Onlist != 0 {
+                                       log.Fatalf("symbol %s listed multiple times", s1.Name)
+                               }
+                               s1.Onlist = 1
+                               Ctxt.Etextp.Next = s1
+                               Ctxt.Etextp = s1
+                       }
+               }
+       }
+
+       // load relocations
+       for i = 0; uint32(i) < c.seg.nsect; i++ {
+               sect = &c.seg.sect[i]
+               s = sect.sym
+               if s == nil {
+                       continue
+               }
+               macholoadrel(m, sect)
+               if sect.rel == nil {
+                       continue
+               }
+               r = make([]Reloc, sect.nreloc)
+               rpi = 0
+               for j = 0; uint32(j) < sect.nreloc; j++ {
+                       rp = &r[rpi]
+                       rel = &sect.rel[j]
+                       if rel.scattered != 0 {
+                               var k int
+                               var ks *LdMachoSect
+
+                               if Thearch.Thechar != '8' {
+                                       // mach-o only uses scattered relocation on 32-bit platforms
+                                       Diag("unexpected scattered relocation")
+
+                                       continue
+                               }
+
+                               // on 386, rewrite scattered 4/1 relocation and some
+                               // scattered 2/1 relocation into the pseudo-pc-relative
+                               // reference that it is.
+                               // assume that the second in the pair is in this section
+                               // and use that as the pc-relative base.
+                               if uint32(j+1) >= sect.nreloc {
+                                       err = fmt.Errorf("unsupported scattered relocation %d", int(rel.type_))
+                                       goto bad
+                               }
+
+                               if sect.rel[j+1].scattered == 0 || sect.rel[j+1].type_ != 1 || (rel.type_ != 4 && rel.type_ != 2) || uint64(sect.rel[j+1].value) < sect.addr || uint64(sect.rel[j+1].value) >= sect.addr+sect.size {
+                                       err = fmt.Errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_))
+                                       goto bad
+                               }
+
+                               rp.Siz = rel.length
+                               rp.Off = int32(rel.addr)
+
+                               // NOTE(rsc): I haven't worked out why (really when)
+                               // we should ignore the addend on a
+                               // scattered relocation, but it seems that the
+                               // common case is we ignore it.
+                               // It's likely that this is not strictly correct
+                               // and that the math should look something
+                               // like the non-scattered case below.
+                               rp.Add = 0
+
+                               // want to make it pc-relative aka relative to rp->off+4
+                               // but the scatter asks for relative to off = sect->rel[j+1].value - sect->addr.
+                               // adjust rp->add accordingly.
+                               rp.Type = R_PCREL
+
+                               rp.Add += int64(uint64(int64(rp.Off)+4) - (uint64(sect.rel[j+1].value) - sect.addr))
+
+                               // now consider the desired symbol.
+                               // find the section where it lives.
+                               for k = 0; uint32(k) < c.seg.nsect; k++ {
+                                       ks = &c.seg.sect[k]
+                                       if ks.addr <= uint64(rel.value) && uint64(rel.value) < ks.addr+ks.size {
+                                               goto foundk
+                                       }
+                               }
+
+                               err = fmt.Errorf("unsupported scattered relocation: invalid address %#x", rel.addr)
+                               goto bad
+
+                       foundk:
+                               if ks.sym != nil {
+                                       rp.Sym = ks.sym
+                                       rp.Add += int64(uint64(rel.value) - ks.addr)
+                               } else if ks.segname == "__IMPORT" && ks.name == "__pointers" {
+                                       // handle reference to __IMPORT/__pointers.
+                                       // how much worse can this get?
+                                       // why are we supporting 386 on the mac anyway?
+                                       rp.Type = 512 + MACHO_FAKE_GOTPCREL
+
+                                       // figure out which pointer this is a reference to.
+                                       k = int(uint64(ks.res1) + (uint64(rel.value)-ks.addr)/4)
+
+                                       // load indirect table for __pointers
+                                       // fetch symbol number
+                                       if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil {
+                                               err = fmt.Errorf("invalid scattered relocation: indirect symbol reference out of range")
+                                               goto bad
+                                       }
+
+                                       k = int(dsymtab.indir[k])
+                                       if k < 0 || uint32(k) >= symtab.nsym {
+                                               err = fmt.Errorf("invalid scattered relocation: symbol reference out of range")
+                                               goto bad
+                                       }
+
+                                       rp.Sym = symtab.sym[k].sym
+                               } else {
+                                       err = fmt.Errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
+                                       goto bad
+                               }
+
+                               rpi++
+
+                               // skip #1 of 2 rel; continue skips #2 of 2.
+                               j++
+
+                               continue
+                       }
+
+                       rp.Siz = rel.length
+                       rp.Type = 512 + (int32(rel.type_) << 1) + int32(rel.pcrel)
+                       rp.Off = int32(rel.addr)
+
+                       // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
+                       if Thearch.Thechar == '6' && rel.extrn == 0 && rel.type_ == 1 {
+                               // Calculate the addend as the offset into the section.
+                               //
+                               // The rip-relative offset stored in the object file is encoded
+                               // as follows:
+                               //
+                               //    movsd     0x00000360(%rip),%xmm0
+                               //
+                               // To get the absolute address of the value this rip-relative address is pointing
+                               // to, we must add the address of the next instruction to it. This is done by
+                               // taking the address of the relocation and adding 4 to it (since the rip-relative
+                               // offset can at most be 32 bits long).  To calculate the offset into the section the
+                               // relocation is referencing, we subtract the vaddr of the start of the referenced
+                               // section found in the original object file.
+                               //
+                               // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
+                               secaddr = c.seg.sect[rel.symnum-1].addr
+
+                               rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr)
+                       } else {
+                               rp.Add = int64(int32(e.Uint32(s.P[rp.Off:])))
+                       }
+
+                       // For i386 Mach-O PC-relative, the addend is written such that
+                       // it *is* the PC being subtracted.  Use that to make
+                       // it match our version of PC-relative.
+                       if rel.pcrel != 0 && Thearch.Thechar == '8' {
+                               rp.Add += int64(rp.Off) + int64(rp.Siz)
+                       }
+                       if rel.extrn == 0 {
+                               if rel.symnum < 1 || rel.symnum > c.seg.nsect {
+                                       err = fmt.Errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
+                                       goto bad
+                               }
+
+                               rp.Sym = c.seg.sect[rel.symnum-1].sym
+                               if rp.Sym == nil {
+                                       err = fmt.Errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
+                                       goto bad
+                               }
+
+                               // References to symbols in other sections
+                               // include that information in the addend.
+                               // We only care about the delta from the
+                               // section base.
+                               if Thearch.Thechar == '8' {
+                                       rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
+                               }
+                       } else {
+                               if rel.symnum >= symtab.nsym {
+                                       err = fmt.Errorf("invalid relocation: symbol reference out of range")
+                                       goto bad
+                               }
+
+                               rp.Sym = symtab.sym[rel.symnum].sym
+                       }
+
+                       rpi++
+               }
+
+               sort.Sort(rbyoff(r[:rpi]))
+               s.R = r
+               s.R = s.R[:rpi]
+       }
+
+       return
+
+bad:
+       Diag("%s: malformed mach-o file: %v", pn, err)
+}
diff --git a/src/cmd/internal/ld/ldpe.go b/src/cmd/internal/ld/ldpe.go
new file mode 100644 (file)
index 0000000..247e829
--- /dev/null
@@ -0,0 +1,550 @@
+// Copyright 2010 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 ld
+
+import (
+       "cmd/internal/obj"
+       "encoding/binary"
+       "fmt"
+       "log"
+       "sort"
+       "strings"
+)
+
+const (
+       IMAGE_SYM_UNDEFINED              = 0
+       IMAGE_SYM_ABSOLUTE               = -1
+       IMAGE_SYM_DEBUG                  = -2
+       IMAGE_SYM_TYPE_NULL              = 0
+       IMAGE_SYM_TYPE_VOID              = 1
+       IMAGE_SYM_TYPE_CHAR              = 2
+       IMAGE_SYM_TYPE_SHORT             = 3
+       IMAGE_SYM_TYPE_INT               = 4
+       IMAGE_SYM_TYPE_LONG              = 5
+       IMAGE_SYM_TYPE_FLOAT             = 6
+       IMAGE_SYM_TYPE_DOUBLE            = 7
+       IMAGE_SYM_TYPE_STRUCT            = 8
+       IMAGE_SYM_TYPE_UNION             = 9
+       IMAGE_SYM_TYPE_ENUM              = 10
+       IMAGE_SYM_TYPE_MOE               = 11
+       IMAGE_SYM_TYPE_BYTE              = 12
+       IMAGE_SYM_TYPE_WORD              = 13
+       IMAGE_SYM_TYPE_UINT              = 14
+       IMAGE_SYM_TYPE_DWORD             = 15
+       IMAGE_SYM_TYPE_PCODE             = 32768
+       IMAGE_SYM_DTYPE_NULL             = 0
+       IMAGE_SYM_DTYPE_POINTER          = 0x10
+       IMAGE_SYM_DTYPE_FUNCTION         = 0x20
+       IMAGE_SYM_DTYPE_ARRAY            = 0x30
+       IMAGE_SYM_CLASS_END_OF_FUNCTION  = -1
+       IMAGE_SYM_CLASS_NULL             = 0
+       IMAGE_SYM_CLASS_AUTOMATIC        = 1
+       IMAGE_SYM_CLASS_EXTERNAL         = 2
+       IMAGE_SYM_CLASS_STATIC           = 3
+       IMAGE_SYM_CLASS_REGISTER         = 4
+       IMAGE_SYM_CLASS_EXTERNAL_DEF     = 5
+       IMAGE_SYM_CLASS_LABEL            = 6
+       IMAGE_SYM_CLASS_UNDEFINED_LABEL  = 7
+       IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8
+       IMAGE_SYM_CLASS_ARGUMENT         = 9
+       IMAGE_SYM_CLASS_STRUCT_TAG       = 10
+       IMAGE_SYM_CLASS_MEMBER_OF_UNION  = 11
+       IMAGE_SYM_CLASS_UNION_TAG        = 12
+       IMAGE_SYM_CLASS_TYPE_DEFINITION  = 13
+       IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14
+       IMAGE_SYM_CLASS_ENUM_TAG         = 15
+       IMAGE_SYM_CLASS_MEMBER_OF_ENUM   = 16
+       IMAGE_SYM_CLASS_REGISTER_PARAM   = 17
+       IMAGE_SYM_CLASS_BIT_FIELD        = 18
+       IMAGE_SYM_CLASS_FAR_EXTERNAL     = 68
+       IMAGE_SYM_CLASS_BLOCK            = 100
+       IMAGE_SYM_CLASS_FUNCTION         = 101
+       IMAGE_SYM_CLASS_END_OF_STRUCT    = 102
+       IMAGE_SYM_CLASS_FILE             = 103
+       IMAGE_SYM_CLASS_SECTION          = 104
+       IMAGE_SYM_CLASS_WEAK_EXTERNAL    = 105
+       IMAGE_SYM_CLASS_CLR_TOKEN        = 107
+       IMAGE_REL_I386_ABSOLUTE          = 0x0000
+       IMAGE_REL_I386_DIR16             = 0x0001
+       IMAGE_REL_I386_REL16             = 0x0002
+       IMAGE_REL_I386_DIR32             = 0x0006
+       IMAGE_REL_I386_DIR32NB           = 0x0007
+       IMAGE_REL_I386_SEG12             = 0x0009
+       IMAGE_REL_I386_SECTION           = 0x000A
+       IMAGE_REL_I386_SECREL            = 0x000B
+       IMAGE_REL_I386_TOKEN             = 0x000C
+       IMAGE_REL_I386_SECREL7           = 0x000D
+       IMAGE_REL_I386_REL32             = 0x0014
+       IMAGE_REL_AMD64_ABSOLUTE         = 0x0000
+       IMAGE_REL_AMD64_ADDR64           = 0x0001
+       IMAGE_REL_AMD64_ADDR32           = 0x0002
+       IMAGE_REL_AMD64_ADDR32NB         = 0x0003
+       IMAGE_REL_AMD64_REL32            = 0x0004
+       IMAGE_REL_AMD64_REL32_1          = 0x0005
+       IMAGE_REL_AMD64_REL32_2          = 0x0006
+       IMAGE_REL_AMD64_REL32_3          = 0x0007
+       IMAGE_REL_AMD64_REL32_4          = 0x0008
+       IMAGE_REL_AMD64_REL32_5          = 0x0009
+       IMAGE_REL_AMD64_SECTION          = 0x000A
+       IMAGE_REL_AMD64_SECREL           = 0x000B
+       IMAGE_REL_AMD64_SECREL7          = 0x000C
+       IMAGE_REL_AMD64_TOKEN            = 0x000D
+       IMAGE_REL_AMD64_SREL32           = 0x000E
+       IMAGE_REL_AMD64_PAIR             = 0x000F
+       IMAGE_REL_AMD64_SSPAN32          = 0x0010
+)
+
+type PeSym struct {
+       name    string
+       value   uint32
+       sectnum uint16
+       type_   uint16
+       sclass  uint8
+       aux     uint8
+       sym     *LSym
+}
+
+type PeSect struct {
+       name string
+       base []byte
+       size uint64
+       sym  *LSym
+       sh   IMAGE_SECTION_HEADER
+}
+
+type PeObj struct {
+       f      *Biobuf
+       name   string
+       base   uint32
+       sect   []PeSect
+       nsect  uint
+       pesym  []PeSym
+       npesym uint
+       fh     IMAGE_FILE_HEADER
+       snames []byte
+}
+
+func ldpe(f *Biobuf, pkg string, length int64, pn string) {
+       var err error
+       var name string
+       var base int32
+       var l uint32
+       var i int
+       var j int
+       var numaux int
+       var peobj *PeObj
+       var sect *PeSect
+       var rsect *PeSect
+       var symbuf [18]uint8
+       var s *LSym
+       var r []Reloc
+       var rp *Reloc
+       var sym *PeSym
+
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
+       }
+
+       sect = nil
+       Ctxt.Version++
+       base = int32(Boffset(f))
+
+       peobj = new(PeObj)
+       peobj.f = f
+       peobj.base = uint32(base)
+       peobj.name = pn
+
+       // read header
+       if err = binary.Read(f, binary.LittleEndian, &peobj.fh); err != nil {
+               goto bad
+       }
+
+       // load section list
+       peobj.sect = make([]PeSect, peobj.fh.NumberOfSections)
+
+       peobj.nsect = uint(peobj.fh.NumberOfSections)
+       for i = 0; i < int(peobj.fh.NumberOfSections); i++ {
+               if err = binary.Read(f, binary.LittleEndian, &peobj.sect[i].sh); err != nil {
+                       goto bad
+               }
+               peobj.sect[i].size = uint64(peobj.sect[i].sh.SizeOfRawData)
+               peobj.sect[i].name = cstring(peobj.sect[i].sh.Name[:])
+       }
+
+       // TODO return error if found .cormeta
+
+       // load string table
+       Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
+
+       if Bread(f, symbuf[:4]) != 4 {
+               goto bad
+       }
+       l = Le32(symbuf[:])
+       peobj.snames = make([]byte, l)
+       Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
+       if Bread(f, peobj.snames) != len(peobj.snames) {
+               goto bad
+       }
+
+       // rewrite section names if they start with /
+       for i = 0; i < int(peobj.fh.NumberOfSections); i++ {
+               if peobj.sect[i].name == "" {
+                       continue
+               }
+               if peobj.sect[i].name[0] != '/' {
+                       continue
+               }
+               l = uint32(obj.Atoi(peobj.sect[i].name[1:]))
+               peobj.sect[i].name = cstring(peobj.snames[l:])
+       }
+
+       // read symbols
+       peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)
+
+       peobj.npesym = uint(peobj.fh.NumberOfSymbols)
+       Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
+       for i = 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
+               Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
+               if Bread(f, symbuf[:]) != len(symbuf) {
+                       goto bad
+               }
+
+               if (symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0) {
+                       l = Le32(symbuf[4:])
+                       peobj.pesym[i].name = cstring(peobj.snames[l:]) // sym name length <= 8
+               } else {
+                       peobj.pesym[i].name = cstring(symbuf[:8])
+               }
+
+               peobj.pesym[i].value = Le32(symbuf[8:])
+               peobj.pesym[i].sectnum = Le16(symbuf[12:])
+               peobj.pesym[i].sclass = symbuf[16]
+               peobj.pesym[i].aux = symbuf[17]
+               peobj.pesym[i].type_ = Le16(symbuf[14:])
+               numaux = int(peobj.pesym[i].aux)
+               if numaux < 0 {
+                       numaux = 0
+               }
+       }
+
+       // create symbols for mapped sections
+       for i = 0; uint(i) < peobj.nsect; i++ {
+               sect = &peobj.sect[i]
+               if sect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
+                       continue
+               }
+
+               if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
+                       // This has been seen for .idata sections, which we
+                       // want to ignore.  See issues 5106 and 5273.
+                       continue
+               }
+
+               if pemap(peobj, sect) < 0 {
+                       goto bad
+               }
+
+               name = fmt.Sprintf("%s(%s)", pkg, sect.name)
+               s = Linklookup(Ctxt, name, Ctxt.Version)
+
+               switch sect.sh.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
+                       s.Type = SRODATA
+
+               case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
+                       s.Type = SNOPTRBSS
+
+               case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
+                       s.Type = SNOPTRDATA
+
+               case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
+                       s.Type = STEXT
+
+               default:
+                       err = fmt.Errorf("unexpected flags %#06x for PE section %s", sect.sh.Characteristics, sect.name)
+                       goto bad
+               }
+
+               s.P = sect.base
+               s.P = s.P[:sect.size]
+               s.Size = int64(sect.size)
+               sect.sym = s
+               if sect.name == ".rsrc" {
+                       setpersrc(sect.sym)
+               }
+       }
+
+       // load relocations
+       for i = 0; uint(i) < peobj.nsect; i++ {
+               rsect = &peobj.sect[i]
+               if rsect.sym == nil || rsect.sh.NumberOfRelocations == 0 {
+                       continue
+               }
+               if rsect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
+                       continue
+               }
+               if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
+                       // This has been seen for .idata sections, which we
+                       // want to ignore.  See issues 5106 and 5273.
+                       continue
+               }
+
+               r = make([]Reloc, rsect.sh.NumberOfRelocations)
+               Bseek(f, int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
+               for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ {
+                       rp = &r[j]
+                       if Bread(f, symbuf[:10]) != 10 {
+                               goto bad
+                       }
+                       var rva uint32
+                       var symindex uint32
+                       var type_ uint16
+                       rva = Le32(symbuf[0:])
+                       symindex = Le32(symbuf[4:])
+                       type_ = Le16(symbuf[8:])
+                       if err = readpesym(peobj, int(symindex), &sym); err != nil {
+                               goto bad
+                       }
+                       if sym.sym == nil {
+                               err = fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", sym.name, symindex, sym.type_)
+                               goto bad
+                       }
+
+                       rp.Sym = sym.sym
+                       rp.Siz = 4
+                       rp.Off = int32(rva)
+                       switch type_ {
+                       default:
+                               Diag("%s: unknown relocation type %d;", pn, type_)
+                               fallthrough
+
+                       case IMAGE_REL_I386_REL32,
+                               IMAGE_REL_AMD64_REL32,
+                               IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
+                               IMAGE_REL_AMD64_ADDR32NB:
+                               rp.Type = R_PCREL
+
+                               rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
+
+                       case IMAGE_REL_I386_DIR32NB,
+                               IMAGE_REL_I386_DIR32:
+                               rp.Type = R_ADDR
+
+                               // load addend from image
+                               rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
+
+                       case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
+                               rp.Siz = 8
+
+                               rp.Type = R_ADDR
+
+                               // load addend from image
+                               rp.Add = int64(Le64(rsect.base[rp.Off:]))
+                       }
+
+                       // ld -r could generate multiple section symbols for the
+                       // same section but with different values, we have to take
+                       // that into account
+                       if issect(&peobj.pesym[symindex]) {
+                               rp.Add += int64(peobj.pesym[symindex].value)
+                       }
+               }
+
+               sort.Sort(rbyoff(r[:rsect.sh.NumberOfRelocations]))
+
+               s = rsect.sym
+               s.R = r
+               s.R = s.R[:rsect.sh.NumberOfRelocations]
+       }
+
+       // enter sub-symbols into symbol table.
+       for i = 0; uint(i) < peobj.npesym; i++ {
+               if peobj.pesym[i].name == "" {
+                       continue
+               }
+               if issect(&peobj.pesym[i]) {
+                       continue
+               }
+               if uint(peobj.pesym[i].sectnum) > peobj.nsect {
+                       continue
+               }
+               if peobj.pesym[i].sectnum > 0 {
+                       sect = &peobj.sect[peobj.pesym[i].sectnum-1]
+                       if sect.sym == nil {
+                               continue
+                       }
+               }
+
+               if err = readpesym(peobj, i, &sym); err != nil {
+                       goto bad
+               }
+
+               s = sym.sym
+               if sym.sectnum == 0 { // extern
+                       if s.Type == SDYNIMPORT {
+                               s.Plt = -2 // flag for dynimport in PE object files.
+                       }
+                       if s.Type == SXREF && sym.value > 0 { // global data
+                               s.Type = SNOPTRDATA
+                               s.Size = int64(sym.value)
+                       }
+
+                       continue
+               } else if sym.sectnum > 0 && uint(sym.sectnum) <= peobj.nsect {
+                       sect = &peobj.sect[sym.sectnum-1]
+                       if sect.sym == nil {
+                               Diag("%s: %s sym == 0!", pn, s.Name)
+                       }
+               } else {
+                       Diag("%s: %s sectnum < 0!", pn, s.Name)
+               }
+
+               if sect == nil {
+                       return
+               }
+
+               if s.Outer != nil {
+                       if s.Dupok != 0 {
+                               continue
+                       }
+                       Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
+                       Errorexit()
+               }
+
+               s.Sub = sect.sym.Sub
+               sect.sym.Sub = s
+               s.Type = sect.sym.Type | SSUB
+               s.Value = int64(sym.value)
+               s.Size = 4
+               s.Outer = sect.sym
+               if sect.sym.Type == STEXT {
+                       if s.External != 0 && s.Dupok == 0 {
+                               Diag("%s: duplicate definition of %s", pn, s.Name)
+                       }
+                       s.External = 1
+               }
+       }
+
+       // Sort outer lists by address, adding to textp.
+       // This keeps textp in increasing address order.
+       for i = 0; uint(i) < peobj.nsect; i++ {
+               s = peobj.sect[i].sym
+               if s == nil {
+                       continue
+               }
+               if s.Sub != nil {
+                       s.Sub = listsort(s.Sub, valuecmp, listsubp)
+               }
+               if s.Type == STEXT {
+                       if s.Onlist != 0 {
+                               log.Fatalf("symbol %s listed multiple times", s.Name)
+                       }
+                       s.Onlist = 1
+                       if Ctxt.Etextp != nil {
+                               Ctxt.Etextp.Next = s
+                       } else {
+                               Ctxt.Textp = s
+                       }
+                       Ctxt.Etextp = s
+                       for s = s.Sub; s != nil; s = s.Sub {
+                               if s.Onlist != 0 {
+                                       log.Fatalf("symbol %s listed multiple times", s.Name)
+                               }
+                               s.Onlist = 1
+                               Ctxt.Etextp.Next = s
+                               Ctxt.Etextp = s
+                       }
+               }
+       }
+
+       return
+
+bad:
+       Diag("%s: malformed pe file: %v", pn, err)
+}
+
+func pemap(peobj *PeObj, sect *PeSect) int {
+       if sect.base != nil {
+               return 0
+       }
+
+       sect.base = make([]byte, sect.sh.SizeOfRawData)
+       if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file
+               return 0
+       }
+       if Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || Bread(peobj.f, sect.base) != len(sect.base) {
+               return -1
+       }
+
+       return 0
+}
+
+func issect(s *PeSym) bool {
+       return s.sclass == IMAGE_SYM_CLASS_STATIC && s.type_ == 0 && s.name[0] == '.'
+}
+
+func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
+       var s *LSym
+       var sym *PeSym
+       var name string
+
+       if uint(i) >= peobj.npesym || i < 0 {
+               err = fmt.Errorf("invalid pe symbol index")
+               return err
+       }
+
+       sym = &peobj.pesym[i]
+       *y = sym
+
+       if issect(sym) {
+               name = peobj.sect[sym.sectnum-1].sym.Name
+       } else {
+               name = sym.name
+               if strings.HasPrefix(name, "__imp_") {
+                       name = name[6:] // __imp_Name => Name
+               }
+               if Thearch.Thechar == '8' && name[0] == '_' {
+                       name = name[1:] // _Name => Name
+               }
+       }
+
+       // remove last @XXX
+       if i := strings.LastIndex(name, "@"); i >= 0 {
+               name = name[:i]
+       }
+
+       switch sym.type_ {
+       default:
+               err = fmt.Errorf("%s: invalid symbol type %d", sym.name, sym.type_)
+               return err
+
+       case IMAGE_SYM_DTYPE_FUNCTION,
+               IMAGE_SYM_DTYPE_NULL:
+               switch sym.sclass {
+               case IMAGE_SYM_CLASS_EXTERNAL: //global
+                       s = Linklookup(Ctxt, name, 0)
+
+               case IMAGE_SYM_CLASS_NULL,
+                       IMAGE_SYM_CLASS_STATIC,
+                       IMAGE_SYM_CLASS_LABEL:
+                       s = Linklookup(Ctxt, name, Ctxt.Version)
+                       s.Dupok = 1
+
+               default:
+                       err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.sclass)
+                       return err
+               }
+       }
+
+       if s != nil && s.Type == 0 && (sym.sclass != IMAGE_SYM_CLASS_STATIC || sym.value != 0) {
+               s.Type = SXREF
+       }
+       if strings.HasPrefix(sym.name, "__imp_") {
+               s.Got = -2 // flag for __imp_
+       }
+       sym.sym = s
+
+       return nil
+}
diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go
new file mode 100644 (file)
index 0000000..bc58fff
--- /dev/null
@@ -0,0 +1,1751 @@
+// Inferno utils/8l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+import (
+       "bytes"
+       "cmd/internal/obj"
+       "fmt"
+       "io/ioutil"
+       "log"
+       "os"
+       "os/exec"
+       "strings"
+)
+
+// Data layout and relocation.
+
+// Derived from Inferno utils/6l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+type Arch struct {
+       Thechar          int
+       Ptrsize          int
+       Intsize          int
+       Regsize          int
+       Funcalign        int
+       Maxalign         int
+       Minlc            int
+       Dwarfregsp       int
+       Linuxdynld       string
+       Freebsddynld     string
+       Netbsddynld      string
+       Openbsddynld     string
+       Dragonflydynld   string
+       Solarisdynld     string
+       Adddynlib        func(string)
+       Adddynrel        func(*LSym, *Reloc)
+       Adddynsym        func(*Link, *LSym)
+       Archinit         func()
+       Archreloc        func(*Reloc, *LSym, *int64) int
+       Archrelocvariant func(*Reloc, *LSym, int64) int64
+       Asmb             func()
+       Elfreloc1        func(*Reloc, int64) int
+       Elfsetupplt      func()
+       Gentext          func()
+       Machoreloc1      func(*Reloc, int64) int
+       Lput             func(uint32)
+       Wput             func(uint16)
+       Vput             func(uint64)
+}
+
+var Thearch Arch
+
+var datap *LSym
+
+var Debug [128]int
+
+var literal string
+
+var Lcsize int32
+
+var rpath string
+
+var Spsize int32
+
+var symlist *LSym
+
+var Symsize int32
+
+// Terrible but standard terminology.
+// A segment describes a block of file to load into memory.
+// A section further describes the pieces of that block for
+// use in debuggers and such.
+
+const (
+       MAXIO   = 8192
+       MINFUNC = 16
+)
+
+type Segment struct {
+       Rwx     uint8
+       Vaddr   uint64
+       Length  uint64
+       Fileoff uint64
+       Filelen uint64
+       Sect    *Section
+}
+
+type Section struct {
+       Rwx     uint8
+       Extnum  int16
+       Align   int32
+       Name    string
+       Vaddr   uint64
+       Length  uint64
+       Next    *Section
+       Seg     *Segment
+       Elfsect interface{}
+       Reloff  uint64
+       Rellen  uint64
+}
+
+var Thestring string
+
+var Thelinkarch *LinkArch
+
+var outfile string
+
+var ndynexp int
+
+var dynexp []*LSym
+
+var nldflag int
+
+var ldflag []string
+
+var havedynamic int
+
+var Funcalign int
+
+var iscgo bool
+
+var elfglobalsymndx int
+
+var flag_installsuffix string
+
+var flag_race int
+
+var Flag_shared int
+
+var tracksym string
+
+var interpreter string
+
+var tmpdir string
+
+var extld string
+
+var extldflags string
+
+var debug_s int // backup old value of debug['s']
+
+var Ctxt *Link
+
+var HEADR int32
+
+var HEADTYPE int32
+
+var INITRND int32
+
+var INITTEXT int64
+
+var INITDAT int64
+
+var INITENTRY string /* entry point */
+
+var nerrors int
+
+var Linkmode int
+
+var liveness int64
+
+// for dynexport field of LSym
+const (
+       CgoExportDynamic = 1 << 0
+       CgoExportStatic  = 1 << 1
+)
+
+var Segtext Segment
+
+var Segrodata Segment
+
+var Segdata Segment
+
+var Segdwarf Segment
+
+type Endian struct {
+       e16 func([]byte) uint16
+       e32 func([]byte) uint32
+       e64 func([]byte) uint64
+}
+
+/* set by call to mywhatsys() */
+
+/* whence for ldpkg */
+const (
+       FileObj = 0 + iota
+       ArchiveObj
+       Pkgdef
+)
+
+var headstring string
+
+// buffered output
+
+var Bso Biobuf
+
+var coutbuf Biobuf
+
+const (
+       AssumeGoldLinker = 0
+)
+
+var symname string = "__.GOSYMDEF"
+
+var pkgname string = "__.PKGDEF"
+
+var cout *os.File
+
+var version int
+
+// Set if we see an object compiled by the host compiler that is not
+// from a package that is known to support internal linking mode.
+var externalobj int = 0
+
+var goroot string
+
+var goarch string
+
+var goos string
+
+var theline string
+
+func Lflag(arg string) {
+       Ctxt.Libdir = append(Ctxt.Libdir, arg)
+}
+
+/*
+ * Unix doesn't like it when we write to a running (or, sometimes,
+ * recently run) binary, so remove the output file before writing it.
+ * On Windows 7, remove() can force a subsequent create() to fail.
+ * S_ISREG() does not exist on Plan 9.
+ */
+func mayberemoveoutfile() {
+       if fi, err := os.Lstat(outfile); err == nil && !fi.Mode().IsRegular() {
+               return
+       }
+       os.Remove(outfile)
+}
+
+func libinit() {
+       var suffix string
+       var suffixsep string
+
+       Funcalign = Thearch.Funcalign
+       mywhatsys() // get goroot, goarch, goos
+
+       // add goroot to the end of the libdir list.
+       suffix = ""
+
+       suffixsep = ""
+       if flag_installsuffix != "" {
+               suffixsep = "_"
+               suffix = flag_installsuffix
+       } else if flag_race != 0 {
+               suffixsep = "_"
+               suffix = "race"
+       }
+
+       Lflag(fmt.Sprintf("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix))
+
+       mayberemoveoutfile()
+       f, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
+       if err != nil {
+               Diag("cannot create %s: %v", outfile, err)
+               Errorexit()
+       }
+
+       cout = f
+       coutbuf = *Binitw(f)
+
+       if INITENTRY == "" {
+               if Flag_shared == 0 {
+                       INITENTRY = fmt.Sprintf("_rt0_%s_%s", goarch, goos)
+               } else {
+                       INITENTRY = fmt.Sprintf("_rt0_%s_%s_lib", goarch, goos)
+               }
+       }
+
+       Linklookup(Ctxt, INITENTRY, 0).Type = SXREF
+}
+
+func Errorexit() {
+       if cout != nil {
+               // For rmtemp run at atexit time on Windows.
+               cout.Close()
+       }
+
+       if nerrors != 0 {
+               if cout != nil {
+                       mayberemoveoutfile()
+               }
+               Exit(2)
+       }
+
+       Exit(0)
+}
+
+func loadinternal(name string) {
+       var pname string
+       var i int
+       var found int
+
+       found = 0
+       for i = 0; i < len(Ctxt.Libdir); i++ {
+               pname = fmt.Sprintf("%s/%s.a", Ctxt.Libdir[i], name)
+               if Debug['v'] != 0 {
+                       fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, pname)
+               }
+               if obj.Access(pname, obj.AEXIST) >= 0 {
+                       addlibpath(Ctxt, "internal", "internal", pname, name)
+                       found = 1
+                       break
+               }
+       }
+
+       if found == 0 {
+               fmt.Fprintf(&Bso, "warning: unable to find %s.a\n", name)
+       }
+}
+
+func loadlib() {
+       var i int
+       var w int
+       var x int
+       var s *LSym
+       var tlsg *LSym
+       var cgostrsym string
+
+       if Flag_shared != 0 {
+               s = Linklookup(Ctxt, "runtime.islibrary", 0)
+               s.Dupok = 1
+               Adduint8(Ctxt, s, 1)
+       }
+
+       loadinternal("runtime")
+       if Thearch.Thechar == '5' {
+               loadinternal("math")
+       }
+       if flag_race != 0 {
+               loadinternal("runtime/race")
+       }
+
+       for i = 0; i < len(Ctxt.Library); i++ {
+               if Debug['v'] > 1 {
+                       fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
+               }
+               iscgo = iscgo || Ctxt.Library[i].Pkg == "runtime/cgo"
+               objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+       }
+
+       if Linkmode == LinkAuto {
+               if iscgo && externalobj != 0 {
+                       Linkmode = LinkExternal
+               } else {
+                       Linkmode = LinkInternal
+               }
+
+               // Force external linking for android.
+               if goos == "android" {
+                       Linkmode = LinkExternal
+               }
+
+               // cgo on Darwin must use external linking
+               // we can always use external linking, but then there will be circular
+               // dependency problems when compiling natively (external linking requires
+               // runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
+               // compiled using external linking.)
+               if Thearch.Thechar == '5' && HEADTYPE == Hdarwin && iscgo {
+                       Linkmode = LinkExternal
+               }
+       }
+
+       if Linkmode == LinkExternal && !iscgo {
+               // This indicates a user requested -linkmode=external.
+               // The startup code uses an import of runtime/cgo to decide
+               // whether to initialize the TLS.  So give it one.  This could
+               // be handled differently but it's an unusual case.
+               loadinternal("runtime/cgo")
+
+               if i < len(Ctxt.Library) {
+                       objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+               }
+
+               // Pretend that we really imported the package.
+               s = Linklookup(Ctxt, "go.importpath.runtime/cgo.", 0)
+
+               s.Type = SDATA
+               s.Dupok = 1
+               s.Reachable = true
+
+               // Provided by the code that imports the package.
+               // Since we are simulating the import, we have to provide this string.
+               cgostrsym = "go.string.\"runtime/cgo\""
+
+               if Linkrlookup(Ctxt, cgostrsym, 0) == nil {
+                       s = Linklookup(Ctxt, cgostrsym, 0)
+                       s.Type = SRODATA
+                       s.Reachable = true
+                       addstrdata(cgostrsym, "runtime/cgo")
+               }
+       }
+
+       if Linkmode == LinkInternal {
+               // Drop all the cgo_import_static declarations.
+               // Turns out we won't be needing them.
+               for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+                       if s.Type == SHOSTOBJ {
+                               // If a symbol was marked both
+                               // cgo_import_static and cgo_import_dynamic,
+                               // then we want to make it cgo_import_dynamic
+                               // now.
+                               if s.Extname != "" && s.Dynimplib != "" && s.Cgoexport == 0 {
+                                       s.Type = SDYNIMPORT
+                               } else {
+                                       s.Type = 0
+                               }
+                       }
+               }
+       }
+
+       tlsg = Linklookup(Ctxt, "runtime.tlsg", 0)
+
+       // For most ports, runtime.tlsg is a placeholder symbol for TLS
+       // relocation. However, the Android and Darwin arm ports need it
+       // to be a real variable.
+       //
+       // TODO(crawshaw): android should require leaving the tlsg->type
+       // alone (as the runtime-provided SNOPTRBSS) just like darwin/arm.
+       // But some other part of the linker is expecting STLSBSS.
+       if goos != "darwin" || Thearch.Thechar != '5' {
+               tlsg.Type = STLSBSS
+       }
+       tlsg.Size = int64(Thearch.Ptrsize)
+       tlsg.Hide = 1
+       tlsg.Reachable = true
+       Ctxt.Tlsg = tlsg
+
+       // Now that we know the link mode, trim the dynexp list.
+       x = CgoExportDynamic
+
+       if Linkmode == LinkExternal {
+               x = CgoExportStatic
+       }
+       w = 0
+       for i = 0; i < len(dynexp); i++ {
+               if int(dynexp[i].Cgoexport)&x != 0 {
+                       dynexp[w] = dynexp[i]
+                       w++
+               }
+       }
+       dynexp = dynexp[:w]
+
+       // In internal link mode, read the host object files.
+       if Linkmode == LinkInternal {
+               hostobjs()
+       } else {
+               hostlinksetup()
+       }
+
+       // We've loaded all the code now.
+       // If there are no dynamic libraries needed, gcc disables dynamic linking.
+       // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
+       // assumes that a dynamic binary always refers to at least one dynamic library.
+       // Rather than be a source of test cases for glibc, disable dynamic linking
+       // the same way that gcc would.
+       //
+       // Exception: on OS X, programs such as Shark only work with dynamic
+       // binaries, so leave it enabled on OS X (Mach-O) binaries.
+       // Also leave it enabled on Solaris which doesn't support
+       // statically linked binaries.
+       if Flag_shared == 0 && havedynamic == 0 && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris {
+               Debug['d'] = 1
+       }
+
+       importcycles()
+}
+
+/*
+ * look for the next file in an archive.
+ * adapted from libmach.
+ */
+func nextar(bp *Biobuf, off int64, a *ArHdr) int64 {
+       if off&1 != 0 {
+               off++
+       }
+       Bseek(bp, off, 0)
+       buf := make([]byte, SAR_HDR)
+       if n := Bread(bp, buf); n < len(buf) {
+               if n >= 0 {
+                       return 0
+               }
+               return -1
+       }
+
+       a.name = artrim(buf[0:16])
+       a.date = artrim(buf[16:28])
+       a.uid = artrim(buf[28:34])
+       a.gid = artrim(buf[34:40])
+       a.mode = artrim(buf[40:48])
+       a.size = artrim(buf[48:58])
+       a.fmag = artrim(buf[58:60])
+
+       arsize := atolwhex(a.size)
+       if arsize&1 != 0 {
+               arsize++
+       }
+       return int64(arsize) + SAR_HDR
+}
+
+func objfile(file string, pkg string) {
+       var off int64
+       var l int64
+       var f *Biobuf
+       var pname string
+       var arhdr ArHdr
+
+       pkg = pathtoprefix(pkg)
+
+       if Debug['v'] > 1 {
+               fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), file, pkg)
+       }
+       Bflush(&Bso)
+       var err error
+       f, err = Bopenr(file)
+       if err != nil {
+               Diag("cannot open file %s: %v", file, err)
+               Errorexit()
+       }
+
+       magbuf := make([]byte, len(ARMAG))
+       if Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) {
+               /* load it as a regular file */
+               l = Bseek(f, 0, 2)
+
+               Bseek(f, 0, 0)
+               ldobj(f, pkg, l, file, file, FileObj)
+               Bterm(f)
+
+               return
+       }
+
+       /* skip over optional __.GOSYMDEF and process __.PKGDEF */
+       off = Boffset(f)
+
+       l = nextar(f, off, &arhdr)
+       if l <= 0 {
+               Diag("%s: short read on archive file symbol header", file)
+               goto out
+       }
+
+       if strings.HasPrefix(arhdr.name, symname) {
+               off += l
+               l = nextar(f, off, &arhdr)
+               if l <= 0 {
+                       Diag("%s: short read on archive file symbol header", file)
+                       goto out
+               }
+       }
+
+       if !strings.HasPrefix(arhdr.name, pkgname) {
+               Diag("%s: cannot find package header", file)
+               goto out
+       }
+
+       off += l
+
+       if Debug['u'] != 0 {
+               ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef)
+       }
+
+       /*
+        * load all the object files from the archive now.
+        * this gives us sequential file access and keeps us
+        * from needing to come back later to pick up more
+        * objects.  it breaks the usual C archive model, but
+        * this is Go, not C.  the common case in Go is that
+        * we need to load all the objects, and then we throw away
+        * the individual symbols that are unused.
+        *
+        * loading every object will also make it possible to
+        * load foreign objects not referenced by __.GOSYMDEF.
+        */
+       for {
+               l = nextar(f, off, &arhdr)
+               if l == 0 {
+                       break
+               }
+               if l < 0 {
+                       Diag("%s: malformed archive", file)
+                       Errorexit()
+                       goto out
+               }
+
+               off += l
+
+               pname = fmt.Sprintf("%s(%s)", file, arhdr.name)
+               l = atolwhex(arhdr.size)
+               ldobj(f, pkg, l, pname, file, ArchiveObj)
+       }
+
+out:
+       Bterm(f)
+}
+
+type Hostobj struct {
+       ld     func(*Biobuf, string, int64, string)
+       pkg    string
+       pn     string
+       file   string
+       off    int64
+       length int64
+}
+
+var hostobj []Hostobj
+
+var nhostobj int
+
+var mhostobj int
+
+// These packages can use internal linking mode.
+// Others trigger external mode.
+var internalpkg = []string{
+       "crypto/x509",
+       "net",
+       "os/user",
+       "runtime/cgo",
+       "runtime/race",
+}
+
+func ldhostobj(ld func(*Biobuf, string, int64, string), f *Biobuf, pkg string, length int64, pn string, file string) {
+       var i int
+       var isinternal int
+       var h *Hostobj
+
+       isinternal = 0
+       for i = 0; i < len(internalpkg); i++ {
+               if pkg == internalpkg[i] {
+                       isinternal = 1
+                       break
+               }
+       }
+
+       // DragonFly declares errno with __thread, which results in a symbol
+       // type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
+       // currently know how to handle TLS relocations, hence we have to
+       // force external linking for any libraries that link in code that
+       // uses errno. This can be removed if the Go linker ever supports
+       // these relocation types.
+       if HEADTYPE == Hdragonfly {
+               if pkg == "net" || pkg == "os/user" {
+                       isinternal = 0
+               }
+       }
+
+       if isinternal == 0 {
+               externalobj = 1
+       }
+
+       hostobj = append(hostobj, Hostobj{})
+       h = &hostobj[len(hostobj)-1]
+       h.ld = ld
+       h.pkg = pkg
+       h.pn = pn
+       h.file = file
+       h.off = Boffset(f)
+       h.length = length
+}
+
+func hostobjs() {
+       var i int
+       var f *Biobuf
+       var h *Hostobj
+
+       for i = 0; i < len(hostobj); i++ {
+               h = &hostobj[i]
+               var err error
+               f, err = Bopenr(h.file)
+               if f == nil {
+                       Ctxt.Cursym = nil
+                       Diag("cannot reopen %s: %v", h.pn, err)
+                       Errorexit()
+               }
+
+               Bseek(f, h.off, 0)
+               h.ld(f, h.pkg, h.length, h.pn)
+               Bterm(f)
+       }
+}
+
+// provided by lib9
+
+func rmtemp() {
+       os.RemoveAll(tmpdir)
+}
+
+func hostlinksetup() {
+       var p string
+
+       if Linkmode != LinkExternal {
+               return
+       }
+
+       // create temporary directory and arrange cleanup
+       if tmpdir == "" {
+               dir, err := ioutil.TempDir("", "go-link-")
+               if err != nil {
+                       log.Fatal(err)
+               }
+               tmpdir = dir
+               AtExit(rmtemp)
+       }
+
+       // change our output to temporary object file
+       cout.Close()
+
+       p = fmt.Sprintf("%s/go.o", tmpdir)
+       var err error
+       cout, err = os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
+       if err != nil {
+               Diag("cannot create %s: %v", p, err)
+               Errorexit()
+       }
+
+       coutbuf = *Binitw(cout)
+}
+
+var hostlink_buf = make([]byte, 64*1024)
+
+func hostlink() {
+       var p string
+       var argv []string
+       var i int
+       var n int
+       var length int
+       var h *Hostobj
+       var f *Biobuf
+
+       if Linkmode != LinkExternal || nerrors > 0 {
+               return
+       }
+
+       if extld == "" {
+               extld = "gcc"
+       }
+       argv = append(argv, extld)
+       switch Thearch.Thechar {
+       case '8':
+               argv = append(argv, "-m32")
+
+       case '6',
+               '9':
+               argv = append(argv, "-m64")
+
+       case '5':
+               argv = append(argv, "-marm")
+       }
+
+       if Debug['s'] == 0 && debug_s == 0 {
+               argv = append(argv, "-gdwarf-2")
+       } else {
+               argv = append(argv, "-s")
+       }
+
+       if HEADTYPE == Hdarwin {
+               argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000")
+       }
+       if HEADTYPE == Hopenbsd {
+               argv = append(argv, "-Wl,-nopie")
+       }
+
+       if Iself && AssumeGoldLinker != 0 /*TypeKind(100016)*/ {
+               argv = append(argv, "-Wl,--rosegment")
+       }
+
+       if Flag_shared != 0 {
+               argv = append(argv, "-Wl,-Bsymbolic")
+               argv = append(argv, "-shared")
+       }
+
+       argv = append(argv, "-o")
+       argv = append(argv, outfile)
+
+       if rpath != "" {
+               argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath))
+       }
+
+       // Force global symbols to be exported for dlopen, etc.
+       if Iself {
+               argv = append(argv, "-rdynamic")
+       }
+
+       if strings.Contains(argv[0], "clang") {
+               argv = append(argv, "-Qunused-arguments")
+       }
+
+       // already wrote main object file
+       // copy host objects to temporary directory
+       for i = 0; i < len(hostobj); i++ {
+               h = &hostobj[i]
+               var err error
+               f, err = Bopenr(h.file)
+               if f == nil {
+                       Ctxt.Cursym = nil
+                       Diag("cannot reopen %s: %v", h.pn, err)
+                       Errorexit()
+               }
+
+               Bseek(f, h.off, 0)
+               p = fmt.Sprintf("%s/%06d.o", tmpdir, i)
+               argv = append(argv, p)
+               w, err := os.Create(p)
+               if err != nil {
+                       Ctxt.Cursym = nil
+                       Diag("cannot create %s: %v", p, err)
+                       Errorexit()
+               }
+
+               length = int(h.length)
+               for length > 0 {
+                       n = Bread(f, hostlink_buf)
+                       if n <= 0 {
+                               break
+                       }
+                       if n > length {
+                               n = length
+                       }
+                       if _, err = w.Write(hostlink_buf[:n]); err != nil {
+                               log.Fatal(err)
+                       }
+                       length -= n
+               }
+
+               if err = w.Close(); err != nil {
+                       Ctxt.Cursym = nil
+                       Diag("cannot write %s: %v", p, err)
+                       Errorexit()
+               }
+
+               Bterm(f)
+       }
+
+       argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
+       for i = 0; i < len(ldflag); i++ {
+               argv = append(argv, ldflag[i])
+       }
+
+       for _, p = range strings.Fields(extldflags) {
+               argv = append(argv, p)
+
+               // clang, unlike GCC, passes -rdynamic to the linker
+               // even when linking with -static, causing a linker
+               // error when using GNU ld.  So take out -rdynamic if
+               // we added it.  We do it in this order, rather than
+               // only adding -rdynamic later, so that -extldflags
+               // can override -rdynamic without using -static.
+               if Iself && p == "-static" {
+                       for i = range argv {
+                               if argv[i] == "-rdynamic" {
+                                       argv[i] = "-static"
+                               }
+                       }
+               }
+       }
+
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "host link:")
+               for i = range argv {
+                       fmt.Fprintf(&Bso, " %v", plan9quote(argv[i]))
+               }
+               fmt.Fprintf(&Bso, "\n")
+               Bflush(&Bso)
+       }
+
+       if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
+               Ctxt.Cursym = nil
+               Diag("%s: running %s failed: %v\n%s", os.Args[0], argv[0], err, out)
+               Errorexit()
+       }
+}
+
+func ldobj(f *Biobuf, pkg string, length int64, pn string, file string, whence int) {
+       var line string
+       var c1 int
+       var c2 int
+       var c3 int
+       var c4 int
+       var magic uint32
+       var import0 int64
+       var import1 int64
+       var eof int64
+       var start int64
+       var t string
+
+       eof = Boffset(f) + length
+
+       pn = pn
+
+       start = Boffset(f)
+       c1 = Bgetc(f)
+       c2 = Bgetc(f)
+       c3 = Bgetc(f)
+       c4 = Bgetc(f)
+       Bseek(f, start, 0)
+
+       magic = uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
+       if magic == 0x7f454c46 { // \x7F E L F
+               ldhostobj(ldelf, f, pkg, length, pn, file)
+               return
+       }
+
+       if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
+               ldhostobj(ldmacho, f, pkg, length, pn, file)
+               return
+       }
+
+       if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 {
+               ldhostobj(ldpe, f, pkg, length, pn, file)
+               return
+       }
+
+       /* check the header */
+       line = Brdline(f, '\n')
+
+       if line == "" {
+               if Blinelen(f) > 0 {
+                       Diag("%s: not an object file", pn)
+                       return
+               }
+
+               goto eof
+       }
+
+       if !strings.HasPrefix(line, "go object ") {
+               if strings.HasSuffix(pn, ".go") {
+                       fmt.Printf("%cl: input %s is not .%c file (use %cg to compile .go files)\n", Thearch.Thechar, pn, Thearch.Thechar, Thearch.Thechar)
+                       Errorexit()
+               }
+
+               if line == Thestring {
+                       // old header format: just $GOOS
+                       Diag("%s: stale object file", pn)
+
+                       return
+               }
+
+               Diag("%s: not an object file", pn)
+
+               return
+       }
+
+       // First, check that the basic goos, goarch, and version match.
+       t = fmt.Sprintf("%s %s %s ", goos, obj.Getgoarch(), obj.Getgoversion())
+
+       line = strings.TrimRight(line, "\n")
+       if !strings.HasPrefix(line[10:]+" ", t) && Debug['f'] == 0 {
+               Diag("%s: object is [%s] expected [%s]", pn, line[10:], t)
+               return
+       }
+
+       // Second, check that longer lines match each other exactly,
+       // so that the Go compiler and write additional information
+       // that must be the same from run to run.
+       if len(line) >= len(t)+10 {
+               if theline == "" {
+                       theline = line[10:]
+               } else if theline != line[10:] {
+                       Diag("%s: object is [%s] expected [%s]", pn, line[10:], theline)
+                       return
+               }
+       }
+
+       /* skip over exports and other info -- ends with \n!\n */
+       import0 = Boffset(f)
+
+       c1 = '\n' // the last line ended in \n
+       c2 = Bgetc(f)
+       c3 = Bgetc(f)
+       for c1 != '\n' || c2 != '!' || c3 != '\n' {
+               c1 = c2
+               c2 = c3
+               c3 = Bgetc(f)
+               if c3 == Beof {
+                       goto eof
+               }
+       }
+
+       import1 = Boffset(f)
+
+       Bseek(f, import0, 0)
+       ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n
+       Bseek(f, import1, 0)
+
+       ldobjfile(Ctxt, f, pkg, eof-Boffset(f), pn)
+
+       return
+
+eof:
+       Diag("truncated object file: %s", pn)
+}
+
+func zerosig(sp string) {
+       var s *LSym
+
+       s = Linklookup(Ctxt, sp, 0)
+       s.Sig = 0
+}
+
+func mywhatsys() {
+       goroot = obj.Getgoroot()
+       goos = obj.Getgoos()
+       goarch = obj.Getgoarch()
+
+       if !strings.HasPrefix(goarch, Thestring) {
+               log.Fatalf("cannot use %cc with GOARCH=%s", Thearch.Thechar, goarch)
+       }
+}
+
+func pathchar() int {
+       return '/'
+}
+
+var hunk []byte
+
+var nhunk uint32
+
+const (
+       NHUNK = 10 << 20
+)
+
+// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
+/*
+ * Convert raw string to the prefix that will be used in the symbol table.
+ * Invalid bytes turn into %xx.         Right now the only bytes that need
+ * escaping are %, ., and ", but we escape all control characters too.
+ *
+ * If you edit this, edit ../gc/subr.c:/^pathtoprefix too.
+ * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
+ */
+func pathtoprefix(s string) string {
+       slash := strings.LastIndex(s, "/")
+       for i := 0; i < len(s); i++ {
+               c := s[i]
+               if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
+                       goto escape
+               }
+       }
+       return s
+
+escape:
+       var buf bytes.Buffer
+       for i := 0; i < len(s); i++ {
+               c := s[i]
+               if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
+                       fmt.Fprintf(&buf, "%%%02x", c)
+                       continue
+               }
+               buf.WriteByte(c)
+       }
+       return buf.String()
+}
+
+func iconv(p string) string {
+       var fp string
+
+       if p == "" {
+               fp += "<nil>"
+               return fp
+       }
+
+       p = pathtoprefix(p)
+       fp += p
+       return fp
+}
+
+func addsection(seg *Segment, name string, rwx int) *Section {
+       var l **Section
+       var sect *Section
+
+       for l = &seg.Sect; *l != nil; l = &(*l).Next {
+       }
+       sect = new(Section)
+       sect.Rwx = uint8(rwx)
+       sect.Name = name
+       sect.Seg = seg
+       sect.Align = int32(Thearch.Ptrsize) // everything is at least pointer-aligned
+       *l = sect
+       return sect
+}
+
+func Le16(b []byte) uint16 {
+       return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func Le32(b []byte) uint32 {
+       return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func Le64(b []byte) uint64 {
+       return uint64(Le32(b)) | uint64(Le32(b[4:]))<<32
+}
+
+func Be16(b []byte) uint16 {
+       return uint16(b[0])<<8 | uint16(b[1])
+}
+
+func Be32(b []byte) uint32 {
+       return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
+}
+
+func Be64(b []byte) uint64 {
+       return uint64(Be32(b))<<32 | uint64(Be32(b[4:]))
+}
+
+var be = Endian{Be16, Be32, Be64}
+
+var le = Endian{Le16, Le32, Le64}
+
+type Chain struct {
+       sym   *LSym
+       up    *Chain
+       limit int
+}
+
+var morestack *LSym
+
+var newstack *LSym
+
+// TODO: Record enough information in new object files to
+// allow stack checks here.
+
+func haslinkregister() bool {
+       return Thearch.Thechar == '5' || Thearch.Thechar == '9'
+}
+
+func callsize() int {
+       if haslinkregister() {
+               return 0
+       }
+       return Thearch.Regsize
+}
+
+func dostkcheck() {
+       var ch Chain
+       var s *LSym
+
+       morestack = Linklookup(Ctxt, "runtime.morestack", 0)
+       newstack = Linklookup(Ctxt, "runtime.newstack", 0)
+
+       // Every splitting function ensures that there are at least StackLimit
+       // bytes available below SP when the splitting prologue finishes.
+       // If the splitting function calls F, then F begins execution with
+       // at least StackLimit - callsize() bytes available.
+       // Check that every function behaves correctly with this amount
+       // of stack, following direct calls in order to piece together chains
+       // of non-splitting functions.
+       ch.up = nil
+
+       ch.limit = obj.StackLimit - callsize()
+
+       // Check every function, but do the nosplit functions in a first pass,
+       // to make the printed failure chains as short as possible.
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               // runtime.racesymbolizethunk is called from gcc-compiled C
+               // code running on the operating system thread stack.
+               // It uses more than the usual amount of stack but that's okay.
+               if s.Name == "runtime.racesymbolizethunk" {
+                       continue
+               }
+
+               if s.Nosplit != 0 {
+                       Ctxt.Cursym = s
+                       ch.sym = s
+                       stkcheck(&ch, 0)
+               }
+       }
+
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               if s.Nosplit == 0 {
+                       Ctxt.Cursym = s
+                       ch.sym = s
+                       stkcheck(&ch, 0)
+               }
+       }
+}
+
+func stkcheck(up *Chain, depth int) int {
+       var ch Chain
+       var ch1 Chain
+       var s *LSym
+       var limit int
+       var r *Reloc
+       var ri int
+       var endr int
+       var pcsp Pciter
+
+       limit = up.limit
+       s = up.sym
+
+       // Don't duplicate work: only need to consider each
+       // function at top of safe zone once.
+       if limit == obj.StackLimit-callsize() {
+               if s.Stkcheck != 0 {
+                       return 0
+               }
+               s.Stkcheck = 1
+       }
+
+       if depth > 100 {
+               Diag("nosplit stack check too deep")
+               stkbroke(up, 0)
+               return -1
+       }
+
+       if s.External != 0 || s.Pcln == nil {
+               // external function.
+               // should never be called directly.
+               // only diagnose the direct caller.
+               if depth == 1 && s.Type != SXREF {
+                       Diag("call to external function %s", s.Name)
+               }
+               return -1
+       }
+
+       if limit < 0 {
+               stkbroke(up, limit)
+               return -1
+       }
+
+       // morestack looks like it calls functions,
+       // but it switches the stack pointer first.
+       if s == morestack {
+               return 0
+       }
+
+       ch.up = up
+
+       // Walk through sp adjustments in function, consuming relocs.
+       ri = 0
+
+       endr = len(s.R)
+       for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
+               // pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
+
+               // Check stack size in effect for this span.
+               if int32(limit)-pcsp.value < 0 {
+                       stkbroke(up, int(int32(limit)-pcsp.value))
+                       return -1
+               }
+
+               // Process calls in this span.
+               for ; ri < endr && uint32(s.R[ri].Off) < pcsp.nextpc; ri++ {
+                       r = &s.R[ri]
+                       switch r.Type {
+                       // Direct call.
+                       case R_CALL,
+                               R_CALLARM,
+                               R_CALLPOWER:
+                               ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
+
+                               ch.sym = r.Sym
+                               if stkcheck(&ch, depth+1) < 0 {
+                                       return -1
+                               }
+
+                               // If this is a call to morestack, we've just raised our limit back
+                               // to StackLimit beyond the frame size.
+                               if strings.HasPrefix(r.Sym.Name, "runtime.morestack") {
+                                       limit = int(obj.StackLimit + s.Locals)
+                                       if haslinkregister() {
+                                               limit += Thearch.Regsize
+                                       }
+                               }
+
+                               // Indirect call.  Assume it is a call to a splitting function,
+                       // so we have to make sure it can call morestack.
+                       // Arrange the data structures to report both calls, so that
+                       // if there is an error, stkprint shows all the steps involved.
+                       case R_CALLIND:
+                               ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
+
+                               ch.sym = nil
+                               ch1.limit = ch.limit - callsize() // for morestack in called prologue
+                               ch1.up = &ch
+                               ch1.sym = morestack
+                               if stkcheck(&ch1, depth+2) < 0 {
+                                       return -1
+                               }
+                       }
+               }
+       }
+
+       return 0
+}
+
+func stkbroke(ch *Chain, limit int) {
+       Diag("nosplit stack overflow")
+       stkprint(ch, limit)
+}
+
+func stkprint(ch *Chain, limit int) {
+       var name string
+
+       if ch.sym != nil {
+               name = ch.sym.Name
+       } else {
+               name = "function pointer"
+       }
+
+       if ch.up == nil {
+               // top of chain.  ch->sym != nil.
+               if ch.sym.Nosplit != 0 {
+                       fmt.Printf("\t%d\tassumed on entry to %s\n", ch.limit, name)
+               } else {
+                       fmt.Printf("\t%d\tguaranteed after split check in %s\n", ch.limit, name)
+               }
+       } else {
+               stkprint(ch.up, ch.limit+callsize())
+               if !haslinkregister() {
+                       fmt.Printf("\t%d\ton entry to %s\n", ch.limit, name)
+               }
+       }
+
+       if ch.limit != limit {
+               fmt.Printf("\t%d\tafter %s uses %d\n", limit, name, ch.limit-limit)
+       }
+}
+
+func Yconv(s *LSym) string {
+       var fp string
+
+       var fmt_ string
+       var i int
+       var str string
+
+       if s == nil {
+               fp += fmt.Sprintf("<nil>")
+       } else {
+               fmt_ = ""
+               fmt_ += fmt.Sprintf("%s @0x%08x [%d]", s.Name, int64(s.Value), int64(s.Size))
+               for i = 0; int64(i) < s.Size; i++ {
+                       if i%8 == 0 {
+                               fmt_ += fmt.Sprintf("\n\t0x%04x ", i)
+                       }
+                       fmt_ += fmt.Sprintf("%02x ", s.P[i])
+               }
+
+               fmt_ += fmt.Sprintf("\n")
+               for i = 0; i < len(s.R); i++ {
+                       fmt_ += fmt.Sprintf("\t0x%04x[%x] %d %s[%x]\n", s.R[i].Off, s.R[i].Siz, s.R[i].Type, s.R[i].Sym.Name, int64(s.R[i].Add))
+               }
+
+               str = fmt_
+               fp += str
+       }
+
+       return fp
+}
+
+func Cflush() {
+       Bflush(&coutbuf)
+}
+
+func Cpos() int64 {
+       return Boffset(&coutbuf)
+}
+
+func Cseek(p int64) {
+       Bseek(&coutbuf, p, 0)
+}
+
+func Cwrite(p []byte) {
+       Bwrite(&coutbuf, p)
+}
+
+func Cput(c uint8) {
+       Bputc(&coutbuf, c)
+}
+
+func usage() {
+       fmt.Fprintf(os.Stderr, "usage: %cl [options] obj.%c\n", Thearch.Thechar, Thearch.Thechar)
+       obj.Flagprint(2)
+       Exit(2)
+}
+
+func setheadtype(s string) {
+       var h int
+
+       h = headtype(s)
+       if h < 0 {
+               fmt.Fprintf(os.Stderr, "unknown header type -H %s\n", s)
+               Errorexit()
+       }
+
+       headstring = s
+       HEADTYPE = int32(headtype(s))
+}
+
+func setinterp(s string) {
+       Debug['I'] = 1 // denote cmdline interpreter override
+       interpreter = s
+}
+
+func doversion() {
+       fmt.Printf("%cl version %s\n", Thearch.Thechar, obj.Getgoversion())
+       Errorexit()
+}
+
+func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
+       var a *Auto
+       var s *LSym
+       var off int32
+
+       // These symbols won't show up in the first loop below because we
+       // skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
+       s = Linklookup(Ctxt, "runtime.text", 0)
+
+       if s.Type == STEXT {
+               put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
+       }
+       s = Linklookup(Ctxt, "runtime.etext", 0)
+       if s.Type == STEXT {
+               put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
+       }
+
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if s.Hide != 0 || (s.Name[0] == '.' && s.Version == 0 && s.Name != ".rathole") {
+                       continue
+               }
+               switch s.Type & SMASK {
+               case SCONST,
+                       SRODATA,
+                       SSYMTAB,
+                       SPCLNTAB,
+                       SDATA,
+                       SNOPTRDATA,
+                       SELFROSECT,
+                       SMACHOGOT,
+                       STYPE,
+                       SSTRING,
+                       SGOSTRING,
+                       SWINDOWS:
+                       if !s.Reachable {
+                               continue
+                       }
+                       put(s, s.Name, 'D', Symaddr(s), s.Size, int(s.Version), s.Gotype)
+                       continue
+
+               case SBSS,
+                       SNOPTRBSS:
+                       if !s.Reachable {
+                               continue
+                       }
+                       if len(s.P) > 0 {
+                               Diag("%s should not be bss (size=%d type=%d special=%d)", s.Name, int(len(s.P)), s.Type, s.Special)
+                       }
+                       put(s, s.Name, 'B', Symaddr(s), s.Size, int(s.Version), s.Gotype)
+                       continue
+
+               case SFILE:
+                       put(nil, s.Name, 'f', s.Value, 0, int(s.Version), nil)
+                       continue
+               }
+       }
+
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype)
+
+               // NOTE(ality): acid can't produce a stack trace without .frame symbols
+               put(nil, ".frame", 'm', int64(s.Locals)+int64(Thearch.Ptrsize), 0, 0, nil)
+
+               for a = s.Autom; a != nil; a = a.Link {
+                       // Emit a or p according to actual offset, even if label is wrong.
+                       // This avoids negative offsets, which cannot be encoded.
+                       if a.Name != A_AUTO && a.Name != A_PARAM {
+                               continue
+                       }
+
+                       // compute offset relative to FP
+                       if a.Name == A_PARAM {
+                               off = a.Aoffset
+                       } else {
+                               off = a.Aoffset - int32(Thearch.Ptrsize)
+                       }
+
+                       // FP
+                       if off >= 0 {
+                               put(nil, a.Asym.Name, 'p', int64(off), 0, 0, a.Gotype)
+                               continue
+                       }
+
+                       // SP
+                       if off <= int32(-Thearch.Ptrsize) {
+                               put(nil, a.Asym.Name, 'a', -(int64(off) + int64(Thearch.Ptrsize)), 0, 0, a.Gotype)
+                               continue
+                       }
+               }
+       }
+
+       // Otherwise, off is addressing the saved program counter.
+       // Something underhanded is going on. Say nothing.
+       if Debug['v'] != 0 || Debug['n'] != 0 {
+               fmt.Fprintf(&Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
+       }
+       Bflush(&Bso)
+}
+
+func Symaddr(s *LSym) int64 {
+       if !s.Reachable {
+               Diag("unreachable symbol in symaddr - %s", s.Name)
+       }
+       return s.Value
+}
+
+func xdefine(p string, t int, v int64) {
+       var s *LSym
+
+       s = Linklookup(Ctxt, p, 0)
+       s.Type = int16(t)
+       s.Value = v
+       s.Reachable = true
+       s.Special = 1
+}
+
+func datoff(addr int64) int64 {
+       if uint64(addr) >= Segdata.Vaddr {
+               return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
+       }
+       if uint64(addr) >= Segtext.Vaddr {
+               return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
+       }
+       Diag("datoff %#x", addr)
+       return 0
+}
+
+func Entryvalue() int64 {
+       var a string
+       var s *LSym
+
+       a = INITENTRY
+       if a[0] >= '0' && a[0] <= '9' {
+               return atolwhex(a)
+       }
+       s = Linklookup(Ctxt, a, 0)
+       if s.Type == 0 {
+               return INITTEXT
+       }
+       if s.Type != STEXT {
+               Diag("entry not text: %s", s.Name)
+       }
+       return s.Value
+}
+
+func undefsym(s *LSym) {
+       var i int
+       var r *Reloc
+
+       Ctxt.Cursym = s
+       for i = 0; i < len(s.R); i++ {
+               r = &s.R[i]
+               if r.Sym == nil { // happens for some external ARM relocs
+                       continue
+               }
+               if r.Sym.Type == Sxxx || r.Sym.Type == SXREF {
+                       Diag("undefined: %s", r.Sym.Name)
+               }
+               if !r.Sym.Reachable {
+                       Diag("use of unreachable symbol: %s", r.Sym.Name)
+               }
+       }
+}
+
+func undef() {
+       var s *LSym
+
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               undefsym(s)
+       }
+       for s = datap; s != nil; s = s.Next {
+               undefsym(s)
+       }
+       if nerrors > 0 {
+               Errorexit()
+       }
+}
+
+func callgraph() {
+       var s *LSym
+       var r *Reloc
+       var i int
+
+       if Debug['c'] == 0 {
+               return
+       }
+
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               for i = 0; i < len(s.R); i++ {
+                       r = &s.R[i]
+                       if r.Sym == nil {
+                               continue
+                       }
+                       if (r.Type == R_CALL || r.Type == R_CALLARM || r.Type == R_CALLPOWER) && r.Sym.Type == STEXT {
+                               fmt.Fprintf(&Bso, "%s calls %s\n", s.Name, r.Sym.Name)
+                       }
+               }
+       }
+}
+
+func Diag(format string, args ...interface{}) {
+       tn := ""
+       sep := ""
+       if Ctxt.Cursym != nil {
+               tn = Ctxt.Cursym.Name
+               sep = ": "
+       }
+       fmt.Printf("%s%s%s\n", tn, sep, fmt.Sprintf(format, args...))
+
+       nerrors++
+       if nerrors > 20 {
+               fmt.Printf("too many errors\n")
+               Errorexit()
+       }
+}
+
+func checkgo() {
+       var s *LSym
+       var r *Reloc
+       var i int
+       var changed int
+
+       if Debug['C'] == 0 {
+               return
+       }
+
+       // TODO(rsc,khr): Eventually we want to get to no Go-called C functions at all,
+       // which would simplify this logic quite a bit.
+
+       // Mark every Go-called C function with cfunc=2, recursively.
+       for {
+               changed = 0
+               for s = Ctxt.Textp; s != nil; s = s.Next {
+                       if s.Cfunc == 0 || (s.Cfunc == 2 && s.Nosplit != 0) {
+                               for i = 0; i < len(s.R); i++ {
+                                       r = &s.R[i]
+                                       if r.Sym == nil {
+                                               continue
+                                       }
+                                       if (r.Type == R_CALL || r.Type == R_CALLARM) && r.Sym.Type == STEXT {
+                                               if r.Sym.Cfunc == 1 {
+                                                       changed = 1
+                                                       r.Sym.Cfunc = 2
+                                               }
+                                       }
+                               }
+                       }
+               }
+               if changed == 0 {
+                       break
+               }
+       }
+
+       // Complain about Go-called C functions that can split the stack
+       // (that can be preempted for garbage collection or trigger a stack copy).
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               if s.Cfunc == 0 || (s.Cfunc == 2 && s.Nosplit != 0) {
+                       for i = 0; i < len(s.R); i++ {
+                               r = &s.R[i]
+                               if r.Sym == nil {
+                                       continue
+                               }
+                               if (r.Type == R_CALL || r.Type == R_CALLARM) && r.Sym.Type == STEXT {
+                                       if s.Cfunc == 0 && r.Sym.Cfunc == 2 && r.Sym.Nosplit == 0 {
+                                               fmt.Printf("Go %s calls C %s\n", s.Name, r.Sym.Name)
+                                       } else if s.Cfunc == 2 && s.Nosplit != 0 && r.Sym.Nosplit == 0 {
+                                               fmt.Printf("Go calls C %s calls %s\n", s.Name, r.Sym.Name)
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+func Rnd(v int64, r int64) int64 {
+       var c int64
+
+       if r <= 0 {
+               return v
+       }
+       v += r - 1
+       c = v % r
+       if c < 0 {
+               c += r
+       }
+       v -= c
+       return v
+}
diff --git a/src/cmd/internal/ld/link.go b/src/cmd/internal/ld/link.go
new file mode 100644 (file)
index 0000000..69702fb
--- /dev/null
@@ -0,0 +1,299 @@
+// Derived from Inferno utils/6l/l.h and related files.
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+import "encoding/binary"
+
+type LSym struct {
+       Name        string
+       Extname     string
+       Type        int16
+       Version     int16
+       Dupok       uint8
+       Cfunc       uint8
+       External    uint8
+       Nosplit     uint8
+       Reachable   bool
+       Cgoexport   uint8
+       Special     uint8
+       Stkcheck    uint8
+       Hide        uint8
+       Leaf        uint8
+       Localentry  uint8
+       Onlist      uint8
+       Dynid       int32
+       Sig         int32
+       Plt         int32
+       Got         int32
+       Align       int32
+       Elfsym      int32
+       Args        int32
+       Locals      int32
+       Value       int64
+       Size        int64
+       Hash        *LSym
+       Allsym      *LSym
+       Next        *LSym
+       Sub         *LSym
+       Outer       *LSym
+       Gotype      *LSym
+       Reachparent *LSym
+       Queue       *LSym
+       File        string
+       Dynimplib   string
+       Dynimpvers  string
+       Sect        interface{}
+       Autom       *Auto
+       Pcln        *Pcln
+       P           []byte
+       R           []Reloc
+}
+
+type Reloc struct {
+       Off     int32
+       Siz     uint8
+       Done    uint8
+       Type    int32
+       Variant int32
+       Add     int64
+       Xadd    int64
+       Sym     *LSym
+       Xsym    *LSym
+}
+
+type Auto struct {
+       Asym    *LSym
+       Link    *Auto
+       Aoffset int32
+       Name    int16
+       Gotype  *LSym
+}
+
+type Link struct {
+       Thechar   int32
+       Thestring string
+       Goarm     int32
+       Headtype  int
+       Arch      *LinkArch
+       Debugasm  int32
+       Debugvlog int32
+       Bso       *Biobuf
+       Windows   int32
+       Goroot    string
+       Hash      map[symVer]*LSym
+       Allsym    *LSym
+       Nsymbol   int32
+       Tlsg      *LSym
+       Libdir    []string
+       Library   []Library
+       Tlsoffset int
+       Diag      func(string, ...interface{})
+       Cursym    *LSym
+       Version   int
+       Textp     *LSym
+       Etextp    *LSym
+       Nhistfile int32
+       Filesyms  *LSym
+}
+
+type LinkArch struct {
+       ByteOrder binary.ByteOrder
+       Name      string
+       Thechar   int
+       Endian    int32
+       Minlc     int
+       Ptrsize   int
+       Regsize   int
+}
+
+type Library struct {
+       Objref string
+       Srcref string
+       File   string
+       Pkg    string
+}
+
+type Pcln struct {
+       Pcsp        Pcdata
+       Pcfile      Pcdata
+       Pcline      Pcdata
+       Pcdata      []Pcdata
+       Npcdata     int
+       Funcdata    []*LSym
+       Funcdataoff []int64
+       Nfuncdata   int
+       File        []*LSym
+       Nfile       int
+       Mfile       int
+       Lastfile    *LSym
+       Lastindex   int
+}
+
+type Pcdata struct {
+       P []byte
+}
+
+type Pciter struct {
+       d       Pcdata
+       p       []byte
+       pc      uint32
+       nextpc  uint32
+       pcscale uint32
+       value   int32
+       start   int
+       done    int
+}
+
+// LSym.type
+const (
+       Sxxx = iota
+       STEXT
+       SELFRXSECT
+       STYPE
+       SSTRING
+       SGOSTRING
+       SGOFUNC
+       SRODATA
+       SFUNCTAB
+       STYPELINK
+       SSYMTAB
+       SPCLNTAB
+       SELFROSECT
+       SMACHOPLT
+       SELFSECT
+       SMACHO
+       SMACHOGOT
+       SWINDOWS
+       SELFGOT
+       SNOPTRDATA
+       SINITARR
+       SDATA
+       SBSS
+       SNOPTRBSS
+       STLSBSS
+       SXREF
+       SMACHOSYMSTR
+       SMACHOSYMTAB
+       SMACHOINDIRECTPLT
+       SMACHOINDIRECTGOT
+       SFILE
+       SFILEPATH
+       SCONST
+       SDYNIMPORT
+       SHOSTOBJ
+       SSUB    = 1 << 8
+       SMASK   = SSUB - 1
+       SHIDDEN = 1 << 9
+)
+
+// Reloc.type
+const (
+       R_ADDR = 1 + iota
+       R_ADDRPOWER
+       R_SIZE
+       R_CALL
+       R_CALLARM
+       R_CALLIND
+       R_CALLPOWER
+       R_CONST
+       R_PCREL
+       R_TLS
+       R_TLS_LE
+       R_TLS_IE
+       R_GOTOFF
+       R_PLT0
+       R_PLT1
+       R_PLT2
+       R_USEFIELD
+       R_POWER_TOC
+)
+
+// Reloc.variant
+const (
+       RV_NONE = iota
+       RV_POWER_LO
+       RV_POWER_HI
+       RV_POWER_HA
+       RV_POWER_DS
+       RV_CHECK_OVERFLOW = 1 << 8
+       RV_TYPE_MASK      = RV_CHECK_OVERFLOW - 1
+)
+
+// Auto.name
+const (
+       A_AUTO = 1 + iota
+       A_PARAM
+)
+
+const (
+       LINKHASH = 100003
+)
+
+// Pcdata iterator.
+//     for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
+
+// symbol version, incremented each time a file is loaded.
+// version==1 is reserved for savehist.
+const (
+       HistVersion = 1
+)
+
+// Link holds the context for writing object code from a compiler
+// to be linker input or for reading that input into the linker.
+
+const (
+       LittleEndian = 0x04030201
+       BigEndian    = 0x01020304
+)
+
+// LinkArch is the definition of a single architecture.
+
+/* executable header types */
+const (
+       Hunknown = 0 + iota
+       Hdarwin
+       Hdragonfly
+       Helf
+       Hfreebsd
+       Hlinux
+       Hnacl
+       Hnetbsd
+       Hopenbsd
+       Hplan9
+       Hsolaris
+       Hwindows
+)
+
+const (
+       LinkAuto = 0 + iota
+       LinkInternal
+       LinkExternal
+)
diff --git a/src/cmd/internal/ld/macho.go b/src/cmd/internal/ld/macho.go
new file mode 100644 (file)
index 0000000..6349642
--- /dev/null
@@ -0,0 +1,892 @@
+// Copyright 2009 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 ld
+
+import (
+       "sort"
+       "strings"
+)
+
+type MachoHdr struct {
+       cpu    uint32
+       subcpu uint32
+}
+
+type MachoSect struct {
+       name    string
+       segname string
+       addr    uint64
+       size    uint64
+       off     uint32
+       align   uint32
+       reloc   uint32
+       nreloc  uint32
+       flag    uint32
+       res1    uint32
+       res2    uint32
+}
+
+type MachoSeg struct {
+       name       string
+       vsize      uint64
+       vaddr      uint64
+       fileoffset uint64
+       filesize   uint64
+       prot1      uint32
+       prot2      uint32
+       nsect      uint32
+       msect      uint32
+       sect       []MachoSect
+       flag       uint32
+}
+
+type MachoLoad struct {
+       type_ uint32
+       data  []uint32
+}
+
+/*
+ * Total amount of space to reserve at the start of the file
+ * for Header, PHeaders, and SHeaders.
+ * May waste some.
+ */
+const (
+       INITIAL_MACHO_HEADR = 4 * 1024
+)
+
+const (
+       MACHO_CPU_AMD64               = 1<<24 | 7
+       MACHO_CPU_386                 = 7
+       MACHO_SUBCPU_X86              = 3
+       MACHO_CPU_ARM                 = 12
+       MACHO_SUBCPU_ARM              = 0
+       MACHO_SUBCPU_ARMV7            = 9
+       MACHO32SYMSIZE                = 12
+       MACHO64SYMSIZE                = 16
+       MACHO_X86_64_RELOC_UNSIGNED   = 0
+       MACHO_X86_64_RELOC_SIGNED     = 1
+       MACHO_X86_64_RELOC_BRANCH     = 2
+       MACHO_X86_64_RELOC_GOT_LOAD   = 3
+       MACHO_X86_64_RELOC_GOT        = 4
+       MACHO_X86_64_RELOC_SUBTRACTOR = 5
+       MACHO_X86_64_RELOC_SIGNED_1   = 6
+       MACHO_X86_64_RELOC_SIGNED_2   = 7
+       MACHO_X86_64_RELOC_SIGNED_4   = 8
+       MACHO_ARM_RELOC_VANILLA       = 0
+       MACHO_ARM_RELOC_BR24          = 5
+       MACHO_GENERIC_RELOC_VANILLA   = 0
+       MACHO_FAKE_GOTPCREL           = 100
+)
+
+// Copyright 2009 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.
+
+// Mach-O file writing
+// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
+
+var macho64 bool
+
+var machohdr MachoHdr
+
+var load []MachoLoad
+
+var seg [16]MachoSeg
+
+var nload int
+
+var mload int
+
+var nseg int
+
+var ndebug int
+
+var nsect int
+
+const (
+       SymKindLocal = 0 + iota
+       SymKindExtdef
+       SymKindUndef
+       NumSymKind
+)
+
+var nkind [NumSymKind]int
+
+var sortsym []*LSym
+
+var nsortsym int
+
+// Amount of space left for adding load commands
+// that refer to dynamic libraries.  Because these have
+// to go in the Mach-O header, we can't just pick a
+// "big enough" header size.  The initial header is
+// one page, the non-dynamic library stuff takes
+// up about 1300 bytes; we overestimate that as 2k.
+var load_budget int = INITIAL_MACHO_HEADR - 2*1024
+
+func Machoinit() {
+       switch Thearch.Thechar {
+       // 64-bit architectures
+       case '6',
+               '9':
+               macho64 = true
+
+               // 32-bit architectures
+       default:
+               break
+       }
+}
+
+func getMachoHdr() *MachoHdr {
+       return &machohdr
+}
+
+func newMachoLoad(type_ uint32, ndata uint32) *MachoLoad {
+       if macho64 && (ndata&1 != 0) {
+               ndata++
+       }
+
+       load = append(load, MachoLoad{})
+       l := &load[len(load)-1]
+       l.type_ = type_
+       l.data = make([]uint32, ndata)
+       return l
+}
+
+func newMachoSeg(name string, msect int) *MachoSeg {
+       var s *MachoSeg
+
+       if nseg >= len(seg) {
+               Diag("too many segs")
+               Errorexit()
+       }
+
+       s = &seg[nseg]
+       nseg++
+       s.name = name
+       s.msect = uint32(msect)
+       s.sect = make([]MachoSect, msect)
+       return s
+}
+
+func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
+       var s *MachoSect
+
+       if seg.nsect >= seg.msect {
+               Diag("too many sects in segment %s", seg.name)
+               Errorexit()
+       }
+
+       s = &seg.sect[seg.nsect]
+       seg.nsect++
+       s.name = name
+       s.segname = segname
+       nsect++
+       return s
+}
+
+// Generic linking code.
+
+var dylib []string
+
+var ndylib int
+
+var linkoff int64
+
+func machowrite() int {
+       var o1 int64
+       var loadsize int
+       var i int
+       var j int
+       var s *MachoSeg
+       var t *MachoSect
+       var l *MachoLoad
+
+       o1 = Cpos()
+
+       loadsize = 4 * 4 * ndebug
+       for i = 0; i < len(load); i++ {
+               loadsize += 4 * (len(load[i].data) + 2)
+       }
+       if macho64 {
+               loadsize += 18 * 4 * nseg
+               loadsize += 20 * 4 * nsect
+       } else {
+               loadsize += 14 * 4 * nseg
+               loadsize += 17 * 4 * nsect
+       }
+
+       if macho64 {
+               Thearch.Lput(0xfeedfacf)
+       } else {
+               Thearch.Lput(0xfeedface)
+       }
+       Thearch.Lput(machohdr.cpu)
+       Thearch.Lput(machohdr.subcpu)
+       if Linkmode == LinkExternal {
+               Thearch.Lput(1) /* file type - mach object */
+       } else {
+               Thearch.Lput(2) /* file type - mach executable */
+       }
+       Thearch.Lput(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
+       Thearch.Lput(uint32(loadsize))
+       Thearch.Lput(1) /* flags - no undefines */
+       if macho64 {
+               Thearch.Lput(0) /* reserved */
+       }
+
+       for i = 0; i < nseg; i++ {
+               s = &seg[i]
+               if macho64 {
+                       Thearch.Lput(25) /* segment 64 */
+                       Thearch.Lput(72 + 80*s.nsect)
+                       strnput(s.name, 16)
+                       Thearch.Vput(s.vaddr)
+                       Thearch.Vput(s.vsize)
+                       Thearch.Vput(s.fileoffset)
+                       Thearch.Vput(s.filesize)
+                       Thearch.Lput(s.prot1)
+                       Thearch.Lput(s.prot2)
+                       Thearch.Lput(s.nsect)
+                       Thearch.Lput(s.flag)
+               } else {
+                       Thearch.Lput(1) /* segment 32 */
+                       Thearch.Lput(56 + 68*s.nsect)
+                       strnput(s.name, 16)
+                       Thearch.Lput(uint32(s.vaddr))
+                       Thearch.Lput(uint32(s.vsize))
+                       Thearch.Lput(uint32(s.fileoffset))
+                       Thearch.Lput(uint32(s.filesize))
+                       Thearch.Lput(s.prot1)
+                       Thearch.Lput(s.prot2)
+                       Thearch.Lput(s.nsect)
+                       Thearch.Lput(s.flag)
+               }
+
+               for j = 0; uint32(j) < s.nsect; j++ {
+                       t = &s.sect[j]
+                       if macho64 {
+                               strnput(t.name, 16)
+                               strnput(t.segname, 16)
+                               Thearch.Vput(t.addr)
+                               Thearch.Vput(t.size)
+                               Thearch.Lput(t.off)
+                               Thearch.Lput(t.align)
+                               Thearch.Lput(t.reloc)
+                               Thearch.Lput(t.nreloc)
+                               Thearch.Lput(t.flag)
+                               Thearch.Lput(t.res1) /* reserved */
+                               Thearch.Lput(t.res2) /* reserved */
+                               Thearch.Lput(0)      /* reserved */
+                       } else {
+                               strnput(t.name, 16)
+                               strnput(t.segname, 16)
+                               Thearch.Lput(uint32(t.addr))
+                               Thearch.Lput(uint32(t.size))
+                               Thearch.Lput(t.off)
+                               Thearch.Lput(t.align)
+                               Thearch.Lput(t.reloc)
+                               Thearch.Lput(t.nreloc)
+                               Thearch.Lput(t.flag)
+                               Thearch.Lput(t.res1) /* reserved */
+                               Thearch.Lput(t.res2) /* reserved */
+                       }
+               }
+       }
+
+       for i = 0; i < len(load); i++ {
+               l = &load[i]
+               Thearch.Lput(l.type_)
+               Thearch.Lput(4 * (uint32(len(l.data)) + 2))
+               for j = 0; j < len(l.data); j++ {
+                       Thearch.Lput(l.data[j])
+               }
+       }
+
+       return int(Cpos() - o1)
+}
+
+func domacho() {
+       var s *LSym
+
+       if Debug['d'] != 0 {
+               return
+       }
+
+       // empirically, string table must begin with " \x00".
+       s = Linklookup(Ctxt, ".machosymstr", 0)
+
+       s.Type = SMACHOSYMSTR
+       s.Reachable = true
+       Adduint8(Ctxt, s, ' ')
+       Adduint8(Ctxt, s, '\x00')
+
+       s = Linklookup(Ctxt, ".machosymtab", 0)
+       s.Type = SMACHOSYMTAB
+       s.Reachable = true
+
+       if Linkmode != LinkExternal {
+               s = Linklookup(Ctxt, ".plt", 0) // will be __symbol_stub
+               s.Type = SMACHOPLT
+               s.Reachable = true
+
+               s = Linklookup(Ctxt, ".got", 0) // will be __nl_symbol_ptr
+               s.Type = SMACHOGOT
+               s.Reachable = true
+               s.Align = 4
+
+               s = Linklookup(Ctxt, ".linkedit.plt", 0) // indirect table for .plt
+               s.Type = SMACHOINDIRECTPLT
+               s.Reachable = true
+
+               s = Linklookup(Ctxt, ".linkedit.got", 0) // indirect table for .got
+               s.Type = SMACHOINDIRECTGOT
+               s.Reachable = true
+       }
+}
+
+func Machoadddynlib(lib string) {
+       // Will need to store the library name rounded up
+       // and 24 bytes of header metadata.  If not enough
+       // space, grab another page of initial space at the
+       // beginning of the output file.
+       load_budget -= (len(lib)+7)/8*8 + 24
+
+       if load_budget < 0 {
+               HEADR += 4096
+               INITTEXT += 4096
+               load_budget += 4096
+       }
+
+       dylib = append(dylib, lib)
+}
+
+func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
+       var msect *MachoSect
+       var buf string
+
+       buf = "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
+
+       msect = newMachoSect(mseg, buf, segname)
+       if sect.Rellen > 0 {
+               msect.reloc = uint32(sect.Reloff)
+               msect.nreloc = uint32(sect.Rellen / 8)
+       }
+
+       for 1<<msect.align < sect.Align {
+               msect.align++
+       }
+       msect.addr = sect.Vaddr
+       msect.size = sect.Length
+
+       if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
+               // data in file
+               if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
+                       Diag("macho cannot represent section %s crossing data and bss", sect.Name)
+               }
+               msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
+       } else {
+               // zero fill
+               msect.off = 0
+
+               msect.flag |= 1
+       }
+
+       if sect.Rwx&1 != 0 {
+               msect.flag |= 0x400 /* has instructions */
+       }
+
+       if sect.Name == ".plt" {
+               msect.name = "__symbol_stub1"
+               msect.flag = 0x80000408 /* only instructions, code, symbol stubs */
+               msect.res1 = 0          //nkind[SymKindLocal];
+               msect.res2 = 6
+       }
+
+       if sect.Name == ".got" {
+               msect.name = "__nl_symbol_ptr"
+               msect.flag = 6                                                     /* section with nonlazy symbol pointers */
+               msect.res1 = uint32(Linklookup(Ctxt, ".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
+       }
+}
+
+func Asmbmacho() {
+       var v int64
+       var w int64
+       var va int64
+       var a int
+       var i int
+       var mh *MachoHdr
+       var ms *MachoSeg
+       var ml *MachoLoad
+       var sect *Section
+
+       /* apple MACH */
+       va = INITTEXT - int64(HEADR)
+
+       mh = getMachoHdr()
+       switch Thearch.Thechar {
+       default:
+               Diag("unknown mach architecture")
+               Errorexit()
+               fallthrough
+
+       case '5':
+               mh.cpu = MACHO_CPU_ARM
+               mh.subcpu = MACHO_SUBCPU_ARMV7
+
+       case '6':
+               mh.cpu = MACHO_CPU_AMD64
+               mh.subcpu = MACHO_SUBCPU_X86
+
+       case '8':
+               mh.cpu = MACHO_CPU_386
+               mh.subcpu = MACHO_SUBCPU_X86
+       }
+
+       ms = nil
+       if Linkmode == LinkExternal {
+               /* segment for entire file */
+               ms = newMachoSeg("", 40)
+
+               ms.fileoffset = Segtext.Fileoff
+               ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
+       }
+
+       /* segment for zero page */
+       if Linkmode != LinkExternal {
+               ms = newMachoSeg("__PAGEZERO", 0)
+               ms.vsize = uint64(va)
+       }
+
+       /* text */
+       v = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND))
+
+       if Linkmode != LinkExternal {
+               ms = newMachoSeg("__TEXT", 20)
+               ms.vaddr = uint64(va)
+               ms.vsize = uint64(v)
+               ms.fileoffset = 0
+               ms.filesize = uint64(v)
+               ms.prot1 = 7
+               ms.prot2 = 5
+       }
+
+       for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+               machoshbits(ms, sect, "__TEXT")
+       }
+
+       /* data */
+       if Linkmode != LinkExternal {
+               w = int64(Segdata.Length)
+               ms = newMachoSeg("__DATA", 20)
+               ms.vaddr = uint64(va) + uint64(v)
+               ms.vsize = uint64(w)
+               ms.fileoffset = uint64(v)
+               ms.filesize = Segdata.Filelen
+               ms.prot1 = 3
+               ms.prot2 = 3
+       }
+
+       for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+               machoshbits(ms, sect, "__DATA")
+       }
+
+       if Linkmode != LinkExternal {
+               switch Thearch.Thechar {
+               default:
+                       Diag("unknown macho architecture")
+                       Errorexit()
+                       fallthrough
+
+               case '5':
+                       ml = newMachoLoad(5, 17+2)           /* unix thread */
+                       ml.data[0] = 1                       /* thread type */
+                       ml.data[1] = 17                      /* word count */
+                       ml.data[2+15] = uint32(Entryvalue()) /* start pc */
+
+               case '6':
+                       ml = newMachoLoad(5, 42+2)                         /* unix thread */
+                       ml.data[0] = 4                                     /* thread type */
+                       ml.data[1] = 42                                    /* word count */
+                       ml.data[2+32] = uint32(Entryvalue())               /* start pc */
+                       ml.data[2+32+1] = uint32(Entryvalue() >> 16 >> 16) // hide >>32 for 8l
+
+               case '8':
+                       ml = newMachoLoad(5, 16+2)           /* unix thread */
+                       ml.data[0] = 1                       /* thread type */
+                       ml.data[1] = 16                      /* word count */
+                       ml.data[2+10] = uint32(Entryvalue()) /* start pc */
+               }
+       }
+
+       if Debug['d'] == 0 {
+               var s1 *LSym
+               var s2 *LSym
+               var s3 *LSym
+               var s4 *LSym
+
+               // must match domacholink below
+               s1 = Linklookup(Ctxt, ".machosymtab", 0)
+
+               s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
+               s3 = Linklookup(Ctxt, ".linkedit.got", 0)
+               s4 = Linklookup(Ctxt, ".machosymstr", 0)
+
+               if Linkmode != LinkExternal {
+                       ms = newMachoSeg("__LINKEDIT", 0)
+                       ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(INITRND)))
+                       ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
+                       ms.fileoffset = uint64(linkoff)
+                       ms.filesize = ms.vsize
+                       ms.prot1 = 7
+                       ms.prot2 = 3
+               }
+
+               ml = newMachoLoad(2, 4)                                    /* LC_SYMTAB */
+               ml.data[0] = uint32(linkoff)                               /* symoff */
+               ml.data[1] = uint32(nsortsym)                              /* nsyms */
+               ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */
+               ml.data[3] = uint32(s4.Size)                               /* strsize */
+
+               machodysymtab()
+
+               if Linkmode != LinkExternal {
+                       ml = newMachoLoad(14, 6) /* LC_LOAD_DYLINKER */
+                       ml.data[0] = 12          /* offset to string */
+                       stringtouint32(ml.data[1:], "/usr/lib/dyld")
+
+                       for i = 0; i < len(dylib); i++ {
+                               ml = newMachoLoad(12, 4+(uint32(len(dylib[i]))+1+7)/8*2) /* LC_LOAD_DYLIB */
+                               ml.data[0] = 24                                          /* offset of string from beginning of load */
+                               ml.data[1] = 0                                           /* time stamp */
+                               ml.data[2] = 0                                           /* version */
+                               ml.data[3] = 0                                           /* compatibility version */
+                               stringtouint32(ml.data[4:], dylib[i])
+                       }
+               }
+       }
+
+       // TODO: dwarf headers go in ms too
+       if Debug['s'] == 0 && Linkmode != LinkExternal {
+               dwarfaddmachoheaders()
+       }
+
+       a = machowrite()
+       if int32(a) > HEADR {
+               Diag("HEADR too small: %d > %d", a, HEADR)
+       }
+}
+
+func symkind(s *LSym) int {
+       if s.Type == SDYNIMPORT {
+               return SymKindUndef
+       }
+       if s.Cgoexport != 0 {
+               return SymKindExtdef
+       }
+       return SymKindLocal
+}
+
+func addsym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
+       if s == nil {
+               return
+       }
+
+       switch type_ {
+       default:
+               return
+
+       case 'D',
+               'B',
+               'T':
+               break
+       }
+
+       if sortsym != nil {
+               sortsym[nsortsym] = s
+               nkind[symkind(s)]++
+       }
+
+       nsortsym++
+}
+
+type machoscmp []*LSym
+
+func (x machoscmp) Len() int {
+       return len(x)
+}
+
+func (x machoscmp) Swap(i, j int) {
+       x[i], x[j] = x[j], x[i]
+}
+
+func (x machoscmp) Less(i, j int) bool {
+       var s1 *LSym
+       var s2 *LSym
+       var k1 int
+       var k2 int
+
+       s1 = x[i]
+       s2 = x[j]
+
+       k1 = symkind(s1)
+       k2 = symkind(s2)
+       if k1 != k2 {
+               return k1-k2 < 0
+       }
+
+       return stringsCompare(s1.Extname, s2.Extname) < 0
+}
+
+func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
+       var s *LSym
+
+       genasmsym(put)
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
+                       if s.Reachable {
+                               put(s, "", 'D', 0, 0, 0, nil)
+                       }
+               }
+       }
+}
+
+func machosymorder() {
+       var i int
+
+       // On Mac OS X Mountain Lion, we must sort exported symbols
+       // So we sort them here and pre-allocate dynid for them
+       // See http://golang.org/issue/4029
+       for i = 0; i < len(dynexp); i++ {
+               dynexp[i].Reachable = true
+       }
+       machogenasmsym(addsym)
+       sortsym = make([]*LSym, nsortsym)
+       nsortsym = 0
+       machogenasmsym(addsym)
+       sort.Sort(machoscmp(sortsym[:nsortsym]))
+       for i = 0; i < nsortsym; i++ {
+               sortsym[i].Dynid = int32(i)
+       }
+}
+
+func machosymtab() {
+       var i int
+       var symtab *LSym
+       var symstr *LSym
+       var s *LSym
+       var o *LSym
+       var p string
+
+       symtab = Linklookup(Ctxt, ".machosymtab", 0)
+       symstr = Linklookup(Ctxt, ".machosymstr", 0)
+
+       for i = 0; i < nsortsym; i++ {
+               s = sortsym[i]
+               Adduint32(Ctxt, symtab, uint32(symstr.Size))
+
+               // Only add _ to C symbols. Go symbols have dot in the name.
+               if !strings.Contains(s.Extname, ".") {
+                       Adduint8(Ctxt, symstr, '_')
+               }
+
+               // replace "·" as ".", because DTrace cannot handle it.
+               if !strings.Contains(s.Extname, "·") {
+                       Addstring(symstr, s.Extname)
+               } else {
+                       for p = s.Extname; p != ""; p = p[1:] {
+                               if uint8(p[0]) == 0xc2 && uint8((p[1:])[0]) == 0xb7 {
+                                       Adduint8(Ctxt, symstr, '.')
+                                       p = p[1:]
+                               } else {
+                                       Adduint8(Ctxt, symstr, uint8(p[0]))
+                               }
+                       }
+
+                       Adduint8(Ctxt, symstr, '\x00')
+               }
+
+               if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
+                       Adduint8(Ctxt, symtab, 0x01)                // type N_EXT, external symbol
+                       Adduint8(Ctxt, symtab, 0)                   // no section
+                       Adduint16(Ctxt, symtab, 0)                  // desc
+                       adduintxx(Ctxt, symtab, 0, Thearch.Ptrsize) // no value
+               } else {
+                       if s.Cgoexport != 0 {
+                               Adduint8(Ctxt, symtab, 0x0f)
+                       } else {
+                               Adduint8(Ctxt, symtab, 0x0e)
+                       }
+                       o = s
+                       for o.Outer != nil {
+                               o = o.Outer
+                       }
+                       if o.Sect == nil {
+                               Diag("missing section for %s", s.Name)
+                               Adduint8(Ctxt, symtab, 0)
+                       } else {
+                               Adduint8(Ctxt, symtab, uint8((o.Sect.(*Section)).Extnum))
+                       }
+                       Adduint16(Ctxt, symtab, 0) // desc
+                       adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize)
+               }
+       }
+}
+
+func machodysymtab() {
+       var n int
+       var ml *MachoLoad
+       var s1 *LSym
+       var s2 *LSym
+       var s3 *LSym
+
+       ml = newMachoLoad(11, 18) /* LC_DYSYMTAB */
+
+       n = 0
+       ml.data[0] = uint32(n)                   /* ilocalsym */
+       ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
+       n += nkind[SymKindLocal]
+
+       ml.data[2] = uint32(n)                    /* iextdefsym */
+       ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
+       n += nkind[SymKindExtdef]
+
+       ml.data[4] = uint32(n)                   /* iundefsym */
+       ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
+
+       ml.data[6] = 0  /* tocoffset */
+       ml.data[7] = 0  /* ntoc */
+       ml.data[8] = 0  /* modtaboff */
+       ml.data[9] = 0  /* nmodtab */
+       ml.data[10] = 0 /* extrefsymoff */
+       ml.data[11] = 0 /* nextrefsyms */
+
+       // must match domacholink below
+       s1 = Linklookup(Ctxt, ".machosymtab", 0)
+
+       s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
+       s3 = Linklookup(Ctxt, ".linkedit.got", 0)
+       ml.data[12] = uint32(linkoff + s1.Size)       /* indirectsymoff */
+       ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */
+
+       ml.data[14] = 0 /* extreloff */
+       ml.data[15] = 0 /* nextrel */
+       ml.data[16] = 0 /* locreloff */
+       ml.data[17] = 0 /* nlocrel */
+}
+
+func Domacholink() int64 {
+       var size int
+       var s1 *LSym
+       var s2 *LSym
+       var s3 *LSym
+       var s4 *LSym
+
+       machosymtab()
+
+       // write data that will be linkedit section
+       s1 = Linklookup(Ctxt, ".machosymtab", 0)
+
+       s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
+       s3 = Linklookup(Ctxt, ".linkedit.got", 0)
+       s4 = Linklookup(Ctxt, ".machosymstr", 0)
+
+       // Force the linkedit section to end on a 16-byte
+       // boundary.  This allows pure (non-cgo) Go binaries
+       // to be code signed correctly.
+       //
+       // Apple's codesign_allocate (a helper utility for
+       // the codesign utility) can do this fine itself if
+       // it is run on a dynamic Mach-O binary.  However,
+       // when it is run on a pure (non-cgo) Go binary, where
+       // the linkedit section is mostly empty, it fails to
+       // account for the extra padding that it itself adds
+       // when adding the LC_CODE_SIGNATURE load command
+       // (which must be aligned on a 16-byte boundary).
+       //
+       // By forcing the linkedit section to end on a 16-byte
+       // boundary, codesign_allocate will not need to apply
+       // any alignment padding itself, working around the
+       // issue.
+       for s4.Size%16 != 0 {
+               Adduint8(Ctxt, s4, 0)
+       }
+
+       size = int(s1.Size + s2.Size + s3.Size + s4.Size)
+
+       if size > 0 {
+               linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND)) + Rnd(int64(Segdata.Filelen), int64(INITRND)) + Rnd(int64(Segdwarf.Filelen), int64(INITRND))
+               Cseek(linkoff)
+
+               Cwrite(s1.P[:s1.Size])
+               Cwrite(s2.P[:s2.Size])
+               Cwrite(s3.P[:s3.Size])
+               Cwrite(s4.P[:s4.Size])
+       }
+
+       return Rnd(int64(size), int64(INITRND))
+}
+
+func machorelocsect(sect *Section, first *LSym) {
+       var sym *LSym
+       var eaddr int32
+       var ri int
+       var r *Reloc
+
+       // If main section has no bits, nothing to relocate.
+       if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
+               return
+       }
+
+       sect.Reloff = uint64(Cpos())
+       for sym = first; sym != nil; sym = sym.Next {
+               if !sym.Reachable {
+                       continue
+               }
+               if uint64(sym.Value) >= sect.Vaddr {
+                       break
+               }
+       }
+
+       eaddr = int32(sect.Vaddr + sect.Length)
+       for ; sym != nil; sym = sym.Next {
+               if !sym.Reachable {
+                       continue
+               }
+               if sym.Value >= int64(eaddr) {
+                       break
+               }
+               Ctxt.Cursym = sym
+
+               for ri = 0; ri < len(sym.R); ri++ {
+                       r = &sym.R[ri]
+                       if r.Done != 0 {
+                               continue
+                       }
+                       if Thearch.Machoreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
+                               Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+                       }
+               }
+       }
+
+       sect.Rellen = uint64(Cpos()) - sect.Reloff
+}
+
+func Machoemitreloc() {
+       var sect *Section
+
+       for Cpos()&7 != 0 {
+               Cput(0)
+       }
+
+       machorelocsect(Segtext.Sect, Ctxt.Textp)
+       for sect = Segtext.Sect.Next; sect != nil; sect = sect.Next {
+               machorelocsect(sect, datap)
+       }
+       for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+               machorelocsect(sect, datap)
+       }
+}
diff --git a/src/cmd/internal/ld/objfile.go b/src/cmd/internal/ld/objfile.go
new file mode 100644 (file)
index 0000000..98b7ba6
--- /dev/null
@@ -0,0 +1,366 @@
+// Copyright 2013 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 ld
+
+import (
+       "bytes"
+       "fmt"
+       "log"
+       "strconv"
+       "strings"
+)
+
+var startmagic string = "\x00\x00go13ld"
+
+var endmagic string = "\xff\xffgo13ld"
+
+func ldobjfile(ctxt *Link, f *Biobuf, pkg string, length int64, pn string) {
+       var c int
+       var buf [8]uint8
+       var start int64
+       var lib string
+
+       start = Boffset(f)
+       ctxt.Version++
+       buf = [8]uint8{}
+       Bread(f, buf[:])
+       if string(buf[:]) != startmagic {
+               log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
+       }
+       c = Bgetc(f)
+       if c != 1 {
+               log.Fatalf("%s: invalid file version number %d", pn, c)
+       }
+
+       for {
+               lib = rdstring(f)
+               if lib == "" {
+                       break
+               }
+               addlib(ctxt, pkg, pn, lib)
+       }
+
+       for {
+               c = Bgetc(f)
+               Bungetc(f)
+               if c == 0xff {
+                       break
+               }
+               readsym(ctxt, f, pkg, pn)
+       }
+
+       buf = [8]uint8{}
+       Bread(f, buf[:])
+       if string(buf[:]) != endmagic {
+               log.Fatalf("%s: invalid file end", pn)
+       }
+
+       if Boffset(f) != start+length {
+               log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(Boffset(f)), int64(start+length))
+       }
+}
+
+var readsym_ndup int
+
+func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) {
+       var i int
+       var j int
+       var c int
+       var t int
+       var v int
+       var n int
+       var nreloc int
+       var size int
+       var dupok int
+       var name string
+       var data []byte
+       var r *Reloc
+       var s *LSym
+       var dup *LSym
+       var typ *LSym
+       var pc *Pcln
+       var a *Auto
+
+       if Bgetc(f) != 0xfe {
+               log.Fatalf("readsym out of sync")
+       }
+       t = int(rdint(f))
+       name = expandpkg(rdstring(f), pkg)
+       v = int(rdint(f))
+       if v != 0 && v != 1 {
+               log.Fatalf("invalid symbol version %d", v)
+       }
+       dupok = int(rdint(f))
+       dupok &= 1
+       size = int(rdint(f))
+       typ = rdsym(ctxt, f, pkg)
+       rddata(f, &data)
+       nreloc = int(rdint(f))
+
+       if v != 0 {
+               v = ctxt.Version
+       }
+       s = Linklookup(ctxt, name, v)
+       dup = nil
+       if s.Type != 0 && s.Type != SXREF {
+               if (t == SDATA || t == SBSS || t == SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
+                       if s.Size < int64(size) {
+                               s.Size = int64(size)
+                       }
+                       if typ != nil && s.Gotype == nil {
+                               s.Gotype = typ
+                       }
+                       return
+               }
+
+               if (s.Type == SDATA || s.Type == SBSS || s.Type == SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
+                       goto overwrite
+               }
+               if s.Type != SBSS && s.Type != SNOPTRBSS && dupok == 0 && s.Dupok == 0 {
+                       log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
+               }
+               if len(s.P) > 0 {
+                       dup = s
+                       s = linknewsym(ctxt, ".dup", readsym_ndup)
+                       readsym_ndup++ // scratch
+               }
+       }
+
+overwrite:
+       s.File = pkg
+       s.Dupok = uint8(dupok)
+       if t == SXREF {
+               log.Fatalf("bad sxref")
+       }
+       if t == 0 {
+               log.Fatalf("missing type for %s in %s", name, pn)
+       }
+       if t == SBSS && (s.Type == SRODATA || s.Type == SNOPTRBSS) {
+               t = int(s.Type)
+       }
+       s.Type = int16(t)
+       if s.Size < int64(size) {
+               s.Size = int64(size)
+       }
+       if typ != nil { // if bss sym defined multiple times, take type from any one def
+               s.Gotype = typ
+       }
+       if dup != nil && typ != nil {
+               dup.Gotype = typ
+       }
+       s.P = data
+       s.P = s.P[:len(data)]
+       if nreloc > 0 {
+               s.R = make([]Reloc, nreloc)
+               s.R = s.R[:nreloc]
+               for i = 0; i < nreloc; i++ {
+                       r = &s.R[i]
+                       r.Off = int32(rdint(f))
+                       r.Siz = uint8(rdint(f))
+                       r.Type = int32(rdint(f))
+                       r.Add = rdint(f)
+                       r.Xadd = rdint(f)
+                       r.Sym = rdsym(ctxt, f, pkg)
+                       r.Xsym = rdsym(ctxt, f, pkg)
+               }
+       }
+
+       if len(s.P) > 0 && dup != nil && len(dup.P) > 0 && strings.HasPrefix(s.Name, "gclocals·") {
+               // content-addressed garbage collection liveness bitmap symbol.
+               // double check for hash collisions.
+               if !bytes.Equal(s.P, dup.P) {
+                       log.Fatalf("dupok hash collision for %s in %s and %s", s.Name, s.File, pn)
+               }
+       }
+
+       if s.Type == STEXT {
+               s.Args = int32(rdint(f))
+               s.Locals = int32(rdint(f))
+               s.Nosplit = uint8(rdint(f))
+               v = int(rdint(f))
+               s.Leaf = uint8(v & 1)
+               s.Cfunc = uint8(v & 2)
+               n = int(rdint(f))
+               for i = 0; i < n; i++ {
+                       a = new(Auto)
+                       a.Asym = rdsym(ctxt, f, pkg)
+                       a.Aoffset = int32(rdint(f))
+                       a.Name = int16(rdint(f))
+                       a.Gotype = rdsym(ctxt, f, pkg)
+                       a.Link = s.Autom
+                       s.Autom = a
+               }
+
+               s.Pcln = new(Pcln)
+               pc = s.Pcln
+               rddata(f, &pc.Pcsp.P)
+               rddata(f, &pc.Pcfile.P)
+               rddata(f, &pc.Pcline.P)
+               n = int(rdint(f))
+               pc.Pcdata = make([]Pcdata, n)
+               pc.Npcdata = n
+               for i = 0; i < n; i++ {
+                       rddata(f, &pc.Pcdata[i].P)
+               }
+               n = int(rdint(f))
+               pc.Funcdata = make([]*LSym, n)
+               pc.Funcdataoff = make([]int64, n)
+               pc.Nfuncdata = n
+               for i = 0; i < n; i++ {
+                       pc.Funcdata[i] = rdsym(ctxt, f, pkg)
+               }
+               for i = 0; i < n; i++ {
+                       pc.Funcdataoff[i] = rdint(f)
+               }
+               n = int(rdint(f))
+               pc.File = make([]*LSym, n)
+               pc.Nfile = n
+               for i = 0; i < n; i++ {
+                       pc.File[i] = rdsym(ctxt, f, pkg)
+               }
+
+               if dup == nil {
+                       if s.Onlist != 0 {
+                               log.Fatalf("symbol %s listed multiple times", s.Name)
+                       }
+                       s.Onlist = 1
+                       if ctxt.Etextp != nil {
+                               ctxt.Etextp.Next = s
+                       } else {
+                               ctxt.Textp = s
+                       }
+                       ctxt.Etextp = s
+               }
+       }
+
+       if ctxt.Debugasm != 0 {
+               fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
+               if s.Version != 0 {
+                       fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
+               }
+               if s.Type != 0 {
+                       fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
+               }
+               if s.Dupok != 0 {
+                       fmt.Fprintf(ctxt.Bso, "dupok ")
+               }
+               if s.Cfunc != 0 {
+                       fmt.Fprintf(ctxt.Bso, "cfunc ")
+               }
+               if s.Nosplit != 0 {
+                       fmt.Fprintf(ctxt.Bso, "nosplit ")
+               }
+               fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
+               if s.Type == STEXT {
+                       fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
+               }
+               fmt.Fprintf(ctxt.Bso, "\n")
+               for i = 0; i < len(s.P); {
+                       fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
+                       for j = i; j < i+16 && j < len(s.P); j++ {
+                               fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
+                       }
+                       for ; j < i+16; j++ {
+                               fmt.Fprintf(ctxt.Bso, "   ")
+                       }
+                       fmt.Fprintf(ctxt.Bso, "  ")
+                       for j = i; j < i+16 && j < len(s.P); j++ {
+                               c = int(s.P[j])
+                               if ' ' <= c && c <= 0x7e {
+                                       fmt.Fprintf(ctxt.Bso, "%c", c)
+                               } else {
+                                       fmt.Fprintf(ctxt.Bso, ".")
+                               }
+                       }
+
+                       fmt.Fprintf(ctxt.Bso, "\n")
+                       i += 16
+               }
+
+               for i = 0; i < len(s.R); i++ {
+                       r = &s.R[i]
+                       fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, r.Sym.Name, int64(r.Add))
+               }
+       }
+}
+
+func rdint(f *Biobuf) int64 {
+       var c int
+       var uv uint64
+       var shift int
+
+       uv = 0
+       for shift = 0; ; shift += 7 {
+               if shift >= 64 {
+                       log.Fatalf("corrupt input")
+               }
+               c = Bgetc(f)
+               uv |= uint64(c&0x7F) << uint(shift)
+               if c&0x80 == 0 {
+                       break
+               }
+       }
+
+       return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
+}
+
+func rdstring(f *Biobuf) string {
+       n := rdint(f)
+       p := make([]byte, n)
+       Bread(f, p)
+       return string(p)
+}
+
+func rddata(f *Biobuf, pp *[]byte) {
+       n := rdint(f)
+       *pp = make([]byte, n)
+       Bread(f, *pp)
+}
+
+var symbuf []byte
+
+func rdsym(ctxt *Link, f *Biobuf, pkg string) *LSym {
+       var n int
+       var v int
+       var p string
+       var s *LSym
+
+       n = int(rdint(f))
+       if n == 0 {
+               rdint(f)
+               return nil
+       }
+
+       if len(symbuf) < n {
+               symbuf = make([]byte, n)
+       }
+       Bread(f, symbuf[:n])
+       p = string(symbuf[:n])
+       v = int(rdint(f))
+       if v != 0 {
+               v = ctxt.Version
+       }
+       s = Linklookup(ctxt, expandpkg(p, pkg), v)
+
+       if v == 0 && s.Name[0] == '$' && s.Type == 0 {
+               if strings.HasPrefix(s.Name, "$f32.") {
+                       var i32 int32
+                       x, _ := strconv.ParseUint(s.Name[5:], 16, 32)
+                       i32 = int32(x)
+                       s.Type = SRODATA
+                       Adduint32(ctxt, s, uint32(i32))
+                       s.Reachable = false
+               } else if strings.HasPrefix(s.Name, "$f64.") || strings.HasPrefix(s.Name, "$i64.") {
+                       var i64 int64
+                       x, _ := strconv.ParseUint(s.Name[5:], 16, 64)
+                       i64 = int64(x)
+                       s.Type = SRODATA
+                       Adduint64(ctxt, s, uint64(i64))
+                       s.Reachable = false
+               }
+       }
+
+       return s
+}
diff --git a/src/cmd/internal/ld/pcln.go b/src/cmd/internal/ld/pcln.go
new file mode 100644 (file)
index 0000000..2900664
--- /dev/null
@@ -0,0 +1,487 @@
+// Copyright 2013 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 ld
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+)
+
+// funcpctab writes to dst a pc-value table mapping the code in func to the values
+// returned by valfunc parameterized by arg. The invocation of valfunc to update the
+// current value is, for each p,
+//
+//     val = valfunc(func, val, p, 0, arg);
+//     record val as value at p->pc;
+//     val = valfunc(func, val, p, 1, arg);
+//
+// where func is the function, val is the current value, p is the instruction being
+// considered, and arg can be used to further parameterize valfunc.
+
+// pctofileline computes either the file number (arg == 0)
+// or the line number (arg == 1) to use at p.
+// Because p->lineno applies to p, phase == 0 (before p)
+// takes care of the update.
+
+// pctospadj computes the sp adjustment in effect.
+// It is oldval plus any adjustment made by p itself.
+// The adjustment by p takes effect only after p, so we
+// apply the change during phase == 1.
+
+// pctopcdata computes the pcdata value in effect at p.
+// A PCDATA instruction sets the value in effect at future
+// non-PCDATA instructions.
+// Since PCDATA instructions have no width in the final code,
+// it does not matter which phase we use for the update.
+
+// iteration over encoded pcdata tables.
+
+func getvarint(pp *[]byte) uint32 {
+       var p []byte
+       var shift int
+       var v uint32
+
+       v = 0
+       p = *pp
+       for shift = 0; ; shift += 7 {
+               v |= uint32(p[0]&0x7F) << uint(shift)
+               tmp4 := p
+               p = p[1:]
+               if tmp4[0]&0x80 == 0 {
+                       break
+               }
+       }
+
+       *pp = p
+       return v
+}
+
+func pciternext(it *Pciter) {
+       var v uint32
+       var dv int32
+
+       it.pc = it.nextpc
+       if it.done != 0 {
+               return
+       }
+       if -cap(it.p) >= -cap(it.d.P[len(it.d.P):]) {
+               it.done = 1
+               return
+       }
+
+       // value delta
+       v = getvarint(&it.p)
+
+       if v == 0 && it.start == 0 {
+               it.done = 1
+               return
+       }
+
+       it.start = 0
+       dv = int32(v>>1) ^ (int32(v<<31) >> 31)
+       it.value += dv
+
+       // pc delta
+       v = getvarint(&it.p)
+
+       it.nextpc = it.pc + v*it.pcscale
+}
+
+func pciterinit(ctxt *Link, it *Pciter, d *Pcdata) {
+       it.d = *d
+       it.p = it.d.P
+       it.pc = 0
+       it.nextpc = 0
+       it.value = -1
+       it.start = 1
+       it.done = 0
+       it.pcscale = uint32(ctxt.Arch.Minlc)
+       pciternext(it)
+}
+
+// Copyright 2013 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.
+
+func addvarint(d *Pcdata, val uint32) {
+       var n int32
+       var v uint32
+       var p []byte
+
+       n = 0
+       for v = val; v >= 0x80; v >>= 7 {
+               n++
+       }
+       n++
+
+       old := len(d.P)
+       for cap(d.P) < len(d.P)+int(n) {
+               d.P = append(d.P[:cap(d.P)], 0)
+       }
+       d.P = d.P[:old+int(n)]
+
+       p = d.P[old:]
+       for v = val; v >= 0x80; v >>= 7 {
+               p[0] = byte(v | 0x80)
+               p = p[1:]
+       }
+       p[0] = byte(v)
+}
+
+func addpctab(ftab *LSym, off int32, d *Pcdata) int32 {
+       var start int32
+
+       start = int32(len(ftab.P))
+       Symgrow(Ctxt, ftab, int64(start)+int64(len(d.P)))
+       copy(ftab.P[start:], d.P)
+
+       return int32(setuint32(Ctxt, ftab, int64(off), uint32(start)))
+}
+
+func ftabaddstring(ftab *LSym, s string) int32 {
+       var n int32
+       var start int32
+
+       n = int32(len(s)) + 1
+       start = int32(len(ftab.P))
+       Symgrow(Ctxt, ftab, int64(start)+int64(n)+1)
+       copy(ftab.P[start:], s)
+       return start
+}
+
+func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
+       var i int
+       var f *LSym
+       var out Pcdata
+       var it Pciter
+       var v uint32
+       var oldval int32
+       var newval int32
+       var val int32
+       var dv int32
+
+       // Give files numbers.
+       for i = 0; i < len(files); i++ {
+               f = files[i]
+               if f.Type != SFILEPATH {
+                       ctxt.Nhistfile++
+                       f.Value = int64(ctxt.Nhistfile)
+                       f.Type = SFILEPATH
+                       f.Next = ctxt.Filesyms
+                       ctxt.Filesyms = f
+               }
+       }
+
+       newval = -1
+       out = Pcdata{}
+
+       for pciterinit(ctxt, &it, d); it.done == 0; pciternext(&it) {
+               // value delta
+               oldval = it.value
+
+               if oldval == -1 {
+                       val = -1
+               } else {
+                       if oldval < 0 || oldval >= int32(len(files)) {
+                               log.Fatalf("bad pcdata %d", oldval)
+                       }
+                       val = int32(files[oldval].Value)
+               }
+
+               dv = val - newval
+               newval = val
+               v = (uint32(dv) << 1) ^ uint32(int32(dv>>31))
+               addvarint(&out, v)
+
+               // pc delta
+               addvarint(&out, (it.nextpc-it.pc)/it.pcscale)
+       }
+
+       // terminating value delta
+       addvarint(&out, 0)
+
+       *d = out
+}
+
+func container(s *LSym) int {
+       // We want to generate func table entries only for the "lowest level" symbols,
+       // not containers of subsymbols.
+       if s != nil && s.Sub != nil {
+               return 1
+       }
+       return 0
+}
+
+// pclntab initializes the pclntab symbol with
+// runtime function and file name information.
+
+var pclntab_zpcln Pcln
+
+func pclntab() {
+       var i int32
+       var nfunc int32
+       var start int32
+       var funcstart int32
+       var ftab *LSym
+       var s *LSym
+       var last *LSym
+       var off int32
+       var end int32
+       var frameptrsize int32
+       var funcdata_bytes int64
+       var pcln *Pcln
+       var it Pciter
+
+       funcdata_bytes = 0
+       ftab = Linklookup(Ctxt, "runtime.pclntab", 0)
+       ftab.Type = SPCLNTAB
+       ftab.Reachable = true
+
+       // See golang.org/s/go12symtab for the format. Briefly:
+       //      8-byte header
+       //      nfunc [thearch.ptrsize bytes]
+       //      function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
+       //      end PC [thearch.ptrsize bytes]
+       //      offset to file table [4 bytes]
+       nfunc = 0
+
+       for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
+               if container(Ctxt.Cursym) == 0 {
+                       nfunc++
+               }
+       }
+
+       Symgrow(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize)+4)
+       setuint32(Ctxt, ftab, 0, 0xfffffffb)
+       setuint8(Ctxt, ftab, 6, uint8(Thearch.Minlc))
+       setuint8(Ctxt, ftab, 7, uint8(Thearch.Ptrsize))
+       setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(Thearch.Ptrsize))
+
+       nfunc = 0
+       last = nil
+       for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
+               last = Ctxt.Cursym
+               if container(Ctxt.Cursym) != 0 {
+                       continue
+               }
+               pcln = Ctxt.Cursym.Pcln
+               if pcln == nil {
+                       pcln = &pclntab_zpcln
+               }
+
+               funcstart = int32(len(ftab.P))
+               funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+
+               setaddr(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), Ctxt.Cursym)
+               setuintxx(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint64(funcstart), int64(Thearch.Ptrsize))
+
+               // fixed size of struct, checked below
+               off = funcstart
+
+               end = funcstart + int32(Thearch.Ptrsize) + 3*4 + 5*4 + int32(pcln.Npcdata)*4 + int32(pcln.Nfuncdata)*int32(Thearch.Ptrsize)
+               if pcln.Nfuncdata > 0 && (end&int32(Thearch.Ptrsize-1) != 0) {
+                       end += 4
+               }
+               Symgrow(Ctxt, ftab, int64(end))
+
+               // entry uintptr
+               off = int32(setaddr(Ctxt, ftab, int64(off), Ctxt.Cursym))
+
+               // name int32
+               off = int32(setuint32(Ctxt, ftab, int64(off), uint32(ftabaddstring(ftab, Ctxt.Cursym.Name))))
+
+               // args int32
+               // TODO: Move into funcinfo.
+               off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Args)))
+
+               // frame int32
+               // TODO: Remove entirely. The pcsp table is more precise.
+               // This is only used by a fallback case during stack walking
+               // when a called function doesn't have argument information.
+               // We need to make sure everything has argument information
+               // and then remove this.
+               frameptrsize = int32(Thearch.Ptrsize)
+
+               if Ctxt.Cursym.Leaf != 0 {
+                       frameptrsize = 0
+               }
+               off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Locals)+uint32(frameptrsize)))
+
+               if pcln != &pclntab_zpcln {
+                       renumberfiles(Ctxt, pcln.File, &pcln.Pcfile)
+                       if false {
+                               // Sanity check the new numbering
+                               for pciterinit(Ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
+                                       if it.value < 1 || it.value > Ctxt.Nhistfile {
+                                               Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, Ctxt.Nhistfile)
+                                               Errorexit()
+                                       }
+                               }
+                       }
+               }
+
+               // pcdata
+               off = addpctab(ftab, off, &pcln.Pcsp)
+
+               off = addpctab(ftab, off, &pcln.Pcfile)
+               off = addpctab(ftab, off, &pcln.Pcline)
+               off = int32(setuint32(Ctxt, ftab, int64(off), uint32(pcln.Npcdata)))
+               off = int32(setuint32(Ctxt, ftab, int64(off), uint32(pcln.Nfuncdata)))
+               for i = 0; i < int32(pcln.Npcdata); i++ {
+                       off = addpctab(ftab, off, &pcln.Pcdata[i])
+               }
+
+               // funcdata, must be pointer-aligned and we're only int32-aligned.
+               // Missing funcdata will be 0 (nil pointer).
+               if pcln.Nfuncdata > 0 {
+                       if off&int32(Thearch.Ptrsize-1) != 0 {
+                               off += 4
+                       }
+                       for i = 0; i < int32(pcln.Nfuncdata); i++ {
+                               if pcln.Funcdata[i] == nil {
+                                       setuintxx(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(Thearch.Ptrsize))
+                               } else {
+                                       // TODO: Dedup.
+                                       funcdata_bytes += pcln.Funcdata[i].Size
+
+                                       setaddrplus(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
+                               }
+                       }
+
+                       off += int32(pcln.Nfuncdata) * int32(Thearch.Ptrsize)
+               }
+
+               if off != end {
+                       Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln.Npcdata, pcln.Nfuncdata, Thearch.Ptrsize)
+                       Errorexit()
+               }
+
+               nfunc++
+       }
+
+       // Final entry of table is just end pc.
+       setaddrplus(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), last, last.Size)
+
+       // Start file table.
+       start = int32(len(ftab.P))
+
+       start += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+       setuint32(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint32(start))
+
+       Symgrow(Ctxt, ftab, int64(start)+(int64(Ctxt.Nhistfile)+1)*4)
+       setuint32(Ctxt, ftab, int64(start), uint32(Ctxt.Nhistfile))
+       for s = Ctxt.Filesyms; s != nil; s = s.Next {
+               setuint32(Ctxt, ftab, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name)))
+       }
+
+       ftab.Size = int64(len(ftab.P))
+
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), int64(ftab.Size), int64(funcdata_bytes))
+       }
+}
+
+const (
+       BUCKETSIZE    = 256 * MINFUNC
+       SUBBUCKETS    = 16
+       SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
+       NOIDX         = 0x7fffffff
+)
+
+// findfunctab generates a lookup table to quickly find the containing
+// function for a pc.  See src/runtime/symtab.go:findfunc for details.
+func findfunctab() {
+       var t *LSym
+       var s *LSym
+       var e *LSym
+       var idx int32
+       var i int32
+       var j int32
+       var nbuckets int32
+       var n int32
+       var base int32
+       var min int64
+       var max int64
+       var p int64
+       var q int64
+       var indexes []int32
+
+       t = Linklookup(Ctxt, "runtime.findfunctab", 0)
+       t.Type = SRODATA
+       t.Reachable = true
+
+       // find min and max address
+       min = Ctxt.Textp.Value
+
+       max = 0
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               max = s.Value + s.Size
+       }
+
+       // for each subbucket, compute the minimum of all symbol indexes
+       // that map to that subbucket.
+       n = int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
+
+       indexes = make([]int32, n)
+       for i = 0; i < n; i++ {
+               indexes[i] = NOIDX
+       }
+       idx = 0
+       for s = Ctxt.Textp; s != nil; s = s.Next {
+               if container(s) != 0 {
+                       continue
+               }
+               p = s.Value
+               e = s.Next
+               for container(e) != 0 {
+                       e = e.Next
+               }
+               if e != nil {
+                       q = e.Value
+               } else {
+                       q = max
+               }
+
+               //print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
+               for ; p < q; p += SUBBUCKETSIZE {
+                       i = int32((p - min) / SUBBUCKETSIZE)
+                       if indexes[i] > idx {
+                               indexes[i] = idx
+                       }
+               }
+
+               i = int32((q - 1 - min) / SUBBUCKETSIZE)
+               if indexes[i] > idx {
+                       indexes[i] = idx
+               }
+               idx++
+       }
+
+       // allocate table
+       nbuckets = int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
+
+       Symgrow(Ctxt, t, 4*int64(nbuckets)+int64(n))
+
+       // fill in table
+       for i = 0; i < nbuckets; i++ {
+               base = indexes[i*SUBBUCKETS]
+               if base == NOIDX {
+                       Diag("hole in findfunctab")
+               }
+               setuint32(Ctxt, t, int64(i)*(4+SUBBUCKETS), uint32(base))
+               for j = 0; j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
+                       idx = indexes[i*SUBBUCKETS+j]
+                       if idx == NOIDX {
+                               Diag("hole in findfunctab")
+                       }
+                       if idx-base >= 256 {
+                               Diag("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
+                       }
+
+                       setuint8(Ctxt, t, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
+               }
+       }
+}
diff --git a/src/cmd/internal/ld/pe.go b/src/cmd/internal/ld/pe.go
new file mode 100644 (file)
index 0000000..c2ef49f
--- /dev/null
@@ -0,0 +1,1060 @@
+// Copyright 2009 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 ld
+
+import (
+       "encoding/binary"
+       "fmt"
+       "sort"
+)
+
+type IMAGE_FILE_HEADER struct {
+       Machine              uint16
+       NumberOfSections     uint16
+       TimeDateStamp        uint32
+       PointerToSymbolTable uint32
+       NumberOfSymbols      uint32
+       SizeOfOptionalHeader uint16
+       Characteristics      uint16
+}
+
+type IMAGE_DATA_DIRECTORY struct {
+       VirtualAddress uint32
+       Size           uint32
+}
+
+type IMAGE_OPTIONAL_HEADER struct {
+       Magic                       uint16
+       MajorLinkerVersion          uint8
+       MinorLinkerVersion          uint8
+       SizeOfCode                  uint32
+       SizeOfInitializedData       uint32
+       SizeOfUninitializedData     uint32
+       AddressOfEntryPoint         uint32
+       BaseOfCode                  uint32
+       BaseOfData                  uint32
+       ImageBase                   uint32
+       SectionAlignment            uint32
+       FileAlignment               uint32
+       MajorOperatingSystemVersion uint16
+       MinorOperatingSystemVersion uint16
+       MajorImageVersion           uint16
+       MinorImageVersion           uint16
+       MajorSubsystemVersion       uint16
+       MinorSubsystemVersion       uint16
+       Win32VersionValue           uint32
+       SizeOfImage                 uint32
+       SizeOfHeaders               uint32
+       CheckSum                    uint32
+       Subsystem                   uint16
+       DllCharacteristics          uint16
+       SizeOfStackReserve          uint32
+       SizeOfStackCommit           uint32
+       SizeOfHeapReserve           uint32
+       SizeOfHeapCommit            uint32
+       LoaderFlags                 uint32
+       NumberOfRvaAndSizes         uint32
+       DataDirectory               [16]IMAGE_DATA_DIRECTORY
+}
+
+type IMAGE_SECTION_HEADER struct {
+       Name                 [8]uint8
+       VirtualSize          uint32
+       VirtualAddress       uint32
+       SizeOfRawData        uint32
+       PointerToRawData     uint32
+       PointerToRelocations uint32
+       PointerToLineNumbers uint32
+       NumberOfRelocations  uint16
+       NumberOfLineNumbers  uint16
+       Characteristics      uint32
+}
+
+type IMAGE_IMPORT_DESCRIPTOR struct {
+       OriginalFirstThunk uint32
+       TimeDateStamp      uint32
+       ForwarderChain     uint32
+       Name               uint32
+       FirstThunk         uint32
+}
+
+type IMAGE_EXPORT_DIRECTORY struct {
+       Characteristics       uint32
+       TimeDateStamp         uint32
+       MajorVersion          uint16
+       MinorVersion          uint16
+       Name                  uint32
+       Base                  uint32
+       NumberOfFunctions     uint32
+       NumberOfNames         uint32
+       AddressOfFunctions    uint32
+       AddressOfNames        uint32
+       AddressOfNameOrdinals uint32
+}
+
+const (
+       PEBASE      = 0x00400000
+       PESECTALIGN = 0x1000
+       PEFILEALIGN = 2 << 8
+)
+
+const (
+       IMAGE_FILE_MACHINE_I386              = 0x14c
+       IMAGE_FILE_MACHINE_AMD64             = 0x8664
+       IMAGE_FILE_RELOCS_STRIPPED           = 0x0001
+       IMAGE_FILE_EXECUTABLE_IMAGE          = 0x0002
+       IMAGE_FILE_LARGE_ADDRESS_AWARE       = 0x0020
+       IMAGE_FILE_32BIT_MACHINE             = 0x0100
+       IMAGE_FILE_DEBUG_STRIPPED            = 0x0200
+       IMAGE_SCN_CNT_CODE                   = 0x00000020
+       IMAGE_SCN_CNT_INITIALIZED_DATA       = 0x00000040
+       IMAGE_SCN_CNT_UNINITIALIZED_DATA     = 0x00000080
+       IMAGE_SCN_MEM_EXECUTE                = 0x20000000
+       IMAGE_SCN_MEM_READ                   = 0x40000000
+       IMAGE_SCN_MEM_WRITE                  = 0x80000000
+       IMAGE_SCN_MEM_DISCARDABLE            = 0x2000000
+       IMAGE_DIRECTORY_ENTRY_EXPORT         = 0
+       IMAGE_DIRECTORY_ENTRY_IMPORT         = 1
+       IMAGE_DIRECTORY_ENTRY_RESOURCE       = 2
+       IMAGE_DIRECTORY_ENTRY_EXCEPTION      = 3
+       IMAGE_DIRECTORY_ENTRY_SECURITY       = 4
+       IMAGE_DIRECTORY_ENTRY_BASERELOC      = 5
+       IMAGE_DIRECTORY_ENTRY_DEBUG          = 6
+       IMAGE_DIRECTORY_ENTRY_COPYRIGHT      = 7
+       IMAGE_DIRECTORY_ENTRY_ARCHITECTURE   = 7
+       IMAGE_DIRECTORY_ENTRY_GLOBALPTR      = 8
+       IMAGE_DIRECTORY_ENTRY_TLS            = 9
+       IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    = 10
+       IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   = 11
+       IMAGE_DIRECTORY_ENTRY_IAT            = 12
+       IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   = 13
+       IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
+       IMAGE_SUBSYSTEM_WINDOWS_GUI          = 2
+       IMAGE_SUBSYSTEM_WINDOWS_CUI          = 3
+)
+
+// X64
+type PE64_IMAGE_OPTIONAL_HEADER struct {
+       Magic                       uint16
+       MajorLinkerVersion          uint8
+       MinorLinkerVersion          uint8
+       SizeOfCode                  uint32
+       SizeOfInitializedData       uint32
+       SizeOfUninitializedData     uint32
+       AddressOfEntryPoint         uint32
+       BaseOfCode                  uint32
+       ImageBase                   uint64
+       SectionAlignment            uint32
+       FileAlignment               uint32
+       MajorOperatingSystemVersion uint16
+       MinorOperatingSystemVersion uint16
+       MajorImageVersion           uint16
+       MinorImageVersion           uint16
+       MajorSubsystemVersion       uint16
+       MinorSubsystemVersion       uint16
+       Win32VersionValue           uint32
+       SizeOfImage                 uint32
+       SizeOfHeaders               uint32
+       CheckSum                    uint32
+       Subsystem                   uint16
+       DllCharacteristics          uint16
+       SizeOfStackReserve          uint64
+       SizeOfStackCommit           uint64
+       SizeOfHeapReserve           uint64
+       SizeOfHeapCommit            uint64
+       LoaderFlags                 uint32
+       NumberOfRvaAndSizes         uint32
+       DataDirectory               [16]IMAGE_DATA_DIRECTORY
+}
+
+// Copyright 2009 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.
+
+// PE (Portable Executable) file writing
+// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
+
+// DOS stub that prints out
+// "This program cannot be run in DOS mode."
+var dosstub = []uint8{
+       0x4d,
+       0x5a,
+       0x90,
+       0x00,
+       0x03,
+       0x00,
+       0x04,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0xff,
+       0xff,
+       0x00,
+       0x00,
+       0x8b,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x40,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x80,
+       0x00,
+       0x00,
+       0x00,
+       0x0e,
+       0x1f,
+       0xba,
+       0x0e,
+       0x00,
+       0xb4,
+       0x09,
+       0xcd,
+       0x21,
+       0xb8,
+       0x01,
+       0x4c,
+       0xcd,
+       0x21,
+       0x54,
+       0x68,
+       0x69,
+       0x73,
+       0x20,
+       0x70,
+       0x72,
+       0x6f,
+       0x67,
+       0x72,
+       0x61,
+       0x6d,
+       0x20,
+       0x63,
+       0x61,
+       0x6e,
+       0x6e,
+       0x6f,
+       0x74,
+       0x20,
+       0x62,
+       0x65,
+       0x20,
+       0x72,
+       0x75,
+       0x6e,
+       0x20,
+       0x69,
+       0x6e,
+       0x20,
+       0x44,
+       0x4f,
+       0x53,
+       0x20,
+       0x6d,
+       0x6f,
+       0x64,
+       0x65,
+       0x2e,
+       0x0d,
+       0x0d,
+       0x0a,
+       0x24,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+       0x00,
+}
+
+var rsrcsym *LSym
+
+var strtbl []byte
+
+var PESECTHEADR int32
+
+var PEFILEHEADR int32
+
+var pe64 int
+
+var pensect int
+
+var nextsectoff int
+
+var nextfileoff int
+
+var textsect int
+
+var datasect int
+
+var fh IMAGE_FILE_HEADER
+
+var oh IMAGE_OPTIONAL_HEADER
+
+var oh64 PE64_IMAGE_OPTIONAL_HEADER
+
+var sh [16]IMAGE_SECTION_HEADER
+
+var dd []IMAGE_DATA_DIRECTORY
+
+type Imp struct {
+       s    *LSym
+       off  uint64
+       next *Imp
+}
+
+type Dll struct {
+       name     string
+       nameoff  uint64
+       thunkoff uint64
+       ms       *Imp
+       next     *Dll
+}
+
+var dr *Dll
+
+var dexport [1024]*LSym
+
+var nexport int
+
+type COFFSym struct {
+       sym       *LSym
+       strtbloff int
+       sect      int
+       value     int64
+}
+
+var coffsym []COFFSym
+
+var ncoffsym int
+
+func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
+       var h *IMAGE_SECTION_HEADER
+
+       if pensect == 16 {
+               Diag("too many sections")
+               Errorexit()
+       }
+
+       h = &sh[pensect]
+       pensect++
+       copy(h.Name[:], name)
+       h.VirtualSize = uint32(sectsize)
+       h.VirtualAddress = uint32(nextsectoff)
+       nextsectoff = int(Rnd(int64(nextsectoff)+int64(sectsize), PESECTALIGN))
+       h.PointerToRawData = uint32(nextfileoff)
+       if filesize > 0 {
+               h.SizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN))
+               nextfileoff += int(h.SizeOfRawData)
+       }
+
+       return h
+}
+
+func chksectoff(h *IMAGE_SECTION_HEADER, off int64) {
+       if off != int64(h.PointerToRawData) {
+               Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(off))
+               Errorexit()
+       }
+}
+
+func chksectseg(h *IMAGE_SECTION_HEADER, s *Segment) {
+       if s.Vaddr-PEBASE != uint64(h.VirtualAddress) {
+               Diag("%s.VirtualAddress = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.VirtualAddress)), uint64(int64(s.Vaddr-PEBASE)))
+               Errorexit()
+       }
+
+       if s.Fileoff != uint64(h.PointerToRawData) {
+               Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(int64(s.Fileoff)))
+               Errorexit()
+       }
+}
+
+func Peinit() {
+       var l int
+
+       switch Thearch.Thechar {
+       // 64-bit architectures
+       case '6':
+               pe64 = 1
+
+               l = binary.Size(&oh64)
+               dd = oh64.DataDirectory[:]
+
+               // 32-bit architectures
+       default:
+               l = binary.Size(&oh)
+
+               dd = oh.DataDirectory[:]
+       }
+
+       PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
+       PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
+       nextsectoff = int(PESECTHEADR)
+       nextfileoff = int(PEFILEHEADR)
+
+       // some mingw libs depend on this symbol, for example, FindPESectionByName
+       xdefine("__image_base__", SDATA, PEBASE)
+
+       xdefine("_image_base__", SDATA, PEBASE)
+}
+
+func pewrite() {
+       Cseek(0)
+       Cwrite(dosstub)
+       strnput("PE", 4)
+
+       binary.Write(&coutbuf, binary.LittleEndian, &fh)
+
+       if pe64 != 0 {
+               binary.Write(&coutbuf, binary.LittleEndian, &oh64)
+       } else {
+               binary.Write(&coutbuf, binary.LittleEndian, &oh)
+       }
+       binary.Write(&coutbuf, binary.LittleEndian, sh[:pensect])
+}
+
+func strput(s string) {
+       coutbuf.w.WriteString(s)
+       Cput(0)
+       // string must be padded to even size
+       if (len(s)+1)%2 != 0 {
+               Cput(0)
+       }
+}
+
+func initdynimport() *Dll {
+       var m *Imp
+       var d *Dll
+       var s *LSym
+       var dynamic *LSym
+
+       dr = nil
+       m = nil
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if !s.Reachable || s.Type != SDYNIMPORT {
+                       continue
+               }
+               for d = dr; d != nil; d = d.next {
+                       if d.name == s.Dynimplib {
+                               m = new(Imp)
+                               break
+                       }
+               }
+
+               if d == nil {
+                       d = new(Dll)
+                       d.name = s.Dynimplib
+                       d.next = dr
+                       dr = d
+                       m = new(Imp)
+               }
+
+               m.s = s
+               m.next = d.ms
+               d.ms = m
+       }
+
+       dynamic = Linklookup(Ctxt, ".windynamic", 0)
+       dynamic.Reachable = true
+       dynamic.Type = SWINDOWS
+       for d = dr; d != nil; d = d.next {
+               for m = d.ms; m != nil; m = m.next {
+                       m.s.Type = SWINDOWS | SSUB
+                       m.s.Sub = dynamic.Sub
+                       dynamic.Sub = m.s
+                       m.s.Value = dynamic.Size
+                       dynamic.Size += int64(Thearch.Ptrsize)
+               }
+
+               dynamic.Size += int64(Thearch.Ptrsize)
+       }
+
+       return dr
+}
+
+func addimports(datsect *IMAGE_SECTION_HEADER) {
+       var isect *IMAGE_SECTION_HEADER
+       var n uint64
+       var oftbase uint64
+       var ftbase uint64
+       var startoff int64
+       var endoff int64
+       var m *Imp
+       var d *Dll
+       var dynamic *LSym
+
+       startoff = Cpos()
+       dynamic = Linklookup(Ctxt, ".windynamic", 0)
+
+       // skip import descriptor table (will write it later)
+       n = 0
+
+       for d = dr; d != nil; d = d.next {
+               n++
+       }
+       Cseek(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
+
+       // write dll names
+       for d = dr; d != nil; d = d.next {
+               d.nameoff = uint64(Cpos()) - uint64(startoff)
+               strput(d.name)
+       }
+
+       // write function names
+       for d = dr; d != nil; d = d.next {
+               for m = d.ms; m != nil; m = m.next {
+                       m.off = uint64(nextsectoff) + uint64(Cpos()) - uint64(startoff)
+                       Wputl(0) // hint
+                       strput(m.s.Extname)
+               }
+       }
+
+       // write OriginalFirstThunks
+       oftbase = uint64(Cpos()) - uint64(startoff)
+
+       n = uint64(Cpos())
+       for d = dr; d != nil; d = d.next {
+               d.thunkoff = uint64(Cpos()) - n
+               for m = d.ms; m != nil; m = m.next {
+                       if pe64 != 0 {
+                               Vputl(m.off)
+                       } else {
+                               Lputl(uint32(m.off))
+                       }
+               }
+
+               if pe64 != 0 {
+                       Vputl(0)
+               } else {
+                       Lputl(0)
+               }
+       }
+
+       // add pe section and pad it at the end
+       n = uint64(Cpos()) - uint64(startoff)
+
+       isect = addpesection(".idata", int(n), int(n))
+       isect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
+       chksectoff(isect, startoff)
+       strnput("", int(uint64(isect.SizeOfRawData)-n))
+       endoff = Cpos()
+
+       // write FirstThunks (allocated in .data section)
+       ftbase = uint64(dynamic.Value) - uint64(datsect.VirtualAddress) - PEBASE
+
+       Cseek(int64(uint64(datsect.PointerToRawData) + ftbase))
+       for d = dr; d != nil; d = d.next {
+               for m = d.ms; m != nil; m = m.next {
+                       if pe64 != 0 {
+                               Vputl(m.off)
+                       } else {
+                               Lputl(uint32(m.off))
+                       }
+               }
+
+               if pe64 != 0 {
+                       Vputl(0)
+               } else {
+                       Lputl(0)
+               }
+       }
+
+       // finally write import descriptor table
+       Cseek(startoff)
+
+       for d = dr; d != nil; d = d.next {
+               Lputl(uint32(uint64(isect.VirtualAddress) + oftbase + d.thunkoff))
+               Lputl(0)
+               Lputl(0)
+               Lputl(uint32(uint64(isect.VirtualAddress) + d.nameoff))
+               Lputl(uint32(uint64(datsect.VirtualAddress) + ftbase + d.thunkoff))
+       }
+
+       Lputl(0) //end
+       Lputl(0)
+       Lputl(0)
+       Lputl(0)
+       Lputl(0)
+
+       // update data directory
+       dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.VirtualAddress
+
+       dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.VirtualSize
+       dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE)
+       dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size)
+
+       Cseek(endoff)
+}
+
+type pescmp []*LSym
+
+func (x pescmp) Len() int {
+       return len(x)
+}
+
+func (x pescmp) Swap(i, j int) {
+       x[i], x[j] = x[j], x[i]
+}
+
+func (x pescmp) Less(i, j int) bool {
+       var s1 *LSym
+       var s2 *LSym
+
+       s1 = x[i]
+       s2 = x[j]
+       return stringsCompare(s1.Extname, s2.Extname) < 0
+}
+
+func initdynexport() {
+       var s *LSym
+
+       nexport = 0
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if !s.Reachable || s.Cgoexport&CgoExportDynamic == 0 {
+                       continue
+               }
+               if nexport+1 > len(dexport) {
+                       Diag("pe dynexport table is full")
+                       Errorexit()
+               }
+
+               dexport[nexport] = s
+               nexport++
+       }
+
+       sort.Sort(pescmp(dexport[:nexport]))
+}
+
+func addexports() {
+       var sect *IMAGE_SECTION_HEADER
+       var e IMAGE_EXPORT_DIRECTORY
+       var size int
+       var i int
+       var va int
+       var va_name int
+       var va_addr int
+       var va_na int
+       var v int
+
+       size = binary.Size(&e) + 10*nexport + len(outfile) + 1
+       for i = 0; i < nexport; i++ {
+               size += len(dexport[i].Extname) + 1
+       }
+
+       if nexport == 0 {
+               return
+       }
+
+       sect = addpesection(".edata", size, size)
+       sect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
+       chksectoff(sect, Cpos())
+       va = int(sect.VirtualAddress)
+       dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
+       dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.VirtualSize
+
+       va_name = va + binary.Size(&e) + nexport*4
+       va_addr = va + binary.Size(&e)
+       va_na = va + binary.Size(&e) + nexport*8
+
+       e.Characteristics = 0
+       e.MajorVersion = 0
+       e.MinorVersion = 0
+       e.NumberOfFunctions = uint32(nexport)
+       e.NumberOfNames = uint32(nexport)
+       e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
+       e.Base = 1
+       e.AddressOfFunctions = uint32(va_addr)
+       e.AddressOfNames = uint32(va_name)
+       e.AddressOfNameOrdinals = uint32(va_na)
+
+       // put IMAGE_EXPORT_DIRECTORY
+       binary.Write(&coutbuf, binary.LittleEndian, &e)
+
+       // put EXPORT Address Table
+       for i = 0; i < nexport; i++ {
+               Lputl(uint32(dexport[i].Value - PEBASE))
+       }
+
+       // put EXPORT Name Pointer Table
+       v = int(e.Name + uint32(len(outfile)) + 1)
+
+       for i = 0; i < nexport; i++ {
+               Lputl(uint32(v))
+               v += len(dexport[i].Extname) + 1
+       }
+
+       // put EXPORT Ordinal Table
+       for i = 0; i < nexport; i++ {
+               Wputl(uint16(i))
+       }
+
+       // put Names
+       strnput(outfile, len(outfile)+1)
+
+       for i = 0; i < nexport; i++ {
+               strnput(dexport[i].Extname, len(dexport[i].Extname)+1)
+       }
+       strnput("", int(sect.SizeOfRawData-uint32(size)))
+}
+
+func dope() {
+       var rel *LSym
+
+       /* relocation table */
+       rel = Linklookup(Ctxt, ".rel", 0)
+
+       rel.Reachable = true
+       rel.Type = SELFROSECT
+
+       initdynimport()
+       initdynexport()
+}
+
+func strtbladd(name string) int {
+       off := len(strtbl) + 4 // offset includes 4-byte length at beginning of table
+       strtbl = append(strtbl, name...)
+       strtbl = append(strtbl, 0)
+       return off
+}
+
+/*
+ * For more than 8 characters section names, name contains a slash (/) that is
+ * followed by an ASCII representation of a decimal number that is an offset into
+ * the string table.
+ * reference: pecoff_v8.docx Page 24.
+ * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
+ */
+func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER {
+       var h *IMAGE_SECTION_HEADER
+       var s string
+       var off int
+
+       if size == 0 {
+               return nil
+       }
+
+       off = strtbladd(name)
+       s = fmt.Sprintf("/%d", off)
+       h = addpesection(s, int(size), int(size))
+       h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
+
+       return h
+}
+
+func addpesym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
+       var cs *COFFSym
+
+       if s == nil {
+               return
+       }
+
+       if s.Sect == nil {
+               return
+       }
+
+       switch type_ {
+       default:
+               return
+
+       case 'D',
+               'B',
+               'T':
+               break
+       }
+
+       if coffsym != nil {
+               cs = &coffsym[ncoffsym]
+               cs.sym = s
+               if len(s.Name) > 8 {
+                       cs.strtbloff = strtbladd(s.Name)
+               }
+               if uint64(s.Value) >= Segdata.Vaddr {
+                       cs.value = int64(uint64(s.Value) - Segdata.Vaddr)
+                       cs.sect = datasect
+               } else if uint64(s.Value) >= Segtext.Vaddr {
+                       cs.value = int64(uint64(s.Value) - Segtext.Vaddr)
+                       cs.sect = textsect
+               } else {
+                       cs.value = 0
+                       cs.sect = 0
+                       Diag("addpesym %#x", addr)
+               }
+       }
+
+       ncoffsym++
+}
+
+func addpesymtable() {
+       var h *IMAGE_SECTION_HEADER
+       var i int
+       var size int
+       var s *COFFSym
+
+       if Debug['s'] == 0 {
+               genasmsym(addpesym)
+               coffsym = make([]COFFSym, ncoffsym)
+               ncoffsym = 0
+               genasmsym(addpesym)
+       }
+
+       size = len(strtbl) + 4 + 18*ncoffsym
+       h = addpesection(".symtab", size, size)
+       h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
+       chksectoff(h, Cpos())
+       fh.PointerToSymbolTable = uint32(Cpos())
+       fh.NumberOfSymbols = uint32(ncoffsym)
+
+       // put COFF symbol table
+       for i = 0; i < ncoffsym; i++ {
+               s = &coffsym[i]
+               if s.strtbloff == 0 {
+                       strnput(s.sym.Name, 8)
+               } else {
+                       Lputl(0)
+                       Lputl(uint32(s.strtbloff))
+               }
+
+               Lputl(uint32(s.value))
+               Wputl(uint16(s.sect))
+               Wputl(0x0308) // "array of structs"
+               Cput(2)       // storage class: external
+               Cput(0)       // no aux entries
+       }
+
+       // put COFF string table
+       Lputl(uint32(len(strtbl)) + 4)
+
+       for i = 0; i < len(strtbl); i++ {
+               Cput(uint8(strtbl[i]))
+       }
+       strnput("", int(h.SizeOfRawData-uint32(size)))
+}
+
+func setpersrc(sym *LSym) {
+       if rsrcsym != nil {
+               Diag("too many .rsrc sections")
+       }
+
+       rsrcsym = sym
+}
+
+func addpersrc() {
+       var h *IMAGE_SECTION_HEADER
+       var p []byte
+       var val uint32
+       var r *Reloc
+       var ri int
+
+       if rsrcsym == nil {
+               return
+       }
+
+       h = addpesection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
+       h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
+       chksectoff(h, Cpos())
+
+       // relocation
+       for ri = 0; ri < len(rsrcsym.R); ri++ {
+               r = &rsrcsym.R[ri]
+               p = rsrcsym.P[r.Off:]
+               val = uint32(int64(h.VirtualAddress) + r.Add)
+
+               // 32-bit little-endian
+               p[0] = byte(val)
+
+               p[1] = byte(val >> 8)
+               p[2] = byte(val >> 16)
+               p[3] = byte(val >> 24)
+       }
+
+       Cwrite(rsrcsym.P)
+       strnput("", int(int64(h.SizeOfRawData)-rsrcsym.Size))
+
+       // update data directory
+       dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.VirtualAddress
+
+       dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize
+}
+
+func Asmbpe() {
+       var t *IMAGE_SECTION_HEADER
+       var d *IMAGE_SECTION_HEADER
+
+       switch Thearch.Thechar {
+       default:
+               Diag("unknown PE architecture")
+               Errorexit()
+               fallthrough
+
+       case '6':
+               fh.Machine = IMAGE_FILE_MACHINE_AMD64
+
+       case '8':
+               fh.Machine = IMAGE_FILE_MACHINE_I386
+       }
+
+       t = addpesection(".text", int(Segtext.Length), int(Segtext.Length))
+       t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
+       chksectseg(t, &Segtext)
+       textsect = pensect
+
+       d = addpesection(".data", int(Segdata.Length), int(Segdata.Filelen))
+       d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
+       chksectseg(d, &Segdata)
+       datasect = pensect
+
+       if Debug['s'] == 0 {
+               dwarfaddpeheaders()
+       }
+
+       Cseek(int64(nextfileoff))
+       addimports(d)
+       addexports()
+       addpesymtable()
+       addpersrc()
+
+       fh.NumberOfSections = uint16(pensect)
+
+       // Being able to produce identical output for identical input is
+       // much more beneficial than having build timestamp in the header.
+       fh.TimeDateStamp = 0
+
+       fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
+       if pe64 != 0 {
+               fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
+               fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE
+               oh64.Magic = 0x20b
+       } else {
+               fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
+               fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE
+               oh.Magic = 0x10b // PE32
+               oh.BaseOfData = d.VirtualAddress
+       }
+
+       // Fill out both oh64 and oh. We only use one. Oh well.
+       oh64.MajorLinkerVersion = 3
+
+       oh.MajorLinkerVersion = 3
+       oh64.MinorLinkerVersion = 0
+       oh.MinorLinkerVersion = 0
+       oh64.SizeOfCode = t.SizeOfRawData
+       oh.SizeOfCode = t.SizeOfRawData
+       oh64.SizeOfInitializedData = d.SizeOfRawData
+       oh.SizeOfInitializedData = d.SizeOfRawData
+       oh64.SizeOfUninitializedData = 0
+       oh.SizeOfUninitializedData = 0
+       oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+       oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+       oh64.BaseOfCode = t.VirtualAddress
+       oh.BaseOfCode = t.VirtualAddress
+       oh64.ImageBase = PEBASE
+       oh.ImageBase = PEBASE
+       oh64.SectionAlignment = PESECTALIGN
+       oh.SectionAlignment = PESECTALIGN
+       oh64.FileAlignment = PEFILEALIGN
+       oh.FileAlignment = PEFILEALIGN
+       oh64.MajorOperatingSystemVersion = 4
+       oh.MajorOperatingSystemVersion = 4
+       oh64.MinorOperatingSystemVersion = 0
+       oh.MinorOperatingSystemVersion = 0
+       oh64.MajorImageVersion = 1
+       oh.MajorImageVersion = 1
+       oh64.MinorImageVersion = 0
+       oh.MinorImageVersion = 0
+       oh64.MajorSubsystemVersion = 4
+       oh.MajorSubsystemVersion = 4
+       oh64.MinorSubsystemVersion = 0
+       oh.MinorSubsystemVersion = 0
+       oh64.SizeOfImage = uint32(nextsectoff)
+       oh.SizeOfImage = uint32(nextsectoff)
+       oh64.SizeOfHeaders = uint32(PEFILEHEADR)
+       oh.SizeOfHeaders = uint32(PEFILEHEADR)
+       if headstring == "windowsgui" {
+               oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
+               oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
+       } else {
+               oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
+               oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
+       }
+
+       // Disable stack growth as we don't want Windows to
+       // fiddle with the thread stack limits, which we set
+       // ourselves to circumvent the stack checks in the
+       // Windows exception dispatcher.
+       // Commit size must be strictly less than reserve
+       // size otherwise reserve will be rounded up to a
+       // larger size, as verified with VMMap.
+
+       // Go code would be OK with 64k stacks, but we need larger stacks for cgo.
+       // That default stack reserve size affects only the main thread,
+       // for other threads we specify stack size in runtime explicitly
+       // (runtime knows whether cgo is enabled or not).
+       // If you change stack reserve sizes here,
+       // change STACKSIZE in runtime/cgo/gcc_windows_{386,amd64}.c as well.
+       if !iscgo {
+               oh64.SizeOfStackReserve = 0x00010000
+               oh.SizeOfStackReserve = 0x00010000
+               oh64.SizeOfStackCommit = 0x0000ffff
+               oh.SizeOfStackCommit = 0x0000ffff
+       } else {
+               oh64.SizeOfStackReserve = 0x00200000
+               oh.SizeOfStackReserve = 0x00100000
+
+               // account for 2 guard pages
+               oh64.SizeOfStackCommit = 0x00200000 - 0x2000
+
+               oh.SizeOfStackCommit = 0x00100000 - 0x2000
+       }
+
+       oh64.SizeOfHeapReserve = 0x00100000
+       oh.SizeOfHeapReserve = 0x00100000
+       oh64.SizeOfHeapCommit = 0x00001000
+       oh.SizeOfHeapCommit = 0x00001000
+       oh64.NumberOfRvaAndSizes = 16
+       oh.NumberOfRvaAndSizes = 16
+
+       pewrite()
+}
diff --git a/src/cmd/internal/ld/pobj.go b/src/cmd/internal/ld/pobj.go
new file mode 100644 (file)
index 0000000..226ccf1
--- /dev/null
@@ -0,0 +1,224 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+import (
+       "cmd/internal/obj"
+       "flag"
+       "fmt"
+       "os"
+       "strings"
+)
+
+// Reading object files.
+
+var noname string = "<none>"
+
+var paramspace string = "FP"
+
+func Ldmain() {
+       Ctxt = linknew(Thelinkarch)
+       Ctxt.Thechar = int32(Thearch.Thechar)
+       Ctxt.Thestring = Thestring
+       Ctxt.Diag = Diag
+       Ctxt.Bso = &Bso
+
+       Bso = *Binitw(os.Stdout)
+       Debug = [128]int{}
+       nerrors = 0
+       outfile = ""
+       HEADTYPE = -1
+       INITTEXT = -1
+       INITDAT = -1
+       INITRND = -1
+       INITENTRY = ""
+       Linkmode = LinkAuto
+
+       // For testing behavior of go command when tools crash.
+       // Undocumented, not in standard flag parser to avoid
+       // exposing in usage message.
+       for _, arg := range os.Args {
+               if arg == "-crash_for_testing" {
+                       *(*int)(nil) = 0
+               }
+       }
+
+       if Thearch.Thechar == '5' && Ctxt.Goarm == 5 {
+               Debug['F'] = 1
+       }
+
+       obj.Flagcount("1", "use alternate profiling code", &Debug['1'])
+       if Thearch.Thechar == '6' {
+               obj.Flagcount("8", "assume 64-bit addresses", &Debug['8'])
+       }
+       obj.Flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo)
+       obj.Flagcount("C", "check Go calls to C code", &Debug['C'])
+       obj.Flagint64("D", "addr: data address", &INITDAT)
+       obj.Flagstr("E", "sym: entry symbol", &INITENTRY)
+       if Thearch.Thechar == '5' {
+               obj.Flagcount("G", "debug pseudo-ops", &Debug['G'])
+       }
+       obj.Flagfn1("I", "interp: set ELF interp", setinterp)
+       obj.Flagfn1("L", "dir: add dir to library path", Lflag)
+       obj.Flagfn1("H", "head: header type", setheadtype)
+       obj.Flagcount("K", "add stack underflow checks", &Debug['K'])
+       if Thearch.Thechar == '5' {
+               obj.Flagcount("M", "disable software div/mod", &Debug['M'])
+       }
+       obj.Flagcount("O", "print pc-line tables", &Debug['O'])
+       obj.Flagcount("Q", "debug byte-register code gen", &Debug['Q'])
+       if Thearch.Thechar == '5' {
+               obj.Flagcount("P", "debug code generation", &Debug['P'])
+       }
+       obj.Flagint32("R", "rnd: address rounding", &INITRND)
+       obj.Flagcount("nil", "check type signatures", &Debug['S'])
+       obj.Flagint64("T", "addr: text address", &INITTEXT)
+       obj.Flagfn0("V", "print version and exit", doversion)
+       obj.Flagcount("W", "disassemble input", &Debug['W'])
+       obj.Flagfn1("X", "name value: define string data", addstrdata1)
+       obj.Flagcount("Z", "clear stack frame on entry", &Debug['Z'])
+       obj.Flagcount("a", "disassemble output", &Debug['a'])
+       obj.Flagcount("c", "dump call graph", &Debug['c'])
+       obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
+       obj.Flagstr("extld", "ld: linker to run in external mode", &extld)
+       obj.Flagstr("extldflags", "ldflags: flags for external linker", &extldflags)
+       obj.Flagcount("f", "ignore version mismatch", &Debug['f'])
+       obj.Flagcount("g", "disable go package data checks", &Debug['g'])
+       obj.Flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix)
+       obj.Flagstr("k", "sym: set field tracking symbol", &tracksym)
+       obj.Flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode)
+       obj.Flagcount("n", "dump symbol table", &Debug['n'])
+       obj.Flagstr("o", "outfile: set output file", &outfile)
+       obj.Flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath)
+       obj.Flagcount("race", "enable race detector", &flag_race)
+       obj.Flagcount("s", "disable symbol table", &Debug['s'])
+       if Thearch.Thechar == '5' || Thearch.Thechar == '6' {
+               obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &Flag_shared)
+       }
+       obj.Flagstr("tmpdir", "dir: leave temporary files in this directory", &tmpdir)
+       obj.Flagcount("u", "reject unsafe packages", &Debug['u'])
+       obj.Flagcount("v", "print link trace", &Debug['v'])
+       obj.Flagcount("w", "disable DWARF generation", &Debug['w'])
+
+       // Clumsy hack to preserve old behavior of -X taking two arguments.
+       for i := 0; i < len(os.Args); i++ {
+               arg := os.Args[i]
+               if (arg == "--X" || arg == "-X") && i+2 < len(os.Args) {
+                       os.Args[i+2] = "-X=VALUE:" + os.Args[i+2]
+                       i += 2
+               } else if (strings.HasPrefix(arg, "--X=") || strings.HasPrefix(arg, "-X=")) && i+1 < len(os.Args) {
+                       os.Args[i+1] = "-X=VALUE:" + os.Args[i+1]
+                       i++
+               }
+       }
+       obj.Flagstr("cpuprofile", "file: write cpu profile to file", &cpuprofile)
+       obj.Flagstr("memprofile", "file: write memory profile to file", &memprofile)
+       obj.Flagparse(usage)
+       startProfile()
+       Ctxt.Bso = &Bso
+       Ctxt.Debugvlog = int32(Debug['v'])
+
+       if flag.NArg() != 1 {
+               usage()
+       }
+
+       if outfile == "" {
+               if HEADTYPE == Hwindows {
+                       outfile = fmt.Sprintf("%c.out.exe", Thearch.Thechar)
+               } else {
+                       outfile = fmt.Sprintf("%c.out", Thearch.Thechar)
+               }
+       }
+
+       libinit() // creates outfile
+
+       if HEADTYPE == -1 {
+               HEADTYPE = int32(headtype(goos))
+       }
+       Ctxt.Headtype = int(HEADTYPE)
+       if headstring == "" {
+               headstring = Headstr(int(HEADTYPE))
+       }
+
+       Thearch.Archinit()
+
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
+       }
+       Bflush(&Bso)
+
+       addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main")
+       loadlib()
+
+       if Thearch.Thechar == '5' {
+               // mark some functions that are only referenced after linker code editing
+               if Debug['F'] != 0 {
+                       mark(Linkrlookup(Ctxt, "_sfloat", 0))
+               }
+               mark(Linklookup(Ctxt, "runtime.read_tls_fallback", 0))
+       }
+
+       checkgo()
+       deadcode()
+       callgraph()
+       paramspace = "SP" /* (FP) now (SP) on output */
+
+       doelf()
+       if HEADTYPE == Hdarwin {
+               domacho()
+       }
+       dostkcheck()
+       if HEADTYPE == Hwindows {
+               dope()
+       }
+       addexport()
+       Thearch.Gentext() // trampolines, call stubs, etc.
+       textaddress()
+       pclntab()
+       findfunctab()
+       symtab()
+       dodata()
+       address()
+       doweak()
+       reloc()
+       Thearch.Asmb()
+       undef()
+       hostlink()
+       if Debug['v'] != 0 {
+               fmt.Fprintf(&Bso, "%5.2f cpu time\n", obj.Cputime())
+               fmt.Fprintf(&Bso, "%d symbols\n", Ctxt.Nsymbol)
+               fmt.Fprintf(&Bso, "%d liveness data\n", liveness)
+       }
+
+       Bflush(&Bso)
+
+       Errorexit()
+}
diff --git a/src/cmd/internal/ld/sym.go b/src/cmd/internal/ld/sym.go
new file mode 100644 (file)
index 0000000..7e275a6
--- /dev/null
@@ -0,0 +1,238 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+       "os"
+       "path/filepath"
+)
+
+func yy_isalpha(c int) bool {
+       return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+}
+
+var headers = []struct {
+       name string
+       val  int
+}{
+       {"darwin", Hdarwin},
+       {"dragonfly", Hdragonfly},
+       {"elf", Helf},
+       {"freebsd", Hfreebsd},
+       {"linux", Hlinux},
+       {"android", Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
+       {"nacl", Hnacl},
+       {"netbsd", Hnetbsd},
+       {"openbsd", Hopenbsd},
+       {"plan9", Hplan9},
+       {"solaris", Hsolaris},
+       {"windows", Hwindows},
+       {"windowsgui", Hwindows},
+}
+
+func linknew(arch *LinkArch) *Link {
+       var ctxt *Link
+       var p string
+       var buf string
+
+       ctxt = new(Link)
+       ctxt.Hash = make(map[symVer]*LSym)
+       ctxt.Arch = arch
+       ctxt.Version = HistVersion
+       ctxt.Goroot = obj.Getgoroot()
+
+       p = obj.Getgoarch()
+       if p != arch.Name {
+               log.Fatalf("invalid goarch %s (want %s)", p, arch.Name)
+       }
+
+       buf, _ = os.Getwd()
+       if buf == "" {
+               buf = "/???"
+       }
+       buf = filepath.ToSlash(buf)
+
+       ctxt.Headtype = headtype(obj.Getgoos())
+       if ctxt.Headtype < 0 {
+               log.Fatalf("unknown goos %s", obj.Getgoos())
+       }
+
+       // Record thread-local storage offset.
+       // TODO(rsc): Move tlsoffset back into the linker.
+       switch ctxt.Headtype {
+       default:
+               log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))
+
+       case Hplan9,
+               Hwindows:
+               break
+
+               /*
+                * ELF uses TLS offset negative from FS.
+                * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
+                * Known to low-level assembly in package runtime and runtime/cgo.
+                */
+       case Hlinux,
+               Hfreebsd,
+               Hnetbsd,
+               Hopenbsd,
+               Hdragonfly,
+               Hsolaris:
+               ctxt.Tlsoffset = -2 * ctxt.Arch.Ptrsize
+
+       case Hnacl:
+               switch ctxt.Arch.Thechar {
+               default:
+                       log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
+
+               case '5':
+                       ctxt.Tlsoffset = 0
+
+               case '6':
+                       ctxt.Tlsoffset = 0
+
+               case '8':
+                       ctxt.Tlsoffset = -8
+               }
+
+               /*
+                * OS X system constants - offset from 0(GS) to our TLS.
+                * Explained in ../../runtime/cgo/gcc_darwin_*.c.
+                */
+       case Hdarwin:
+               switch ctxt.Arch.Thechar {
+               default:
+                       log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
+
+               case '6':
+                       ctxt.Tlsoffset = 0x8a0
+
+               case '8':
+                       ctxt.Tlsoffset = 0x468
+
+               case '5':
+                       ctxt.Tlsoffset = 0 // dummy value, not needed
+               }
+       }
+
+       // On arm, record goarm.
+       if ctxt.Arch.Thechar == '5' {
+               p = obj.Getgoarm()
+               if p != "" {
+                       ctxt.Goarm = int32(obj.Atoi(p))
+               } else {
+                       ctxt.Goarm = 6
+               }
+       }
+
+       return ctxt
+}
+
+func linknewsym(ctxt *Link, symb string, v int) *LSym {
+       var s *LSym
+
+       s = new(LSym)
+       *s = LSym{}
+
+       s.Dynid = -1
+       s.Plt = -1
+       s.Got = -1
+       s.Name = symb
+       s.Type = 0
+       s.Version = int16(v)
+       s.Value = 0
+       s.Sig = 0
+       s.Size = 0
+       ctxt.Nsymbol++
+
+       s.Allsym = ctxt.Allsym
+       ctxt.Allsym = s
+
+       return s
+}
+
+type symVer struct {
+       sym string
+       ver int
+}
+
+func _lookup(ctxt *Link, symb string, v int, creat int) *LSym {
+       s := ctxt.Hash[symVer{symb, v}]
+       if s != nil {
+               return s
+       }
+       if creat == 0 {
+               return nil
+       }
+
+       s = linknewsym(ctxt, symb, v)
+       s.Extname = s.Name
+       ctxt.Hash[symVer{symb, v}] = s
+       return s
+}
+
+func Linklookup(ctxt *Link, name string, v int) *LSym {
+       return _lookup(ctxt, name, v, 1)
+}
+
+// read-only lookup
+func Linkrlookup(ctxt *Link, name string, v int) *LSym {
+       return _lookup(ctxt, name, v, 0)
+}
+
+var headstr_buf string
+
+func Headstr(v int) string {
+       var i int
+
+       for i = 0; i < len(headers); i++ {
+               if v == headers[i].val {
+                       return headers[i].name
+               }
+       }
+       headstr_buf = fmt.Sprintf("%d", v)
+       return headstr_buf
+}
+
+func headtype(name string) int {
+       var i int
+
+       for i = 0; i < len(headers); i++ {
+               if name == headers[i].name {
+                       return headers[i].val
+               }
+       }
+       return -1
+}
diff --git a/src/cmd/internal/ld/symtab.go b/src/cmd/internal/ld/symtab.go
new file mode 100644 (file)
index 0000000..997300c
--- /dev/null
@@ -0,0 +1,440 @@
+// Inferno utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+import "strings"
+
+// Symbol table.
+
+var maxelfstr int
+
+func putelfstr(s string) int {
+       var off int
+       var n int
+
+       if len(Elfstrdat) == 0 && s != "" {
+               // first entry must be empty string
+               putelfstr("")
+       }
+
+       // Rewrite · to . for ASCII-only tools like DTrace (sigh)
+       s = strings.Replace(s, "·", ".", -1)
+
+       n = len(s) + 1
+       for len(Elfstrdat)+n > cap(Elfstrdat) {
+               Elfstrdat = append(Elfstrdat[:cap(Elfstrdat)], 0)[:len(Elfstrdat)]
+       }
+
+       off = len(Elfstrdat)
+       Elfstrdat = Elfstrdat[:off+n]
+       copy(Elfstrdat[off:], s)
+
+       return off
+}
+
+func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) {
+       switch Thearch.Thechar {
+       case '6',
+               '9':
+               Thearch.Lput(uint32(off))
+               Cput(uint8(info))
+               Cput(uint8(other))
+               Thearch.Wput(uint16(shndx))
+               Thearch.Vput(uint64(addr))
+               Thearch.Vput(uint64(size))
+               Symsize += ELF64SYMSIZE
+
+       default:
+               Thearch.Lput(uint32(off))
+               Thearch.Lput(uint32(addr))
+               Thearch.Lput(uint32(size))
+               Cput(uint8(info))
+               Cput(uint8(other))
+               Thearch.Wput(uint16(shndx))
+               Symsize += ELF32SYMSIZE
+       }
+}
+
+var numelfsym int = 1 // 0 is reserved
+
+var elfbind int
+
+func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
+       var bind int
+       var type_ int
+       var off int
+       var other int
+       var xo *LSym
+
+       switch t {
+       default:
+               return
+
+       case 'T':
+               type_ = STT_FUNC
+
+       case 'D':
+               type_ = STT_OBJECT
+
+       case 'B':
+               type_ = STT_OBJECT
+       }
+
+       xo = x
+       for xo.Outer != nil {
+               xo = xo.Outer
+       }
+       if xo.Sect == nil {
+               Ctxt.Cursym = x
+               Diag("missing section in putelfsym")
+               return
+       }
+
+       if (xo.Sect.(*Section)).Elfsect == nil {
+               Ctxt.Cursym = x
+               Diag("missing ELF section in putelfsym")
+               return
+       }
+
+       // One pass for each binding: STB_LOCAL, STB_GLOBAL,
+       // maybe one day STB_WEAK.
+       bind = STB_GLOBAL
+
+       if ver != 0 || (x.Type&SHIDDEN != 0) {
+               bind = STB_LOCAL
+       }
+
+       // In external linking mode, we have to invoke gcc with -rdynamic
+       // to get the exported symbols put into the dynamic symbol table.
+       // To avoid filling the dynamic table with lots of unnecessary symbols,
+       // mark all Go symbols local (not global) in the final executable.
+       if Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 {
+               bind = STB_LOCAL
+       }
+
+       if bind != elfbind {
+               return
+       }
+
+       off = putelfstr(s)
+       if Linkmode == LinkExternal {
+               addr -= int64((xo.Sect.(*Section)).Vaddr)
+       }
+       other = 2
+       if x.Type&SHIDDEN != 0 {
+               other = 0
+       }
+       putelfsyment(off, addr, size, bind<<4|type_&0xf, ((xo.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, other)
+       x.Elfsym = int32(numelfsym)
+       numelfsym++
+}
+
+func putelfsectionsym(s *LSym, shndx int) {
+       putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
+       s.Elfsym = int32(numelfsym)
+       numelfsym++
+}
+
+func putelfsymshndx(sympos int64, shndx int) {
+       var here int64
+
+       here = Cpos()
+       switch Thearch.Thechar {
+       case '6':
+               Cseek(sympos + 6)
+
+       default:
+               Cseek(sympos + 14)
+       }
+
+       Thearch.Wput(uint16(shndx))
+       Cseek(here)
+}
+
+func Asmelfsym() {
+       var s *LSym
+       var name string
+
+       // the first symbol entry is reserved
+       putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
+
+       dwarfaddelfsectionsyms()
+
+       elfbind = STB_LOCAL
+       genasmsym(putelfsym)
+
+       if Linkmode == LinkExternal && HEADTYPE != Hopenbsd {
+               s = Linklookup(Ctxt, "runtime.tlsg", 0)
+               if s.Sect == nil {
+                       Ctxt.Cursym = nil
+                       Diag("missing section for %s", s.Name)
+                       Errorexit()
+               }
+
+               if goos == "android" {
+                       // Android emulates runtime.tlsg as a regular variable.
+                       putelfsyment(putelfstr(s.Name), 0, s.Size, STB_LOCAL<<4|STT_OBJECT, ((s.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, 0)
+               } else {
+                       putelfsyment(putelfstr(s.Name), 0, s.Size, STB_LOCAL<<4|STT_TLS, ((s.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, 0)
+               }
+
+               s.Elfsym = int32(numelfsym)
+               numelfsym++
+       }
+
+       elfbind = STB_GLOBAL
+       elfglobalsymndx = numelfsym
+       genasmsym(putelfsym)
+
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if s.Type != SHOSTOBJ && (s.Type != SDYNIMPORT || !s.Reachable) {
+                       continue
+               }
+               if s.Type == SDYNIMPORT {
+                       name = s.Extname
+               } else {
+                       name = s.Name
+               }
+               putelfsyment(putelfstr(name), 0, 0, STB_GLOBAL<<4|STT_NOTYPE, 0, 0)
+               s.Elfsym = int32(numelfsym)
+               numelfsym++
+       }
+}
+
+func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
+       var i int
+       var l int
+
+       switch t {
+       case 'T',
+               'L',
+               'D',
+               'B':
+               if ver != 0 {
+                       t += 'a' - 'A'
+               }
+               fallthrough
+
+       case 'a',
+               'p',
+               'f',
+               'z',
+               'Z',
+               'm':
+               l = 4
+               if HEADTYPE == Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
+                       Lputb(uint32(addr >> 32))
+                       l = 8
+               }
+
+               Lputb(uint32(addr))
+               Cput(uint8(t + 0x80)) /* 0x80 is variable length */
+
+               if t == 'z' || t == 'Z' {
+                       Cput(uint8(s[0]))
+                       for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 {
+                               Cput(uint8(s[i]))
+                               Cput(uint8(s[i+1]))
+                       }
+
+                       Cput(0)
+                       Cput(0)
+                       i++
+               } else {
+                       /* skip the '<' in filenames */
+                       if t == 'f' {
+                               s = s[1:]
+                       }
+                       for i = 0; i < len(s); i++ {
+                               Cput(uint8(s[i]))
+                       }
+                       Cput(0)
+               }
+
+               Symsize += int32(l) + 1 + int32(i) + 1
+
+       default:
+               return
+       }
+}
+
+func Asmplan9sym() {
+       genasmsym(putplan9sym)
+}
+
+var symt *LSym
+
+func Wputl(w uint16) {
+       Cput(uint8(w))
+       Cput(uint8(w >> 8))
+}
+
+func Wputb(w uint16) {
+       Cput(uint8(w >> 8))
+       Cput(uint8(w))
+}
+
+func Lputb(l uint32) {
+       Cput(uint8(l >> 24))
+       Cput(uint8(l >> 16))
+       Cput(uint8(l >> 8))
+       Cput(uint8(l))
+}
+
+func Lputl(l uint32) {
+       Cput(uint8(l))
+       Cput(uint8(l >> 8))
+       Cput(uint8(l >> 16))
+       Cput(uint8(l >> 24))
+}
+
+func Vputb(v uint64) {
+       Lputb(uint32(v >> 32))
+       Lputb(uint32(v))
+}
+
+func Vputl(v uint64) {
+       Lputl(uint32(v))
+       Lputl(uint32(v >> 32))
+}
+
+func symtab() {
+       var s *LSym
+       var symtype *LSym
+       var symtypelink *LSym
+       var symgostring *LSym
+       var symgofunc *LSym
+
+       dosymtype()
+
+       // Define these so that they'll get put into the symbol table.
+       // data.c:/^address will provide the actual values.
+       xdefine("runtime.text", STEXT, 0)
+
+       xdefine("runtime.etext", STEXT, 0)
+       xdefine("runtime.typelink", SRODATA, 0)
+       xdefine("runtime.etypelink", SRODATA, 0)
+       xdefine("runtime.rodata", SRODATA, 0)
+       xdefine("runtime.erodata", SRODATA, 0)
+       xdefine("runtime.noptrdata", SNOPTRDATA, 0)
+       xdefine("runtime.enoptrdata", SNOPTRDATA, 0)
+       xdefine("runtime.data", SDATA, 0)
+       xdefine("runtime.edata", SDATA, 0)
+       xdefine("runtime.bss", SBSS, 0)
+       xdefine("runtime.ebss", SBSS, 0)
+       xdefine("runtime.noptrbss", SNOPTRBSS, 0)
+       xdefine("runtime.enoptrbss", SNOPTRBSS, 0)
+       xdefine("runtime.end", SBSS, 0)
+       xdefine("runtime.epclntab", SRODATA, 0)
+       xdefine("runtime.esymtab", SRODATA, 0)
+
+       // garbage collection symbols
+       s = Linklookup(Ctxt, "runtime.gcdata", 0)
+
+       s.Type = SRODATA
+       s.Size = 0
+       s.Reachable = true
+       xdefine("runtime.egcdata", SRODATA, 0)
+
+       s = Linklookup(Ctxt, "runtime.gcbss", 0)
+       s.Type = SRODATA
+       s.Size = 0
+       s.Reachable = true
+       xdefine("runtime.egcbss", SRODATA, 0)
+
+       // pseudo-symbols to mark locations of type, string, and go string data.
+       s = Linklookup(Ctxt, "type.*", 0)
+
+       s.Type = STYPE
+       s.Size = 0
+       s.Reachable = true
+       symtype = s
+
+       s = Linklookup(Ctxt, "go.string.*", 0)
+       s.Type = SGOSTRING
+       s.Size = 0
+       s.Reachable = true
+       symgostring = s
+
+       s = Linklookup(Ctxt, "go.func.*", 0)
+       s.Type = SGOFUNC
+       s.Size = 0
+       s.Reachable = true
+       symgofunc = s
+
+       symtypelink = Linklookup(Ctxt, "runtime.typelink", 0)
+
+       symt = Linklookup(Ctxt, "runtime.symtab", 0)
+       symt.Type = SSYMTAB
+       symt.Size = 0
+       symt.Reachable = true
+
+       // assign specific types so that they sort together.
+       // within a type they sort by size, so the .* symbols
+       // just defined above will be first.
+       // hide the specific symbols.
+       for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+               if !s.Reachable || s.Special != 0 || s.Type != SRODATA {
+                       continue
+               }
+               if strings.HasPrefix(s.Name, "type.") {
+                       s.Type = STYPE
+                       s.Hide = 1
+                       s.Outer = symtype
+               }
+
+               if strings.HasPrefix(s.Name, "go.typelink.") {
+                       s.Type = STYPELINK
+                       s.Hide = 1
+                       s.Outer = symtypelink
+               }
+
+               if strings.HasPrefix(s.Name, "go.string.") {
+                       s.Type = SGOSTRING
+                       s.Hide = 1
+                       s.Outer = symgostring
+               }
+
+               if strings.HasPrefix(s.Name, "go.func.") {
+                       s.Type = SGOFUNC
+                       s.Hide = 1
+                       s.Outer = symgofunc
+               }
+
+               if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") {
+                       s.Type = SGOFUNC
+                       s.Hide = 1
+                       s.Outer = symgofunc
+                       s.Align = 4
+                       liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
+               }
+       }
+}
diff --git a/src/cmd/internal/ld/textflag.go b/src/cmd/internal/ld/textflag.go
new file mode 100644 (file)
index 0000000..335f20d
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright 2013 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 ld
+
+// Writing and reading of Go object files.
+//
+// Originally, Go object files were Plan 9 object files, but no longer.
+// Now they are more like standard object files, in that each symbol is defined
+// by an associated memory image (bytes) and a list of relocations to apply
+// during linking. We do not (yet?) use a standard file format, however.
+// For now, the format is chosen to be as simple as possible to read and write.
+// It may change for reasons of efficiency, or we may even switch to a
+// standard file format if there are compelling benefits to doing so.
+// See golang.org/s/go13linker for more background.
+//
+// The file format is:
+//
+//     - magic header: "\x00\x00go13ld"
+//     - byte 1 - version number
+//     - sequence of strings giving dependencies (imported packages)
+//     - empty string (marks end of sequence)
+//     - sequence of defined symbols
+//     - byte 0xff (marks end of sequence)
+//     - magic footer: "\xff\xffgo13ld"
+//
+// All integers are stored in a zigzag varint format.
+// See golang.org/s/go12symtab for a definition.
+//
+// Data blocks and strings are both stored as an integer
+// followed by that many bytes.
+//
+// A symbol reference is a string name followed by a version.
+// An empty name corresponds to a nil LSym* pointer.
+//
+// Each symbol is laid out as the following fields (taken from LSym*):
+//
+//     - byte 0xfe (sanity check for synchronization)
+//     - type [int]
+//     - name [string]
+//     - version [int]
+//     - flags [int]
+//             1 dupok
+//     - size [int]
+//     - gotype [symbol reference]
+//     - p [data block]
+//     - nr [int]
+//     - r [nr relocations, sorted by off]
+//
+// If type == STEXT, there are a few more fields:
+//
+//     - args [int]
+//     - locals [int]
+//     - nosplit [int]
+//     - flags [int]
+//             1 leaf
+//             2 C function
+//     - nlocal [int]
+//     - local [nlocal automatics]
+//     - pcln [pcln table]
+//
+// Each relocation has the encoding:
+//
+//     - off [int]
+//     - siz [int]
+//     - type [int]
+//     - add [int]
+//     - xadd [int]
+//     - sym [symbol reference]
+//     - xsym [symbol reference]
+//
+// Each local has the encoding:
+//
+//     - asym [symbol reference]
+//     - offset [int]
+//     - type [int]
+//     - gotype [symbol reference]
+//
+// The pcln table has the encoding:
+//
+//     - pcsp [data block]
+//     - pcfile [data block]
+//     - pcline [data block]
+//     - npcdata [int]
+//     - pcdata [npcdata data blocks]
+//     - nfuncdata [int]
+//     - funcdata [nfuncdata symbol references]
+//     - funcdatasym [nfuncdata ints]
+//     - nfile [int]
+//     - file [nfile symbol references]
+//
+// The file layout and meaning of type integers are architecture-independent.
+//
+// TODO(rsc): The file format is good for a first pass but needs work.
+//     - There are SymID in the object file that should really just be strings.
+//     - The actual symbol memory images are interlaced with the symbol
+//       metadata. They should be separated, to reduce the I/O required to
+//       load just the metadata.
+//     - The symbol references should be shortened, either with a symbol
+//       table or by using a simple backward index to an earlier mentioned symbol.
+
+// Copyright 2013 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.
+
+// This file defines flags attached to various functions
+// and data objects.  The compilers, assemblers, and linker must
+// all agree on these values.
+
+// Don't profile the marked routine.  This flag is deprecated.
+
+// It is ok for the linker to get multiple of these symbols.  It will
+// pick one of the duplicates to use.
+
+// Don't insert stack check preamble.
+
+// Put this data in a read-only section.
+
+// This data contains no pointers.
+
+// This is a wrapper function and should not count as disabling 'recover'.
+
+// This function uses its incoming context register.
+const (
+       NOPROF   = 1
+       DUPOK    = 2
+       NOSPLIT  = 4
+       RODATA   = 8
+       NOPTR    = 16
+       WRAPPER  = 32
+       NEEDCTXT = 64
+)
diff --git a/src/cmd/internal/ld/util.go b/src/cmd/internal/ld/util.go
new file mode 100644 (file)
index 0000000..9a56f09
--- /dev/null
@@ -0,0 +1,369 @@
+// Copyright 2015 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 ld
+
+import (
+       "bufio"
+       "bytes"
+       "encoding/binary"
+       "io"
+       "log"
+       "os"
+       "runtime/pprof"
+       "strings"
+       "time"
+)
+
+func cstring(x []byte) string {
+       i := bytes.IndexByte(x, '\x00')
+       if i >= 0 {
+               x = x[:i]
+       }
+       return string(x)
+}
+
+func plan9quote(s string) string {
+       if s == "" {
+               goto needquote
+       }
+       for i := 0; i < len(s); i++ {
+               if s[i] <= ' ' || s[i] == '\'' {
+                       goto needquote
+               }
+       }
+       return s
+
+needquote:
+       return "'" + strings.Replace(s, "'", "''", -1) + "'"
+}
+
+func tokenize(s string) []string {
+       var f []string
+       for {
+               s = strings.TrimLeft(s, " \t\r\n")
+               if s == "" {
+                       break
+               }
+               quote := false
+               i := 0
+               for ; i < len(s); i++ {
+                       if s[i] == '\'' {
+                               if quote && i+1 < len(s) && s[i+1] == '\'' {
+                                       i++
+                                       continue
+                               }
+                               quote = !quote
+                       }
+                       if !quote && (s[i] == ' ' || s[i] == '\t' || s[i] == '\r' || s[i] == '\n') {
+                               break
+                       }
+               }
+               next := s[:i]
+               s = s[i:]
+               if strings.Contains(next, "'") {
+                       var buf []byte
+                       quote := false
+                       for i := 0; i < len(next); i++ {
+                               if next[i] == '\'' {
+                                       if quote && i+1 < len(next) && next[i+1] == '\'' {
+                                               i++
+                                               buf = append(buf, '\'')
+                                       }
+                                       quote = !quote
+                                       continue
+                               }
+                               buf = append(buf, next[i])
+                       }
+                       next = string(buf)
+               }
+               f = append(f, next)
+       }
+       return f
+}
+
+func cutStringAtNUL(s string) string {
+       if i := strings.Index(s, "\x00"); i >= 0 {
+               s = s[:i]
+       }
+       return s
+}
+
+type Biobuf struct {
+       unget    [2]int
+       numUnget int
+       f        *os.File
+       r        *bufio.Reader
+       w        *bufio.Writer
+       linelen  int
+}
+
+func Bopenw(name string) (*Biobuf, error) {
+       f, err := os.Create(name)
+       if err != nil {
+               return nil, err
+       }
+       return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
+}
+
+func Bopenr(name string) (*Biobuf, error) {
+       f, err := os.Open(name)
+       if err != nil {
+               return nil, err
+       }
+       return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
+}
+
+func Binitw(w *os.File) *Biobuf {
+       return &Biobuf{w: bufio.NewWriter(w), f: w}
+}
+
+func (b *Biobuf) Write(p []byte) (int, error) {
+       return b.w.Write(p)
+}
+
+func Bwritestring(b *Biobuf, p string) (int, error) {
+       return b.w.WriteString(p)
+}
+
+func Bseek(b *Biobuf, offset int64, whence int) int64 {
+       if b.w != nil {
+               if err := b.w.Flush(); err != nil {
+                       log.Fatalf("writing output: %v", err)
+               }
+       } else if b.r != nil {
+               if whence == 1 {
+                       offset -= int64(b.r.Buffered())
+               }
+       }
+       off, err := b.f.Seek(offset, whence)
+       if err != nil {
+               log.Panicf("seeking in output [%d %d %p]: %v", offset, whence, b.f, err)
+       }
+       if b.r != nil {
+               b.r.Reset(b.f)
+       }
+       return off
+}
+
+func Boffset(b *Biobuf) int64 {
+       if b.w != nil {
+               if err := b.w.Flush(); err != nil {
+                       log.Fatalf("writing output: %v", err)
+               }
+       }
+       off, err := b.f.Seek(0, 1)
+       if err != nil {
+               log.Fatalf("seeking in output [0, 1]: %v", err)
+       }
+       if b.r != nil {
+               off -= int64(b.r.Buffered())
+       }
+       return off
+}
+
+func (b *Biobuf) Flush() error {
+       return b.w.Flush()
+}
+
+func Bwrite(b *Biobuf, p []byte) (int, error) {
+       return b.w.Write(p)
+}
+
+func Bputc(b *Biobuf, c byte) {
+       b.w.WriteByte(c)
+}
+
+const Beof = -1
+
+func Bread(b *Biobuf, p []byte) int {
+       if b.numUnget > 0 {
+               Bseek(b, -int64(b.numUnget), 1)
+               b.numUnget = 0
+       }
+       n, err := io.ReadFull(b.r, p)
+       if n == 0 {
+               if err != nil && err != io.EOF {
+                       n = -1
+               }
+       }
+       return n
+}
+
+func Bgetc(b *Biobuf) int {
+       if b.numUnget > 0 {
+               b.numUnget--
+               return int(b.unget[b.numUnget])
+       }
+       c, err := b.r.ReadByte()
+       r := int(c)
+       if err != nil {
+               r = -1
+       }
+       b.unget[1] = b.unget[0]
+       b.unget[0] = r
+       return r
+}
+
+func Bgetrune(b *Biobuf) int {
+       if b.numUnget > 0 {
+               Bseek(b, -int64(b.numUnget), 1)
+               b.numUnget = 0
+       }
+       r, _, err := b.r.ReadRune()
+       if err != nil {
+               return -1
+       }
+       return int(r)
+}
+
+func Bungetrune(b *Biobuf) {
+       b.r.UnreadRune()
+}
+
+func (b *Biobuf) Read(p []byte) (int, error) {
+       return b.r.Read(p)
+}
+
+func Brdline(b *Biobuf, delim int) string {
+       if b.numUnget > 0 {
+               Bseek(b, -int64(b.numUnget), 1)
+               b.numUnget = 0
+       }
+       s, err := b.r.ReadBytes(byte(delim))
+       if err != nil {
+               log.Fatalf("reading input: %v", err)
+       }
+       b.linelen = len(s)
+       return string(s)
+}
+
+func Brdstr(b *Biobuf, delim int, cut int) string {
+       if b.numUnget > 0 {
+               Bseek(b, -int64(b.numUnget), 1)
+               b.numUnget = 0
+       }
+       s, err := b.r.ReadString(byte(delim))
+       if err != nil {
+               log.Fatalf("reading input: %v", err)
+       }
+       if len(s) > 0 && cut > 0 {
+               s = s[:len(s)-1]
+       }
+       return s
+}
+
+func Access(name string, mode int) int {
+       if mode != 0 {
+               panic("bad access")
+       }
+       _, err := os.Stat(name)
+       if err != nil {
+               return -1
+       }
+       return 0
+}
+
+func Blinelen(b *Biobuf) int {
+       return b.linelen
+}
+
+func Bungetc(b *Biobuf) {
+       b.numUnget++
+}
+
+func Bflush(b *Biobuf) error {
+       return b.w.Flush()
+}
+
+func Bterm(b *Biobuf) error {
+       var err error
+       if b.w != nil {
+               err = b.w.Flush()
+       }
+       err1 := b.f.Close()
+       if err == nil {
+               err = err1
+       }
+       return err
+}
+
+// strings.Compare, introduced in Go 1.5.
+func stringsCompare(a, b string) int {
+       if a == b {
+               return 0
+       }
+       if a < b {
+               return -1
+       }
+       return +1
+}
+
+var atExitFuncs []func()
+
+func AtExit(f func()) {
+       atExitFuncs = append(atExitFuncs, f)
+}
+
+func Exit(code int) {
+       for i := len(atExitFuncs) - 1; i >= 0; i-- {
+               f := atExitFuncs[i]
+               atExitFuncs = atExitFuncs[:i]
+               f()
+       }
+       os.Exit(code)
+}
+
+var cpuprofile string
+var memprofile string
+
+func startProfile() {
+       if cpuprofile != "" {
+               f, err := os.Create(cpuprofile)
+               if err != nil {
+                       log.Fatalf("%v", err)
+               }
+               if err := pprof.StartCPUProfile(f); err != nil {
+                       log.Fatalf("%v", err)
+               }
+               AtExit(pprof.StopCPUProfile)
+       }
+       if memprofile != "" {
+               f, err := os.Create(memprofile)
+               if err != nil {
+                       log.Fatalf("%v", err)
+               }
+               AtExit(func() {
+                       if err := pprof.WriteHeapProfile(f); err != nil {
+                               log.Fatalf("%v", err)
+                       }
+               })
+       }
+}
+
+func artrim(x []byte) string {
+       i := 0
+       j := len(x)
+       for i < len(x) && x[i] == ' ' {
+               i++
+       }
+       for j > i && x[j-1] == ' ' {
+               j--
+       }
+       return string(x[i:j])
+}
+
+func stringtouint32(x []uint32, s string) {
+       for i := 0; len(s) > 0; i++ {
+               var buf [4]byte
+               s = s[copy(buf[:], s):]
+               x[i] = binary.LittleEndian.Uint32(buf[:])
+       }
+}
+
+var start = time.Now()
+
+func elapsed() float64 {
+       return time.Since(start).Seconds()
+}
diff --git a/src/cmd/internal/ld/z.go b/src/cmd/internal/ld/z.go
new file mode 100644 (file)
index 0000000..7330ae2
--- /dev/null
@@ -0,0 +1 @@
+package ld
diff --git a/src/cmd/new5l/asm.go b/src/cmd/new5l/asm.go
new file mode 100644 (file)
index 0000000..909f682
--- /dev/null
@@ -0,0 +1,777 @@
+// Inferno utils/5l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+)
+import "cmd/internal/ld"
+
+func needlib(name string) int {
+       var p string
+       var s *ld.LSym
+
+       if name[0] == '\x00' {
+               return 0
+       }
+
+       /* reuse hash code in symbol table */
+       p = fmt.Sprintf(".dynlib.%s", name)
+
+       s = ld.Linklookup(ld.Ctxt, p, 0)
+
+       if s.Type == 0 {
+               s.Type = 100 // avoid SDATA, etc.
+               return 1
+       }
+
+       return 0
+}
+
+func gentext() {
+}
+
+// Preserve highest 8 bits of a, and do addition to lower 24-bit
+// of a and b; used to adjust ARM branch intruction's target
+func braddoff(a int32, b int32) int32 {
+       return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
+}
+
+func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
+       ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
+       ld.Adduint32(ld.Ctxt, rel, ld.R_ARM_RELATIVE)
+}
+
+func adddynrel(s *ld.LSym, r *ld.Reloc) {
+       var targ *ld.LSym
+       var rel *ld.LSym
+
+       targ = r.Sym
+       ld.Ctxt.Cursym = s
+
+       switch r.Type {
+       default:
+               if r.Type >= 256 {
+                       ld.Diag("unexpected relocation type %d", r.Type)
+                       return
+               }
+
+               // Handle relocations found in ELF object files.
+       case 256 + ld.R_ARM_PLT32:
+               r.Type = ld.R_CALLARM
+
+               if targ.Type == ld.SDYNIMPORT {
+                       addpltsym(ld.Ctxt, targ)
+                       r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+                       r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
+               }
+
+               return
+
+       case 256 + ld.R_ARM_THM_PC22: // R_ARM_THM_CALL
+               ld.Diag("R_ARM_THM_CALL, are you using -marm?")
+
+               ld.Errorexit()
+               return
+
+       case 256 + ld.R_ARM_GOT32: // R_ARM_GOT_BREL
+               if targ.Type != ld.SDYNIMPORT {
+                       addgotsyminternal(ld.Ctxt, targ)
+               } else {
+                       addgotsym(ld.Ctxt, targ)
+               }
+
+               r.Type = ld.R_CONST // write r->add during relocsym
+               r.Sym = nil
+               r.Add += int64(targ.Got)
+               return
+
+       case 256 + ld.R_ARM_GOT_PREL: // GOT(nil) + A - nil
+               if targ.Type != ld.SDYNIMPORT {
+                       addgotsyminternal(ld.Ctxt, targ)
+               } else {
+                       addgotsym(ld.Ctxt, targ)
+               }
+
+               r.Type = ld.R_PCREL
+               r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+               r.Add += int64(targ.Got) + 4
+               return
+
+       case 256 + ld.R_ARM_GOTOFF: // R_ARM_GOTOFF32
+               r.Type = ld.R_GOTOFF
+
+               return
+
+       case 256 + ld.R_ARM_GOTPC: // R_ARM_BASE_PREL
+               r.Type = ld.R_PCREL
+
+               r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+               r.Add += 4
+               return
+
+       case 256 + ld.R_ARM_CALL:
+               r.Type = ld.R_CALLARM
+               if targ.Type == ld.SDYNIMPORT {
+                       addpltsym(ld.Ctxt, targ)
+                       r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+                       r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
+               }
+
+               return
+
+       case 256 + ld.R_ARM_REL32: // R_ARM_REL32
+               r.Type = ld.R_PCREL
+
+               r.Add += 4
+               return
+
+       case 256 + ld.R_ARM_ABS32:
+               if targ.Type == ld.SDYNIMPORT {
+                       ld.Diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
+               }
+               r.Type = ld.R_ADDR
+               return
+
+               // we can just ignore this, because we are targeting ARM V5+ anyway
+       case 256 + ld.R_ARM_V4BX:
+               if r.Sym != nil {
+                       // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
+                       r.Sym.Type = 0
+               }
+
+               r.Sym = nil
+               return
+
+       case 256 + ld.R_ARM_PC24,
+               256 + ld.R_ARM_JUMP24:
+               r.Type = ld.R_CALLARM
+               if targ.Type == ld.SDYNIMPORT {
+                       addpltsym(ld.Ctxt, targ)
+                       r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+                       r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
+               }
+
+               return
+       }
+
+       // Handle references to ELF symbols from our own object files.
+       if targ.Type != ld.SDYNIMPORT {
+               return
+       }
+
+       switch r.Type {
+       case ld.R_CALLARM:
+               addpltsym(ld.Ctxt, targ)
+               r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+               r.Add = int64(targ.Plt)
+               return
+
+       case ld.R_ADDR:
+               if s.Type != ld.SDATA {
+                       break
+               }
+               if ld.Iself {
+                       adddynsym(ld.Ctxt, targ)
+                       rel = ld.Linklookup(ld.Ctxt, ".rel", 0)
+                       ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
+                       ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynmic reloc
+                       r.Type = ld.R_CONST                                                                // write r->add during relocsym
+                       r.Sym = nil
+                       return
+               }
+       }
+
+       ld.Ctxt.Cursym = s
+       ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+}
+
+func elfreloc1(r *ld.Reloc, sectoff int64) int {
+       var elfsym int32
+
+       ld.Thearch.Lput(uint32(sectoff))
+
+       elfsym = r.Xsym.Elfsym
+       switch r.Type {
+       default:
+               return -1
+
+       case ld.R_ADDR:
+               if r.Siz == 4 {
+                       ld.Thearch.Lput(ld.R_ARM_ABS32 | uint32(elfsym)<<8)
+               } else {
+                       return -1
+               }
+
+       case ld.R_PCREL:
+               if r.Siz == 4 {
+                       ld.Thearch.Lput(ld.R_ARM_REL32 | uint32(elfsym)<<8)
+               } else {
+                       return -1
+               }
+
+       case ld.R_CALLARM:
+               if r.Siz == 4 {
+                       if r.Add&0xff000000 == 0xeb000000 { // BL
+                               ld.Thearch.Lput(ld.R_ARM_CALL | uint32(elfsym)<<8)
+                       } else {
+                               ld.Thearch.Lput(ld.R_ARM_JUMP24 | uint32(elfsym)<<8)
+                       }
+               } else {
+                       return -1
+               }
+
+       case ld.R_TLS:
+               if r.Siz == 4 {
+                       if ld.Flag_shared != 0 {
+                               ld.Thearch.Lput(ld.R_ARM_TLS_IE32 | uint32(elfsym)<<8)
+                       } else {
+                               ld.Thearch.Lput(ld.R_ARM_TLS_LE32 | uint32(elfsym)<<8)
+                       }
+               } else {
+                       return -1
+               }
+       }
+
+       return 0
+}
+
+func elfsetupplt() {
+       var plt *ld.LSym
+       var got *ld.LSym
+
+       plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+       got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+       if plt.Size == 0 {
+               // str lr, [sp, #-4]!
+               ld.Adduint32(ld.Ctxt, plt, 0xe52de004)
+
+               // ldr lr, [pc, #4]
+               ld.Adduint32(ld.Ctxt, plt, 0xe59fe004)
+
+               // add lr, pc, lr
+               ld.Adduint32(ld.Ctxt, plt, 0xe08fe00e)
+
+               // ldr pc, [lr, #8]!
+               ld.Adduint32(ld.Ctxt, plt, 0xe5bef008)
+
+               // .word &GLOBAL_OFFSET_TABLE[0] - .
+               ld.Addpcrelplus(ld.Ctxt, plt, got, 4)
+
+               // the first .plt entry requires 3 .plt.got entries
+               ld.Adduint32(ld.Ctxt, got, 0)
+
+               ld.Adduint32(ld.Ctxt, got, 0)
+               ld.Adduint32(ld.Ctxt, got, 0)
+       }
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+       var v uint32
+       var rs *ld.LSym
+
+       rs = r.Xsym
+
+       if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_CALLARM {
+               if rs.Dynid < 0 {
+                       ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+                       return -1
+               }
+
+               v = uint32(rs.Dynid)
+               v |= 1 << 27 // external relocation
+       } else {
+               v = uint32((rs.Sect.(*ld.Section)).Extnum)
+               if v == 0 {
+                       ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
+                       return -1
+               }
+       }
+
+       switch r.Type {
+       default:
+               return -1
+
+       case ld.R_ADDR:
+               v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
+
+       case ld.R_CALLARM:
+               v |= 1 << 24 // pc-relative bit
+               v |= ld.MACHO_ARM_RELOC_BR24 << 28
+       }
+
+       switch r.Siz {
+       default:
+               return -1
+
+       case 1:
+               v |= 0 << 25
+
+       case 2:
+               v |= 1 << 25
+
+       case 4:
+               v |= 2 << 25
+
+       case 8:
+               v |= 3 << 25
+       }
+
+       ld.Thearch.Lput(uint32(sectoff))
+       ld.Thearch.Lput(v)
+       return 0
+}
+
+func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+       var rs *ld.LSym
+
+       if ld.Linkmode == ld.LinkExternal {
+               switch r.Type {
+               case ld.R_CALLARM:
+                       r.Done = 0
+
+                       // 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 *= 4
+                       for rs.Outer != nil {
+                               r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
+                               rs = rs.Outer
+                       }
+
+                       if rs.Type != ld.SHOSTOBJ && rs.Sect == nil {
+                               ld.Diag("missing section for %s", rs.Name)
+                       }
+                       r.Xsym = rs
+
+                       // ld64 for arm seems to want the symbol table to contain offset
+                       // into the section rather than pseudo virtual address that contains
+                       // the section load address.
+                       // we need to compensate that by removing the instruction's address
+                       // from addend.
+                       if ld.HEADTYPE == ld.Hdarwin {
+                               r.Xadd -= ld.Symaddr(s) + int64(r.Off)
+                       }
+
+                       *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4))))
+                       return 0
+               }
+
+               return -1
+       }
+
+       switch r.Type {
+       case ld.R_CONST:
+               *val = r.Add
+               return 0
+
+       case ld.R_GOTOFF:
+               *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+               return 0
+
+               // The following three arch specific relocations are only for generation of
+       // Linux/ARM ELF's PLT entry (3 assembler instruction)
+       case ld.R_PLT0: // add ip, pc, #0xXX00000
+               if ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got.plt", 0)) < ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0)) {
+                       ld.Diag(".got.plt should be placed after .plt section.")
+               }
+               *val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add)) >> 20))
+               return 0
+
+       case ld.R_PLT1: // add ip, ip, #0xYY000
+               *val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+4)) >> 12))
+
+               return 0
+
+       case ld.R_PLT2: // ldr pc, [ip, #0xZZZ]!
+               *val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+8)))
+
+               return 0
+
+       case ld.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))))
+
+               return 0
+       }
+
+       return -1
+}
+
+func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+       log.Fatalf("unexpected relocation variant")
+       return t
+}
+
+func addpltreloc(ctxt *ld.Link, plt *ld.LSym, got *ld.LSym, sym *ld.LSym, typ int) *ld.Reloc {
+       var r *ld.Reloc
+
+       r = ld.Addrel(plt)
+       r.Sym = got
+       r.Off = int32(plt.Size)
+       r.Siz = 4
+       r.Type = int32(typ)
+       r.Add = int64(sym.Got) - 8
+
+       plt.Reachable = true
+       plt.Size += 4
+       ld.Symgrow(ctxt, plt, plt.Size)
+
+       return r
+}
+
+func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+       var plt *ld.LSym
+       var got *ld.LSym
+       var rel *ld.LSym
+
+       if s.Plt >= 0 {
+               return
+       }
+
+       adddynsym(ctxt, s)
+
+       if ld.Iself {
+               plt = ld.Linklookup(ctxt, ".plt", 0)
+               got = ld.Linklookup(ctxt, ".got.plt", 0)
+               rel = ld.Linklookup(ctxt, ".rel.plt", 0)
+               if plt.Size == 0 {
+                       elfsetupplt()
+               }
+
+               // .got entry
+               s.Got = int32(got.Size)
+
+               // In theory, all GOT should point to the first PLT entry,
+               // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
+               // dynamic linker won't, so we'd better do it ourselves.
+               ld.Addaddrplus(ctxt, got, plt, 0)
+
+               // .plt entry, this depends on the .got entry
+               s.Plt = int32(plt.Size)
+
+               addpltreloc(ctxt, plt, got, s, ld.R_PLT0) // add lr, pc, #0xXX00000
+               addpltreloc(ctxt, plt, got, s, ld.R_PLT1) // add lr, lr, #0xYY000
+               addpltreloc(ctxt, plt, got, s, ld.R_PLT2) // ldr pc, [lr, #0xZZZ]!
+
+               // rel
+               ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
+
+               ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_JUMP_SLOT))
+       } else {
+               ld.Diag("addpltsym: unsupported binary format")
+       }
+}
+
+func addgotsyminternal(ctxt *ld.Link, s *ld.LSym) {
+       var got *ld.LSym
+
+       if s.Got >= 0 {
+               return
+       }
+
+       got = ld.Linklookup(ctxt, ".got", 0)
+       s.Got = int32(got.Size)
+
+       ld.Addaddrplus(ctxt, got, s, 0)
+
+       if ld.Iself {
+       } else {
+               ld.Diag("addgotsyminternal: unsupported binary format")
+       }
+}
+
+func addgotsym(ctxt *ld.Link, s *ld.LSym) {
+       var got *ld.LSym
+       var rel *ld.LSym
+
+       if s.Got >= 0 {
+               return
+       }
+
+       adddynsym(ctxt, s)
+       got = ld.Linklookup(ctxt, ".got", 0)
+       s.Got = int32(got.Size)
+       ld.Adduint32(ctxt, got, 0)
+
+       if ld.Iself {
+               rel = ld.Linklookup(ctxt, ".rel", 0)
+               ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
+               ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_GLOB_DAT))
+       } else {
+               ld.Diag("addgotsym: unsupported binary format")
+       }
+}
+
+func adddynsym(ctxt *ld.Link, s *ld.LSym) {
+       var d *ld.LSym
+       var t int
+       var name string
+
+       if s.Dynid >= 0 {
+               return
+       }
+
+       if ld.Iself {
+               s.Dynid = int32(ld.Nelfsym)
+               ld.Nelfsym++
+
+               d = ld.Linklookup(ctxt, ".dynsym", 0)
+
+               /* name */
+               name = s.Extname
+
+               ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
+
+               /* value */
+               if s.Type == ld.SDYNIMPORT {
+                       ld.Adduint32(ctxt, d, 0)
+               } else {
+                       ld.Addaddr(ctxt, d, s)
+               }
+
+               /* size */
+               ld.Adduint32(ctxt, d, 0)
+
+               /* type */
+               t = ld.STB_GLOBAL << 4
+
+               if (s.Cgoexport&ld.CgoExportDynamic != 0) && s.Type&ld.SMASK == ld.STEXT {
+                       t |= ld.STT_FUNC
+               } else {
+                       t |= ld.STT_OBJECT
+               }
+               ld.Adduint8(ctxt, d, uint8(t))
+               ld.Adduint8(ctxt, d, 0)
+
+               /* shndx */
+               if s.Type == ld.SDYNIMPORT {
+                       ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
+               } else {
+                       ld.Adduint16(ctxt, d, 1)
+               }
+       } else {
+               ld.Diag("adddynsym: unsupported binary format")
+       }
+}
+
+func adddynlib(lib string) {
+       var s *ld.LSym
+
+       if needlib(lib) == 0 {
+               return
+       }
+
+       if ld.Iself {
+               s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
+               if s.Size == 0 {
+                       ld.Addstring(s, "")
+               }
+               ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
+       } else if ld.HEADTYPE == ld.Hdarwin {
+               ld.Machoadddynlib(lib)
+       } else {
+               ld.Diag("adddynlib: unsupported binary format")
+       }
+}
+
+func asmb() {
+       var symo uint32
+       var dwarfoff uint32
+       var machlink uint32
+       var sect *ld.Section
+       var sym *ld.LSym
+       var i int
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+
+       if ld.Iself {
+               ld.Asmbelfsetup()
+       }
+
+       sect = ld.Segtext.Sect
+       ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+       ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+       for sect = sect.Next; sect != nil; sect = sect.Next {
+               ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+               ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+       }
+
+       if ld.Segrodata.Filelen > 0 {
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+               }
+               ld.Bflush(&ld.Bso)
+
+               ld.Cseek(int64(ld.Segrodata.Fileoff))
+               ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+       }
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+
+       ld.Cseek(int64(ld.Segdata.Fileoff))
+       ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+       machlink = 0
+       if ld.HEADTYPE == ld.Hdarwin {
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+               }
+
+               if ld.Debug['w'] == 0 {
+                       dwarfoff = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
+                       ld.Cseek(int64(dwarfoff))
+
+                       ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+                       ld.Dwarfemitdebugsections()
+                       ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
+               }
+
+               machlink = uint32(ld.Domacholink())
+       }
+
+       /* output symbol table */
+       ld.Symsize = 0
+
+       ld.Lcsize = 0
+       symo = 0
+       if ld.Debug['s'] == 0 {
+               // TODO: rationalize
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+               }
+               ld.Bflush(&ld.Bso)
+               switch ld.HEADTYPE {
+               default:
+                       if ld.Iself {
+                               symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+                               symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+                       }
+
+               case ld.Hplan9:
+                       symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+
+               case ld.Hdarwin:
+                       symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink))
+               }
+
+               ld.Cseek(int64(symo))
+               switch ld.HEADTYPE {
+               default:
+                       if ld.Iself {
+                               if ld.Debug['v'] != 0 {
+                                       fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+                               }
+                               ld.Asmelfsym()
+                               ld.Cflush()
+                               ld.Cwrite(ld.Elfstrdat)
+
+                               if ld.Debug['v'] != 0 {
+                                       fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+                               }
+                               ld.Dwarfemitdebugsections()
+
+                               if ld.Linkmode == ld.LinkExternal {
+                                       ld.Elfemitreloc()
+                               }
+                       }
+
+               case ld.Hplan9:
+                       ld.Asmplan9sym()
+                       ld.Cflush()
+
+                       sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
+                       if sym != nil {
+                               ld.Lcsize = int32(len(sym.P))
+                               for i = 0; int32(i) < ld.Lcsize; i++ {
+                                       ld.Cput(uint8(sym.P[i]))
+                               }
+
+                               ld.Cflush()
+                       }
+
+               case ld.Hdarwin:
+                       if ld.Linkmode == ld.LinkExternal {
+                               ld.Machoemitreloc()
+                       }
+               }
+       }
+
+       ld.Ctxt.Cursym = nil
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+       ld.Cseek(0)
+       switch ld.HEADTYPE {
+       default:
+       case ld.Hplan9: /* plan 9 */
+               ld.Thearch.Lput(0x647)                      /* magic */
+               ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
+               ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
+               ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
+               ld.Thearch.Lput(uint32(ld.Symsize))      /* nsyms */
+               ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
+               ld.Thearch.Lput(0)
+               ld.Thearch.Lput(uint32(ld.Lcsize))
+
+       case ld.Hlinux,
+               ld.Hfreebsd,
+               ld.Hnetbsd,
+               ld.Hopenbsd,
+               ld.Hnacl:
+               ld.Asmbelf(int64(symo))
+
+       case ld.Hdarwin:
+               ld.Asmbmacho()
+       }
+
+       ld.Cflush()
+       if ld.Debug['c'] != 0 {
+               fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
+               fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
+               fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
+               fmt.Printf("symsize=%d\n", ld.Symsize)
+               fmt.Printf("lcsize=%d\n", ld.Lcsize)
+               fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
+       }
+}
diff --git a/src/cmd/new5l/l.go b/src/cmd/new5l/l.go
new file mode 100644 (file)
index 0000000..9eb078d
--- /dev/null
@@ -0,0 +1,78 @@
+// Inferno utils/5l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+// Writing object files.
+
+// Inferno utils/5l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+const (
+       thechar   = '5'
+       PtrSize   = 4
+       IntSize   = 4
+       RegSize   = 4
+       MaxAlign  = 8
+       FuncAlign = 4
+       MINLC     = 4
+)
+
+/* Used by ../ld/dwarf.c */
+const (
+       DWARFREGSP = 13
+)
diff --git a/src/cmd/new5l/obj.go b/src/cmd/new5l/obj.go
new file mode 100644 (file)
index 0000000..98ebbc2
--- /dev/null
@@ -0,0 +1,182 @@
+// Inferno utils/5l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+)
+import "cmd/internal/ld"
+
+// Reading object files.
+
+func main() {
+       linkarchinit()
+       ld.Ldmain()
+}
+
+func linkarchinit() {
+       ld.Thestring = "arm"
+       ld.Thelinkarch = &ld.Linkarm
+
+       ld.Thearch.Thechar = thechar
+       ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
+       ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
+       ld.Thearch.Regsize = ld.Thelinkarch.Regsize
+       ld.Thearch.Funcalign = FuncAlign
+       ld.Thearch.Maxalign = MaxAlign
+       ld.Thearch.Minlc = MINLC
+       ld.Thearch.Dwarfregsp = DWARFREGSP
+
+       ld.Thearch.Adddynlib = adddynlib
+       ld.Thearch.Adddynrel = adddynrel
+       ld.Thearch.Adddynsym = adddynsym
+       ld.Thearch.Archinit = archinit
+       ld.Thearch.Archreloc = archreloc
+       ld.Thearch.Archrelocvariant = archrelocvariant
+       ld.Thearch.Asmb = asmb
+       ld.Thearch.Elfreloc1 = elfreloc1
+       ld.Thearch.Elfsetupplt = elfsetupplt
+       ld.Thearch.Gentext = gentext
+       ld.Thearch.Machoreloc1 = machoreloc1
+       ld.Thearch.Lput = ld.Lputl
+       ld.Thearch.Wput = ld.Wputl
+       ld.Thearch.Vput = ld.Vputl
+
+       ld.Thearch.Linuxdynld = "/lib/ld-linux.so.3" // 2 for OABI, 3 for EABI
+       ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
+       ld.Thearch.Openbsddynld = "XXX"
+       ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
+       ld.Thearch.Dragonflydynld = "XXX"
+       ld.Thearch.Solarisdynld = "XXX"
+}
+
+func archinit() {
+       var s *ld.LSym
+
+       // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+       // Go was built; see ../../make.bash.
+       if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
+               ld.Linkmode = ld.LinkInternal
+       }
+
+       switch ld.HEADTYPE {
+       default:
+               if ld.Linkmode == ld.LinkAuto {
+                       ld.Linkmode = ld.LinkInternal
+               }
+               if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
+                       log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
+               }
+
+       case ld.Hlinux,
+               ld.Hfreebsd,
+               ld.Hnacl,
+               ld.Hdarwin:
+               break
+       }
+
+       switch ld.HEADTYPE {
+       default:
+               ld.Diag("unknown -H option")
+               ld.Errorexit()
+               fallthrough
+
+       case ld.Hplan9: /* plan 9 */
+               ld.HEADR = 32
+
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 4128
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+
+       case ld.Hlinux, /* arm elf */
+               ld.Hfreebsd,
+               ld.Hnetbsd:
+               ld.Debug['d'] = 0
+               // with dynamic linking
+               ld.Elfinit()
+               ld.HEADR = ld.ELFRESERVE
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 0x10000 + int64(ld.HEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+
+       case ld.Hnacl:
+               ld.Elfinit()
+               ld.HEADR = 0x10000
+               ld.Funcalign = 16
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 0x20000
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 0x10000
+               }
+
+       case ld.Hdarwin: /* apple MACH */
+               ld.Debug['w'] = 1 // disable DWARF generataion
+               ld.Machoinit()
+               ld.HEADR = ld.INITIAL_MACHO_HEADR
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 4096 + int64(ld.HEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+       }
+
+       if ld.INITDAT != 0 && ld.INITRND != 0 {
+               fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+       }
+
+       // embed goarm to runtime.goarm
+       s = ld.Linklookup(ld.Ctxt, "runtime.goarm", 0)
+
+       s.Type = ld.SRODATA
+       ld.Adduint8(ld.Ctxt, s, uint8(ld.Ctxt.Goarm))
+}
diff --git a/src/cmd/new6l/asm.go b/src/cmd/new6l/asm.go
new file mode 100644 (file)
index 0000000..72e9dbf
--- /dev/null
@@ -0,0 +1,829 @@
+// Inferno utils/6l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+)
+import "cmd/internal/ld"
+
+func PADDR(x uint32) uint32 {
+       return x &^ 0x80000000
+}
+
+var zeroes string
+
+func needlib(name string) int {
+       var p string
+       var s *ld.LSym
+
+       if name[0] == '\x00' {
+               return 0
+       }
+
+       /* reuse hash code in symbol table */
+       p = fmt.Sprintf(".elfload.%s", name)
+
+       s = ld.Linklookup(ld.Ctxt, p, 0)
+
+       if s.Type == 0 {
+               s.Type = 100 // avoid SDATA, etc.
+               return 1
+       }
+
+       return 0
+}
+
+func gentext() {
+}
+
+func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
+       ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
+       ld.Adduint64(ld.Ctxt, rela, ld.R_X86_64_RELATIVE)
+       ld.Addaddrplus(ld.Ctxt, rela, r.Sym, r.Add) // Addend
+}
+
+func adddynrel(s *ld.LSym, r *ld.Reloc) {
+       var targ *ld.LSym
+       var rela *ld.LSym
+       var got *ld.LSym
+
+       targ = r.Sym
+       ld.Ctxt.Cursym = s
+
+       switch r.Type {
+       default:
+               if r.Type >= 256 {
+                       ld.Diag("unexpected relocation type %d", r.Type)
+                       return
+               }
+
+               // Handle relocations found in ELF object files.
+       case 256 + ld.R_X86_64_PC32:
+               if targ.Type == ld.SDYNIMPORT {
+                       ld.Diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
+               }
+               if targ.Type == 0 || targ.Type == ld.SXREF {
+                       ld.Diag("unknown symbol %s in pcrel", targ.Name)
+               }
+               r.Type = ld.R_PCREL
+               r.Add += 4
+               return
+
+       case 256 + ld.R_X86_64_PLT32:
+               r.Type = ld.R_PCREL
+               r.Add += 4
+               if targ.Type == ld.SDYNIMPORT {
+                       addpltsym(targ)
+                       r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+                       r.Add += int64(targ.Plt)
+               }
+
+               return
+
+       case 256 + ld.R_X86_64_GOTPCREL:
+               if targ.Type != ld.SDYNIMPORT {
+                       // have symbol
+                       if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
+                               // turn MOVQ of GOT entry into LEAQ of symbol itself
+                               s.P[r.Off-2] = 0x8d
+
+                               r.Type = ld.R_PCREL
+                               r.Add += 4
+                               return
+                       }
+               }
+
+               // fall back to using GOT and hope for the best (CMOV*)
+               // TODO: just needs relocation, no need to put in .dynsym
+               addgotsym(targ)
+
+               r.Type = ld.R_PCREL
+               r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+               r.Add += 4
+               r.Add += int64(targ.Got)
+               return
+
+       case 256 + ld.R_X86_64_64:
+               if targ.Type == ld.SDYNIMPORT {
+                       ld.Diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
+               }
+               r.Type = ld.R_ADDR
+               return
+
+               // TODO: What is the difference between all these?
+       // Handle relocations found in Mach-O object files.
+       case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
+               512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
+               512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
+               r.Type = ld.R_ADDR
+
+               if targ.Type == ld.SDYNIMPORT {
+                       ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
+               }
+               return
+
+       case 512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
+               if targ.Type == ld.SDYNIMPORT {
+                       addpltsym(targ)
+                       r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+                       r.Add = int64(targ.Plt)
+                       r.Type = ld.R_PCREL
+                       return
+               }
+               fallthrough
+
+               // fall through
+       case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
+               512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
+               512 + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
+               512 + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
+               512 + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
+               r.Type = ld.R_PCREL
+
+               if targ.Type == ld.SDYNIMPORT {
+                       ld.Diag("unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
+               }
+               return
+
+       case 512 + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
+               if targ.Type != ld.SDYNIMPORT {
+                       // have symbol
+                       // turn MOVQ of GOT entry into LEAQ of symbol itself
+                       if r.Off < 2 || s.P[r.Off-2] != 0x8b {
+                               ld.Diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
+                               return
+                       }
+
+                       s.P[r.Off-2] = 0x8d
+                       r.Type = ld.R_PCREL
+                       return
+               }
+               fallthrough
+
+               // fall through
+       case 512 + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
+               if targ.Type != ld.SDYNIMPORT {
+                       ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+               }
+               addgotsym(targ)
+               r.Type = ld.R_PCREL
+               r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+               r.Add += int64(targ.Got)
+               return
+       }
+
+       // Handle references to ELF symbols from our own object files.
+       if targ.Type != ld.SDYNIMPORT {
+               return
+       }
+
+       switch r.Type {
+       case ld.R_CALL,
+               ld.R_PCREL:
+               addpltsym(targ)
+               r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+               r.Add = int64(targ.Plt)
+               return
+
+       case ld.R_ADDR:
+               if s.Type == ld.STEXT && ld.Iself {
+                       // The code is asking for the address of an external
+                       // function.  We provide it with the address of the
+                       // correspondent GOT symbol.
+                       addgotsym(targ)
+
+                       r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+                       r.Add += int64(targ.Got)
+                       return
+               }
+
+               if s.Type != ld.SDATA {
+                       break
+               }
+               if ld.Iself {
+                       adddynsym(ld.Ctxt, targ)
+                       rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
+                       ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
+                       if r.Siz == 8 {
+                               ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_64))
+                       } else {
+                               ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_32))
+                       }
+                       ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
+                       r.Type = 256 // ignore during relocsym
+                       return
+               }
+
+               if ld.HEADTYPE == ld.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
+                       // Mach-O relocations are a royal pain to lay out.
+                       // They use a compact stateful bytecode representation
+                       // that is too much bother to deal with.
+                       // Instead, interpret the C declaration
+                       //      void *_Cvar_stderr = &stderr;
+                       // as making _Cvar_stderr the name of a GOT entry
+                       // for stderr.  This is separate from the usual GOT entry,
+                       // just in case the C code assigns to the variable,
+                       // and of course it only works for single pointers,
+                       // but we only need to support cgo and that's all it needs.
+                       adddynsym(ld.Ctxt, targ)
+
+                       got = ld.Linklookup(ld.Ctxt, ".got", 0)
+                       s.Type = got.Type | ld.SSUB
+                       s.Outer = got
+                       s.Sub = got.Sub
+                       got.Sub = s
+                       s.Value = got.Size
+                       ld.Adduint64(ld.Ctxt, got, 0)
+                       ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
+                       r.Type = 256 // ignore during relocsym
+                       return
+               }
+       }
+
+       ld.Ctxt.Cursym = s
+       ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+}
+
+func elfreloc1(r *ld.Reloc, sectoff int64) int {
+       var elfsym int32
+
+       ld.Thearch.Vput(uint64(sectoff))
+
+       elfsym = r.Xsym.Elfsym
+       switch r.Type {
+       default:
+               return -1
+
+       case ld.R_ADDR:
+               if r.Siz == 4 {
+                       ld.Thearch.Vput(ld.R_X86_64_32 | uint64(elfsym)<<32)
+               } else if r.Siz == 8 {
+                       ld.Thearch.Vput(ld.R_X86_64_64 | uint64(elfsym)<<32)
+               } else {
+                       return -1
+               }
+
+       case ld.R_TLS_LE:
+               if r.Siz == 4 {
+                       ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
+               } else {
+                       return -1
+               }
+
+       case ld.R_CALL:
+               if r.Siz == 4 {
+                       if r.Xsym.Type == ld.SDYNIMPORT {
+                               ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
+                       } else {
+                               ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
+                       }
+               } else {
+                       return -1
+               }
+
+       case ld.R_PCREL:
+               if r.Siz == 4 {
+                       ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
+               } else {
+                       return -1
+               }
+
+       case ld.R_TLS:
+               if r.Siz == 4 {
+                       if ld.Flag_shared != 0 {
+                               ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
+                       } else {
+                               ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
+                       }
+               } else {
+                       return -1
+               }
+       }
+
+       ld.Thearch.Vput(uint64(r.Xadd))
+       return 0
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+       var v uint32
+       var rs *ld.LSym
+
+       rs = r.Xsym
+
+       if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_PCREL {
+               if rs.Dynid < 0 {
+                       ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+                       return -1
+               }
+
+               v = uint32(rs.Dynid)
+               v |= 1 << 27 // external relocation
+       } else {
+               v = uint32((rs.Sect.(*ld.Section)).Extnum)
+               if v == 0 {
+                       ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
+                       return -1
+               }
+       }
+
+       switch r.Type {
+       default:
+               return -1
+
+       case ld.R_ADDR:
+               v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
+
+       case ld.R_CALL:
+               v |= 1 << 24 // pc-relative bit
+               v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
+
+               // NOTE: Only works with 'external' relocation. Forced above.
+       case ld.R_PCREL:
+               v |= 1 << 24 // pc-relative bit
+               v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
+       }
+
+       switch r.Siz {
+       default:
+               return -1
+
+       case 1:
+               v |= 0 << 25
+
+       case 2:
+               v |= 1 << 25
+
+       case 4:
+               v |= 2 << 25
+
+       case 8:
+               v |= 3 << 25
+       }
+
+       ld.Thearch.Lput(uint32(sectoff))
+       ld.Thearch.Lput(v)
+       return 0
+}
+
+func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+       return -1
+}
+
+func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+       log.Fatalf("unexpected relocation variant")
+       return t
+}
+
+func elfsetupplt() {
+       var plt *ld.LSym
+       var got *ld.LSym
+
+       plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+       got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+       if plt.Size == 0 {
+               // pushq got+8(IP)
+               ld.Adduint8(ld.Ctxt, plt, 0xff)
+
+               ld.Adduint8(ld.Ctxt, plt, 0x35)
+               ld.Addpcrelplus(ld.Ctxt, plt, got, 8)
+
+               // jmpq got+16(IP)
+               ld.Adduint8(ld.Ctxt, plt, 0xff)
+
+               ld.Adduint8(ld.Ctxt, plt, 0x25)
+               ld.Addpcrelplus(ld.Ctxt, plt, got, 16)
+
+               // nopl 0(AX)
+               ld.Adduint32(ld.Ctxt, plt, 0x00401f0f)
+
+               // assume got->size == 0 too
+               ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
+
+               ld.Adduint64(ld.Ctxt, got, 0)
+               ld.Adduint64(ld.Ctxt, got, 0)
+       }
+}
+
+func addpltsym(s *ld.LSym) {
+       if s.Plt >= 0 {
+               return
+       }
+
+       adddynsym(ld.Ctxt, s)
+
+       if ld.Iself {
+               var plt *ld.LSym
+               var got *ld.LSym
+               var rela *ld.LSym
+
+               plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+               got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+               rela = ld.Linklookup(ld.Ctxt, ".rela.plt", 0)
+               if plt.Size == 0 {
+                       elfsetupplt()
+               }
+
+               // jmpq *got+size(IP)
+               ld.Adduint8(ld.Ctxt, plt, 0xff)
+
+               ld.Adduint8(ld.Ctxt, plt, 0x25)
+               ld.Addpcrelplus(ld.Ctxt, plt, got, got.Size)
+
+               // add to got: pointer to current pos in plt
+               ld.Addaddrplus(ld.Ctxt, got, plt, plt.Size)
+
+               // pushq $x
+               ld.Adduint8(ld.Ctxt, plt, 0x68)
+
+               ld.Adduint32(ld.Ctxt, plt, uint32((got.Size-24-8)/8))
+
+               // jmpq .plt
+               ld.Adduint8(ld.Ctxt, plt, 0xe9)
+
+               ld.Adduint32(ld.Ctxt, plt, uint32(-(plt.Size + 4)))
+
+               // rela
+               ld.Addaddrplus(ld.Ctxt, rela, got, got.Size-8)
+
+               ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_JMP_SLOT))
+               ld.Adduint64(ld.Ctxt, rela, 0)
+
+               s.Plt = int32(plt.Size - 16)
+       } else if ld.HEADTYPE == ld.Hdarwin {
+               // To do lazy symbol lookup right, we're supposed
+               // to tell the dynamic loader which library each
+               // symbol comes from and format the link info
+               // section just so.  I'm too lazy (ha!) to do that
+               // so for now we'll just use non-lazy pointers,
+               // which don't need to be told which library to use.
+               //
+               // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
+               // has details about what we're avoiding.
+
+               var plt *ld.LSym
+
+               addgotsym(s)
+               plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+
+               ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
+
+               // jmpq *got+size(IP)
+               s.Plt = int32(plt.Size)
+
+               ld.Adduint8(ld.Ctxt, plt, 0xff)
+               ld.Adduint8(ld.Ctxt, plt, 0x25)
+               ld.Addpcrelplus(ld.Ctxt, plt, ld.Linklookup(ld.Ctxt, ".got", 0), int64(s.Got))
+       } else {
+               ld.Diag("addpltsym: unsupported binary format")
+       }
+}
+
+func addgotsym(s *ld.LSym) {
+       var got *ld.LSym
+       var rela *ld.LSym
+
+       if s.Got >= 0 {
+               return
+       }
+
+       adddynsym(ld.Ctxt, s)
+       got = ld.Linklookup(ld.Ctxt, ".got", 0)
+       s.Got = int32(got.Size)
+       ld.Adduint64(ld.Ctxt, got, 0)
+
+       if ld.Iself {
+               rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
+               ld.Addaddrplus(ld.Ctxt, rela, got, int64(s.Got))
+               ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT))
+               ld.Adduint64(ld.Ctxt, rela, 0)
+       } else if ld.HEADTYPE == ld.Hdarwin {
+               ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(s.Dynid))
+       } else {
+               ld.Diag("addgotsym: unsupported binary format")
+       }
+}
+
+func adddynsym(ctxt *ld.Link, s *ld.LSym) {
+       var d *ld.LSym
+       var t int
+       var name string
+
+       if s.Dynid >= 0 {
+               return
+       }
+
+       if ld.Iself {
+               s.Dynid = int32(ld.Nelfsym)
+               ld.Nelfsym++
+
+               d = ld.Linklookup(ctxt, ".dynsym", 0)
+
+               name = s.Extname
+               ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
+
+               /* type */
+               t = ld.STB_GLOBAL << 4
+
+               if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
+                       t |= ld.STT_FUNC
+               } else {
+                       t |= ld.STT_OBJECT
+               }
+               ld.Adduint8(ctxt, d, uint8(t))
+
+               /* reserved */
+               ld.Adduint8(ctxt, d, 0)
+
+               /* section where symbol is defined */
+               if s.Type == ld.SDYNIMPORT {
+                       ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
+               } else {
+                       ld.Adduint16(ctxt, d, 1)
+               }
+
+               /* value */
+               if s.Type == ld.SDYNIMPORT {
+                       ld.Adduint64(ctxt, d, 0)
+               } else {
+                       ld.Addaddr(ctxt, d, s)
+               }
+
+               /* size of object */
+               ld.Adduint64(ctxt, d, uint64(s.Size))
+
+               if s.Cgoexport&ld.CgoExportDynamic == 0 && s.Dynimplib != "" && needlib(s.Dynimplib) != 0 {
+                       ld.Elfwritedynent(ld.Linklookup(ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
+               }
+       } else if ld.HEADTYPE == ld.Hdarwin {
+               ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
+       } else if ld.HEADTYPE == ld.Hwindows {
+       } else // already taken care of
+       {
+               ld.Diag("adddynsym: unsupported binary format")
+       }
+}
+
+func adddynlib(lib string) {
+       var s *ld.LSym
+
+       if needlib(lib) == 0 {
+               return
+       }
+
+       if ld.Iself {
+               s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
+               if s.Size == 0 {
+                       ld.Addstring(s, "")
+               }
+               ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
+       } else if ld.HEADTYPE == ld.Hdarwin {
+               ld.Machoadddynlib(lib)
+       } else {
+               ld.Diag("adddynlib: unsupported binary format")
+       }
+}
+
+func asmb() {
+       var magic int32
+       var i int
+       var vl int64
+       var symo int64
+       var dwarfoff int64
+       var machlink int64
+       var sect *ld.Section
+       var sym *ld.LSym
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f codeblk\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+
+       if ld.Iself {
+               ld.Asmbelfsetup()
+       }
+
+       sect = ld.Segtext.Sect
+       ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+       ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+       for sect = sect.Next; sect != nil; sect = sect.Next {
+               ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+               ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+       }
+
+       if ld.Segrodata.Filelen > 0 {
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+               }
+               ld.Bflush(&ld.Bso)
+
+               ld.Cseek(int64(ld.Segrodata.Fileoff))
+               ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+       }
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+
+       ld.Cseek(int64(ld.Segdata.Fileoff))
+       ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+       machlink = 0
+       if ld.HEADTYPE == ld.Hdarwin {
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+               }
+
+               dwarfoff = ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))
+               ld.Cseek(dwarfoff)
+
+               ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+               ld.Dwarfemitdebugsections()
+               ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
+
+               machlink = ld.Domacholink()
+       }
+
+       switch ld.HEADTYPE {
+       default:
+               ld.Diag("unknown header type %d", ld.HEADTYPE)
+               fallthrough
+
+       case ld.Hplan9,
+               ld.Helf:
+               break
+
+       case ld.Hdarwin:
+               ld.Debug['8'] = 1 /* 64-bit addresses */
+
+       case ld.Hlinux,
+               ld.Hfreebsd,
+               ld.Hnetbsd,
+               ld.Hopenbsd,
+               ld.Hdragonfly,
+               ld.Hsolaris:
+               ld.Debug['8'] = 1 /* 64-bit addresses */
+
+       case ld.Hnacl,
+               ld.Hwindows:
+               break
+       }
+
+       ld.Symsize = 0
+       ld.Spsize = 0
+       ld.Lcsize = 0
+       symo = 0
+       if ld.Debug['s'] == 0 {
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+               }
+               ld.Bflush(&ld.Bso)
+               switch ld.HEADTYPE {
+               default:
+               case ld.Hplan9,
+                       ld.Helf:
+                       ld.Debug['s'] = 1
+                       symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+
+               case ld.Hdarwin:
+                       symo = int64(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
+
+               case ld.Hlinux,
+                       ld.Hfreebsd,
+                       ld.Hnetbsd,
+                       ld.Hopenbsd,
+                       ld.Hdragonfly,
+                       ld.Hsolaris,
+                       ld.Hnacl:
+                       symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+                       symo = ld.Rnd(symo, int64(ld.INITRND))
+
+               case ld.Hwindows:
+                       symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+                       symo = ld.Rnd(symo, ld.PEFILEALIGN)
+               }
+
+               ld.Cseek(symo)
+               switch ld.HEADTYPE {
+               default:
+                       if ld.Iself {
+                               ld.Cseek(symo)
+                               ld.Asmelfsym()
+                               ld.Cflush()
+                               ld.Cwrite(ld.Elfstrdat)
+
+                               if ld.Debug['v'] != 0 {
+                                       fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+                               }
+
+                               ld.Dwarfemitdebugsections()
+
+                               if ld.Linkmode == ld.LinkExternal {
+                                       ld.Elfemitreloc()
+                               }
+                       }
+
+               case ld.Hplan9:
+                       ld.Asmplan9sym()
+                       ld.Cflush()
+
+                       sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
+                       if sym != nil {
+                               ld.Lcsize = int32(len(sym.P))
+                               for i = 0; int32(i) < ld.Lcsize; i++ {
+                                       ld.Cput(uint8(sym.P[i]))
+                               }
+
+                               ld.Cflush()
+                       }
+
+               case ld.Hwindows:
+                       if ld.Debug['v'] != 0 {
+                               fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+                       }
+
+                       ld.Dwarfemitdebugsections()
+
+               case ld.Hdarwin:
+                       if ld.Linkmode == ld.LinkExternal {
+                               ld.Machoemitreloc()
+                       }
+               }
+       }
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+       ld.Cseek(0)
+       switch ld.HEADTYPE {
+       default:
+       case ld.Hplan9: /* plan9 */
+               magic = 4*26*26 + 7
+
+               magic |= 0x00008000                  /* fat header */
+               ld.Lputb(uint32(magic))              /* magic */
+               ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
+               ld.Lputb(uint32(ld.Segdata.Filelen))
+               ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
+               ld.Lputb(uint32(ld.Symsize)) /* nsyms */
+               vl = ld.Entryvalue()
+               ld.Lputb(PADDR(uint32(vl))) /* va of entry */
+               ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
+               ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
+               ld.Vputb(uint64(vl))        /* va of entry */
+
+       case ld.Hdarwin:
+               ld.Asmbmacho()
+
+       case ld.Hlinux,
+               ld.Hfreebsd,
+               ld.Hnetbsd,
+               ld.Hopenbsd,
+               ld.Hdragonfly,
+               ld.Hsolaris,
+               ld.Hnacl:
+               ld.Asmbelf(symo)
+
+       case ld.Hwindows:
+               ld.Asmbpe()
+       }
+
+       ld.Cflush()
+}
diff --git a/src/cmd/new6l/l.go b/src/cmd/new6l/l.go
new file mode 100644 (file)
index 0000000..f698679
--- /dev/null
@@ -0,0 +1,78 @@
+// Inferno utils/6l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+// Writing object files.
+
+// Inferno utils/6l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+const (
+       thechar   = '6'
+       MaxAlign  = 32
+       FuncAlign = 16
+)
+
+const (
+       MINLC = 1
+)
+
+/* Used by ../ld/dwarf.c */
+const (
+       DWARFREGSP = 7
+)
diff --git a/src/cmd/new6l/obj.go b/src/cmd/new6l/obj.go
new file mode 100644 (file)
index 0000000..a34e30d
--- /dev/null
@@ -0,0 +1,215 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+)
+import "cmd/internal/ld"
+
+// Reading object files.
+
+func main() {
+       linkarchinit()
+       ld.Ldmain()
+}
+
+func linkarchinit() {
+       ld.Thestring = "amd64"
+       ld.Thelinkarch = &ld.Linkamd64
+       if obj.Getgoarch() == "amd64p32" {
+               ld.Thelinkarch = &ld.Linkamd64p32
+       }
+
+       ld.Thearch.Thechar = thechar
+       ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
+       ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
+       ld.Thearch.Regsize = ld.Thelinkarch.Regsize
+       ld.Thearch.Funcalign = FuncAlign
+       ld.Thearch.Maxalign = MaxAlign
+       ld.Thearch.Minlc = MINLC
+       ld.Thearch.Dwarfregsp = DWARFREGSP
+
+       ld.Thearch.Adddynlib = adddynlib
+       ld.Thearch.Adddynrel = adddynrel
+       ld.Thearch.Adddynsym = adddynsym
+       ld.Thearch.Archinit = archinit
+       ld.Thearch.Archreloc = archreloc
+       ld.Thearch.Archrelocvariant = archrelocvariant
+       ld.Thearch.Asmb = asmb
+       ld.Thearch.Elfreloc1 = elfreloc1
+       ld.Thearch.Elfsetupplt = elfsetupplt
+       ld.Thearch.Gentext = gentext
+       ld.Thearch.Machoreloc1 = machoreloc1
+       ld.Thearch.Lput = ld.Lputl
+       ld.Thearch.Wput = ld.Wputl
+       ld.Thearch.Vput = ld.Vputl
+
+       ld.Thearch.Linuxdynld = "/lib64/ld-linux-x86-64.so.2"
+       ld.Thearch.Freebsddynld = "/libexec/ld-elf.so.1"
+       ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
+       ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
+       ld.Thearch.Dragonflydynld = "/usr/libexec/ld-elf.so.2"
+       ld.Thearch.Solarisdynld = "/lib/amd64/ld.so.1"
+}
+
+func archinit() {
+       // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+       // Go was built; see ../../make.bash.
+       if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
+               ld.Linkmode = ld.LinkInternal
+       }
+
+       if ld.Flag_shared != 0 {
+               ld.Linkmode = ld.LinkExternal
+       }
+
+       switch ld.HEADTYPE {
+       default:
+               if ld.Linkmode == ld.LinkAuto {
+                       ld.Linkmode = ld.LinkInternal
+               }
+               if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
+                       log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
+               }
+
+       case ld.Hdarwin,
+               ld.Hdragonfly,
+               ld.Hfreebsd,
+               ld.Hlinux,
+               ld.Hnacl,
+               ld.Hnetbsd,
+               ld.Hopenbsd,
+               ld.Hsolaris:
+               break
+       }
+
+       switch ld.HEADTYPE {
+       default:
+               ld.Diag("unknown -H option")
+               ld.Errorexit()
+               fallthrough
+
+       case ld.Hplan9: /* plan 9 */
+               ld.HEADR = 32 + 8
+
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 0x200000 + int64(ld.HEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 0x200000
+               }
+
+       case ld.Helf: /* elf32 executable */
+               ld.HEADR = int32(ld.Rnd(52+3*32, 16))
+
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 0x80110000
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+
+       case ld.Hdarwin: /* apple MACH */
+               ld.Machoinit()
+
+               ld.HEADR = ld.INITIAL_MACHO_HEADR
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 4096 + int64(ld.HEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+
+       case ld.Hlinux, /* elf64 executable */
+               ld.Hfreebsd,   /* freebsd */
+               ld.Hnetbsd,    /* netbsd */
+               ld.Hopenbsd,   /* openbsd */
+               ld.Hdragonfly, /* dragonfly */
+               ld.Hsolaris:   /* solaris */
+               ld.Elfinit()
+
+               ld.HEADR = ld.ELFRESERVE
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = (1 << 22) + int64(ld.HEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+
+       case ld.Hnacl:
+               ld.Elfinit()
+               ld.Debug['w']++ // disable dwarf, which gets confused and is useless anyway
+               ld.HEADR = 0x10000
+               ld.Funcalign = 32
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 0x20000
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 0x10000
+               }
+
+       case ld.Hwindows: /* PE executable */
+               ld.Peinit()
+
+               ld.HEADR = ld.PEFILEHEADR
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = ld.PESECTALIGN
+               }
+       }
+
+       if ld.INITDAT != 0 && ld.INITRND != 0 {
+               fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+       }
+}
diff --git a/src/cmd/new6l/z.go b/src/cmd/new6l/z.go
new file mode 100644 (file)
index 0000000..06ab7d0
--- /dev/null
@@ -0,0 +1 @@
+package main
diff --git a/src/cmd/new8l/asm.go b/src/cmd/new8l/asm.go
new file mode 100644 (file)
index 0000000..295c62e
--- /dev/null
@@ -0,0 +1,734 @@
+// Inferno utils/8l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+)
+import "cmd/internal/ld"
+
+func needlib(name string) int {
+       var p string
+       var s *ld.LSym
+
+       if name[0] == '\x00' {
+               return 0
+       }
+
+       /* reuse hash code in symbol table */
+       p = fmt.Sprintf(".dynlib.%s", name)
+
+       s = ld.Linklookup(ld.Ctxt, p, 0)
+
+       if s.Type == 0 {
+               s.Type = 100 // avoid SDATA, etc.
+               return 1
+       }
+
+       return 0
+}
+
+func gentext() {
+}
+
+func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
+       log.Fatalf("adddynrela not implemented")
+}
+
+func adddynrel(s *ld.LSym, r *ld.Reloc) {
+       var targ *ld.LSym
+       var rel *ld.LSym
+       var got *ld.LSym
+
+       targ = r.Sym
+       ld.Ctxt.Cursym = s
+
+       switch r.Type {
+       default:
+               if r.Type >= 256 {
+                       ld.Diag("unexpected relocation type %d", r.Type)
+                       return
+               }
+
+               // Handle relocations found in ELF object files.
+       case 256 + ld.R_386_PC32:
+               if targ.Type == ld.SDYNIMPORT {
+                       ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
+               }
+               if targ.Type == 0 || targ.Type == ld.SXREF {
+                       ld.Diag("unknown symbol %s in pcrel", targ.Name)
+               }
+               r.Type = ld.R_PCREL
+               r.Add += 4
+               return
+
+       case 256 + ld.R_386_PLT32:
+               r.Type = ld.R_PCREL
+               r.Add += 4
+               if targ.Type == ld.SDYNIMPORT {
+                       addpltsym(ld.Ctxt, targ)
+                       r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+                       r.Add += int64(targ.Plt)
+               }
+
+               return
+
+       case 256 + ld.R_386_GOT32:
+               if targ.Type != ld.SDYNIMPORT {
+                       // have symbol
+                       if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
+                               // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
+                               s.P[r.Off-2] = 0x8d
+
+                               r.Type = ld.R_GOTOFF
+                               return
+                       }
+
+                       if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
+                               // turn PUSHL of GOT entry into PUSHL of symbol itself.
+                               // use unnecessary SS prefix to keep instruction same length.
+                               s.P[r.Off-2] = 0x36
+
+                               s.P[r.Off-1] = 0x68
+                               r.Type = ld.R_ADDR
+                               return
+                       }
+
+                       ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+                       return
+               }
+
+               addgotsym(ld.Ctxt, targ)
+               r.Type = ld.R_CONST // write r->add during relocsym
+               r.Sym = nil
+               r.Add += int64(targ.Got)
+               return
+
+       case 256 + ld.R_386_GOTOFF:
+               r.Type = ld.R_GOTOFF
+               return
+
+       case 256 + ld.R_386_GOTPC:
+               r.Type = ld.R_PCREL
+               r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+               r.Add += 4
+               return
+
+       case 256 + ld.R_386_32:
+               if targ.Type == ld.SDYNIMPORT {
+                       ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
+               }
+               r.Type = ld.R_ADDR
+               return
+
+       case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
+               r.Type = ld.R_ADDR
+               if targ.Type == ld.SDYNIMPORT {
+                       ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
+               }
+               return
+
+       case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
+               if targ.Type == ld.SDYNIMPORT {
+                       addpltsym(ld.Ctxt, targ)
+                       r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+                       r.Add = int64(targ.Plt)
+                       r.Type = ld.R_PCREL
+                       return
+               }
+
+               r.Type = ld.R_PCREL
+               return
+
+       case 512 + ld.MACHO_FAKE_GOTPCREL:
+               if targ.Type != ld.SDYNIMPORT {
+                       // have symbol
+                       // turn MOVL of GOT entry into LEAL of symbol itself
+                       if r.Off < 2 || s.P[r.Off-2] != 0x8b {
+                               ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+                               return
+                       }
+
+                       s.P[r.Off-2] = 0x8d
+                       r.Type = ld.R_PCREL
+                       return
+               }
+
+               addgotsym(ld.Ctxt, targ)
+               r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+               r.Add += int64(targ.Got)
+               r.Type = ld.R_PCREL
+               return
+       }
+
+       // Handle references to ELF symbols from our own object files.
+       if targ.Type != ld.SDYNIMPORT {
+               return
+       }
+
+       switch r.Type {
+       case ld.R_CALL,
+               ld.R_PCREL:
+               addpltsym(ld.Ctxt, targ)
+               r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+               r.Add = int64(targ.Plt)
+               return
+
+       case ld.R_ADDR:
+               if s.Type != ld.SDATA {
+                       break
+               }
+               if ld.Iself {
+                       adddynsym(ld.Ctxt, targ)
+                       rel = ld.Linklookup(ld.Ctxt, ".rel", 0)
+                       ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
+                       ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
+                       r.Type = ld.R_CONST // write r->add during relocsym
+                       r.Sym = nil
+                       return
+               }
+
+               if ld.HEADTYPE == ld.Hdarwin && s.Size == PtrSize && r.Off == 0 {
+                       // Mach-O relocations are a royal pain to lay out.
+                       // They use a compact stateful bytecode representation
+                       // that is too much bother to deal with.
+                       // Instead, interpret the C declaration
+                       //      void *_Cvar_stderr = &stderr;
+                       // as making _Cvar_stderr the name of a GOT entry
+                       // for stderr.  This is separate from the usual GOT entry,
+                       // just in case the C code assigns to the variable,
+                       // and of course it only works for single pointers,
+                       // but we only need to support cgo and that's all it needs.
+                       adddynsym(ld.Ctxt, targ)
+
+                       got = ld.Linklookup(ld.Ctxt, ".got", 0)
+                       s.Type = got.Type | ld.SSUB
+                       s.Outer = got
+                       s.Sub = got.Sub
+                       got.Sub = s
+                       s.Value = got.Size
+                       ld.Adduint32(ld.Ctxt, got, 0)
+                       ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
+                       r.Type = 256 // ignore during relocsym
+                       return
+               }
+       }
+
+       ld.Ctxt.Cursym = s
+       ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+}
+
+func elfreloc1(r *ld.Reloc, sectoff int64) int {
+       var elfsym int32
+
+       ld.Thearch.Lput(uint32(sectoff))
+
+       elfsym = r.Xsym.Elfsym
+       switch r.Type {
+       default:
+               return -1
+
+       case ld.R_ADDR:
+               if r.Siz == 4 {
+                       ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8)
+               } else {
+                       return -1
+               }
+
+       case ld.R_CALL,
+               ld.R_PCREL:
+               if r.Siz == 4 {
+                       ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
+               } else {
+                       return -1
+               }
+
+       case ld.R_TLS_LE,
+               ld.R_TLS_IE:
+               if r.Siz == 4 {
+                       ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
+               } else {
+                       return -1
+               }
+       }
+
+       return 0
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+       var v uint32
+       var rs *ld.LSym
+
+       rs = r.Xsym
+
+       if rs.Type == ld.SHOSTOBJ {
+               if rs.Dynid < 0 {
+                       ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+                       return -1
+               }
+
+               v = uint32(rs.Dynid)
+               v |= 1 << 27 // external relocation
+       } else {
+               v = uint32((rs.Sect.(*ld.Section)).Extnum)
+               if v == 0 {
+                       ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
+                       return -1
+               }
+       }
+
+       switch r.Type {
+       default:
+               return -1
+
+       case ld.R_ADDR:
+               v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
+
+       case ld.R_CALL,
+               ld.R_PCREL:
+               v |= 1 << 24 // pc-relative bit
+               v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
+       }
+
+       switch r.Siz {
+       default:
+               return -1
+
+       case 1:
+               v |= 0 << 25
+
+       case 2:
+               v |= 1 << 25
+
+       case 4:
+               v |= 2 << 25
+
+       case 8:
+               v |= 3 << 25
+       }
+
+       ld.Thearch.Lput(uint32(sectoff))
+       ld.Thearch.Lput(v)
+       return 0
+}
+
+func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+       if ld.Linkmode == ld.LinkExternal {
+               return -1
+       }
+       switch r.Type {
+       case ld.R_CONST:
+               *val = r.Add
+               return 0
+
+       case ld.R_GOTOFF:
+               *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+               return 0
+       }
+
+       return -1
+}
+
+func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+       log.Fatalf("unexpected relocation variant")
+       return t
+}
+
+func elfsetupplt() {
+       var plt *ld.LSym
+       var got *ld.LSym
+
+       plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+       got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+       if plt.Size == 0 {
+               // pushl got+4
+               ld.Adduint8(ld.Ctxt, plt, 0xff)
+
+               ld.Adduint8(ld.Ctxt, plt, 0x35)
+               ld.Addaddrplus(ld.Ctxt, plt, got, 4)
+
+               // jmp *got+8
+               ld.Adduint8(ld.Ctxt, plt, 0xff)
+
+               ld.Adduint8(ld.Ctxt, plt, 0x25)
+               ld.Addaddrplus(ld.Ctxt, plt, got, 8)
+
+               // zero pad
+               ld.Adduint32(ld.Ctxt, plt, 0)
+
+               // assume got->size == 0 too
+               ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
+
+               ld.Adduint32(ld.Ctxt, got, 0)
+               ld.Adduint32(ld.Ctxt, got, 0)
+       }
+}
+
+func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+       var plt *ld.LSym
+       var got *ld.LSym
+       var rel *ld.LSym
+
+       if s.Plt >= 0 {
+               return
+       }
+
+       adddynsym(ctxt, s)
+
+       if ld.Iself {
+               plt = ld.Linklookup(ctxt, ".plt", 0)
+               got = ld.Linklookup(ctxt, ".got.plt", 0)
+               rel = ld.Linklookup(ctxt, ".rel.plt", 0)
+               if plt.Size == 0 {
+                       elfsetupplt()
+               }
+
+               // jmpq *got+size
+               ld.Adduint8(ctxt, plt, 0xff)
+
+               ld.Adduint8(ctxt, plt, 0x25)
+               ld.Addaddrplus(ctxt, plt, got, got.Size)
+
+               // add to got: pointer to current pos in plt
+               ld.Addaddrplus(ctxt, got, plt, plt.Size)
+
+               // pushl $x
+               ld.Adduint8(ctxt, plt, 0x68)
+
+               ld.Adduint32(ctxt, plt, uint32(rel.Size))
+
+               // jmp .plt
+               ld.Adduint8(ctxt, plt, 0xe9)
+
+               ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4)))
+
+               // rel
+               ld.Addaddrplus(ctxt, rel, got, got.Size-4)
+
+               ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT))
+
+               s.Plt = int32(plt.Size - 16)
+       } else if ld.HEADTYPE == ld.Hdarwin {
+               // Same laziness as in 6l.
+
+               var plt *ld.LSym
+
+               plt = ld.Linklookup(ctxt, ".plt", 0)
+
+               addgotsym(ctxt, s)
+
+               ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
+
+               // jmpq *got+size(IP)
+               s.Plt = int32(plt.Size)
+
+               ld.Adduint8(ctxt, plt, 0xff)
+               ld.Adduint8(ctxt, plt, 0x25)
+               ld.Addaddrplus(ctxt, plt, ld.Linklookup(ctxt, ".got", 0), int64(s.Got))
+       } else {
+               ld.Diag("addpltsym: unsupported binary format")
+       }
+}
+
+func addgotsym(ctxt *ld.Link, s *ld.LSym) {
+       var got *ld.LSym
+       var rel *ld.LSym
+
+       if s.Got >= 0 {
+               return
+       }
+
+       adddynsym(ctxt, s)
+       got = ld.Linklookup(ctxt, ".got", 0)
+       s.Got = int32(got.Size)
+       ld.Adduint32(ctxt, got, 0)
+
+       if ld.Iself {
+               rel = ld.Linklookup(ctxt, ".rel", 0)
+               ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
+               ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT))
+       } else if ld.HEADTYPE == ld.Hdarwin {
+               ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid))
+       } else {
+               ld.Diag("addgotsym: unsupported binary format")
+       }
+}
+
+func adddynsym(ctxt *ld.Link, s *ld.LSym) {
+       var d *ld.LSym
+       var t int
+       var name string
+
+       if s.Dynid >= 0 {
+               return
+       }
+
+       if ld.Iself {
+               s.Dynid = int32(ld.Nelfsym)
+               ld.Nelfsym++
+
+               d = ld.Linklookup(ctxt, ".dynsym", 0)
+
+               /* name */
+               name = s.Extname
+
+               ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
+
+               /* value */
+               if s.Type == ld.SDYNIMPORT {
+                       ld.Adduint32(ctxt, d, 0)
+               } else {
+                       ld.Addaddr(ctxt, d, s)
+               }
+
+               /* size */
+               ld.Adduint32(ctxt, d, 0)
+
+               /* type */
+               t = ld.STB_GLOBAL << 4
+
+               if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
+                       t |= ld.STT_FUNC
+               } else {
+                       t |= ld.STT_OBJECT
+               }
+               ld.Adduint8(ctxt, d, uint8(t))
+               ld.Adduint8(ctxt, d, 0)
+
+               /* shndx */
+               if s.Type == ld.SDYNIMPORT {
+                       ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
+               } else {
+                       ld.Adduint16(ctxt, d, 1)
+               }
+       } else if ld.HEADTYPE == ld.Hdarwin {
+               ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
+       } else if ld.HEADTYPE == ld.Hwindows {
+       } else // already taken care of
+       {
+               ld.Diag("adddynsym: unsupported binary format")
+       }
+}
+
+func adddynlib(lib string) {
+       var s *ld.LSym
+
+       if needlib(lib) == 0 {
+               return
+       }
+
+       if ld.Iself {
+               s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
+               if s.Size == 0 {
+                       ld.Addstring(s, "")
+               }
+               ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
+       } else if ld.HEADTYPE == ld.Hdarwin {
+               ld.Machoadddynlib(lib)
+       } else if ld.HEADTYPE != ld.Hwindows {
+               ld.Diag("adddynlib: unsupported binary format")
+       }
+}
+
+func asmb() {
+       var magic int32
+       var symo uint32
+       var dwarfoff uint32
+       var machlink uint32
+       var sect *ld.Section
+       var sym *ld.LSym
+       var i int
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+
+       if ld.Iself {
+               ld.Asmbelfsetup()
+       }
+
+       sect = ld.Segtext.Sect
+       ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+       ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+       for sect = sect.Next; sect != nil; sect = sect.Next {
+               ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+               ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+       }
+
+       if ld.Segrodata.Filelen > 0 {
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+               }
+               ld.Bflush(&ld.Bso)
+
+               ld.Cseek(int64(ld.Segrodata.Fileoff))
+               ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+       }
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+
+       ld.Cseek(int64(ld.Segdata.Fileoff))
+       ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+       machlink = 0
+       if ld.HEADTYPE == ld.Hdarwin {
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+               }
+
+               dwarfoff = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
+               ld.Cseek(int64(dwarfoff))
+
+               ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+               ld.Dwarfemitdebugsections()
+               ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
+
+               machlink = uint32(ld.Domacholink())
+       }
+
+       ld.Symsize = 0
+       ld.Spsize = 0
+       ld.Lcsize = 0
+       symo = 0
+       if ld.Debug['s'] == 0 {
+               // TODO: rationalize
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+               }
+               ld.Bflush(&ld.Bso)
+               switch ld.HEADTYPE {
+               default:
+                       if ld.Iself {
+                               symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+                               symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+                       }
+
+               case ld.Hplan9:
+                       symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+
+               case ld.Hdarwin:
+                       symo = uint32(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
+
+               case ld.Hwindows:
+                       symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+                       symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
+               }
+
+               ld.Cseek(int64(symo))
+               switch ld.HEADTYPE {
+               default:
+                       if ld.Iself {
+                               if ld.Debug['v'] != 0 {
+                                       fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+                               }
+                               ld.Asmelfsym()
+                               ld.Cflush()
+                               ld.Cwrite(ld.Elfstrdat)
+
+                               if ld.Debug['v'] != 0 {
+                                       fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+                               }
+                               ld.Dwarfemitdebugsections()
+
+                               if ld.Linkmode == ld.LinkExternal {
+                                       ld.Elfemitreloc()
+                               }
+                       }
+
+               case ld.Hplan9:
+                       ld.Asmplan9sym()
+                       ld.Cflush()
+
+                       sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
+                       if sym != nil {
+                               ld.Lcsize = int32(len(sym.P))
+                               for i = 0; int32(i) < ld.Lcsize; i++ {
+                                       ld.Cput(uint8(sym.P[i]))
+                               }
+
+                               ld.Cflush()
+                       }
+
+               case ld.Hwindows:
+                       if ld.Debug['v'] != 0 {
+                               fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+                       }
+                       ld.Dwarfemitdebugsections()
+
+               case ld.Hdarwin:
+                       if ld.Linkmode == ld.LinkExternal {
+                               ld.Machoemitreloc()
+                       }
+               }
+       }
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+       ld.Cseek(0)
+       switch ld.HEADTYPE {
+       default:
+       case ld.Hplan9: /* plan9 */
+               magic = 4*11*11 + 7
+
+               ld.Lputb(uint32(magic))              /* magic */
+               ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
+               ld.Lputb(uint32(ld.Segdata.Filelen))
+               ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
+               ld.Lputb(uint32(ld.Symsize))      /* nsyms */
+               ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */
+               ld.Lputb(uint32(ld.Spsize))       /* sp offsets */
+               ld.Lputb(uint32(ld.Lcsize))       /* line offsets */
+
+       case ld.Hdarwin:
+               ld.Asmbmacho()
+
+       case ld.Hlinux,
+               ld.Hfreebsd,
+               ld.Hnetbsd,
+               ld.Hopenbsd,
+               ld.Hdragonfly,
+               ld.Hnacl:
+               ld.Asmbelf(int64(symo))
+
+       case ld.Hwindows:
+               ld.Asmbpe()
+       }
+
+       ld.Cflush()
+}
diff --git a/src/cmd/new8l/l.go b/src/cmd/new8l/l.go
new file mode 100644 (file)
index 0000000..fbeee98
--- /dev/null
@@ -0,0 +1,78 @@
+// Inferno utils/8l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+// Writing object files.
+
+// Inferno utils/8l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+const (
+       thechar   = '8'
+       PtrSize   = 4
+       IntSize   = 4
+       RegSize   = 4
+       MaxAlign  = 32
+       FuncAlign = 16
+       MINLC     = 1
+)
+
+/* Used by ../ld/dwarf.c */
+const (
+       DWARFREGSP = 4
+)
diff --git a/src/cmd/new8l/obj.go b/src/cmd/new8l/obj.go
new file mode 100644 (file)
index 0000000..5d44721
--- /dev/null
@@ -0,0 +1,191 @@
+// Inferno utils/8l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+)
+import "cmd/internal/ld"
+
+// Reading object files.
+
+func main() {
+       linkarchinit()
+       ld.Ldmain()
+}
+
+func linkarchinit() {
+       ld.Thestring = "386"
+       ld.Thelinkarch = &ld.Link386
+
+       ld.Thearch.Thechar = thechar
+       ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
+       ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
+       ld.Thearch.Regsize = ld.Thelinkarch.Regsize
+       ld.Thearch.Funcalign = FuncAlign
+       ld.Thearch.Maxalign = MaxAlign
+       ld.Thearch.Minlc = MINLC
+       ld.Thearch.Dwarfregsp = DWARFREGSP
+
+       ld.Thearch.Adddynlib = adddynlib
+       ld.Thearch.Adddynrel = adddynrel
+       ld.Thearch.Adddynsym = adddynsym
+       ld.Thearch.Archinit = archinit
+       ld.Thearch.Archreloc = archreloc
+       ld.Thearch.Archrelocvariant = archrelocvariant
+       ld.Thearch.Asmb = asmb
+       ld.Thearch.Elfreloc1 = elfreloc1
+       ld.Thearch.Elfsetupplt = elfsetupplt
+       ld.Thearch.Gentext = gentext
+       ld.Thearch.Machoreloc1 = machoreloc1
+       ld.Thearch.Lput = ld.Lputl
+       ld.Thearch.Wput = ld.Wputl
+       ld.Thearch.Vput = ld.Vputl
+
+       ld.Thearch.Linuxdynld = "/lib/ld-linux.so.2"
+       ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
+       ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
+       ld.Thearch.Netbsddynld = "/usr/libexec/ld.elf_so"
+       ld.Thearch.Dragonflydynld = "/usr/libexec/ld-elf.so.2"
+       ld.Thearch.Solarisdynld = "/lib/ld.so.1"
+}
+
+func archinit() {
+       // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+       // Go was built; see ../../make.bash.
+       if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
+               ld.Linkmode = ld.LinkInternal
+       }
+
+       switch ld.HEADTYPE {
+       default:
+               if ld.Linkmode == ld.LinkAuto {
+                       ld.Linkmode = ld.LinkInternal
+               }
+               if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
+                       log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
+               }
+
+       case ld.Hdarwin,
+               ld.Hdragonfly,
+               ld.Hfreebsd,
+               ld.Hlinux,
+               ld.Hnetbsd,
+               ld.Hopenbsd:
+               break
+       }
+
+       switch ld.HEADTYPE {
+       default:
+               ld.Diag("unknown -H option")
+               ld.Errorexit()
+               fallthrough
+
+       case ld.Hplan9: /* plan 9 */
+               ld.HEADR = 32
+
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 4096 + 32
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+
+       case ld.Hdarwin: /* apple MACH */
+               ld.Machoinit()
+
+               ld.HEADR = ld.INITIAL_MACHO_HEADR
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 4096 + int64(ld.HEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+
+       case ld.Hlinux, /* elf32 executable */
+               ld.Hfreebsd,
+               ld.Hnetbsd,
+               ld.Hopenbsd,
+               ld.Hdragonfly:
+               ld.Elfinit()
+
+               ld.HEADR = ld.ELFRESERVE
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 0x08048000 + int64(ld.HEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+
+       case ld.Hnacl:
+               ld.Elfinit()
+               ld.HEADR = 0x10000
+               ld.Funcalign = 32
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 0x20000
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 0x10000
+               }
+
+       case ld.Hwindows: /* PE executable */
+               ld.Peinit()
+
+               ld.HEADR = ld.PEFILEHEADR
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = ld.PESECTALIGN
+               }
+       }
+
+       if ld.INITDAT != 0 && ld.INITRND != 0 {
+               fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+       }
+}
diff --git a/src/cmd/new9l/asm.go b/src/cmd/new9l/asm.go
new file mode 100644 (file)
index 0000000..eab0ef2
--- /dev/null
@@ -0,0 +1,851 @@
+// Inferno utils/5l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+)
+import "cmd/internal/ld"
+
+func needlib(name string) int {
+       var p string
+       var s *ld.LSym
+
+       if name[0] == '\x00' {
+               return 0
+       }
+
+       /* reuse hash code in symbol table */
+       p = fmt.Sprintf(".dynlib.%s", name)
+
+       s = ld.Linklookup(ld.Ctxt, p, 0)
+
+       if s.Type == 0 {
+               s.Type = 100 // avoid SDATA, etc.
+               return 1
+       }
+
+       return 0
+}
+
+func gentext() {
+       var s *ld.LSym
+       var stub *ld.LSym
+       var pprevtextp **ld.LSym
+       var r *ld.Reloc
+       var n string
+       var o1 uint32
+       var i int
+
+       // The ppc64 ABI PLT has similar concepts to other
+       // architectures, but is laid out quite differently.  When we
+       // see an R_PPC64_REL24 relocation to a dynamic symbol
+       // (indicating that the call needs to go through the PLT), we
+       // generate up to three stubs and reserve a PLT slot.
+       //
+       // 1) The call site will be bl x; nop (where the relocation
+       //    applies to the bl).  We rewrite this to bl x_stub; ld
+       //    r2,24(r1).  The ld is necessary because x_stub will save
+       //    r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
+       //
+       // 2) We reserve space for a pointer in the .plt section (once
+       //    per referenced dynamic function).  .plt is a data
+       //    section filled solely by the dynamic linker (more like
+       //    .plt.got on other architectures).  Initially, the
+       //    dynamic linker will fill each slot with a pointer to the
+       //    corresponding x@plt entry point.
+       //
+       // 3) We generate the "call stub" x_stub (once per dynamic
+       //    function/object file pair).  This saves the TOC in the
+       //    TOC save slot, reads the function pointer from x's .plt
+       //    slot and calls it like any other global entry point
+       //    (including setting r12 to the function address).
+       //
+       // 4) We generate the "symbol resolver stub" x@plt (once per
+       //    dynamic function).  This is solely a branch to the glink
+       //    resolver stub.
+       //
+       // 5) We generate the glink resolver stub (only once).  This
+       //    computes which symbol resolver stub we came through and
+       //    invokes the dynamic resolver via a pointer provided by
+       //    the dynamic linker.  This will patch up the .plt slot to
+       //    point directly at the function so future calls go
+       //    straight from the call stub to the real function, and
+       //    then call the function.
+
+       // NOTE: It's possible we could make ppc64 closer to other
+       // architectures: ppc64's .plt is like .plt.got on other
+       // platforms and ppc64's .glink is like .plt on other
+       // platforms.
+
+       // Find all R_PPC64_REL24 relocations that reference dynamic
+       // imports.  Reserve PLT entries for these symbols and
+       // generate call stubs.  The call stubs need to live in .text,
+       // which is why we need to do this pass this early.
+       //
+       // This assumes "case 1" from the ABI, where the caller needs
+       // us to save and restore the TOC pointer.
+       pprevtextp = &ld.Ctxt.Textp
+
+       for s = *pprevtextp; s != nil; (func() { pprevtextp = &s.Next; s = *pprevtextp })() {
+               for i = range s.R {
+                       r = &s.R[i]
+                       if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != ld.SDYNIMPORT {
+                               continue
+                       }
+
+                       // Reserve PLT entry and generate symbol
+                       // resolver
+                       addpltsym(ld.Ctxt, r.Sym)
+
+                       // Generate call stub
+                       n = fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
+
+                       stub = ld.Linklookup(ld.Ctxt, n, 0)
+                       stub.Reachable = stub.Reachable || s.Reachable
+                       if stub.Size == 0 {
+                               // Need outer to resolve .TOC.
+                               stub.Outer = s
+
+                               // Link in to textp before s (we could
+                               // do it after, but would have to skip
+                               // the subsymbols)
+                               *pprevtextp = stub
+
+                               stub.Next = s
+                               pprevtextp = &stub.Next
+
+                               gencallstub(1, stub, r.Sym)
+                       }
+
+                       // Update the relocation to use the call stub
+                       r.Sym = stub
+
+                       // Restore TOC after bl.  The compiler put a
+                       // nop here for us to overwrite.
+                       o1 = 0xe8410018 // ld r2,24(r1)
+                       ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off:], o1)
+               }
+       }
+}
+
+// Construct a call stub in stub that calls symbol targ via its PLT
+// entry.
+func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
+       var plt *ld.LSym
+       var r *ld.Reloc
+
+       if abicase != 1 {
+               // If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
+               // relocations, we'll need to implement cases 2 and 3.
+               log.Fatalf("gencallstub only implements case 1 calls")
+       }
+
+       plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+
+       stub.Type = ld.STEXT
+
+       // Save TOC pointer in TOC save slot
+       ld.Adduint32(ld.Ctxt, stub, 0xf8410018) // std r2,24(r1)
+
+       // Load the function pointer from the PLT.
+       r = ld.Addrel(stub)
+
+       r.Off = int32(stub.Size)
+       r.Sym = plt
+       r.Add = int64(targ.Plt)
+       r.Siz = 2
+       if ld.Ctxt.Arch.Endian == ld.BigEndian {
+               r.Off += int32(r.Siz)
+       }
+       r.Type = ld.R_POWER_TOC
+       r.Variant = ld.RV_POWER_HA
+       ld.Adduint32(ld.Ctxt, stub, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
+       r = ld.Addrel(stub)
+       r.Off = int32(stub.Size)
+       r.Sym = plt
+       r.Add = int64(targ.Plt)
+       r.Siz = 2
+       if ld.Ctxt.Arch.Endian == ld.BigEndian {
+               r.Off += int32(r.Siz)
+       }
+       r.Type = ld.R_POWER_TOC
+       r.Variant = ld.RV_POWER_LO
+       ld.Adduint32(ld.Ctxt, stub, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
+
+       // Jump to the loaded pointer
+       ld.Adduint32(ld.Ctxt, stub, 0x7d8903a6) // mtctr r12
+       ld.Adduint32(ld.Ctxt, stub, 0x4e800420) // bctr
+}
+
+func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
+       log.Fatalf("adddynrela not implemented")
+}
+
+func adddynrel(s *ld.LSym, r *ld.Reloc) {
+       var targ *ld.LSym
+       var rela *ld.LSym
+
+       targ = r.Sym
+       ld.Ctxt.Cursym = s
+
+       switch r.Type {
+       default:
+               if r.Type >= 256 {
+                       ld.Diag("unexpected relocation type %d", r.Type)
+                       return
+               }
+
+               // Handle relocations found in ELF object files.
+       case 256 + ld.R_PPC64_REL24:
+               r.Type = ld.R_CALLPOWER
+
+               // This is a local call, so the caller isn't setting
+               // up r12 and r2 is the same for the caller and
+               // callee.  Hence, we need to go to the local entry
+               // point.  (If we don't do this, the callee will try
+               // to use r12 to compute r2.)
+               r.Add += int64(r.Sym.Localentry) * 4
+
+               if targ.Type == ld.SDYNIMPORT {
+                       // Should have been handled in elfsetupplt
+                       ld.Diag("unexpected R_PPC64_REL24 for dyn import")
+               }
+
+               return
+
+       case 256 + ld.R_PPC64_ADDR64:
+               r.Type = ld.R_ADDR
+               if targ.Type == ld.SDYNIMPORT {
+                       // These happen in .toc sections
+                       adddynsym(ld.Ctxt, targ)
+
+                       rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
+                       ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
+                       ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_PPC64_ADDR64))
+                       ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
+                       r.Type = 256 // ignore during relocsym
+               }
+
+               return
+
+       case 256 + ld.R_PPC64_TOC16:
+               r.Type = ld.R_POWER_TOC
+               r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
+               return
+
+       case 256 + ld.R_PPC64_TOC16_LO:
+               r.Type = ld.R_POWER_TOC
+               r.Variant = ld.RV_POWER_LO
+               return
+
+       case 256 + ld.R_PPC64_TOC16_HA:
+               r.Type = ld.R_POWER_TOC
+               r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
+               return
+
+       case 256 + ld.R_PPC64_TOC16_HI:
+               r.Type = ld.R_POWER_TOC
+               r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
+               return
+
+       case 256 + ld.R_PPC64_TOC16_DS:
+               r.Type = ld.R_POWER_TOC
+               r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
+               return
+
+       case 256 + ld.R_PPC64_TOC16_LO_DS:
+               r.Type = ld.R_POWER_TOC
+               r.Variant = ld.RV_POWER_DS
+               return
+
+       case 256 + ld.R_PPC64_REL16_LO:
+               r.Type = ld.R_PCREL
+               r.Variant = ld.RV_POWER_LO
+               r.Add += 2 // Compensate for relocation size of 2
+               return
+
+       case 256 + ld.R_PPC64_REL16_HI:
+               r.Type = ld.R_PCREL
+               r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
+               r.Add += 2
+               return
+
+       case 256 + ld.R_PPC64_REL16_HA:
+               r.Type = ld.R_PCREL
+               r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
+               r.Add += 2
+               return
+       }
+
+       // Handle references to ELF symbols from our own object files.
+       if targ.Type != ld.SDYNIMPORT {
+               return
+       }
+
+       // TODO(austin): Translate our relocations to ELF
+
+       ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+}
+
+func elfreloc1(r *ld.Reloc, sectoff int64) int {
+       // TODO(minux)
+       return -1
+}
+
+func elfsetupplt() {
+       var plt *ld.LSym
+
+       plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+       if plt.Size == 0 {
+               // The dynamic linker stores the address of the
+               // dynamic resolver and the DSO identifier in the two
+               // doublewords at the beginning of the .plt section
+               // before the PLT array.  Reserve space for these.
+               plt.Size = 16
+       }
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+       return -1
+}
+
+// Return the value of .TOC. for symbol s
+func symtoc(s *ld.LSym) int64 {
+       var toc *ld.LSym
+
+       if s.Outer != nil {
+               toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Outer.Version))
+       } else {
+               toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Version))
+       }
+
+       if toc == nil {
+               ld.Diag("TOC-relative relocation in object without .TOC.")
+               return 0
+       }
+
+       return toc.Value
+}
+
+func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+       var o1 uint32
+       var o2 uint32
+       var t int64
+
+       if ld.Linkmode == ld.LinkExternal {
+               // TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
+               // R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO.
+               // R_CALLPOWER corresponds to R_PPC_REL24.
+               return -1
+       }
+
+       switch r.Type {
+       case ld.R_CONST:
+               *val = r.Add
+               return 0
+
+       case ld.R_GOTOFF:
+               *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+               return 0
+
+               // r->add is two ppc64 instructions holding an immediate 32-bit constant.
+       // We want to add r->sym's address to that constant.
+       // The encoding of the immediate x<<16 + y,
+       // where x is the low 16 bits of the first instruction and y is the low 16
+       // bits of the second. Both x and y are signed (int16, not uint16).
+       case ld.R_ADDRPOWER:
+               o1 = uint32(r.Add >> 32)
+
+               o2 = uint32(r.Add)
+               t = ld.Symaddr(r.Sym)
+               if t < 0 {
+                       ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
+               }
+
+               t += ((int64(o1) & 0xffff) << 16) + (int64(int32(o2)) << 16 >> 16)
+               if t&0x8000 != 0 {
+                       t += 0x10000
+               }
+               o1 = uint32(int64(o1&0xffff0000) | (t>>16)&0xffff)
+               o2 = uint32(int64(o2&0xffff0000) | t&0xffff)
+
+               // when laid out, the instruction order must always be o1, o2.
+               if ld.Ctxt.Arch.Endian == ld.BigEndian {
+                       *val = int64(o1)<<32 | int64(o2)
+               } else {
+                       *val = int64(o2)<<32 | int64(o1)
+               }
+               return 0
+
+               // Bits 6 through 29 = (S + A - P) >> 2
+       case ld.R_CALLPOWER:
+               if ld.Ctxt.Arch.Endian == ld.BigEndian {
+                       o1 = ld.Be32(s.P[r.Off:])
+               } else {
+                       o1 = ld.Le32(s.P[r.Off:])
+               }
+
+               t = ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
+               if t&3 != 0 {
+                       ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
+               }
+               if int64(int32(t<<6)>>6) != t {
+                       // TODO(austin) This can happen if text > 32M.
+                       // Add a call trampoline to .text in that case.
+                       ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
+               }
+
+               *val = int64(o1)&0xfc000003 | t&^0xfc000003
+               return 0
+
+       case ld.R_POWER_TOC: // S + A - .TOC.
+               *val = ld.Symaddr(r.Sym) + r.Add - symtoc(s)
+
+               return 0
+       }
+
+       return -1
+}
+
+func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+       var o1 uint32
+       switch r.Variant & ld.RV_TYPE_MASK {
+       default:
+               ld.Diag("unexpected relocation variant %d", r.Variant)
+               fallthrough
+
+       case ld.RV_NONE:
+               return t
+
+       case ld.RV_POWER_LO:
+               if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
+                       // Whether to check for signed or unsigned
+                       // overflow depends on the instruction
+                       if ld.Ctxt.Arch.Endian == ld.BigEndian {
+                               o1 = ld.Be32(s.P[r.Off-2:])
+                       } else {
+                               o1 = ld.Le32(s.P[r.Off:])
+                       }
+                       switch o1 >> 26 {
+                       case 24, // ori
+                               26, // xori
+                               28: // andi
+                               if t>>16 != 0 {
+                                       goto overflow
+                               }
+
+                       default:
+                               if int64(int16(t)) != t {
+                                       goto overflow
+                               }
+                       }
+               }
+
+               return int64(int16(t))
+
+       case ld.RV_POWER_HA:
+               t += 0x8000
+               fallthrough
+
+               // Fallthrough
+       case ld.RV_POWER_HI:
+               t >>= 16
+
+               if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
+                       // Whether to check for signed or unsigned
+                       // overflow depends on the instruction
+                       if ld.Ctxt.Arch.Endian == ld.BigEndian {
+                               o1 = ld.Be32(s.P[r.Off-2:])
+                       } else {
+                               o1 = ld.Le32(s.P[r.Off:])
+                       }
+                       switch o1 >> 26 {
+                       case 25, // oris
+                               27, // xoris
+                               29: // andis
+                               if t>>16 != 0 {
+                                       goto overflow
+                               }
+
+                       default:
+                               if int64(int16(t)) != t {
+                                       goto overflow
+                               }
+                       }
+               }
+
+               return int64(int16(t))
+
+       case ld.RV_POWER_DS:
+               if ld.Ctxt.Arch.Endian == ld.BigEndian {
+                       o1 = uint32(ld.Be16(s.P[r.Off:]))
+               } else {
+                       o1 = uint32(ld.Le16(s.P[r.Off:]))
+               }
+               if t&3 != 0 {
+                       ld.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
+               }
+               if (r.Variant&ld.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
+                       goto overflow
+               }
+               return int64(o1)&0x3 | int64(int16(t))
+       }
+
+overflow:
+       ld.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
+       return t
+}
+
+func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+       if s.Plt >= 0 {
+               return
+       }
+
+       adddynsym(ctxt, s)
+
+       if ld.Iself {
+               var plt *ld.LSym
+               var rela *ld.LSym
+               var glink *ld.LSym
+               var r *ld.Reloc
+
+               plt = ld.Linklookup(ctxt, ".plt", 0)
+               rela = ld.Linklookup(ctxt, ".rela.plt", 0)
+               if plt.Size == 0 {
+                       elfsetupplt()
+               }
+
+               // Create the glink resolver if necessary
+               glink = ensureglinkresolver()
+
+               // Write symbol resolver stub (just a branch to the
+               // glink resolver stub)
+               r = ld.Addrel(glink)
+
+               r.Sym = glink
+               r.Off = int32(glink.Size)
+               r.Siz = 4
+               r.Type = ld.R_CALLPOWER
+               ld.Adduint32(ctxt, glink, 0x48000000) // b .glink
+
+               // In the ppc64 ABI, the dynamic linker is responsible
+               // for writing the entire PLT.  We just need to
+               // reserve 8 bytes for each PLT entry and generate a
+               // JMP_SLOT dynamic relocation for it.
+               //
+               // TODO(austin): ABI v1 is different
+               s.Plt = int32(plt.Size)
+
+               plt.Size += 8
+
+               ld.Addaddrplus(ctxt, rela, plt, int64(s.Plt))
+               ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_PPC64_JMP_SLOT))
+               ld.Adduint64(ctxt, rela, 0)
+       } else {
+               ld.Diag("addpltsym: unsupported binary format")
+       }
+}
+
+// Generate the glink resolver stub if necessary and return the .glink section
+func ensureglinkresolver() *ld.LSym {
+       var glink *ld.LSym
+       var s *ld.LSym
+       var r *ld.Reloc
+
+       glink = ld.Linklookup(ld.Ctxt, ".glink", 0)
+       if glink.Size != 0 {
+               return glink
+       }
+
+       // This is essentially the resolver from the ppc64 ELF ABI.
+       // At entry, r12 holds the address of the symbol resolver stub
+       // for the target routine and the argument registers hold the
+       // arguments for the target routine.
+       //
+       // This stub is PIC, so first get the PC of label 1 into r11.
+       // Other things will be relative to this.
+       ld.Adduint32(ld.Ctxt, glink, 0x7c0802a6) // mflr r0
+       ld.Adduint32(ld.Ctxt, glink, 0x429f0005) // bcl 20,31,1f
+       ld.Adduint32(ld.Ctxt, glink, 0x7d6802a6) // 1: mflr r11
+       ld.Adduint32(ld.Ctxt, glink, 0x7c0803a6) // mtlf r0
+
+       // Compute the .plt array index from the entry point address.
+       // Because this is PIC, everything is relative to label 1b (in
+       // r11):
+       //   r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
+       ld.Adduint32(ld.Ctxt, glink, 0x3800ffd0) // li r0,-(res_0-1b)=-48
+       ld.Adduint32(ld.Ctxt, glink, 0x7c006214) // add r0,r0,r12
+       ld.Adduint32(ld.Ctxt, glink, 0x7c0b0050) // sub r0,r0,r11
+       ld.Adduint32(ld.Ctxt, glink, 0x7800f082) // srdi r0,r0,2
+
+       // r11 = address of the first byte of the PLT
+       r = ld.Addrel(glink)
+
+       r.Off = int32(glink.Size)
+       r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+       r.Siz = 8
+       r.Type = ld.R_ADDRPOWER
+
+       // addis r11,0,.plt@ha; addi r11,r11,.plt@l
+       r.Add = 0x3d600000<<32 | 0x396b0000
+
+       glink.Size += 8
+
+       // Load r12 = dynamic resolver address and r11 = DSO
+       // identifier from the first two doublewords of the PLT.
+       ld.Adduint32(ld.Ctxt, glink, 0xe98b0000) // ld r12,0(r11)
+       ld.Adduint32(ld.Ctxt, glink, 0xe96b0008) // ld r11,8(r11)
+
+       // Jump to the dynamic resolver
+       ld.Adduint32(ld.Ctxt, glink, 0x7d8903a6) // mtctr r12
+       ld.Adduint32(ld.Ctxt, glink, 0x4e800420) // bctr
+
+       // The symbol resolvers must immediately follow.
+       //   res_0:
+
+       // Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
+       // before the first symbol resolver stub.
+       s = ld.Linklookup(ld.Ctxt, ".dynamic", 0)
+
+       ld.Elfwritedynentsymplus(s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
+
+       return glink
+}
+
+func adddynsym(ctxt *ld.Link, s *ld.LSym) {
+       var d *ld.LSym
+       var t int
+       var name string
+
+       if s.Dynid >= 0 {
+               return
+       }
+
+       if ld.Iself {
+               s.Dynid = int32(ld.Nelfsym)
+               ld.Nelfsym++
+
+               d = ld.Linklookup(ctxt, ".dynsym", 0)
+
+               name = s.Extname
+               ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
+
+               /* type */
+               t = ld.STB_GLOBAL << 4
+
+               if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
+                       t |= ld.STT_FUNC
+               } else {
+                       t |= ld.STT_OBJECT
+               }
+               ld.Adduint8(ctxt, d, uint8(t))
+
+               /* reserved */
+               ld.Adduint8(ctxt, d, 0)
+
+               /* section where symbol is defined */
+               if s.Type == ld.SDYNIMPORT {
+                       ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
+               } else {
+                       ld.Adduint16(ctxt, d, 1)
+               }
+
+               /* value */
+               if s.Type == ld.SDYNIMPORT {
+                       ld.Adduint64(ctxt, d, 0)
+               } else {
+                       ld.Addaddr(ctxt, d, s)
+               }
+
+               /* size of object */
+               ld.Adduint64(ctxt, d, uint64(s.Size))
+       } else {
+               ld.Diag("adddynsym: unsupported binary format")
+       }
+}
+
+func adddynlib(lib string) {
+       var s *ld.LSym
+
+       if needlib(lib) == 0 {
+               return
+       }
+
+       if ld.Iself {
+               s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
+               if s.Size == 0 {
+                       ld.Addstring(s, "")
+               }
+               ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
+       } else {
+               ld.Diag("adddynlib: unsupported binary format")
+       }
+}
+
+func asmb() {
+       var symo uint32
+       var sect *ld.Section
+       var sym *ld.LSym
+       var i int
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+
+       if ld.Iself {
+               ld.Asmbelfsetup()
+       }
+
+       sect = ld.Segtext.Sect
+       ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+       ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+       for sect = sect.Next; sect != nil; sect = sect.Next {
+               ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+               ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+       }
+
+       if ld.Segrodata.Filelen > 0 {
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+               }
+               ld.Bflush(&ld.Bso)
+
+               ld.Cseek(int64(ld.Segrodata.Fileoff))
+               ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+       }
+
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+
+       ld.Cseek(int64(ld.Segdata.Fileoff))
+       ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+       /* output symbol table */
+       ld.Symsize = 0
+
+       ld.Lcsize = 0
+       symo = 0
+       if ld.Debug['s'] == 0 {
+               // TODO: rationalize
+               if ld.Debug['v'] != 0 {
+                       fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+               }
+               ld.Bflush(&ld.Bso)
+               switch ld.HEADTYPE {
+               default:
+                       if ld.Iself {
+                               symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+                               symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+                       }
+
+               case ld.Hplan9:
+                       symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+               }
+
+               ld.Cseek(int64(symo))
+               switch ld.HEADTYPE {
+               default:
+                       if ld.Iself {
+                               if ld.Debug['v'] != 0 {
+                                       fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+                               }
+                               ld.Asmelfsym()
+                               ld.Cflush()
+                               ld.Cwrite(ld.Elfstrdat)
+
+                               if ld.Debug['v'] != 0 {
+                                       fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+                               }
+                               ld.Dwarfemitdebugsections()
+
+                               if ld.Linkmode == ld.LinkExternal {
+                                       ld.Elfemitreloc()
+                               }
+                       }
+
+               case ld.Hplan9:
+                       ld.Asmplan9sym()
+                       ld.Cflush()
+
+                       sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
+                       if sym != nil {
+                               ld.Lcsize = int32(len(sym.P))
+                               for i = 0; int32(i) < ld.Lcsize; i++ {
+                                       ld.Cput(uint8(sym.P[i]))
+                               }
+
+                               ld.Cflush()
+                       }
+               }
+       }
+
+       ld.Ctxt.Cursym = nil
+       if ld.Debug['v'] != 0 {
+               fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+       }
+       ld.Bflush(&ld.Bso)
+       ld.Cseek(0)
+       switch ld.HEADTYPE {
+       default:
+       case ld.Hplan9: /* plan 9 */
+               ld.Thearch.Lput(0x647)                      /* magic */
+               ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
+               ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
+               ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
+               ld.Thearch.Lput(uint32(ld.Symsize))      /* nsyms */
+               ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
+               ld.Thearch.Lput(0)
+               ld.Thearch.Lput(uint32(ld.Lcsize))
+
+       case ld.Hlinux,
+               ld.Hfreebsd,
+               ld.Hnetbsd,
+               ld.Hopenbsd,
+               ld.Hnacl:
+               ld.Asmbelf(int64(symo))
+       }
+
+       ld.Cflush()
+       if ld.Debug['c'] != 0 {
+               fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
+               fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
+               fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
+               fmt.Printf("symsize=%d\n", ld.Symsize)
+               fmt.Printf("lcsize=%d\n", ld.Lcsize)
+               fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
+       }
+}
diff --git a/src/cmd/new9l/l.go b/src/cmd/new9l/l.go
new file mode 100644 (file)
index 0000000..7ddac3f
--- /dev/null
@@ -0,0 +1,77 @@
+// Inferno utils/5l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+// Writing object files.
+
+// cmd/9l/l.h from Vita Nuova.
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+const (
+       thechar   = '9'
+       PtrSize   = 8
+       IntSize   = 8
+       RegSize   = 8
+       MaxAlign  = 32
+       FuncAlign = 8
+       MINLC     = 4
+)
+
+/* Used by ../ld/dwarf.c */
+const (
+       DWARFREGSP = 1
+)
diff --git a/src/cmd/new9l/obj.go b/src/cmd/new9l/obj.go
new file mode 100644 (file)
index 0000000..8bba6be
--- /dev/null
@@ -0,0 +1,165 @@
+// Inferno utils/5l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+       "cmd/internal/obj"
+       "fmt"
+       "log"
+)
+import "cmd/internal/ld"
+
+// Reading object files.
+
+func main() {
+       linkarchinit()
+       ld.Ldmain()
+}
+
+func linkarchinit() {
+       ld.Thestring = obj.Getgoarch()
+       if ld.Thestring == "ppc64le" {
+               ld.Thelinkarch = &ld.Linkppc64le
+       } else {
+               ld.Thelinkarch = &ld.Linkppc64
+       }
+
+       ld.Thearch.Thechar = thechar
+       ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
+       ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
+       ld.Thearch.Regsize = ld.Thelinkarch.Regsize
+       ld.Thearch.Funcalign = FuncAlign
+       ld.Thearch.Maxalign = MaxAlign
+       ld.Thearch.Minlc = MINLC
+       ld.Thearch.Dwarfregsp = DWARFREGSP
+
+       ld.Thearch.Adddynlib = adddynlib
+       ld.Thearch.Adddynrel = adddynrel
+       ld.Thearch.Adddynsym = adddynsym
+       ld.Thearch.Archinit = archinit
+       ld.Thearch.Archreloc = archreloc
+       ld.Thearch.Archrelocvariant = archrelocvariant
+       ld.Thearch.Asmb = asmb
+       ld.Thearch.Elfreloc1 = elfreloc1
+       ld.Thearch.Elfsetupplt = elfsetupplt
+       ld.Thearch.Gentext = gentext
+       ld.Thearch.Machoreloc1 = machoreloc1
+       if ld.Thelinkarch == &ld.Linkppc64le {
+               ld.Thearch.Lput = ld.Lputl
+               ld.Thearch.Wput = ld.Wputl
+               ld.Thearch.Vput = ld.Vputl
+       } else {
+               ld.Thearch.Lput = ld.Lputb
+               ld.Thearch.Wput = ld.Wputb
+               ld.Thearch.Vput = ld.Vputb
+       }
+
+       // TODO(austin): ABI v1 uses /usr/lib/ld.so.1
+       ld.Thearch.Linuxdynld = "/lib64/ld64.so.1"
+
+       ld.Thearch.Freebsddynld = "XXX"
+       ld.Thearch.Openbsddynld = "XXX"
+       ld.Thearch.Netbsddynld = "XXX"
+       ld.Thearch.Dragonflydynld = "XXX"
+       ld.Thearch.Solarisdynld = "XXX"
+}
+
+func archinit() {
+       // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+       // Go was built; see ../../make.bash.
+       if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
+               ld.Linkmode = ld.LinkInternal
+       }
+
+       switch ld.HEADTYPE {
+       default:
+               if ld.Linkmode == ld.LinkAuto {
+                       ld.Linkmode = ld.LinkInternal
+               }
+               if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
+                       log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
+               }
+       }
+
+       switch ld.HEADTYPE {
+       default:
+               ld.Diag("unknown -H option")
+               ld.Errorexit()
+               fallthrough
+
+       case ld.Hplan9: /* plan 9 */
+               ld.HEADR = 32
+
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 4128
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 4096
+               }
+
+       case ld.Hlinux: /* ppc64 elf */
+               if ld.Thestring == "ppc64" {
+                       ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet
+               }
+               ld.Elfinit()
+               ld.HEADR = ld.ELFRESERVE
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 0x10000 + int64(ld.HEADR)
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 0x10000
+               }
+
+       case ld.Hnacl:
+               ld.Elfinit()
+               ld.HEADR = 0x10000
+               ld.Funcalign = 16
+               if ld.INITTEXT == -1 {
+                       ld.INITTEXT = 0x20000
+               }
+               if ld.INITDAT == -1 {
+                       ld.INITDAT = 0
+               }
+               if ld.INITRND == -1 {
+                       ld.INITRND = 0x10000
+               }
+       }
+
+       if ld.INITDAT != 0 && ld.INITRND != 0 {
+               fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+       }
+}