mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Deleting the string merging pass makes the linker 30-35% faster but makes jujud (using the github.com/davecheney/benchjuju snapshot) 2.5% larger. Two optimizations bring the space overhead down to 0.6%. First, change the default alignment for string data to 1 byte. (It was previously defaulting to larger amounts, usually pointer width.) Second, write out the type string for T (usually a bigger expression) as "*T"[1:], so that the type strings for T and *T share storage. Combined, these obtain the bulk of the benefit of string merging at essentially no cost. The remaining benefit from string merging is not worth the excessive cost, so delete it. As penance for making the jujud binary 0.6% larger, the next CL in this sequence trims the reflect functype information enough to make the jujud binary overall 0.75% smaller (that is, that CL has a net -1.35% effect). For #6853. Fixes #14648. Change-Id: I3fdd74c85410930c36bb66160ca4174ed540fc6e Reviewed-on: https://go-review.googlesource.com/20334 Reviewed-by: David Crawshaw <crawshaw@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Russ Cox <rsc@golang.org>
1843 lines
46 KiB
Go
1843 lines
46 KiB
Go
// 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"
|
|
"strconv"
|
|
"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.Attr |= AttrReachable
|
|
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.Attr |= AttrReachable
|
|
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.Attr |= AttrReachable
|
|
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.Attr |= AttrReachable
|
|
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.Attr |= AttrReachable
|
|
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.Attr |= AttrReachable
|
|
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() {
|
|
if !(Thearch.Thechar == '9' && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") {
|
|
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.Attr.Reachable() {
|
|
Diag("unreachable sym in relocation: %s %s", s.Name, r.Sym.Name)
|
|
}
|
|
|
|
switch r.Type {
|
|
default:
|
|
switch siz {
|
|
default:
|
|
Diag("bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
|
|
case 1:
|
|
o = int64(s.P[off])
|
|
case 2:
|
|
o = int64(Ctxt.Arch.ByteOrder.Uint16(s.P[off:]))
|
|
case 4:
|
|
o = int64(Ctxt.Arch.ByteOrder.Uint32(s.P[off:]))
|
|
case 8:
|
|
o = int64(Ctxt.Arch.ByteOrder.Uint64(s.P[off:]))
|
|
}
|
|
if Thearch.Archreloc(r, s, &o) < 0 {
|
|
Diag("unknown reloc %d", r.Type)
|
|
}
|
|
|
|
case obj.R_TLS_LE:
|
|
isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
|
|
|
|
if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
|
|
r.Done = 0
|
|
if r.Sym == nil {
|
|
r.Sym = Ctxt.Tlsg
|
|
}
|
|
r.Xsym = r.Sym
|
|
r.Xadd = r.Add
|
|
o = 0
|
|
if Thearch.Thechar != '6' {
|
|
o = r.Add
|
|
}
|
|
break
|
|
}
|
|
|
|
if 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
|
|
} else if Iself || Ctxt.Headtype == obj.Hplan9 || Ctxt.Headtype == obj.Hdarwin || isAndroidX86 {
|
|
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:
|
|
isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
|
|
|
|
if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
|
|
r.Done = 0
|
|
if r.Sym == nil {
|
|
r.Sym = Ctxt.Tlsg
|
|
}
|
|
r.Xsym = r.Sym
|
|
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 https://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.Attr.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.Attr.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 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()
|
|
}
|
|
|
|
if addr < sym.Value {
|
|
strnput("", int(sym.Value-addr))
|
|
addr = sym.Value
|
|
}
|
|
p = sym.P
|
|
Cwrite(p)
|
|
addr += int64(len(sym.P))
|
|
if addr < sym.Value+sym.Size {
|
|
strnput("", int(sym.Value+sym.Size-addr))
|
|
addr = sym.Value + sym.Size
|
|
}
|
|
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
|
|
}
|
|
}
|
|
|
|
if addr < eaddr {
|
|
strnput("", int(eaddr-addr))
|
|
}
|
|
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.Attr.Reachable() {
|
|
continue
|
|
}
|
|
if sym.Value >= addr {
|
|
break
|
|
}
|
|
}
|
|
|
|
eaddr := addr + size
|
|
var q []byte
|
|
for ; sym != nil; sym = sym.Next {
|
|
if !sym.Attr.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)
|
|
q = sym.P
|
|
|
|
for len(q) >= 16 {
|
|
fmt.Fprintf(&Bso, "%.6x\t% x\n", uint64(addr), q[:16])
|
|
addr += 16
|
|
q = q[16:]
|
|
}
|
|
|
|
if len(q) > 0 {
|
|
fmt.Fprintf(&Bso, "%.6x\t% x\n", uint64(addr), q)
|
|
addr += int64(len(q))
|
|
}
|
|
}
|
|
|
|
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))
|
|
}
|
|
|
|
var zeros [512]byte
|
|
|
|
// strnput writes the first n bytes of s.
|
|
// If n is larger then len(s),
|
|
// it is padded with NUL bytes.
|
|
func strnput(s string, n int) {
|
|
if len(s) >= n {
|
|
Cwritestring(s[:n])
|
|
} else {
|
|
Cwritestring(s)
|
|
n -= len(s)
|
|
for n > 0 {
|
|
if len(zeros) >= n {
|
|
Cwrite(zeros[:n])
|
|
return
|
|
} else {
|
|
Cwrite(zeros[:])
|
|
n -= len(zeros)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var strdata []*LSym
|
|
|
|
func addstrdata1(arg string) {
|
|
i := strings.Index(arg, "=")
|
|
if i < 0 {
|
|
Exitf("-X flag requires argument of the form importpath.name=value")
|
|
}
|
|
addstrdata(arg[:i], arg[i+1:])
|
|
}
|
|
|
|
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.Attr |= AttrDuplicateOK
|
|
reachable := s.Attr.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.Attr.Set(AttrReachable, reachable)
|
|
|
|
strdata = append(strdata, s)
|
|
|
|
sp.Attr.Set(AttrReachable, reachable)
|
|
}
|
|
|
|
func checkstrdata() {
|
|
for _, s := range strdata {
|
|
if s.Type == obj.STEXT {
|
|
Diag("cannot use -X with text symbol %s", s.Name)
|
|
} else if s.Gotype != nil && s.Gotype.Name != "type.string" {
|
|
Diag("cannot use -X with non-string symbol %s", s.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func Addstring(s *LSym, str string) int64 {
|
|
if s.Type == 0 {
|
|
s.Type = obj.SNOPTRDATA
|
|
}
|
|
s.Attr |= AttrReachable
|
|
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.Attr |= AttrReachable
|
|
sym.Attr |= AttrLocal
|
|
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.Attr |= AttrDuplicateOK
|
|
Addaddr(Ctxt, sp, s)
|
|
}
|
|
|
|
func dosymtype() {
|
|
for _, s := range Ctxt.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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// symalign returns the required alignment for the given symbol s.
|
|
func symalign(s *LSym) int32 {
|
|
min := int32(Thearch.Minalign)
|
|
if s.Align >= min {
|
|
return s.Align
|
|
} else if s.Align != 0 {
|
|
return min
|
|
}
|
|
if strings.HasPrefix(s.Name, "go.string.") && !strings.HasPrefix(s.Name, "go.string.hdr.") {
|
|
// String data is just bytes.
|
|
// If we align it, we waste a lot of space to padding.
|
|
return 1
|
|
}
|
|
align := int32(Thearch.Maxalign)
|
|
for int64(align) > s.Size && align > min {
|
|
align >>= 1
|
|
}
|
|
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
|
|
const cutoff int64 = 2e9 // 2 GB (or so; looks better in errors than 2^31)
|
|
switch {
|
|
case s.Size < 0:
|
|
Diag("%s: negative size (%d bytes)", s.Name, s.Size)
|
|
case s.Size > cutoff:
|
|
Diag("%s: symbol too large (%d bytes)", s.Name, s.Size)
|
|
case datsize <= cutoff && datsize+s.Size > cutoff:
|
|
Diag("%s: too much data (over %d bytes)", s.Name, cutoff)
|
|
}
|
|
*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 := range Ctxt.Allsym {
|
|
if !s.Attr.Reachable() || s.Attr.Special() {
|
|
continue
|
|
}
|
|
if obj.STEXT < s.Type && s.Type < obj.SXREF {
|
|
if s.Attr.OnList() {
|
|
log.Fatalf("symbol %s listed multiple times", s.Name)
|
|
}
|
|
s.Attr |= AttrOnList
|
|
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
|
|
|
|
if UseRelro() {
|
|
// "read only" data with relocations needs to go in its own section
|
|
// when building a shared library. We do this by boosting objects of
|
|
// type SXXX with relocations to type SXXXRELRO.
|
|
for s := datap; s != nil; s = s.Next {
|
|
if (s.Type >= obj.STYPE && s.Type <= obj.SFUNCTAB && len(s.R) > 0) || s.Type == obj.SGOSTRINGHDR {
|
|
s.Type += (obj.STYPERELRO - obj.STYPE)
|
|
if s.Outer != nil {
|
|
s.Outer.Type = s.Type
|
|
}
|
|
}
|
|
}
|
|
// Check that we haven't made two symbols with the same .Outer into
|
|
// different types (because references two symbols with non-nil Outer
|
|
// become references to the outer symbol + offset it's vital that the
|
|
// symbol and the outer end up in the same section).
|
|
for s := datap; s != nil; s = s.Next {
|
|
if s.Outer != nil && s.Outer.Type != s.Type {
|
|
Diag("inconsistent types for %s and its Outer %s (%d != %d)",
|
|
s.Name, s.Outer.Name, s.Type, s.Outer.Type)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
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 s != nil && s.Type == obj.STLSBSS {
|
|
if Iself && (Linkmode == LinkExternal || Debug['d'] == 0) && HEADTYPE != obj.Hopenbsd {
|
|
sect = addsection(&Segdata, ".tbss", 06)
|
|
sect.Align = int32(Thearch.Ptrsize)
|
|
sect.Vaddr = 0
|
|
} else {
|
|
sect = nil
|
|
}
|
|
datsize = 0
|
|
|
|
for ; s != nil && s.Type == obj.STLSBSS; s = s.Next {
|
|
datsize = aligndatsize(datsize, s)
|
|
s.Sect = sect
|
|
s.Value = datsize
|
|
growdatsize(&datsize, s)
|
|
}
|
|
|
|
if sect != nil {
|
|
sect.Length = uint64(datsize)
|
|
}
|
|
}
|
|
|
|
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.STYPERELRO-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.STYPERELRO; 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
|
|
|
|
// There is some data that are conceptually read-only but are written to by
|
|
// relocations. On GNU systems, we can arrange for the dynamic linker to
|
|
// mprotect sections after relocations are applied by giving them write
|
|
// permissions in the object file and calling them ".data.rel.ro.FOO". We
|
|
// divide the .rodata section between actual .rodata and .data.rel.ro.rodata,
|
|
// but for the other sections that this applies to, we just write a read-only
|
|
// .FOO section or a read-write .data.rel.ro.FOO section depending on the
|
|
// situation.
|
|
// TODO(mwhudson): It would make sense to do this more widely, but it makes
|
|
// the system linker segfault on darwin.
|
|
relro_perms := 04
|
|
relro_prefix := ""
|
|
|
|
if UseRelro() {
|
|
relro_perms = 06
|
|
relro_prefix = ".data.rel.ro"
|
|
/* data only written by relocations */
|
|
sect = addsection(segro, ".data.rel.ro", 06)
|
|
|
|
sect.Align = maxalign(s, obj.STYPELINK-1)
|
|
datsize = Rnd(datsize, int64(sect.Align))
|
|
sect.Vaddr = 0
|
|
for ; s != nil && s.Type < obj.STYPELINK; s = s.Next {
|
|
datsize = aligndatsize(datsize, s)
|
|
if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
|
|
Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name)
|
|
}
|
|
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, relro_prefix+".typelink", relro_perms)
|
|
|
|
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, relro_prefix+".gosymtab", relro_perms)
|
|
|
|
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, relro_prefix+".gopclntab", relro_perms)
|
|
|
|
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++
|
|
}
|
|
}
|
|
|
|
// Add buildid to beginning of text segment, on non-ELF systems.
|
|
// Non-ELF binary formats are not always flexible enough to
|
|
// give us a place to put the Go build ID. On those systems, we put it
|
|
// at the very beginning of the text segment.
|
|
// This ``header'' is read by cmd/go.
|
|
func textbuildid() {
|
|
if Iself || buildid == "" {
|
|
return
|
|
}
|
|
|
|
sym := Linklookup(Ctxt, "go.buildid", 0)
|
|
sym.Attr |= AttrReachable
|
|
// The \xff is invalid UTF-8, meant to make it less likely
|
|
// to find one of these accidentally.
|
|
data := "\xff Go build ID: " + strconv.Quote(buildid) + "\n \xff"
|
|
sym.Type = obj.STEXT
|
|
sym.P = []byte(data)
|
|
sym.Size = int64(len(sym.P))
|
|
|
|
sym.Next = Ctxt.Textp
|
|
Ctxt.Textp = sym
|
|
}
|
|
|
|
// 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 {
|
|
if Iself && s.Name == ".tbss" {
|
|
continue
|
|
}
|
|
vlen = int64(s.Length)
|
|
if s.Next != nil && !(Iself && s.Next.Name == ".tbss") {
|
|
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
|
|
if UseRelro() {
|
|
// There is another section (.data.rel.ro) when building a shared
|
|
// object on elf systems.
|
|
typelink = typelink.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.Attr |= AttrLocal
|
|
xdefine("runtime.egcdata", obj.SRODATA, Symaddr(sym)+sym.Size)
|
|
Linklookup(Ctxt, "runtime.egcdata", 0).Sect = sym.Sect
|
|
|
|
sym = Linklookup(Ctxt, "runtime.gcbss", 0)
|
|
sym.Attr |= AttrLocal
|
|
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))
|
|
}
|