aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/ld/data.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/internal/ld/data.go')
-rw-r--r--src/cmd/link/internal/ld/data.go708
1 files changed, 435 insertions, 273 deletions
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 31613e5cef..7c4b08a805 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -37,6 +37,7 @@ import (
"cmd/internal/gcprog"
"cmd/internal/objabi"
"cmd/internal/sys"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"compress/zlib"
"encoding/binary"
@@ -99,7 +100,7 @@ func trampoline(ctxt *Link, s *sym.Symbol) {
if Symaddr(r.Sym) == 0 && (r.Sym.Type != sym.SDYNIMPORT && r.Sym.Type != sym.SUNDEFEXT) {
if r.Sym.File != s.File {
if !isRuntimeDepPkg(s.File) || !isRuntimeDepPkg(r.Sym.File) {
- ctxt.ErrorUnresolved(s, r)
+ ctxt.errorUnresolved(s, r)
}
// runtime and its dependent packages may call to each other.
// they are fine, as they will be laid down together.
@@ -126,7 +127,9 @@ func trampoline(ctxt *Link, s *sym.Symbol) {
//
// This is a performance-critical function for the linker; be careful
// to avoid introducing unnecessary allocations in the main loop.
-func relocsym(ctxt *Link, s *sym.Symbol) {
+// TODO: This function is called in parallel. When the Loader wavefront
+// reaches here, calls into the loader need to be parallel as well.
+func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *ArchSyms, s *sym.Symbol) {
if len(s.R) == 0 {
return
}
@@ -157,8 +160,8 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) {
// When putting the runtime but not main into a shared library
// these symbols are undefined and that's OK.
- if ctxt.BuildMode == BuildModeShared || ctxt.BuildMode == BuildModePlugin {
- if r.Sym.Name == "main.main" || (ctxt.BuildMode != BuildModePlugin && r.Sym.Name == "main..inittask") {
+ if target.IsShared() || target.IsPlugin() {
+ if r.Sym.Name == "main.main" || (!target.IsPlugin() && r.Sym.Name == "main..inittask") {
r.Sym.Type = sym.SDYNIMPORT
} else if strings.HasPrefix(r.Sym.Name, "go.info.") {
// Skip go.info symbols. They are only needed to communicate
@@ -166,7 +169,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
continue
}
} else {
- ctxt.ErrorUnresolved(s, r)
+ err.errorUnresolved(s, r)
continue
}
}
@@ -180,21 +183,21 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
// We need to be able to reference dynimport symbols when linking against
// shared libraries, and Solaris, Darwin and AIX need it always
- if ctxt.HeadType != objabi.Hsolaris && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Haix && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !ctxt.DynlinkingGo() && !r.Sym.Attr.SubSymbol() {
- if !(ctxt.Arch.Family == sys.PPC64 && ctxt.LinkMode == LinkExternal && r.Sym.Name == ".TOC.") {
- Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(ctxt.Arch, r.Type))
+ if !target.IsSolaris() && !target.IsDarwin() && !target.IsAIX() && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !target.IsDynlinkingGo() && !r.Sym.Attr.SubSymbol() {
+ if !(target.IsPPC64() && target.IsExternal() && r.Sym.Name == ".TOC.") {
+ Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(target.Arch, r.Type))
}
}
if r.Sym != nil && r.Sym.Type != sym.STLSBSS && r.Type != objabi.R_WEAKADDROFF && !r.Sym.Attr.Reachable() {
Errorf(s, "unreachable sym in relocation: %s", r.Sym.Name)
}
- if ctxt.LinkMode == LinkExternal {
+ if target.IsExternal() {
r.InitExt()
}
// TODO(mundaym): remove this special case - see issue 14218.
- if ctxt.Arch.Family == sys.S390X {
+ if target.IsS390X() {
switch r.Type {
case objabi.R_PCRELDBL:
r.InitExt()
@@ -215,33 +218,33 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
case 1:
o = int64(s.P[off])
case 2:
- o = int64(ctxt.Arch.ByteOrder.Uint16(s.P[off:]))
+ o = int64(target.Arch.ByteOrder.Uint16(s.P[off:]))
case 4:
- o = int64(ctxt.Arch.ByteOrder.Uint32(s.P[off:]))
+ o = int64(target.Arch.ByteOrder.Uint32(s.P[off:]))
case 8:
- o = int64(ctxt.Arch.ByteOrder.Uint64(s.P[off:]))
+ o = int64(target.Arch.ByteOrder.Uint64(s.P[off:]))
}
- if offset, ok := thearch.Archreloc(ctxt, r, s, o); ok {
+ if offset, ok := thearch.Archreloc(target, syms, r, s, o); ok {
o = offset
} else {
- Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type))
+ Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(target.Arch, r.Type))
}
case objabi.R_TLS_LE:
- if ctxt.LinkMode == LinkExternal && ctxt.IsELF {
+ if target.IsExternal() && target.IsElf() {
r.Done = false
if r.Sym == nil {
- r.Sym = ctxt.Tlsg
+ r.Sym = syms.Tlsg
}
r.Xsym = r.Sym
r.Xadd = r.Add
o = 0
- if ctxt.Arch.Family != sys.AMD64 {
+ if !target.IsAMD64() {
o = r.Add
}
break
}
- if ctxt.IsELF && ctxt.Arch.Family == sys.ARM {
+ if target.IsElf() && target.IsARM() {
// 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).
@@ -250,43 +253,43 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
// related to the fact that our own TLS storage happens
// to take up 8 bytes.
o = 8 + r.Sym.Value
- } else if ctxt.IsELF || ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hdarwin {
- o = int64(ctxt.Tlsoffset) + r.Add
- } else if ctxt.HeadType == objabi.Hwindows {
+ } else if target.IsElf() || target.IsPlan9() || target.IsDarwin() {
+ o = int64(syms.Tlsoffset) + r.Add
+ } else if target.IsWindows() {
o = r.Add
} else {
- log.Fatalf("unexpected R_TLS_LE relocation for %v", ctxt.HeadType)
+ log.Fatalf("unexpected R_TLS_LE relocation for %v", target.HeadType)
}
case objabi.R_TLS_IE:
- if ctxt.LinkMode == LinkExternal && ctxt.IsELF {
+ if target.IsExternal() && target.IsElf() {
r.Done = false
if r.Sym == nil {
- r.Sym = ctxt.Tlsg
+ r.Sym = syms.Tlsg
}
r.Xsym = r.Sym
r.Xadd = r.Add
o = 0
- if ctxt.Arch.Family != sys.AMD64 {
+ if !target.IsAMD64() {
o = r.Add
}
break
}
- if ctxt.BuildMode == BuildModePIE && ctxt.IsELF {
+ if target.IsPIE() && target.IsElf() {
// We are linking the final executable, so we
// can optimize any TLS IE relocation to LE.
if thearch.TLSIEtoLE == nil {
- log.Fatalf("internal linking of TLS IE not supported on %v", ctxt.Arch.Family)
+ log.Fatalf("internal linking of TLS IE not supported on %v", target.Arch.Family)
}
thearch.TLSIEtoLE(s, int(off), int(r.Siz))
- o = int64(ctxt.Tlsoffset)
- // TODO: o += r.Add when ctxt.Arch.Family != sys.AMD64?
+ o = int64(syms.Tlsoffset)
+ // TODO: o += r.Add when !target.IsAmd64()?
// Why do we treat r.Add differently on AMD64?
// Is the external linker using Xadd at all?
} else {
log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", s.Name)
}
case objabi.R_ADDR:
- if ctxt.LinkMode == LinkExternal && r.Sym.Type != sym.SCONST {
+ if target.IsExternal() && r.Sym.Type != sym.SCONST {
r.Done = false
// set up addend for eventual relocation via outer symbol.
@@ -304,20 +307,20 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
r.Xsym = rs
o = r.Xadd
- if ctxt.IsELF {
- if ctxt.Arch.Family == sys.AMD64 {
+ if target.IsElf() {
+ if target.IsAMD64() {
o = 0
}
- } else if ctxt.HeadType == objabi.Hdarwin {
+ } else if target.IsDarwin() {
if rs.Type != sym.SHOSTOBJ {
o += Symaddr(rs)
}
- } else if ctxt.HeadType == objabi.Hwindows {
+ } else if target.IsWindows() {
// nothing to do
- } else if ctxt.HeadType == objabi.Haix {
+ } else if target.IsAIX() {
o = Symaddr(r.Sym) + r.Add
} else {
- Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, ctxt.HeadType)
+ Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
}
break
@@ -327,14 +330,14 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
// as section addresses can change once loaded.
// The "default" symbol address is still needed by the loader so
// the current relocation can't be skipped.
- if ctxt.HeadType == objabi.Haix && r.Sym.Type != sym.SDYNIMPORT {
+ if target.IsAIX() && r.Sym.Type != sym.SDYNIMPORT {
// It's not possible to make a loader relocation in a
// symbol which is not inside .data section.
// FIXME: It should be forbidden to have R_ADDR from a
// symbol which isn't in .data. However, as .text has the
// same address once loaded, this is possible.
if s.Sect.Seg == &Segdata {
- Xcoffadddynrel(ctxt, s, r)
+ Xcoffadddynrel(target, ldr, s, r)
}
}
@@ -345,7 +348,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
// 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 && ctxt.Arch.PtrSize > 4 && siz == 4 {
+ if int32(o) < 0 && target.Arch.PtrSize > 4 && siz == 4 {
Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", r.Sym.Name, uint64(o), Symaddr(r.Sym), r.Add)
errorexit()
}
@@ -354,7 +357,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
}
- if ctxt.LinkMode == LinkExternal {
+ if target.IsExternal() {
r.Done = false
// On most platforms, the external linker needs to adjust DWARF references
@@ -362,7 +365,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
// DWARF linking, and it understands how to follow section offsets.
// Leaving in the relocation records confuses it (see
// https://golang.org/issue/22068) so drop them for Darwin.
- if ctxt.HeadType == objabi.Hdarwin {
+ if target.IsDarwin() {
r.Done = true
}
@@ -371,15 +374,15 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
// IMAGE_REL_I386_DIR32, IMAGE_REL_AMD64_ADDR64 and IMAGE_REL_AMD64_ADDR32.
// Do not replace R_DWARFSECREF with R_ADDR for windows -
// let PE code emit correct relocations.
- if ctxt.HeadType != objabi.Hwindows {
+ if !target.IsWindows() {
r.Type = objabi.R_ADDR
}
- r.Xsym = ctxt.Syms.ROLookup(r.Sym.Sect.Name, 0)
+ r.Xsym = r.Sym.Sect.Sym
r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
o = r.Xadd
- if ctxt.IsELF && ctxt.Arch.Family == sys.AMD64 {
+ if target.IsElf() && target.IsAMD64() {
o = 0
}
break
@@ -406,7 +409,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
case objabi.R_GOTPCREL:
- if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin && r.Sym != nil && r.Sym.Type != sym.SCONST {
+ if target.IsDynlinkingGo() && target.IsDarwin() && r.Sym != nil && r.Sym.Type != sym.SCONST {
r.Done = false
r.Xadd = r.Add
r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
@@ -418,18 +421,18 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
}
fallthrough
case objabi.R_CALL, objabi.R_PCREL:
- if ctxt.LinkMode == LinkExternal && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
+ if target.IsExternal() && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
// pass through to the external linker.
r.Done = false
r.Xadd = 0
- if ctxt.IsELF {
+ if target.IsElf() {
r.Xadd -= int64(r.Siz)
}
r.Xsym = r.Sym
o = 0
break
}
- if ctxt.LinkMode == LinkExternal && r.Sym != nil && r.Sym.Type != sym.SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) {
+ if target.IsExternal() && r.Sym != nil && r.Sym.Type != sym.SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) {
r.Done = false
// set up addend for eventual relocation via outer symbol.
@@ -448,14 +451,14 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
r.Xsym = rs
o = r.Xadd
- if ctxt.IsELF {
- if ctxt.Arch.Family == sys.AMD64 {
+ if target.IsElf() {
+ if target.IsAMD64() {
o = 0
}
- } else if ctxt.HeadType == objabi.Hdarwin {
+ } else if target.IsDarwin() {
if r.Type == objabi.R_CALL {
- if ctxt.LinkMode == LinkExternal && rs.Type == sym.SDYNIMPORT {
- switch ctxt.Arch.Family {
+ if target.IsExternal() && rs.Type == sym.SDYNIMPORT {
+ switch target.Arch.Family {
case sys.AMD64:
// AMD64 dynamic relocations are relative to the end of the relocation.
o += int64(r.Siz)
@@ -470,18 +473,18 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
}
o -= int64(r.Off) // relative to section offset, not symbol
}
- } else if ctxt.Arch.Family == sys.ARM {
+ } else if target.IsARM() {
// see ../arm/asm.go:/machoreloc1
o += Symaddr(rs) - s.Value - int64(r.Off)
} else {
o += int64(r.Siz)
}
- } else if ctxt.HeadType == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 { // only amd64 needs PCREL
+ } else if target.IsWindows() && target.IsAMD64() { // 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)
} else {
- Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, ctxt.HeadType)
+ Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
}
break
@@ -497,10 +500,10 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
o = r.Sym.Size + r.Add
case objabi.R_XCOFFREF:
- if ctxt.HeadType != objabi.Haix {
+ if !target.IsAIX() {
Errorf(s, "find XCOFF R_REF on non-XCOFF files")
}
- if ctxt.LinkMode != LinkExternal {
+ if !target.IsExternal() {
Errorf(s, "find XCOFF R_REF with internal linking")
}
r.Xsym = r.Sym
@@ -516,10 +519,10 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
o = r.Add
}
- if ctxt.Arch.Family == sys.PPC64 || ctxt.Arch.Family == sys.S390X {
+ if target.IsPPC64() || target.IsS390X() {
r.InitExt()
if r.Variant != sym.RV_NONE {
- o = thearch.Archrelocvariant(ctxt, r, s, o)
+ o = thearch.Archrelocvariant(target, syms, r, s, o)
}
}
@@ -534,7 +537,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
if r.Xsym != nil {
xnam = r.Xsym.Name
}
- fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x (xsym: %s +%#x) [type %d (%s)/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, addr, r.Add, xnam, r.Xadd, r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Variant, o)
+ fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x (xsym: %s +%#x) [type %d (%s)/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, addr, r.Add, xnam, r.Xadd, r.Type, sym.RelocName(target.Arch, r.Type), r.Variant, o)
}
switch siz {
default:
@@ -549,7 +552,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
Errorf(s, "relocation address for %s is too big: %#x", r.Sym.Name, o)
}
i16 := int16(o)
- ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
+ target.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
case 4:
if r.Type == objabi.R_PCREL || r.Type == objabi.R_CALL {
if o != int64(int32(o)) {
@@ -562,64 +565,95 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
}
fl := int32(o)
- ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
+ target.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
case 8:
- ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
+ target.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
}
}
}
func (ctxt *Link) reloc() {
- for _, s := range ctxt.Textp {
- relocsym(ctxt, s)
- }
- for _, s := range datap {
- relocsym(ctxt, s)
- }
- for _, s := range dwarfp {
- relocsym(ctxt, s)
- }
+ var wg sync.WaitGroup
+ target := &ctxt.Target
+ ldr := ctxt.loader
+ reporter := &ctxt.ErrorReporter
+ syms := &ctxt.ArchSyms
+ wg.Add(3)
+ go func() {
+ for _, s := range ctxt.Textp {
+ relocsym(target, ldr, reporter, syms, s)
+ }
+ wg.Done()
+ }()
+ go func() {
+ for _, s := range ctxt.datap {
+ relocsym(target, ldr, reporter, syms, s)
+ }
+ wg.Done()
+ }()
+ go func() {
+ for _, s := range dwarfp {
+ relocsym(target, ldr, reporter, syms, s)
+ }
+ wg.Done()
+ }()
+ wg.Wait()
}
-func windynrelocsym(ctxt *Link, rel, s *sym.Symbol) {
- for ri := range s.R {
- r := &s.R[ri]
- targ := r.Sym
- if targ == nil {
+func windynrelocsym(ctxt *Link, rel *loader.SymbolBuilder, s loader.Sym) {
+ var su *loader.SymbolBuilder
+ relocs := ctxt.loader.Relocs(s)
+ for ri := 0; ri < relocs.Count(); ri++ {
+ r := relocs.At2(ri)
+ targ := r.Sym()
+ if targ == 0 {
continue
}
- if !targ.Attr.Reachable() {
- if r.Type == objabi.R_WEAKADDROFF {
+ rt := r.Type()
+ if !ctxt.loader.AttrReachable(targ) {
+ if rt == objabi.R_WEAKADDROFF {
continue
}
- Errorf(s, "dynamic relocation to unreachable symbol %s", targ.Name)
+ ctxt.Errorf(s, "dynamic relocation to unreachable symbol %s",
+ ctxt.loader.SymName(targ))
}
- if r.Sym.Plt() == -2 && r.Sym.Got() != -2 { // make dynimport JMP table for PE object files.
- targ.SetPlt(int32(rel.Size))
- r.Sym = rel
- r.Add = int64(targ.Plt())
+
+ tplt := ctxt.loader.SymPlt(targ)
+ tgot := ctxt.loader.SymGot(targ)
+ if tplt == -2 && tgot != -2 { // make dynimport JMP table for PE object files.
+ tplt := int32(rel.Size())
+ ctxt.loader.SetPlt(targ, tplt)
+
+ if su == nil {
+ su = ctxt.loader.MakeSymbolUpdater(s)
+ }
+ r.SetSym(rel.Sym())
+ r.SetAdd(int64(tplt))
// jmp *addr
switch ctxt.Arch.Family {
default:
- Errorf(s, "unsupported arch %v", ctxt.Arch.Family)
+ ctxt.Errorf(s, "unsupported arch %v", ctxt.Arch.Family)
return
case sys.I386:
rel.AddUint8(0xff)
rel.AddUint8(0x25)
- rel.AddAddr(ctxt.Arch, targ)
+ rel.AddAddrPlus(ctxt.Arch, targ, 0)
rel.AddUint8(0x90)
rel.AddUint8(0x90)
case sys.AMD64:
rel.AddUint8(0xff)
rel.AddUint8(0x24)
rel.AddUint8(0x25)
- rel.AddAddrPlus4(targ, 0)
+ rel.AddAddrPlus4(ctxt.Arch, targ, 0)
rel.AddUint8(0x90)
}
- } else if r.Sym.Plt() >= 0 {
- r.Sym = rel
- r.Add = int64(targ.Plt())
+ } else if tplt >= 0 {
+ if su == nil {
+ su = ctxt.loader.MakeSymbolUpdater(s)
+ }
+ r.SetSym(rel.Sym())
+ r.SetAdd(int64(tplt))
}
}
}
@@ -627,32 +661,32 @@ func windynrelocsym(ctxt *Link, rel, s *sym.Symbol) {
// windynrelocsyms generates jump table to C library functions that will be
// added later. windynrelocsyms writes the table into .rel symbol.
func (ctxt *Link) windynrelocsyms() {
- if !(ctxt.HeadType == objabi.Hwindows && iscgo && ctxt.LinkMode == LinkInternal) {
+ if !(ctxt.IsWindows() && iscgo && ctxt.IsInternal()) {
return
}
- /* relocation table */
- rel := ctxt.Syms.Lookup(".rel", 0)
- rel.Attr |= sym.AttrReachable
- rel.Type = sym.STEXT
- ctxt.Textp = append(ctxt.Textp, rel)
+ rel := ctxt.loader.LookupOrCreateSym(".rel", 0)
+ relu := ctxt.loader.MakeSymbolUpdater(rel)
+ relu.SetType(sym.STEXT)
- for _, s := range ctxt.Textp {
- if s == rel {
- continue
- }
- windynrelocsym(ctxt, rel, s)
+ for _, s := range ctxt.Textp2 {
+ windynrelocsym(ctxt, relu, s)
}
+
+ ctxt.Textp2 = append(ctxt.Textp2, rel)
}
func dynrelocsym(ctxt *Link, s *sym.Symbol) {
+ target := &ctxt.Target
+ ldr := ctxt.loader
+ syms := &ctxt.ArchSyms
for ri := range s.R {
r := &s.R[ri]
if ctxt.BuildMode == BuildModePIE && ctxt.LinkMode == LinkInternal {
// It's expected that some relocations will be done
// later by relocsym (R_TLS_LE, R_ADDROFF), so
// don't worry if Adddynrel returns false.
- thearch.Adddynrel(ctxt, s, r)
+ thearch.Adddynrel(target, ldr, syms, s, r)
continue
}
@@ -660,7 +694,7 @@ func dynrelocsym(ctxt *Link, s *sym.Symbol) {
if r.Sym != nil && !r.Sym.Attr.Reachable() {
Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name)
}
- if !thearch.Adddynrel(ctxt, s, r) {
+ if !thearch.Adddynrel(target, ldr, syms, s, r) {
Errorf(s, "unsupported dynamic relocation for symbol %s (type=%d (%s) stype=%d (%s))", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Type, r.Sym.Type)
}
}
@@ -690,15 +724,16 @@ func dynreloc(ctxt *Link, data *[sym.SXREF][]*sym.Symbol) {
}
}
-func Codeblk(ctxt *Link, addr int64, size int64) {
- CodeblkPad(ctxt, addr, size, zeros[:])
+func Codeblk(ctxt *Link, out *OutBuf, addr int64, size int64) {
+ CodeblkPad(ctxt, out, addr, size, zeros[:])
}
-func CodeblkPad(ctxt *Link, addr int64, size int64, pad []byte) {
+
+func CodeblkPad(ctxt *Link, out *OutBuf, addr int64, size int64, pad []byte) {
if *flagA {
ctxt.Logf("codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, ctxt.Out.Offset())
}
- blk(ctxt.Out, ctxt.Textp, addr, size, pad)
+ writeBlocks(out, ctxt.outSem, ctxt.Textp, addr, size, pad)
/* again for printing */
if !*flagA {
@@ -756,9 +791,86 @@ func CodeblkPad(ctxt *Link, addr int64, size int64, pad []byte) {
}
}
-func blk(out *OutBuf, syms []*sym.Symbol, addr, size int64, pad []byte) {
+const blockSize = 1 << 20 // 1MB chunks written at a time.
+
+// writeBlocks writes a specified chunk of symbols to the output buffer. It
+// breaks the write up into ≥blockSize chunks to write them out, and schedules
+// as many goroutines as necessary to accomplish this task. This call then
+// blocks, waiting on the writes to complete. Note that we use the sem parameter
+// to limit the number of concurrent writes taking place.
+func writeBlocks(out *OutBuf, sem chan int, syms []*sym.Symbol, addr, size int64, pad []byte) {
for i, s := range syms {
- if !s.Attr.SubSymbol() && s.Value >= addr {
+ if s.Value >= addr && !s.Attr.SubSymbol() {
+ syms = syms[i:]
+ break
+ }
+ }
+
+ var wg sync.WaitGroup
+ max, lastAddr, written := int64(blockSize), addr+size, int64(0)
+ for addr < lastAddr {
+ // Find the last symbol we'd write.
+ idx := -1
+ for i, s := range syms {
+ // If the next symbol's size would put us out of bounds on the total length,
+ // stop looking.
+ if s.Value+s.Size > lastAddr {
+ break
+ }
+
+ // We're gonna write this symbol.
+ idx = i
+
+ // If we cross over the max size, we've got enough symbols.
+ if s.Value+s.Size > addr+max {
+ break
+ }
+ }
+
+ // If we didn't find any symbols to write, we're done here.
+ if idx < 0 {
+ break
+ }
+
+ // Compute the length to write, including padding.
+ // We need to write to the end address (lastAddr), or the next symbol's
+ // start address, whichever comes first. If there is no more symbols,
+ // just write to lastAddr. This ensures we don't leave holes between the
+ // blocks or at the end.
+ length := int64(0)
+ if idx+1 < len(syms) {
+ length = syms[idx+1].Value - addr
+ }
+ if length == 0 || length > lastAddr-addr {
+ length = lastAddr - addr
+ }
+
+ // Start the block output operator.
+ if o, err := out.View(uint64(out.Offset() + written)); err == nil {
+ sem <- 1
+ wg.Add(1)
+ go func(o *OutBuf, syms []*sym.Symbol, addr, size int64, pad []byte) {
+ writeBlock(o, syms, addr, size, pad)
+ wg.Done()
+ <-sem
+ }(o, syms, addr, length, pad)
+ } else { // output not mmaped, don't parallelize.
+ writeBlock(out, syms, addr, length, pad)
+ }
+
+ // Prepare for the next loop.
+ if idx != -1 {
+ syms = syms[idx+1:]
+ }
+ written += length
+ addr += length
+ }
+ wg.Wait()
+}
+
+func writeBlock(out *OutBuf, syms []*sym.Symbol, addr, size int64, pad []byte) {
+ for i, s := range syms {
+ if s.Value >= addr && !s.Attr.SubSymbol() {
syms = syms[i:]
break
}
@@ -802,11 +914,26 @@ func blk(out *OutBuf, syms []*sym.Symbol, addr, size int64, pad []byte) {
if addr < eaddr {
out.WriteStringPad("", int(eaddr-addr), pad)
}
- out.Flush()
}
-func Datblk(ctxt *Link, addr int64, size int64) {
- writeDatblkToOutBuf(ctxt, ctxt.Out, addr, size)
+type writeFn func(*Link, *OutBuf, int64, int64)
+
+// WriteParallel handles scheduling parallel execution of data write functions.
+func WriteParallel(wg *sync.WaitGroup, fn writeFn, ctxt *Link, seek, vaddr, length uint64) {
+ if out, err := ctxt.Out.View(seek); err != nil {
+ ctxt.Out.SeekSet(int64(seek))
+ fn(ctxt, ctxt.Out, int64(vaddr), int64(length))
+ } else {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ fn(ctxt, out, int64(vaddr), int64(length))
+ }()
+ }
+}
+
+func Datblk(ctxt *Link, out *OutBuf, addr, size int64) {
+ writeDatblkToOutBuf(ctxt, out, addr, size)
}
// Used only on Wasm for now.
@@ -823,14 +950,14 @@ func writeDatblkToOutBuf(ctxt *Link, out *OutBuf, addr int64, size int64) {
ctxt.Logf("datblk [%#x,%#x) at offset %#x\n", addr, addr+size, ctxt.Out.Offset())
}
- blk(out, datap, addr, size, zeros[:])
+ writeBlocks(out, ctxt.outSem, ctxt.datap, addr, size, zeros[:])
/* again for printing */
if !*flagA {
return
}
- syms := datap
+ syms := ctxt.datap
for i, sym := range syms {
if sym.Value >= addr {
syms = syms[i:]
@@ -892,12 +1019,12 @@ func writeDatblkToOutBuf(ctxt *Link, out *OutBuf, addr int64, size int64) {
ctxt.Logf("\t%.8x|\n", uint(eaddr))
}
-func Dwarfblk(ctxt *Link, addr int64, size int64) {
+func Dwarfblk(ctxt *Link, out *OutBuf, addr int64, size int64) {
if *flagA {
ctxt.Logf("dwarfblk [%#x,%#x) at offset %#x\n", addr, addr+size, ctxt.Out.Offset())
}
- blk(ctxt.Out, dwarfp, addr, size, zeros[:])
+ writeBlocks(out, ctxt.outSem, dwarfp, addr, size, zeros[:])
}
var zeros [512]byte
@@ -927,48 +1054,43 @@ func addstrdata1(ctxt *Link, arg string) {
}
// addstrdata sets the initial value of the string variable name to value.
-func addstrdata(ctxt *Link, name, value string) {
- s := ctxt.Syms.ROLookup(name, 0)
- if s == nil || s.Gotype == nil {
- // Not defined in the loaded packages.
+func addstrdata(arch *sys.Arch, l *loader.Loader, name, value string) {
+ s := l.Lookup(name, 0)
+ if s == 0 {
return
}
- if s.Gotype.Name != "type.string" {
- Errorf(s, "cannot set with -X: not a var of type string (%s)", s.Gotype.Name)
+ if goType := l.SymGoType(s); goType == 0 {
+ return
+ } else if typeName := l.SymName(goType); typeName != "type.string" {
+ Errorf(nil, "%s: cannot set with -X: not a var of type string (%s)", name, typeName)
return
}
- if s.Type == sym.SBSS {
- s.Type = sym.SDATA
+ if !l.AttrReachable(s) {
+ return // don't bother setting unreachable variable
}
-
- p := fmt.Sprintf("%s.str", s.Name)
- sp := ctxt.Syms.Lookup(p, 0)
-
- Addstring(sp, value)
- sp.Type = sym.SRODATA
-
- s.Size = 0
- s.P = s.P[:0]
- if s.Attr.ReadOnly() {
- s.P = make([]byte, 0, ctxt.Arch.PtrSize*2)
- s.Attr.Set(sym.AttrReadOnly, false)
+ bld := l.MakeSymbolUpdater(s)
+ if bld.Type() == sym.SBSS {
+ bld.SetType(sym.SDATA)
}
- s.R = s.R[:0]
- reachable := s.Attr.Reachable()
- s.AddAddr(ctxt.Arch, sp)
- s.AddUint(ctxt.Arch, uint64(len(value)))
- // 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(sym.AttrReachable, reachable)
+ p := fmt.Sprintf("%s.str", name)
+ sp := l.LookupOrCreateSym(p, 0)
+ sbld := l.MakeSymbolUpdater(sp)
- sp.Attr.Set(sym.AttrReachable, reachable)
+ sbld.Addstring(value)
+ sbld.SetType(sym.SRODATA)
+
+ bld.SetSize(0)
+ bld.SetData(make([]byte, 0, arch.PtrSize*2))
+ bld.SetReadOnly(false)
+ bld.SetRelocs(nil)
+ bld.AddAddrPlus(arch, sp, 0)
+ bld.AddUint(arch, uint64(len(value)))
}
func (ctxt *Link) dostrdata() {
for _, name := range strnames {
- addstrdata(ctxt, name, strdata[name])
+ addstrdata(ctxt.Arch, ctxt.loader, name, strdata[name])
}
}
@@ -1139,71 +1261,131 @@ func checkdatsize(ctxt *Link, datsize int64, symn sym.SymKind) {
}
}
-// datap is a collection of reachable data symbols in address order.
-// Generated by dodata.
-var datap []*sym.Symbol
+// fixZeroSizedSymbols gives a few special symbols with zero size some space.
+func fixZeroSizedSymbols(ctxt *Link) {
+ // The values in moduledata are filled out by relocations
+ // pointing to the addresses of these special symbols.
+ // Typically these symbols have no size and are not laid
+ // out with their matching section.
+ //
+ // However on darwin, dyld will find the special symbol
+ // in the first loaded module, even though it is local.
+ //
+ // (An hypothesis, formed without looking in the dyld sources:
+ // these special symbols have no size, so their address
+ // matches a real symbol. The dynamic linker assumes we
+ // want the normal symbol with the same address and finds
+ // it in the other module.)
+ //
+ // To work around this we lay out the symbls whose
+ // addresses are vital for multi-module programs to work
+ // as normal symbols, and give them a little size.
+ //
+ // On AIX, as all DATA sections are merged together, ld might not put
+ // these symbols at the beginning of their respective section if there
+ // aren't real symbols, their alignment might not match the
+ // first symbol alignment. Therefore, there are explicitly put at the
+ // beginning of their section with the same alignment.
+ if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
+ return
+ }
-func (ctxt *Link) dodata() {
- if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- // The values in moduledata are filled out by relocations
- // pointing to the addresses of these special symbols.
- // Typically these symbols have no size and are not laid
- // out with their matching section.
- //
- // However on darwin, dyld will find the special symbol
- // in the first loaded module, even though it is local.
- //
- // (An hypothesis, formed without looking in the dyld sources:
- // these special symbols have no size, so their address
- // matches a real symbol. The dynamic linker assumes we
- // want the normal symbol with the same address and finds
- // it in the other module.)
- //
- // To work around this we lay out the symbls whose
- // addresses are vital for multi-module programs to work
- // as normal symbols, and give them a little size.
- //
- // On AIX, as all DATA sections are merged together, ld might not put
- // these symbols at the beginning of their respective section if there
- // aren't real symbols, their alignment might not match the
- // first symbol alignment. Therefore, there are explicitly put at the
- // beginning of their section with the same alignment.
- bss := ctxt.Syms.Lookup("runtime.bss", 0)
- bss.Size = 8
- bss.Attr.Set(sym.AttrSpecial, false)
-
- ctxt.Syms.Lookup("runtime.ebss", 0).Attr.Set(sym.AttrSpecial, false)
-
- data := ctxt.Syms.Lookup("runtime.data", 0)
- data.Size = 8
- data.Attr.Set(sym.AttrSpecial, false)
-
- edata := ctxt.Syms.Lookup("runtime.edata", 0)
- edata.Attr.Set(sym.AttrSpecial, false)
- if ctxt.HeadType == objabi.Haix {
- // XCOFFTOC symbols are part of .data section.
- edata.Type = sym.SXCOFFTOC
- }
+ bss := ctxt.Syms.Lookup("runtime.bss", 0)
+ bss.Size = 8
+ bss.Attr.Set(sym.AttrSpecial, false)
- types := ctxt.Syms.Lookup("runtime.types", 0)
- types.Type = sym.STYPE
- types.Size = 8
- types.Attr.Set(sym.AttrSpecial, false)
+ ctxt.Syms.Lookup("runtime.ebss", 0).Attr.Set(sym.AttrSpecial, false)
- etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
- etypes.Type = sym.SFUNCTAB
- etypes.Attr.Set(sym.AttrSpecial, false)
+ data := ctxt.Syms.Lookup("runtime.data", 0)
+ data.Size = 8
+ data.Attr.Set(sym.AttrSpecial, false)
- if ctxt.HeadType == objabi.Haix {
- rodata := ctxt.Syms.Lookup("runtime.rodata", 0)
- rodata.Type = sym.SSTRING
- rodata.Size = 8
- rodata.Attr.Set(sym.AttrSpecial, false)
+ edata := ctxt.Syms.Lookup("runtime.edata", 0)
+ edata.Attr.Set(sym.AttrSpecial, false)
+ if ctxt.HeadType == objabi.Haix {
+ // XCOFFTOC symbols are part of .data section.
+ edata.Type = sym.SXCOFFTOC
+ }
+
+ types := ctxt.Syms.Lookup("runtime.types", 0)
+ types.Type = sym.STYPE
+ types.Size = 8
+ types.Attr.Set(sym.AttrSpecial, false)
+
+ etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
+ etypes.Type = sym.SFUNCTAB
+ etypes.Attr.Set(sym.AttrSpecial, false)
+
+ if ctxt.HeadType == objabi.Haix {
+ rodata := ctxt.Syms.Lookup("runtime.rodata", 0)
+ rodata.Type = sym.SSTRING
+ rodata.Size = 8
+ rodata.Attr.Set(sym.AttrSpecial, false)
- ctxt.Syms.Lookup("runtime.erodata", 0).Attr.Set(sym.AttrSpecial, false)
+ ctxt.Syms.Lookup("runtime.erodata", 0).Attr.Set(sym.AttrSpecial, false)
+ }
+}
+
+// makeRelroForSharedLib creates a section of readonly data if necessary.
+func makeRelroForSharedLib(target *Link, data *[sym.SXREF][]*sym.Symbol) {
+ if !target.UseRelro() {
+ return
+ }
+
+ // "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 _, symnro := range sym.ReadOnly {
+ symnrelro := sym.RelROMap[symnro]
+
+ ro := []*sym.Symbol{}
+ relro := data[symnrelro]
+
+ for _, s := range data[symnro] {
+ isRelro := len(s.R) > 0
+ switch s.Type {
+ case sym.STYPE, sym.STYPERELRO, sym.SGOFUNCRELRO:
+ // Symbols are not sorted yet, so it is possible
+ // that an Outer symbol has been changed to a
+ // relro Type before it reaches here.
+ isRelro = true
+ case sym.SFUNCTAB:
+ if target.IsAIX() && s.Name == "runtime.etypes" {
+ // runtime.etypes must be at the end of
+ // the relro datas.
+ isRelro = true
+ }
+ }
+ if isRelro {
+ s.Type = symnrelro
+ if s.Outer != nil {
+ s.Outer.Type = s.Type
+ }
+ relro = append(relro, s)
+ } else {
+ ro = append(ro, s)
+ }
+ }
+ // 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 := range relro {
+ if s.Outer != nil && s.Outer.Type != s.Type {
+ Errorf(s, "inconsistent types for symbol and its Outer %s (%v != %v)",
+ s.Outer.Name, s.Type, s.Outer.Type)
+ }
}
+
+ data[symnro] = ro
+ data[symnrelro] = relro
}
+}
+
+func (ctxt *Link) dodata() {
+ // Give zeros sized symbols space if necessary.
+ fixZeroSizedSymbols(ctxt)
// Collect data symbols by type into data.
var data [sym.SXREF][]*sym.Symbol
@@ -1228,57 +1410,8 @@ func (ctxt *Link) dodata() {
}
dynreloc(ctxt, &data)
- if ctxt.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 _, symnro := range sym.ReadOnly {
- symnrelro := sym.RelROMap[symnro]
-
- ro := []*sym.Symbol{}
- relro := data[symnrelro]
-
- for _, s := range data[symnro] {
- isRelro := len(s.R) > 0
- switch s.Type {
- case sym.STYPE, sym.STYPERELRO, sym.SGOFUNCRELRO:
- // Symbols are not sorted yet, so it is possible
- // that an Outer symbol has been changed to a
- // relro Type before it reaches here.
- isRelro = true
- case sym.SFUNCTAB:
- if ctxt.HeadType == objabi.Haix && s.Name == "runtime.etypes" {
- // runtime.etypes must be at the end of
- // the relro datas.
- isRelro = true
- }
- }
- if isRelro {
- s.Type = symnrelro
- if s.Outer != nil {
- s.Outer.Type = s.Type
- }
- relro = append(relro, s)
- } else {
- ro = append(ro, s)
- }
- }
-
- // 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 := range relro {
- if s.Outer != nil && s.Outer.Type != s.Type {
- Errorf(s, "inconsistent types for symbol and its Outer %s (%v != %v)",
- s.Outer.Name, s.Type, s.Outer.Type)
- }
- }
-
- data[symnro] = ro
- data[symnrelro] = relro
- }
- }
+ // Move any RO data with relocations to a separate section.
+ makeRelroForSharedLib(ctxt, &data)
// Sort symbols.
var dataMaxAlign [sym.SXREF]int32
@@ -1767,7 +1900,7 @@ func (ctxt *Link) dodata() {
}
for symn := sym.SELFRXSECT; symn < sym.SXREF; symn++ {
- datap = append(datap, data[symn]...)
+ ctxt.datap = append(ctxt.datap, data[symn]...)
}
dwarfGenerateDebugSyms(ctxt)
@@ -1780,6 +1913,7 @@ func (ctxt *Link) dodata() {
}
sect = addsection(ctxt.Arch, &Segdwarf, s.Name, 04)
+ sect.Sym = s
sect.Align = 1
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
@@ -1794,18 +1928,20 @@ func (ctxt *Link) dodata() {
for i < len(dwarfp) {
curType := dwarfp[i].Type
var sect *sym.Section
+ var sectname string
switch curType {
case sym.SDWARFINFO:
- sect = addsection(ctxt.Arch, &Segdwarf, ".debug_info", 04)
+ sectname = ".debug_info"
case sym.SDWARFRANGE:
- sect = addsection(ctxt.Arch, &Segdwarf, ".debug_ranges", 04)
+ sectname = ".debug_ranges"
case sym.SDWARFLOC:
- sect = addsection(ctxt.Arch, &Segdwarf, ".debug_loc", 04)
+ sectname = ".debug_loc"
default:
// Error is unrecoverable, so panic.
panic(fmt.Sprintf("unknown DWARF section %v", curType))
}
-
+ sect = addsection(ctxt.Arch, &Segdwarf, sectname, 04)
+ sect.Sym = ctxt.Syms.ROLookup(sectname, 0)
sect.Align = 1
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
@@ -1980,18 +2116,19 @@ func (ctxt *Link) textbuildid() {
return
}
- s := ctxt.Syms.Lookup("go.buildid", 0)
- s.Attr |= sym.AttrReachable
+ ldr := ctxt.loader
+ s := ldr.CreateSymForUpdate("go.buildid", 0)
+ s.SetReachable(true)
// 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(*flagBuildid) + "\n \xff"
- s.Type = sym.STEXT
- s.P = []byte(data)
- s.Size = int64(len(s.P))
+ s.SetType(sym.STEXT)
+ s.SetData([]byte(data))
+ s.SetSize(int64(len(data)))
- ctxt.Textp = append(ctxt.Textp, nil)
- copy(ctxt.Textp[1:], ctxt.Textp)
- ctxt.Textp[0] = s
+ ctxt.Textp2 = append(ctxt.Textp2, 0)
+ copy(ctxt.Textp2[1:], ctxt.Textp2)
+ ctxt.Textp2[0] = s.Sym()
}
func (ctxt *Link) buildinfo() {
@@ -2317,7 +2454,7 @@ func (ctxt *Link) address() []*sym.Segment {
}
}
- for _, s := range datap {
+ for _, s := range ctxt.datap {
if s.Sect != nil {
s.Value += int64(s.Sect.Vaddr)
}
@@ -2392,6 +2529,24 @@ func (ctxt *Link) address() []*sym.Segment {
ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
+ if ctxt.IsSolaris() {
+ // On Solaris, in the runtime it sets the external names of the
+ // end symbols. Unset them and define separate symbols, so we
+ // keep both.
+ etext := ctxt.Syms.ROLookup("runtime.etext", 0)
+ edata := ctxt.Syms.ROLookup("runtime.edata", 0)
+ end := ctxt.Syms.ROLookup("runtime.end", 0)
+ etext.SetExtname("runtime.etext")
+ edata.SetExtname("runtime.edata")
+ end.SetExtname("runtime.end")
+ ctxt.xdefine("_etext", etext.Type, etext.Value)
+ ctxt.xdefine("_edata", edata.Type, edata.Value)
+ ctxt.xdefine("_end", end.Type, end.Value)
+ ctxt.Syms.ROLookup("_etext", 0).Sect = etext.Sect
+ ctxt.Syms.ROLookup("_edata", 0).Sect = edata.Sect
+ ctxt.Syms.ROLookup("_end", 0).Sect = end.Sect
+ }
+
return order
}
@@ -2454,6 +2609,8 @@ func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte {
binary.BigEndian.PutUint64(sizeBytes[:], uint64(total))
buf.Write(sizeBytes[:])
+ var relocbuf []byte // temporary buffer for applying relocations
+
// Using zlib.BestSpeed achieves very nearly the same
// compression levels of zlib.DefaultCompression, but takes
// substantially less time. This is important because DWARF
@@ -2462,17 +2619,22 @@ func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte {
if err != nil {
log.Fatalf("NewWriterLevel failed: %s", err)
}
+ target := &ctxt.Target
+ ldr := ctxt.loader
+ reporter := &ctxt.ErrorReporter
+ archSyms := &ctxt.ArchSyms
for _, s := range syms {
// s.P may be read-only. Apply relocations in a
// temporary buffer, and immediately write it out.
oldP := s.P
wasReadOnly := s.Attr.ReadOnly()
if len(s.R) != 0 && wasReadOnly {
- ctxt.relocbuf = append(ctxt.relocbuf[:0], s.P...)
- s.P = ctxt.relocbuf
+ relocbuf = append(relocbuf[:0], s.P...)
+ s.P = relocbuf
+ // TODO: This function call needs to be parallelized when the loader wavefront gets here.
s.Attr.Set(sym.AttrReadOnly, false)
}
- relocsym(ctxt, s)
+ relocsym(target, ldr, reporter, archSyms, s)
if _, err := z.Write(s.P); err != nil {
log.Fatalf("compression failed: %s", err)
}