--- /dev/null
+// 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
+}
--- /dev/null
+// 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,
+}
--- /dev/null
+// 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))
+}
--- /dev/null
+// 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))
+}
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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
+)
--- /dev/null
+// 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
+}
--- /dev/null
+/*
+ * 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 __ */
--- /dev/null
+// 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()
+ }
+}
--- /dev/null
+// 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
+}
--- /dev/null
+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
+}
--- /dev/null
+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 = §.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)
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+)
--- /dev/null
+// 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)
+ }
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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))
+ }
+ }
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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)
+ }
+ }
+}
--- /dev/null
+// 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
+)
--- /dev/null
+// 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()
+}
--- /dev/null
+package ld
--- /dev/null
+// 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))
+ }
+}
--- /dev/null
+// 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
+)
--- /dev/null
+// 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))
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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
+)
--- /dev/null
+// 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))
+ }
+}
--- /dev/null
+package main
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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
+)
--- /dev/null
+// 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))
+ }
+}
--- /dev/null
+// 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))
+ }
+}
--- /dev/null
+// 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
+)
--- /dev/null
+// 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))
+ }
+}