diff options
Diffstat (limited to 'src/cmd/link/internal/ld/data.go')
| -rw-r--r-- | src/cmd/link/internal/ld/data.go | 1728 |
1 files changed, 1728 insertions, 0 deletions
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go new file mode 100644 index 0000000000..fd1cdd64bb --- /dev/null +++ b/src/cmd/link/internal/ld/data.go @@ -0,0 +1,1728 @@ +// 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/gcprog" + "cmd/internal/obj" + "fmt" + "log" + "os" + "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 = obj.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 { + 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 adduint(ctxt *Link, s *LSym, v uint64) int64 { + return adduintxx(ctxt, s, v, Thearch.Intsize) +} + +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 { + if s.Type == 0 { + s.Type = obj.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 = obj.R_ADDR + r.Add = add + return i + int64(r.Siz) +} + +func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 { + if s.Type == 0 { + s.Type = obj.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 = obj.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 { + if s.Type == 0 { + s.Type = obj.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 = obj.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 { + if s.Type == 0 { + s.Type = obj.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 = obj.R_SIZE + return i + int64(r.Siz) +} + +func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 { + if s.Type == 0 { + s.Type = obj.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 = obj.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 != obj.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 { + 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 off int32 + var siz int32 + var fl int32 + var o int64 + + Ctxt.Cursym = s + for ri := int32(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&(obj.SMASK|obj.SHIDDEN) == 0 || r.Sym.Type&obj.SMASK == obj.SXREF) { + // When putting the runtime but not main into a shared library + // these symbols are undefined and that's OK. + if Buildmode == BuildmodeShared && (r.Sym.Name == "main.main" || r.Sym.Name == "main.init") { + r.Sym.Type = obj.SDYNIMPORT + } else { + Diag("%s: not defined", r.Sym.Name) + continue + } + } + + if r.Type >= 256 { + continue + } + if r.Siz == 0 { // informational relocation - no work to do + continue + } + + // We need to be able to reference dynimport symbols when linking against + // shared libraries, and Solaris needs it always + if HEADTYPE != obj.Hsolaris && r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT && !DynlinkingGo() { + Diag("unhandled relocation for %s (type %d rtype %d)", r.Sym.Name, r.Sym.Type, r.Type) + } + if r.Sym != nil && r.Sym.Type != obj.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 == obj.R_TLS && goos == "android" { + r.Type = obj.R_ADDR + } + + switch r.Type { + default: + o = 0 + if Thearch.Archreloc(r, s, &o) < 0 { + Diag("unknown reloc %d", r.Type) + } + + case obj.R_TLS: + if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd { + r.Done = 0 + r.Sym = Ctxt.Tlsg + r.Xsym = Ctxt.Tlsg + r.Xadd = r.Add + o = r.Add + break + } + 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 obj.R_TLS_LE: + if Linkmode == LinkExternal && Iself && HEADTYPE != obj.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 == obj.Hplan9 || Ctxt.Headtype == obj.Hdarwin { + o = int64(Ctxt.Tlsoffset) + r.Add + } else if Ctxt.Headtype == obj.Hwindows { + o = r.Add + } else { + log.Fatalf("unexpected R_TLS_LE relocation for %s", Headstr(Ctxt.Headtype)) + } + + case obj.R_TLS_IE: + if Linkmode == LinkExternal && Iself && HEADTYPE != obj.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 + } + log.Fatalf("cannot handle R_TLS_IE when linking internally") + + case obj.R_ADDR: + if Linkmode == LinkExternal && r.Sym.Type != obj.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 != obj.SHOSTOBJ && rs.Type != obj.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 == obj.Hdarwin { + // ld64 for arm64 has a bug where if the address pointed to by o exists in the + // symbol table (dynid >= 0), or is inside a symbol that exists in the symbol + // table, then it will add o twice into the relocated value. + // The workaround is that on arm64 don't ever add symaddr to o and always use + // extern relocation by requiring rs->dynid >= 0. + if rs.Type != obj.SHOSTOBJ { + if Thearch.Thechar == '7' && rs.Dynid < 0 { + Diag("R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o) + } + if Thearch.Thechar != '7' { + o += Symaddr(rs) + } + } + } else if HEADTYPE == obj.Hwindows { + // nothing to do + } 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 (%#x + %#x)", uint64(o), Symaddr(r.Sym), r.Add) + errorexit() + } + + // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. + case obj.R_CALL, obj.R_GOTPCREL, obj.R_PCREL: + if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != obj.SCONST && (r.Sym.Sect != Ctxt.Cursym.Sect || r.Type == obj.R_GOTPCREL) { + 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 != obj.SHOSTOBJ && rs.Type != obj.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 == obj.Hdarwin { + if r.Type == obj.R_CALL { + if rs.Type != obj.SHOSTOBJ { + o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr) + } + o -= int64(r.Off) // relative to section offset, not symbol + } else { + o += int64(r.Siz) + } + } else if HEADTYPE == obj.Hwindows && Thearch.Thechar == '6' { // only amd64 needs PCREL + // PE/COFF's PC32 relocation uses the address after the relocated + // bytes as the base. Compensate by skewing the addend. + o += int64(r.Siz) + // GNU ld always add VirtualAddress of the .text section to the + // relocated address, compensate that. + o -= int64(s.Sect.Vaddr - PEBASE) + } 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 obj.R_SIZE: + o = r.Sym.Size + r.Add + } + + if r.Variant != RV_NONE { + o = Thearch.Archrelocvariant(r, s, o) + } + + if false { + nam := "<nil>" + if r.Sym != nil { + nam = r.Sym.Name + } + fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x [type %d/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, Symaddr(r.Sym), r.Add, r.Type, r.Variant, 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 == obj.R_PCREL || r.Type == obj.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() { + if Debug['v'] != 0 { + fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime()) + } + Bso.Flush() + + 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) { + if HEADTYPE == obj.Hwindows && Linkmode != LinkExternal { + rel := Linklookup(Ctxt, ".rel", 0) + if s == rel { + return + } + var r *Reloc + var targ *LSym + 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 + } + + var r *Reloc + for ri := 0; ri < len(s.R); ri++ { + r = &s.R[ri] + if r.Sym != nil && r.Sym.Type == obj.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() { + // -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 != obj.Hwindows { + return + } + if Debug['v'] != 0 { + fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime()) + } + Bso.Flush() + + 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 + + for sym = start; sym != nil; sym = sym.Next { + if sym.Type&obj.SSUB == 0 && sym.Value >= addr { + break + } + } + + eaddr := addr + size + var ep []byte + var p []byte + for ; sym != nil; sym = sym.Next { + if sym.Type&obj.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) { + 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 + } + + var sym *LSym + for sym = Ctxt.Textp; sym != nil; sym = sym.Next { + if !sym.Reachable { + continue + } + if sym.Value >= addr { + break + } + } + + eaddr := addr + size + var n int64 + var q []byte + 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) + } + } + + Bso.Flush() +} + +func Datblk(addr int64, size int64) { + 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 + } + + var sym *LSym + for sym = datap; sym != nil; sym = sym.Next { + if sym.Value >= addr { + break + } + } + + eaddr := addr + size + var ep []byte + var i int64 + var p []byte + var r *Reloc + var rsname string + var typ string + 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 obj.R_ADDR: + typ = "addr" + + case obj.R_PCREL: + typ = "pcrel" + + case obj.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) { + p := fmt.Sprintf("%s.str", name) + sp := Linklookup(Ctxt, p, 0) + + Addstring(sp, value) + sp.Type = obj.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 { + if s.Type == 0 { + s.Type = obj.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) +} + +// addgostring adds str, as a Go string value, to s. symname is the name of the +// symbol used to define the string data and must be unique per linked object. +func addgostring(s *LSym, symname, str string) { + sym := Linklookup(Ctxt, symname, 0) + if sym.Type != obj.Sxxx { + Diag("duplicate symname in addgostring: %s", symname) + } + sym.Reachable = true + sym.Local = true + sym.Type = obj.SRODATA + sym.Size = int64(len(str)) + sym.P = []byte(str) + Addaddr(Ctxt, s, sym) + adduint(Ctxt, s, uint64(len(str))) +} + +func addinitarrdata(s *LSym) { + p := s.Name + ".ptr" + sp := Linklookup(Ctxt, p, 0) + sp.Type = obj.SINITARR + sp.Size = 0 + sp.Dupok = 1 + Addaddr(Ctxt, sp, s) +} + +func dosymtype() { + for s := Ctxt.Allsym; s != nil; s = s.Allsym { + if len(s.P) > 0 { + if s.Type == obj.SBSS { + s.Type = obj.SDATA + } + if s.Type == obj.SNOPTRBSS { + s.Type = obj.SNOPTRDATA + } + } + // Create a new entry in the .init_array section that points to the + // library initializer function. + switch Buildmode { + case BuildmodeCArchive, BuildmodeCShared: + if s.Name == INITENTRY { + addinitarrdata(s) + } + } + } +} + +func symalign(s *LSym) 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 + + max := int32(0) + for ; s != nil && int(s.Type) <= type_; s = s.Next { + align = symalign(s) + if max < align { + max = align + } + } + + return max +} + +const debugGCProg = false + +type GCProg struct { + sym *LSym + w gcprog.Writer +} + +func (p *GCProg) Init(name string) { + p.sym = Linklookup(Ctxt, name, 0) + p.w.Init(p.writeByte) + if debugGCProg { + fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name) + p.w.Debug(os.Stderr) + } +} + +func (p *GCProg) writeByte(x byte) { + Adduint8(Ctxt, p.sym, x) +} + +func (p *GCProg) End(size int64) { + p.w.ZeroUntil(size / int64(Thearch.Ptrsize)) + p.w.End() + if debugGCProg { + fmt.Fprintf(os.Stderr, "ld: end GCProg\n") + } +} + +func (p *GCProg) AddSym(s *LSym) { + typ := s.Gotype + // Things without pointers should be in SNOPTRDATA or SNOPTRBSS; + // everything we see should have pointers and should therefore have a type. + if typ == nil { + Diag("missing Go type information for global symbol: %s size %d", s.Name, int(s.Size)) + return + } + + ptrsize := int64(Thearch.Ptrsize) + nptr := decodetype_ptrdata(typ) / ptrsize + + if debugGCProg { + fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr) + } + + if decodetype_usegcprog(typ) == 0 { + // Copy pointers from mask into program. + mask := decodetype_gcmask(typ) + for i := int64(0); i < nptr; i++ { + if (mask[i/8]>>uint(i%8))&1 != 0 { + p.w.Ptr(s.Value/ptrsize + i) + } + } + return + } + + // Copy program. + prog := decodetype_gcprog(typ) + p.w.ZeroUntil(s.Value / ptrsize) + p.w.Append(prog[4:], nptr) +} + +func growdatsize(datsizep *int64, s *LSym) { + 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() { + if Debug['v'] != 0 { + fmt.Fprintf(&Bso, "%5.2f dodata\n", obj.Cputime()) + } + Bso.Flush() + + var last *LSym + datap = nil + + for s := Ctxt.Allsym; s != nil; s = s.Allsym { + if !s.Reachable || s.Special != 0 { + continue + } + if obj.STEXT < s.Type && s.Type < obj.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 == obj.Hdarwin { + machosymorder() + } + dynreloc() + + /* some symbols may no longer belong in datap (Mach-O) */ + var l **LSym + var s *LSym + for l = &datap; ; { + s = *l + if s == nil { + break + } + + if s.Type <= obj.STEXT || obj.SXREF <= s.Type { + *l = s.Next + } else { + l = &s.Next + } + } + + *l = nil + + datap = listsort(datap, datcmp, listnextp) + + if Iself { + // Make .rela and .rela.plt contiguous, the ELF ABI requires this + // and Solaris actually cares. + var relplt *LSym + for l = &datap; *l != nil; l = &(*l).Next { + if (*l).Name == ".rel.plt" || (*l).Name == ".rela.plt" { + relplt = (*l) + *l = (*l).Next + break + } + } + if relplt != nil { + for s = datap; s != nil; s = s.Next { + if s.Name == ".rel" || s.Name == ".rela" { + relplt.Next = s.Next + s.Next = relplt + } + } + } + } + + /* + * 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 < obj.SELFSECT; s = s.Next { + } + + /* writable ELF sections */ + datsize := int64(0) + + var sect *Section + for ; s != nil && s.Type < obj.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 = obj.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 == obj.SELFGOT { + sect := addsection(&Segdata, ".got", 06) + sect.Align = maxalign(s, obj.SELFGOT) + datsize = Rnd(datsize, int64(sect.Align)) + sect.Vaddr = uint64(datsize) + var toc *LSym + for ; s != nil && s.Type == obj.SELFGOT; s = s.Next { + datsize = aligndatsize(datsize, s) + s.Sect = sect + s.Type = obj.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, obj.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 < obj.SINITARR; s = s.Next { + datsize = aligndatsize(datsize, s) + s.Sect = sect + s.Type = obj.SDATA + s.Value = int64(uint64(datsize) - sect.Vaddr) + growdatsize(&datsize, s) + } + + sect.Length = uint64(datsize) - sect.Vaddr + + hasinitarr := Linkshared + + /* shared library initializer */ + switch Buildmode { + case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared: + hasinitarr = true + } + + if hasinitarr { + sect := addsection(&Segdata, ".init_array", 06) + sect.Align = maxalign(s, obj.SINITARR) + datsize = Rnd(datsize, int64(sect.Align)) + sect.Vaddr = uint64(datsize) + for ; s != nil && s.Type == obj.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, obj.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 + var gc GCProg + gc.Init("runtime.gcdata") + for ; s != nil && s.Type < obj.SBSS; s = s.Next { + if s.Type == obj.SINITARR { + Ctxt.Cursym = s + Diag("unexpected symbol type %d", s.Type) + } + + s.Sect = sect + s.Type = obj.SDATA + datsize = aligndatsize(datsize, s) + s.Value = int64(uint64(datsize) - sect.Vaddr) + gc.AddSym(s) + growdatsize(&datsize, s) + } + sect.Length = uint64(datsize) - sect.Vaddr + gc.End(int64(sect.Length)) + + /* bss */ + sect = addsection(&Segdata, ".bss", 06) + sect.Align = maxalign(s, obj.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 + gc = GCProg{} + gc.Init("runtime.gcbss") + for ; s != nil && s.Type < obj.SNOPTRBSS; s = s.Next { + s.Sect = sect + datsize = aligndatsize(datsize, s) + s.Value = int64(uint64(datsize) - sect.Vaddr) + gc.AddSym(s) + growdatsize(&datsize, s) + } + sect.Length = uint64(datsize) - sect.Vaddr + gc.End(int64(sect.Length)) + + /* pointer-free bss */ + sect = addsection(&Segdata, ".noptrbss", 06) + + sect.Align = maxalign(s, obj.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 == obj.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 == obj.STLSBSS && HEADTYPE != obj.Hopenbsd { + sect := addsection(&Segdata, ".tbss", 06) + sect.Align = int32(Thearch.Ptrsize) + sect.Vaddr = 0 + datsize = 0 + for ; s != nil && s.Type == obj.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 == obj.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. + */ + var segro *Segment + 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 < obj.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 = obj.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, obj.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 < obj.STYPELINK; s = s.Next { + datsize = aligndatsize(datsize, s) + s.Sect = sect + s.Type = obj.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, obj.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 == obj.STYPELINK; s = s.Next { + datsize = aligndatsize(datsize, s) + s.Sect = sect + s.Type = obj.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, obj.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 < obj.SPCLNTAB; s = s.Next { + datsize = aligndatsize(datsize, s) + s.Sect = sect + s.Type = obj.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, obj.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 < obj.SELFROSECT; s = s.Next { + datsize = aligndatsize(datsize, s) + s.Sect = sect + s.Type = obj.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 < obj.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 = obj.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 := int32(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 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&obj.SSUB != 0 { + continue + } + if sym.Align != 0 { + va = uint64(Rnd(int64(va), int64(sym.Align))) + } else { + va = uint64(Rnd(int64(va), int64(Funcalign))) + } + sym.Value = 0 + for sub = sym; sub != nil; sub = sub.Sub { + sub.Value += int64(va) + } + 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() { + 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 == obj.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 == obj.Hwindows { + Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN)) + } + if HEADTYPE == obj.Hplan9 { + Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen + } + var data *Section + var noptr *Section + var bss *Section + var noptrbss *Section + var vlen int64 + 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 + var rodata *Section + if Segrodata.Sect != nil { + rodata = Segrodata.Sect + } else { + rodata = text.Next + } + typelink := rodata.Next + symtab := typelink.Next + pclntab := symtab.Next + + var sub *LSym + for sym := datap; sym != nil; sym = sym.Next { + Ctxt.Cursym = sym + if sym.Sect != nil { + sym.Value += int64(sym.Sect.Vaddr) + } + for sub = sym.Sub; sub != nil; sub = sub.Sub { + sub.Value += sym.Value + } + } + + if Buildmode == BuildmodeShared { + s := Linklookup(Ctxt, "go.link.abihashbytes", 0) + sectSym := Linklookup(Ctxt, ".note.go.abihash", 0) + s.Sect = sectSym.Sect + s.Value = int64(sectSym.Sect.Vaddr + 16) + } + + xdefine("runtime.text", obj.STEXT, int64(text.Vaddr)) + xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length)) + xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr)) + xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length)) + xdefine("runtime.typelink", obj.SRODATA, int64(typelink.Vaddr)) + xdefine("runtime.etypelink", obj.SRODATA, int64(typelink.Vaddr+typelink.Length)) + + sym := Linklookup(Ctxt, "runtime.gcdata", 0) + sym.Local = true + xdefine("runtime.egcdata", obj.SRODATA, Symaddr(sym)+sym.Size) + Linklookup(Ctxt, "runtime.egcdata", 0).Sect = sym.Sect + + sym = Linklookup(Ctxt, "runtime.gcbss", 0) + sym.Local = true + xdefine("runtime.egcbss", obj.SRODATA, Symaddr(sym)+sym.Size) + Linklookup(Ctxt, "runtime.egcbss", 0).Sect = sym.Sect + + xdefine("runtime.symtab", obj.SRODATA, int64(symtab.Vaddr)) + xdefine("runtime.esymtab", obj.SRODATA, int64(symtab.Vaddr+symtab.Length)) + xdefine("runtime.pclntab", obj.SRODATA, int64(pclntab.Vaddr)) + xdefine("runtime.epclntab", obj.SRODATA, int64(pclntab.Vaddr+pclntab.Length)) + xdefine("runtime.noptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr)) + xdefine("runtime.enoptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr+noptr.Length)) + xdefine("runtime.bss", obj.SBSS, int64(bss.Vaddr)) + xdefine("runtime.ebss", obj.SBSS, int64(bss.Vaddr+bss.Length)) + xdefine("runtime.data", obj.SDATA, int64(data.Vaddr)) + xdefine("runtime.edata", obj.SDATA, int64(data.Vaddr+data.Length)) + xdefine("runtime.noptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr)) + xdefine("runtime.enoptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length)) + xdefine("runtime.end", obj.SBSS, int64(Segdata.Vaddr+Segdata.Length)) +} |
