aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2020-04-30 17:08:35 -0400
committerCherry Zhang <cherryyz@google.com>2020-04-30 17:08:35 -0400
commitd0754cfe4ac2b28caf969765e8d6f995c600daf7 (patch)
tree192c81ac8159e0030a735722d3129a8c1d3b7d2d /src
parent0f8fecaba762c352db481d4919edf404f5590d22 (diff)
parent76c6cce1160996e730d87e620ddb674b1d54f96e (diff)
downloadgo-d0754cfe4ac2b28caf969765e8d6f995c600daf7.tar.xz
cmd: merge branch 'dev.link' into master
In the dev.link branch we continued developing the new object file format support and the linker improvements described in https://golang.org/s/better-linker . Since the last merge, more progress has been made to improve the new linker. This is a clean merge. Change-Id: Ide5ad6fcec9cede99e9b21c4548929b4ba1f4185
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/gc/iexport.go6
-rw-r--r--src/cmd/compile/internal/gc/iimport.go11
-rw-r--r--src/cmd/compile/internal/gc/main.go22
-rw-r--r--src/cmd/internal/goobj/readnew.go6
-rw-r--r--src/cmd/internal/goobj2/objfile.go60
-rw-r--r--src/cmd/internal/obj/line.go5
-rw-r--r--src/cmd/internal/obj/link.go5
-rw-r--r--src/cmd/internal/obj/objfile.go5
-rw-r--r--src/cmd/internal/obj/objfile2.go14
-rw-r--r--src/cmd/internal/obj/sym.go10
-rw-r--r--src/cmd/link/internal/amd64/asm.go275
-rw-r--r--src/cmd/link/internal/amd64/obj.go2
-rw-r--r--src/cmd/link/internal/arm/asm.go227
-rw-r--r--src/cmd/link/internal/arm/obj.go2
-rw-r--r--src/cmd/link/internal/arm64/asm.go217
-rw-r--r--src/cmd/link/internal/arm64/obj.go2
-rw-r--r--src/cmd/link/internal/ld/data.go1705
-rw-r--r--src/cmd/link/internal/ld/data2.go518
-rw-r--r--src/cmd/link/internal/ld/decodesym.go242
-rw-r--r--src/cmd/link/internal/ld/dwarf2.go59
-rw-r--r--src/cmd/link/internal/ld/elf.go169
-rw-r--r--src/cmd/link/internal/ld/elf2.go25
-rw-r--r--src/cmd/link/internal/ld/errors.go73
-rw-r--r--src/cmd/link/internal/ld/go.go24
-rw-r--r--src/cmd/link/internal/ld/ld.go15
-rw-r--r--src/cmd/link/internal/ld/lib.go123
-rw-r--r--src/cmd/link/internal/ld/link.go8
-rw-r--r--src/cmd/link/internal/ld/macho.go146
-rw-r--r--src/cmd/link/internal/ld/main.go52
-rw-r--r--src/cmd/link/internal/ld/outbuf.go12
-rw-r--r--src/cmd/link/internal/ld/pe.go2
-rw-r--r--src/cmd/link/internal/ld/sym.go15
-rw-r--r--src/cmd/link/internal/ld/symtab.go17
-rw-r--r--src/cmd/link/internal/ld/target.go31
-rw-r--r--src/cmd/link/internal/ld/util.go10
-rw-r--r--src/cmd/link/internal/ld/xcoff.go115
-rw-r--r--src/cmd/link/internal/ld/xcoff2.go113
-rw-r--r--src/cmd/link/internal/loader/loader.go309
-rw-r--r--src/cmd/link/internal/loader/loader_test.go17
-rw-r--r--src/cmd/link/internal/loader/symbolbuilder.go23
-rw-r--r--src/cmd/link/internal/mips/asm.go4
-rw-r--r--src/cmd/link/internal/mips64/asm.go4
-rw-r--r--src/cmd/link/internal/ppc64/asm.go116
-rw-r--r--src/cmd/link/internal/ppc64/obj.go2
-rw-r--r--src/cmd/link/internal/riscv64/asm.go2
-rw-r--r--src/cmd/link/internal/s390x/asm.go180
-rw-r--r--src/cmd/link/internal/s390x/obj.go2
-rw-r--r--src/cmd/link/internal/sym/library.go25
-rw-r--r--src/cmd/link/internal/sym/segment.go5
-rw-r--r--src/cmd/link/internal/sym/sizeof_test.go2
-rw-r--r--src/cmd/link/internal/sym/symbol.go114
-rw-r--r--src/cmd/link/internal/sym/symbols.go3
-rw-r--r--src/cmd/link/internal/wasm/asm.go43
-rw-r--r--src/cmd/link/internal/x86/asm.go255
-rw-r--r--src/cmd/link/internal/x86/obj.go2
-rw-r--r--src/cmd/link/link_test.go58
-rw-r--r--src/cmd/link/testdata/testIndexMismatch/a.go8
-rw-r--r--src/cmd/link/testdata/testIndexMismatch/b.go8
-rw-r--r--src/cmd/link/testdata/testIndexMismatch/main.go9
59 files changed, 3091 insertions, 2443 deletions
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
index 917bf2394a..35b8d985cb 100644
--- a/src/cmd/compile/internal/gc/iexport.go
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -35,6 +35,8 @@
// }
// }
//
+// Fingerprint [8]byte
+//
// uvarint means a uint64 written out using uvarint encoding.
//
// []T means a uvarint followed by that many T objects. In other
@@ -296,6 +298,10 @@ func iexport(out *bufio.Writer) {
io.Copy(out, &hdr)
io.Copy(out, &p.strings)
io.Copy(out, &p.data0)
+
+ // Add fingerprint (used by linker object file).
+ // Attach this to the end, so tools (e.g. gcimporter) don't care.
+ out.Write(Ctxt.Fingerprint[:])
}
// writeIndex writes out an object index. mainIndex indicates whether
diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go
index 9bd736e1c7..f3e65ff736 100644
--- a/src/cmd/compile/internal/gc/iimport.go
+++ b/src/cmd/compile/internal/gc/iimport.go
@@ -10,6 +10,7 @@ package gc
import (
"cmd/compile/internal/types"
"cmd/internal/bio"
+ "cmd/internal/goobj2"
"cmd/internal/obj"
"cmd/internal/src"
"encoding/binary"
@@ -95,7 +96,7 @@ func (r *intReader) uint64() uint64 {
return i
}
-func iimport(pkg *types.Pkg, in *bio.Reader) {
+func iimport(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj2.FingerprintType) {
ir := &intReader{in, pkg}
version := ir.uint64()
@@ -188,6 +189,14 @@ func iimport(pkg *types.Pkg, in *bio.Reader) {
inlineImporter[s] = iimporterAndOffset{p, off}
}
}
+
+ // Fingerprint
+ n, err := in.Read(fingerprint[:])
+ if err != nil || n != len(fingerprint) {
+ yyerror("import %s: error reading fingerprint", pkg.Path)
+ errorexit()
+ }
+ return fingerprint
}
type iimporter struct {
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 2152c619fa..756cdbd3c9 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -14,6 +14,7 @@ import (
"cmd/compile/internal/types"
"cmd/internal/bio"
"cmd/internal/dwarf"
+ "cmd/internal/goobj2"
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/src"
@@ -1254,15 +1255,6 @@ func importfile(f *Val) *types.Pkg {
}
}
- // assume files move (get installed) so don't record the full path
- if packageFile != nil {
- // If using a packageFile map, assume path_ can be recorded directly.
- Ctxt.AddImport(path_)
- } else {
- // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
- Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):])
- }
-
// In the importfile, if we find:
// $$\n (textual format): not supported anymore
// $$B\n (binary format) : import directly, then feed the lexer a dummy statement
@@ -1287,6 +1279,7 @@ func importfile(f *Val) *types.Pkg {
c, _ = imp.ReadByte()
}
+ var fingerprint goobj2.FingerprintType
switch c {
case '\n':
yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
@@ -1310,13 +1303,22 @@ func importfile(f *Val) *types.Pkg {
yyerror("import %s: unexpected package format byte: %v", file, c)
errorexit()
}
- iimport(importpkg, imp)
+ fingerprint = iimport(importpkg, imp)
default:
yyerror("no import in %q", path_)
errorexit()
}
+ // assume files move (get installed) so don't record the full path
+ if packageFile != nil {
+ // If using a packageFile map, assume path_ can be recorded directly.
+ Ctxt.AddImport(path_, fingerprint)
+ } else {
+ // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
+ Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):], fingerprint)
+ }
+
if importpkg.Height >= myheight {
myheight = importpkg.Height + 1
}
diff --git a/src/cmd/internal/goobj/readnew.go b/src/cmd/internal/goobj/readnew.go
index 5654da44d6..3e710576b6 100644
--- a/src/cmd/internal/goobj/readnew.go
+++ b/src/cmd/internal/goobj/readnew.go
@@ -25,7 +25,11 @@ func (r *objReader) readNew() {
}
// Imports
- r.p.Imports = rr.Autolib()
+ autolib := rr.Autolib()
+ for _, p := range autolib {
+ r.p.Imports = append(r.p.Imports, p.Pkg)
+ // Ignore fingerprint (for tools like objdump which only reads one object).
+ }
pkglist := rr.Pkglist()
diff --git a/src/cmd/internal/goobj2/objfile.go b/src/cmd/internal/goobj2/objfile.go
index bee29a0ad6..28702ebf07 100644
--- a/src/cmd/internal/goobj2/objfile.go
+++ b/src/cmd/internal/goobj2/objfile.go
@@ -19,17 +19,21 @@ import (
// New object file format.
//
// Header struct {
-// Magic [...]byte // "\x00go115ld"
-// Flags uint32
-// // TODO: Fingerprint
-// Offsets [...]uint32 // byte offset of each block below
+// Magic [...]byte // "\x00go115ld"
+// Fingerprint [8]byte
+// Flags uint32
+// Offsets [...]uint32 // byte offset of each block below
// }
//
// Strings [...]struct {
// Data [...]byte
// }
//
-// Autolib [...]string // imported packages (for file loading) // TODO: add fingerprints
+// Autolib [...]struct { // imported packages (for file loading)
+// Pkg string
+// Fingerprint [8]byte
+// }
+//
// PkgIndex [...]string // referenced packages by index
//
// DwarfFiles [...]string
@@ -119,6 +123,10 @@ import (
const stringRefSize = 8 // two uint32s
+type FingerprintType [8]byte
+
+func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
+
// Package Index.
const (
PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols
@@ -149,15 +157,17 @@ const (
// File header.
// TODO: probably no need to export this.
type Header struct {
- Magic string
- Flags uint32
- Offsets [NBlk]uint32
+ Magic string
+ Fingerprint FingerprintType
+ Flags uint32
+ Offsets [NBlk]uint32
}
const Magic = "\x00go115ld"
func (h *Header) Write(w *Writer) {
w.RawString(h.Magic)
+ w.Bytes(h.Fingerprint[:])
w.Uint32(h.Flags)
for _, x := range h.Offsets {
w.Uint32(x)
@@ -171,6 +181,8 @@ func (h *Header) Read(r *Reader) error {
return errors.New("wrong magic, not a Go object file")
}
off := uint32(len(h.Magic))
+ copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
+ off += 8
h.Flags = r.uint32At(off)
off += 4
for i := range h.Offsets {
@@ -184,6 +196,19 @@ func (h *Header) Size() int {
return len(h.Magic) + 4 + 4*len(h.Offsets)
}
+// Autolib
+type ImportedPkg struct {
+ Pkg string
+ Fingerprint FingerprintType
+}
+
+const importedPkgSize = stringRefSize + 8
+
+func (p *ImportedPkg) Write(w *Writer) {
+ w.StringRef(p.Pkg)
+ w.Bytes(p.Fingerprint[:])
+}
+
// Symbol definition.
//
// Serialized format:
@@ -495,12 +520,18 @@ func (r *Reader) StringRef(off uint32) string {
return r.StringAt(r.uint32At(off+4), l)
}
-func (r *Reader) Autolib() []string {
- n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / stringRefSize
- s := make([]string, n)
+func (r *Reader) Fingerprint() FingerprintType {
+ return r.h.Fingerprint
+}
+
+func (r *Reader) Autolib() []ImportedPkg {
+ n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
+ s := make([]ImportedPkg, n)
+ off := r.h.Offsets[BlkAutolib]
for i := range s {
- off := r.h.Offsets[BlkAutolib] + uint32(i)*stringRefSize
- s[i] = r.StringRef(off)
+ s[i].Pkg = r.StringRef(off)
+ copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
+ off += importedPkgSize
}
return s
}
@@ -508,9 +539,10 @@ func (r *Reader) Autolib() []string {
func (r *Reader) Pkglist() []string {
n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
s := make([]string, n)
+ off := r.h.Offsets[BlkPkgIdx]
for i := range s {
- off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
s[i] = r.StringRef(off)
+ off += stringRefSize
}
return s
}
diff --git a/src/cmd/internal/obj/line.go b/src/cmd/internal/obj/line.go
index fecf90c491..79ecb0068f 100644
--- a/src/cmd/internal/obj/line.go
+++ b/src/cmd/internal/obj/line.go
@@ -5,12 +5,13 @@
package obj
import (
+ "cmd/internal/goobj2"
"cmd/internal/src"
)
// AddImport adds a package to the list of imported packages.
-func (ctxt *Link) AddImport(pkg string) {
- ctxt.Imports = append(ctxt.Imports, pkg)
+func (ctxt *Link) AddImport(pkg string, fingerprint goobj2.FingerprintType) {
+ ctxt.Imports = append(ctxt.Imports, goobj2.ImportedPkg{Pkg: pkg, Fingerprint: fingerprint})
}
func linkgetlineFromPos(ctxt *Link, xpos src.XPos) (f string, l int32) {
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 65e58887e6..32906a3e05 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -33,6 +33,7 @@ package obj
import (
"bufio"
"cmd/internal/dwarf"
+ "cmd/internal/goobj2"
"cmd/internal/objabi"
"cmd/internal/src"
"cmd/internal/sys"
@@ -666,7 +667,7 @@ type Link struct {
PosTable src.PosTable
InlTree InlTree // global inlining tree used by gc/inl.go
DwFixups *DwarfFixupTable
- Imports []string
+ Imports []goobj2.ImportedPkg
DiagFunc func(string, ...interface{})
DiagFlush func()
DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node
@@ -699,6 +700,8 @@ type Link struct {
defs []*LSym // list of defined symbols in the current package
nonpkgdefs []*LSym // list of defined non-package symbols
nonpkgrefs []*LSym // list of referenced non-package symbols
+
+ Fingerprint goobj2.FingerprintType // fingerprint of symbol indices, to catch index mismatch
}
func (ctxt *Link) Diag(format string, args ...interface{}) {
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 2b0c45d6b2..6d7f42ed0b 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -98,8 +98,9 @@ func WriteObjFile(ctxt *Link, bout *bio.Writer, pkgpath string) {
w.wr.WriteByte(1)
// Autolib
- for _, pkg := range ctxt.Imports {
- w.writeString(pkg)
+ for _, p := range ctxt.Imports {
+ w.writeString(p.Pkg)
+ // This object format ignores p.Fingerprint.
}
w.writeString("")
diff --git a/src/cmd/internal/obj/objfile2.go b/src/cmd/internal/obj/objfile2.go
index 9792ef0846..061e43c434 100644
--- a/src/cmd/internal/obj/objfile2.go
+++ b/src/cmd/internal/obj/objfile2.go
@@ -38,7 +38,11 @@ func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
if ctxt.Flag_shared {
flags |= goobj2.ObjFlagShared
}
- h := goobj2.Header{Magic: goobj2.Magic, Flags: flags}
+ h := goobj2.Header{
+ Magic: goobj2.Magic,
+ Fingerprint: ctxt.Fingerprint,
+ Flags: flags,
+ }
h.Write(w.Writer)
// String table
@@ -46,8 +50,8 @@ func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
// Autolib
h.Offsets[goobj2.BlkAutolib] = w.Offset()
- for _, pkg := range ctxt.Imports {
- w.StringRef(pkg)
+ for i := range ctxt.Imports {
+ ctxt.Imports[i].Write(w.Writer)
}
// Package references
@@ -180,8 +184,8 @@ func (w *writer) init() {
func (w *writer) StringTable() {
w.AddString("")
- for _, pkg := range w.ctxt.Imports {
- w.AddString(pkg)
+ for _, p := range w.ctxt.Imports {
+ w.AddString(p.Pkg)
}
for _, pkg := range w.pkglist {
w.AddString(pkg)
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index 03ce8ddc5a..4a8b0ebb6f 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -34,6 +34,7 @@ package obj
import (
"cmd/internal/goobj2"
"cmd/internal/objabi"
+ "crypto/md5"
"fmt"
"log"
"math"
@@ -241,6 +242,15 @@ func (ctxt *Link) NumberSyms(asm bool) {
ctxt.pkgIdx[pkg] = ipkg
ipkg++
})
+
+ // Compute a fingerprint of the indices, for exporting.
+ if !asm {
+ h := md5.New()
+ for _, s := range ctxt.defs {
+ h.Write([]byte(s.Name))
+ }
+ copy(ctxt.Fingerprint[:], h.Sum(nil)[:])
+ }
}
// Returns whether s is a non-package symbol, which needs to be referenced
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index d26a9a234c..f3b3d703b5 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -78,48 +78,55 @@ func makeWritable(s *sym.Symbol) {
}
}
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
+func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
+ targ := r.Sym()
+ var targType sym.SymKind
+ if targ != 0 {
+ targType = ldr.SymType(targ)
+ }
- switch r.Type {
+ switch r.Type() {
default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
+ if r.Type() >= objabi.ElfRelocOffset {
+ ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false
}
// Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", ldr.SymName(targ))
}
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly.
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
+ if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
+ ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
}
- r.Type = objabi.R_PCREL
- r.Add += 4
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+4)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", ldr.SymName(targ))
}
- if targ.Type == 0 || targ.Type == sym.SXREF {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
+ if targType == 0 || targType == sym.SXREF {
+ ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
}
- r.Type = objabi.R_PCREL
- r.Add += 8
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+8)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
- r.Type = objabi.R_PCREL
- r.Add += 4
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+4)
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
}
return true
@@ -127,34 +134,36 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX):
- if targ.Type != sym.SDYNIMPORT {
+ su := ldr.MakeSymbolUpdater(s)
+ if targType != sym.SDYNIMPORT {
// have symbol
- if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
- makeWritable(s)
+ sData := ldr.Data(s)
+ if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
+ su.MakeWritable()
// turn MOVQ of GOT entry into LEAQ of symbol itself
- s.P[r.Off-2] = 0x8d
-
- r.Type = objabi.R_PCREL
- r.Add += 4
+ writeableData := su.Data()
+ writeableData[r.Off()-2] = 0x8d
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+4)
return true
}
}
// fall back to using GOT and hope for the best (CMOV*)
// TODO: just needs relocation, no need to put in .dynsym
- addgotsym(target, syms, targ)
+ addgotsym2(target, ldr, syms, targ)
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += 4
- r.Add += int64(targ.Got())
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocSym(rIdx, syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+4+int64(ldr.SymGot(targ)))
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ADDR
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ADDR)
if target.IsPIE() && target.IsInternal() {
// For internal linking PIE, this R_ADDR relocation cannot
// be resolved statically. We need to generate a dynamic
@@ -168,19 +177,21 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
// TODO: What is the difference between all these?
- r.Type = objabi.R_ADDR
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ADDR)
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
}
return true
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
- r.Type = objabi.R_PCREL
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
return true
}
fallthrough
@@ -190,44 +201,53 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
- r.Type = objabi.R_PCREL
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", ldr.SymName(targ))
}
return true
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
- if targ.Type != sym.SDYNIMPORT {
+ if targType != sym.SDYNIMPORT {
// have symbol
// turn MOVQ of GOT entry into LEAQ of symbol itself
- if r.Off < 2 || s.P[r.Off-2] != 0x8b {
- ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
+ sdata := ldr.Data(s)
+ if r.Off() < 2 || sdata[r.Off()-2] != 0x8b {
+ ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
return false
}
- makeWritable(s)
- s.P[r.Off-2] = 0x8d
- r.Type = objabi.R_PCREL
+ su := ldr.MakeSymbolUpdater(s)
+ su.MakeWritable()
+ sdata = su.Data()
+ sdata[r.Off()-2] = 0x8d
+ su.SetRelocType(rIdx, objabi.R_PCREL)
return true
}
fallthrough
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
- if targ.Type != sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+ if targType != sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
}
- addgotsym(target, syms, targ)
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
+ addgotsym2(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocSym(rIdx, syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true
}
- switch r.Type {
+ // Reread the reloc to incorporate any changes in type above.
+ relocs := ldr.Relocs(s)
+ *r = relocs.At2(rIdx)
+
+ switch r.Type() {
case objabi.R_CALL,
objabi.R_PCREL:
- if targ.Type != sym.SDYNIMPORT {
+ if targType != sym.SDYNIMPORT {
// nothing to do, the relocation will be laid out in reloc
return true
}
@@ -237,26 +257,28 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
}
// Internal linking, for both ELF and Mach-O.
// Build a PLT entry and change the relocation target to that entry.
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
+ addpltsym2(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
return true
case objabi.R_ADDR:
- if s.Type == sym.STEXT && target.IsElf() {
+ if ldr.SymType(s) == sym.STEXT && target.IsElf() {
+ su := ldr.MakeSymbolUpdater(s)
if target.IsSolaris() {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
+ addpltsym2(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
return true
}
// The code is asking for the address of an external
// function. We provide it with the address of the
// correspondent GOT symbol.
- addgotsym(target, syms, targ)
+ addgotsym2(target, ldr, syms, targ)
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
+ su.SetRelocSym(rIdx, syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true
}
@@ -293,7 +315,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
// symbol offset as determined by reloc(), not the
// final dynamically linked address as a dynamic
// relocation would provide.
- switch s.Name {
+ switch ldr.SymName(s) {
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
return false
}
@@ -304,7 +326,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
// linking, in which case the relocation will be
// prepared in the 'reloc' phase and passed to the
// external linker in the 'asmb' phase.
- if s.Type != sym.SDATA && s.Type != sym.SRODATA {
+ if ldr.SymType(s) != sym.SDATA && ldr.SymType(s) != sym.SRODATA {
break
}
}
@@ -327,14 +349,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
// AddAddrPlus is used for r_offset and r_addend to
// generate new R_ADDR relocations that will update
// these fields in the 'reloc' phase.
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, s, int64(r.Off))
- if r.Siz == 8 {
+ rela := ldr.MakeSymbolUpdater(syms.Rela2)
+ rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
+ if r.Siz() == 8 {
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
} else {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
+ ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
- rela.AddAddrPlus(target.Arch, targ, int64(r.Add))
+ rela.AddAddrPlus(target.Arch, targ, int64(r.Add()))
// Not mark r done here. So we still apply it statically,
// so in the file content we'll also have the right offset
// to the relocation target. So it can be examined statically
@@ -342,7 +364,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
return true
}
- if target.IsDarwin() && s.Size == int64(target.Arch.PtrSize) && r.Off == 0 {
+ if target.IsDarwin() && ldr.SymSize(s) == int64(target.Arch.PtrSize) && r.Off() == 0 {
// Mach-O relocations are a royal pain to lay out.
// They use a compact stateful bytecode representation
// that is too much bother to deal with.
@@ -353,18 +375,17 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- ld.Adddynsym(target, syms, targ)
+ ld.Adddynsym2(ldr, target, syms, targ)
- got := syms.GOT
- s.Type = got.Type
- s.Attr |= sym.AttrSubSymbol
- s.Outer = got
- s.Sub = got.Sub
- got.Sub = s
- s.Value = got.Size
+ got := ldr.MakeSymbolUpdater(syms.GOT2)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetType(got.Type())
+ got.PrependSub(s)
+ su.SetValue(got.Size())
got.AddUint64(target.Arch, 0)
- syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid))
- r.Type = objabi.ElfRelocOffset // ignore during relocsym
+ leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
+ leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ)))
+ su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
return true
}
}
@@ -375,7 +396,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write64(uint64(sectoff))
- elfsym := r.Xsym.ElfsymForReloc()
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type {
default:
return false
@@ -569,18 +590,18 @@ func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.S
}
}
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
+func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymPlt(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
+ ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() {
- plt := syms.PLT
- got := syms.GOTPLT
- rela := syms.RelaPLT
- if plt.Size == 0 {
+ plt := ldr.MakeSymbolUpdater(syms.PLT2)
+ got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
+ rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
+ if plt.Size() == 0 {
panic("plt is not set up")
}
@@ -588,28 +609,29 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
plt.AddUint8(0xff)
plt.AddUint8(0x25)
- plt.AddPCRelPlus(target.Arch, got, got.Size)
+ plt.AddPCRelPlus(target.Arch, got.Sym(), got.Size())
// add to got: pointer to current pos in plt
- got.AddAddrPlus(target.Arch, plt, plt.Size)
+ got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
// pushq $x
plt.AddUint8(0x68)
- plt.AddUint32(target.Arch, uint32((got.Size-24-8)/8))
+ plt.AddUint32(target.Arch, uint32((got.Size()-24-8)/8))
// jmpq .plt
plt.AddUint8(0xe9)
- plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
+ plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
// rela
- rela.AddAddrPlus(target.Arch, got, got.Size-8)
+ rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT)))
+ sDynid := ldr.SymDynid(s)
+ rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
rela.AddUint64(target.Arch, 0)
- s.SetPlt(int32(plt.Size - 16))
+ ldr.SetPlt(s, int32(plt.Size()-16))
} else if target.IsDarwin() {
// To do lazy symbol lookup right, we're supposed
// to tell the dynamic loader which library each
@@ -621,45 +643,48 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
// https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
// has details about what we're avoiding.
- addgotsym(target, syms, s)
- plt := syms.PLT
+ addgotsym2(target, ldr, syms, s)
+ plt := ldr.MakeSymbolUpdater(syms.PLT2)
- syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid))
+ sDynid := ldr.SymDynid(s)
+ lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT2)
+ lep.AddUint32(target.Arch, uint32(sDynid))
// jmpq *got+size(IP)
- s.SetPlt(int32(plt.Size))
+ ldr.SetPlt(s, int32(plt.Size()))
plt.AddUint8(0xff)
plt.AddUint8(0x25)
- plt.AddPCRelPlus(target.Arch, syms.GOT, int64(s.Got()))
+ plt.AddPCRelPlus(target.Arch, syms.GOT2, int64(ldr.SymGot(s)))
} else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
+ ldr.Errorf(s, "addpltsym: unsupported binary format")
}
}
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
+func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymGot(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
+ ld.Adddynsym2(ldr, target, syms, s)
+ got := ldr.MakeSymbolUpdater(syms.GOT2)
+ ldr.SetGot(s, int32(got.Size()))
got.AddUint64(target.Arch, 0)
if target.IsElf() {
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT)))
+ rela := ldr.MakeSymbolUpdater(syms.Rela2)
+ rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
+ rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_X86_64_GLOB_DAT)))
rela.AddUint64(target.Arch, 0)
} else if target.IsDarwin() {
- syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid))
+ leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
+ leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
} else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
+ ldr.Errorf(s, "addgotsym: unsupported binary format")
}
}
-func asmb(ctxt *ld.Link) {
+func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF {
ld.Asmbelfsetup()
}
@@ -816,7 +841,7 @@ func asmb2(ctxt *ld.Link) {
}
}
-func tlsIEtoLE(s *sym.Symbol, off, size int) {
+func tlsIEtoLE(P []byte, off, size int) {
// Transform the PC-relative instruction into a constant load.
// That is,
//
@@ -827,7 +852,7 @@ func tlsIEtoLE(s *sym.Symbol, off, size int) {
if off < 3 {
log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction")
}
- op := s.P[off-3 : off]
+ op := P[off-3 : off]
reg := op[2] >> 3
if op[1] == 0x8b || reg == 4 {
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index fec775f142..1fbbf60366 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
+ Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index 446691f318..e42ea0f6e5 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -103,24 +103,30 @@ func braddoff(a int32, b int32) int32 {
return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
}
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
+func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
- switch r.Type {
+ targ := r.Sym()
+ var targType sym.SymKind
+ if targ != 0 {
+ targType = ldr.SymType(targ)
+ }
+
+ switch r.Type() {
default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
+ if r.Type() >= objabi.ElfRelocOffset {
+ ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false
}
// Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PLT32):
- r.Type = objabi.R_CALLARM
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CALLARM)
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4)))
}
return true
@@ -130,113 +136,112 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT32): // R_ARM_GOT_BREL
- if targ.Type != sym.SDYNIMPORT {
- addgotsyminternal(target, syms, targ)
+ if targType != sym.SDYNIMPORT {
+ addgotsyminternal2(target, ldr, syms, targ)
} else {
- addgotsym(target, syms, targ)
+ addgotsym2(target, ldr, syms, targ)
}
- r.Type = objabi.R_CONST // write r->add during relocsym
- r.Sym = nil
- r.Add += int64(targ.Got())
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
+ su.SetRelocSym(rIdx, 0)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT_PREL): // GOT(nil) + A - nil
- if targ.Type != sym.SDYNIMPORT {
- addgotsyminternal(target, syms, targ)
+ if targType != sym.SDYNIMPORT {
+ addgotsyminternal2(target, ldr, syms, targ)
} else {
- addgotsym(target, syms, targ)
+ addgotsym2(target, ldr, syms, targ)
}
-
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += int64(targ.Got()) + 4
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocSym(rIdx, syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+4+int64(ldr.SymGot(targ)))
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTOFF): // R_ARM_GOTOFF32
- r.Type = objabi.R_GOTOFF
-
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_GOTOFF)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTPC): // R_ARM_BASE_PREL
- r.Type = objabi.R_PCREL
-
- r.Sym = syms.GOT
- r.Add += 4
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocSym(rIdx, syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+4)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_CALL):
- r.Type = objabi.R_CALLARM
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CALLARM)
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4)))
}
-
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_REL32): // R_ARM_REL32
- r.Type = objabi.R_PCREL
-
- r.Add += 4
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+4)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_ABS32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ADDR
- return true
-
- // we can just ignore this, because we are targeting ARM V5+ anyway
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_V4BX):
- if r.Sym != nil {
- // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
- r.Sym.Type = 0
- }
-
- r.Sym = nil
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ADDR)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PC24),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_JUMP24):
- r.Type = objabi.R_CALLARM
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CALLARM)
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4)))
}
return true
}
// Handle references to ELF symbols from our own object files.
- if targ.Type != sym.SDYNIMPORT {
+ if targType != sym.SDYNIMPORT {
return true
}
- switch r.Type {
+ // Reread the reloc to incorporate any changes in type above.
+ relocs := ldr.Relocs(s)
+ *r = relocs.At2(rIdx)
+
+ switch r.Type() {
case objabi.R_CALLARM:
if target.IsExternal() {
// External linker will do this relocation.
return true
}
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
+ addpltsym2(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
return true
case objabi.R_ADDR:
- if s.Type != sym.SDATA {
+ if ldr.SymType(s) != sym.SDATA {
break
}
if target.IsElf() {
- ld.Adddynsym(target, syms, targ)
- rel := syms.Rel
- rel.AddAddrPlus(target.Arch, s, int64(r.Off))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
- r.Type = objabi.R_CONST // write r->add during relocsym
- r.Sym = nil
+ ld.Adddynsym2(ldr, target, syms, targ)
+ rel := ldr.MakeSymbolUpdater(syms.Rel2)
+ rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
+ rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
+ su.SetRelocSym(rIdx, 0)
return true
}
}
@@ -247,7 +252,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write32(uint32(sectoff))
- elfsym := r.Xsym.ElfsymForReloc()
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type {
default:
return false
@@ -592,94 +597,92 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
return t
}
-func addpltreloc(plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, typ objabi.RelocType) {
- r := plt.AddRel()
- r.Sym = got
- r.Off = int32(plt.Size)
- r.Siz = 4
- r.Type = typ
- r.Add = int64(s.Got()) - 8
+func addpltreloc2(ldr *loader.Loader, plt *loader.SymbolBuilder, got *loader.SymbolBuilder, s loader.Sym, typ objabi.RelocType) {
+ r, _ := plt.AddRel(typ)
+ r.SetSym(got.Sym())
+ r.SetOff(int32(plt.Size()))
+ r.SetSiz(4)
+ r.SetAdd(int64(ldr.SymGot(s)) - 8)
- plt.Attr |= sym.AttrReachable
- plt.Size += 4
- plt.Grow(plt.Size)
+ plt.SetReachable(true)
+ plt.SetSize(plt.Size() + 4)
+ plt.Grow(plt.Size())
}
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
+func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymPlt(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
+ ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() {
- plt := syms.PLT
- got := syms.GOTPLT
- rel := syms.RelPLT
- if plt.Size == 0 {
+ plt := ldr.MakeSymbolUpdater(syms.PLT2)
+ got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
+ rel := ldr.MakeSymbolUpdater(syms.RelPLT2)
+ if plt.Size() == 0 {
panic("plt is not set up")
}
// .got entry
- s.SetGot(int32(got.Size))
+ ldr.SetGot(s, int32(got.Size()))
// In theory, all GOT should point to the first PLT entry,
// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
// dynamic linker won't, so we'd better do it ourselves.
- got.AddAddrPlus(target.Arch, plt, 0)
+ got.AddAddrPlus(target.Arch, plt.Sym(), 0)
// .plt entry, this depends on the .got entry
- s.SetPlt(int32(plt.Size))
+ ldr.SetPlt(s, int32(plt.Size()))
- addpltreloc(plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000
- addpltreloc(plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000
- addpltreloc(plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]!
+ addpltreloc2(ldr, plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000
+ addpltreloc2(ldr, plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000
+ addpltreloc2(ldr, plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]!
// rel
- rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
+ rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_JUMP_SLOT)))
+ rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_JUMP_SLOT)))
} else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
+ ldr.Errorf(s, "addpltsym: unsupported binary format")
}
}
-func addgotsyminternal(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
+func addgotsyminternal2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymGot(s) >= 0 {
return
}
- got := syms.GOT
- s.SetGot(int32(got.Size))
-
+ got := ldr.MakeSymbolUpdater(syms.GOT2)
+ ldr.SetGot(s, int32(got.Size()))
got.AddAddrPlus(target.Arch, s, 0)
if target.IsElf() {
} else {
- ld.Errorf(s, "addgotsyminternal: unsupported binary format")
+ ldr.Errorf(s, "addgotsyminternal: unsupported binary format")
}
}
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
+func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymGot(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
- got.AddUint32(target.Arch, 0)
+ ld.Adddynsym2(ldr, target, syms, s)
+ got := ldr.MakeSymbolUpdater(syms.GOT2)
+ ldr.SetGot(s, int32(got.Size()))
+ got.AddUint64(target.Arch, 0)
if target.IsElf() {
- rel := syms.Rel
- rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_GLOB_DAT)))
+ rel := ldr.MakeSymbolUpdater(syms.Rel2)
+ rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
+ rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_GLOB_DAT)))
} else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
+ ldr.Errorf(s, "addgotsym: unsupported binary format")
}
}
-func asmb(ctxt *ld.Link) {
+func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF {
ld.Asmbelfsetup()
}
diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go
index b277fb2a43..653f16dba1 100644
--- a/src/cmd/link/internal/arm/obj.go
+++ b/src/cmd/link/internal/arm/obj.go
@@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
+ Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 46bda74c4c..f49172ea23 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -78,86 +78,97 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
initfunc.AddReloc(rel2)
}
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
+func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
- switch r.Type {
+ targ := r.Sym()
+ var targType sym.SymKind
+ if targ != 0 {
+ targType = ldr.SymType(targ)
+ }
+
+ switch r.Type() {
default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
+ if r.Type() >= objabi.ElfRelocOffset {
+ ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false
}
// Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", ldr.SymName(targ))
}
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly.
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
+ if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
+ ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
}
- r.Type = objabi.R_PCREL
- r.Add += 4
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+4)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", ldr.SymName(targ))
}
- if targ.Type == 0 || targ.Type == sym.SXREF {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
+ if targType == 0 || targType == sym.SXREF {
+ ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
}
- r.Type = objabi.R_PCREL
- r.Add += 8
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+8)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26):
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
}
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in callarm64", targ.Name)
+ if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
+ ldr.Errorf(s, "unknown symbol %s in callarm64", ldr.SymName(targ))
}
- r.Type = objabi.R_CALLARM64
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CALLARM64)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC):
- if targ.Type != sym.SDYNIMPORT {
+ if targType != sym.SDYNIMPORT {
// have symbol
// TODO: turn LDR of GOT entry into ADR of symbol itself
}
// fall back to using GOT
// TODO: just needs relocation, no need to put in .dynsym
- addgotsym(target, syms, targ)
-
- r.Type = objabi.R_ARM64_GOT
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
+ addgotsym2(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
+ su.SetRelocSym(rIdx, syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
- if targ.Type == 0 || targ.Type == sym.SXREF {
- ld.Errorf(s, "unknown symbol %s", targ.Name)
+ if targType == 0 || targType == sym.SXREF {
+ ldr.Errorf(s, "unknown symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ARM64_PCREL
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ADDR
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ADDR)
if target.IsPIE() && target.IsInternal() {
// For internal linking PIE, this R_ADDR relocation cannot
// be resolved statically. We need to generate a dynamic
@@ -167,39 +178,48 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ARM64_LDST8
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_LDST8)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ARM64_LDST32
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_LDST32)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ARM64_LDST64
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_LDST64)
+
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ARM64_LDST128
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_LDST128)
return true
}
- switch r.Type {
+ // Reread the reloc to incorporate any changes in type above.
+ relocs := ldr.Relocs(s)
+ *r = relocs.At2(rIdx)
+
+ switch r.Type() {
case objabi.R_CALL,
objabi.R_PCREL,
objabi.R_CALLARM64:
- if targ.Type != sym.SDYNIMPORT {
+ if targType != sym.SDYNIMPORT {
// nothing to do, the relocation will be laid out in reloc
return true
}
@@ -209,14 +229,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
}
case objabi.R_ADDR:
- if s.Type == sym.STEXT && target.IsElf() {
+ if ldr.SymType(s) == sym.STEXT && target.IsElf() {
// The code is asking for the address of an external
// function. We provide it with the address of the
// correspondent GOT symbol.
- addgotsym(target, syms, targ)
-
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
+ addgotsym2(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true
}
@@ -253,7 +273,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
// symbol offset as determined by reloc(), not the
// final dynamically linked address as a dynamic
// relocation would provide.
- switch s.Name {
+ switch ldr.SymName(s) {
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
return false
}
@@ -264,7 +284,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
// linking, in which case the relocation will be
// prepared in the 'reloc' phase and passed to the
// external linker in the 'asmb' phase.
- if s.Type != sym.SDATA && s.Type != sym.SRODATA {
+ if ldr.SymType(s) != sym.SDATA && ldr.SymType(s) != sym.SRODATA {
break
}
}
@@ -287,14 +307,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
// AddAddrPlus is used for r_offset and r_addend to
// generate new R_ADDR relocations that will update
// these fields in the 'reloc' phase.
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, s, int64(r.Off))
- if r.Siz == 8 {
+ rela := ldr.MakeSymbolUpdater(syms.Rela2)
+ rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
+ if r.Siz() == 8 {
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
} else {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
+ ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
- rela.AddAddrPlus(target.Arch, targ, int64(r.Add))
+ rela.AddAddrPlus(target.Arch, targ, int64(r.Add()))
// Not mark r done here. So we still apply it statically,
// so in the file content we'll also have the right offset
// to the relocation target. So it can be examined statically
@@ -308,7 +328,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write64(uint64(sectoff))
- elfsym := r.Xsym.ElfsymForReloc()
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type {
default:
return false
@@ -737,75 +757,80 @@ func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loade
}
}
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
+func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymPlt(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
+ ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() {
- plt := syms.PLT
- gotplt := syms.GOTPLT
- rela := syms.RelaPLT
- if plt.Size == 0 {
+ plt := ldr.MakeSymbolUpdater(syms.PLT2)
+ gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT2)
+ rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
+ if plt.Size() == 0 {
panic("plt is not set up")
}
// adrp x16, &got.plt[0]
- plt.AddAddrPlus4(gotplt, gotplt.Size)
- plt.SetUint32(target.Arch, plt.Size-4, 0x90000010)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
+ plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
+ plt.SetUint32(target.Arch, plt.Size()-4, 0x90000010)
+ relocs := plt.Relocs()
+ plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
// <offset> is the offset value of &got.plt[n] to &got.plt[0]
// ldr x17, [x16, <offset>]
- plt.AddAddrPlus4(gotplt, gotplt.Size)
- plt.SetUint32(target.Arch, plt.Size-4, 0xf9400211)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
+ plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
+ plt.SetUint32(target.Arch, plt.Size()-4, 0xf9400211)
+ relocs = plt.Relocs()
+ plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
// add x16, x16, <offset>
- plt.AddAddrPlus4(gotplt, gotplt.Size)
- plt.SetUint32(target.Arch, plt.Size-4, 0x91000210)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL
+ plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
+ plt.SetUint32(target.Arch, plt.Size()-4, 0x91000210)
+ relocs = plt.Relocs()
+ plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_PCREL)
// br x17
plt.AddUint32(target.Arch, 0xd61f0220)
// add to got.plt: pointer to plt[0]
- gotplt.AddAddrPlus(target.Arch, plt, 0)
+ gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
// rela
- rela.AddAddrPlus(target.Arch, gotplt, gotplt.Size-8)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
+ rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
+ sDynid := ldr.SymDynid(s)
+
+ rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
rela.AddUint64(target.Arch, 0)
- s.SetPlt(int32(plt.Size - 16))
+ ldr.SetPlt(s, int32(plt.Size()-16))
} else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
+ ldr.Errorf(s, "addpltsym: unsupported binary format")
}
}
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
+func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymGot(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
+ ld.Adddynsym2(ldr, target, syms, s)
+ got := ldr.MakeSymbolUpdater(syms.GOT2)
+ ldr.SetGot(s, int32(got.Size()))
got.AddUint64(target.Arch, 0)
if target.IsElf() {
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_GLOB_DAT)))
+ rela := ldr.MakeSymbolUpdater(syms.Rela2)
+ rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
+ rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_AARCH64_GLOB_DAT)))
rela.AddUint64(target.Arch, 0)
} else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
+ ldr.Errorf(s, "addgotsym: unsupported binary format")
}
}
-func asmb(ctxt *ld.Link) {
+func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF {
ld.Asmbelfsetup()
}
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index c2ac6e7ad1..ffce0cb17d 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
+ Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 5cd7727cd0..44e9b884ff 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -120,136 +120,139 @@ func trampoline(ctxt *Link, s loader.Sym) {
}
-// relocsym resolve relocations in "s". The main loop walks through
-// the list of relocations attached to "s" and resolves them where
-// applicable. Relocations are often architecture-specific, requiring
-// calls into the 'archreloc' and/or 'archrelocvariant' functions for
-// the architecture. When external linking is in effect, it may not be
-// possible to completely resolve the address/offset for a symbol, in
-// which case the goal is to lay the groundwork for turning a given
-// relocation into an external reloc (to be applied by the external
-// linker). For more on how relocations work in general, see
+// relocsym resolve relocations in "s", updating the symbol's content
+// in "P".
+// The main loop walks through the list of relocations attached to "s"
+// and resolves them where applicable. Relocations are often
+// architecture-specific, requiring calls into the 'archreloc' and/or
+// 'archrelocvariant' functions for the architecture. When external
+// linking is in effect, it may not be possible to completely resolve
+// the address/offset for a symbol, in which case the goal is to lay
+// the groundwork for turning a given relocation into an external reloc
+// (to be applied by the external linker). For more on how relocations
+// work in general, see
//
// "Linkers and Loaders", by John R. Levine (Morgan Kaufmann, 1999), ch. 7
//
// This is a performance-critical function for the linker; be careful
// to avoid introducing unnecessary allocations in the main loop.
-// 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 {
+func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *ArchSyms, s loader.Sym, P []byte) {
+ relocs := ldr.Relocs(s)
+ if relocs.Count() == 0 {
return
}
- if s.Attr.ReadOnly() {
- // The symbol's content is backed by read-only memory.
- // Copy it to writable memory to apply relocations.
- s.P = append([]byte(nil), s.P...)
- s.Attr.Set(sym.AttrReadOnly, false)
- }
- for ri := int32(0); ri < int32(len(s.R)); ri++ {
- r := &s.R[ri]
- if r.Done {
- // Relocation already processed by an earlier phase.
- continue
+ for ri := 0; ri < relocs.Count(); ri++ {
+ r := relocs.At2(ri)
+ off := r.Off()
+ siz := int32(r.Siz())
+ rs := r.Sym()
+ if rs != 0 {
+ rs = ldr.ResolveABIAlias(rs)
}
- r.Done = true
- off := r.Off
- siz := int32(r.Siz)
- if off < 0 || off+siz > int32(len(s.P)) {
+ rt := r.Type()
+ if off < 0 || off+siz > int32(len(P)) {
rname := ""
- if r.Sym != nil {
- rname = r.Sym.Name
+ if rs != 0 {
+ rname = ldr.SymName(rs)
}
- Errorf(s, "invalid relocation %s: %d+%d not in [%d,%d)", rname, off, siz, 0, len(s.P))
+ err.Errorf(s, "invalid relocation %s: %d+%d not in [%d,%d)", rname, off, siz, 0, len(P))
continue
}
- if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) {
+ var rst sym.SymKind
+ if rs != 0 {
+ rst = ldr.SymType(rs)
+ }
+
+ if rs != 0 && ((rst == sym.Sxxx && !ldr.AttrVisibilityHidden(rs)) || rst == sym.SXREF) {
// When putting the runtime but not main into a shared library
// these symbols are undefined and that's OK.
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.") {
+ if ldr.SymName(rs) == "main.main" || (!target.IsPlugin() && ldr.SymName(rs) == "main..inittask") {
+ sb := ldr.MakeSymbolUpdater(rs)
+ sb.SetType(sym.SDYNIMPORT)
+ } else if strings.HasPrefix(ldr.SymName(rs), "go.info.") {
// Skip go.info symbols. They are only needed to communicate
// DWARF info between the compiler and linker.
continue
}
} else {
- err.errorUnresolved(s, r)
+ err.errorUnresolved(ldr, s, rs)
continue
}
}
- if r.Type >= objabi.ElfRelocOffset {
+ if rt >= objabi.ElfRelocOffset {
continue
}
- if r.Siz == 0 { // informational relocation - no work to do
+ if 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, Darwin and AIX need it always
- 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 !target.IsSolaris() && !target.IsDarwin() && !target.IsAIX() && rs != 0 && rst == sym.SDYNIMPORT && !target.IsDynlinkingGo() && !ldr.AttrSubSymbol(rs) {
+ if !(target.IsPPC64() && target.IsExternal() && ldr.SymName(rs) == ".TOC.") {
+ err.Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", ldr.SymName(rs), rst, rst, rt, sym.RelocName(target.Arch, rt))
}
}
- 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 rs != 0 && rst != sym.STLSBSS && rt != objabi.R_WEAKADDROFF && rt != objabi.R_METHODOFF && !ldr.AttrReachable(rs) {
+ err.Errorf(s, "unreachable sym in relocation: %s", ldr.SymName(rs))
}
if target.IsExternal() {
- r.InitExt()
+ panic("external linking not implemented")
+ //r.InitExt()
}
// TODO(mundaym): remove this special case - see issue 14218.
- if target.IsS390X() {
- switch r.Type {
- case objabi.R_PCRELDBL:
- r.InitExt()
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- case objabi.R_CALL:
- r.InitExt()
- r.Variant = sym.RV_390_DBL
- }
- }
+ //if target.IsS390X() {
+ // switch r.Type {
+ // case objabi.R_PCRELDBL:
+ // r.InitExt()
+ // r.Type = objabi.R_PCREL
+ // r.Variant = sym.RV_390_DBL
+ // case objabi.R_CALL:
+ // r.InitExt()
+ // r.Variant = sym.RV_390_DBL
+ // }
+ //}
var o int64
- switch r.Type {
+ switch rt {
default:
- switch siz {
- default:
- Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
- case 1:
- o = int64(s.P[off])
- case 2:
- o = int64(target.Arch.ByteOrder.Uint16(s.P[off:]))
- case 4:
- o = int64(target.Arch.ByteOrder.Uint32(s.P[off:]))
- case 8:
- o = int64(target.Arch.ByteOrder.Uint64(s.P[off:]))
- }
- 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(target.Arch, r.Type))
- }
+ panic("not implemented")
+ //switch siz {
+ //default:
+ // err.Errorf(s, "bad reloc size %#x for %s", uint32(siz), ldr.SymName(rs))
+ //case 1:
+ // o = int64(P[off])
+ //case 2:
+ // o = int64(target.Arch.ByteOrder.Uint16(P[off:]))
+ //case 4:
+ // o = int64(target.Arch.ByteOrder.Uint32(P[off:]))
+ //case 8:
+ // o = int64(target.Arch.ByteOrder.Uint64(P[off:]))
+ //}
+ //if out, ok := thearch.Archreloc(ldr, target, syms, &r, s, o); ok {
+ // o = out
+ //} else {
+ // err.Errorf(s, "unknown reloc to %v: %d (%s)", ldr.SymName(rs), rt, sym.RelocName(target.Arch, rt))
+ //}
case objabi.R_TLS_LE:
- if target.IsExternal() && target.IsElf() {
- r.Done = false
- if r.Sym == nil {
- r.Sym = syms.Tlsg
- }
- r.Xsym = r.Sym
- r.Xadd = r.Add
- o = 0
- if !target.IsAMD64() {
- o = r.Add
- }
- break
- }
+ //if target.IsExternal() && target.IsElf() {
+ // r.Done = false
+ // if r.Sym == nil {
+ // r.Sym = syms.Tlsg
+ // }
+ // r.Xsym = r.Sym
+ // r.Xadd = r.Add
+ // o = 0
+ // if !target.IsAMD64() {
+ // o = r.Add
+ // }
+ // break
+ //}
if target.IsElf() && target.IsARM() {
// On ELF ARM, the thread pointer is 8 bytes before
@@ -259,96 +262,93 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch
// 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
+ o = 8 + ldr.SymValue(rs)
} else if target.IsElf() || target.IsPlan9() || target.IsDarwin() {
- o = int64(syms.Tlsoffset) + r.Add
+ o = int64(syms.Tlsoffset) + r.Add()
} else if target.IsWindows() {
- o = r.Add
+ o = r.Add()
} else {
log.Fatalf("unexpected R_TLS_LE relocation for %v", target.HeadType)
}
case objabi.R_TLS_IE:
- if target.IsExternal() && target.IsElf() {
- r.Done = false
- if r.Sym == nil {
- r.Sym = syms.Tlsg
- }
- r.Xsym = r.Sym
- r.Xadd = r.Add
- o = 0
- if !target.IsAMD64() {
- o = r.Add
- }
- break
- }
+ //if target.IsExternal() && target.IsElf() {
+ // r.Done = false
+ // if r.Sym == nil {
+ // r.Sym = syms.Tlsg
+ // }
+ // r.Xsym = r.Sym
+ // r.Xadd = r.Add
+ // o = 0
+ // if !target.IsAMD64() {
+ // o = r.Add
+ // }
+ // break
+ //}
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", target.Arch.Family)
}
- thearch.TLSIEtoLE(s, int(off), int(r.Siz))
+ thearch.TLSIEtoLE(P, int(off), int(siz))
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)
+ log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
}
case objabi.R_ADDR:
- if target.IsExternal() && r.Sym.Type != sym.SCONST {
- r.Done = false
-
- // 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 != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
- Errorf(s, "missing section for relocation target %s", rs.Name)
- }
- r.Xsym = rs
-
- o = r.Xadd
- if target.IsElf() {
- if target.IsAMD64() {
- o = 0
- }
- } else if target.IsDarwin() {
- if rs.Type != sym.SHOSTOBJ {
- o += Symaddr(rs)
- }
- } else if target.IsWindows() {
- // nothing to do
- } else if target.IsAIX() {
- o = Symaddr(r.Sym) + r.Add
- } else {
- Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
- }
-
- break
- }
+ //if target.IsExternal() && r.Sym.Type != sym.SCONST {
+ // r.Done = false
+ //
+ // // 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 != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
+ // Errorf(s, "missing section for relocation target %s", rs.Name)
+ // }
+ // r.Xsym = rs
+ //
+ // o = r.Xadd
+ // if target.IsElf() {
+ // if target.IsAMD64() {
+ // o = 0
+ // }
+ // } else if target.IsDarwin() {
+ // if rs.Type != sym.SHOSTOBJ {
+ // o += Symaddr(rs)
+ // }
+ // } else if target.IsWindows() {
+ // // nothing to do
+ // } else if target.IsAIX() {
+ // o = Symaddr(r.Sym) + r.Add
+ // } else {
+ // Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
+ // }
+ //
+ // break
+ //}
// On AIX, a second relocation must be done by the loader,
// 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 target.IsAIX() && r.Sym.Type != sym.SDYNIMPORT {
+ if target.IsAIX() && rst != 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(target, ldr, s, r)
+ if ldr.SymSect(s).Seg == &Segdata {
+ //Xcoffadddynrel(target, ldr, err, s, &r) // XXX
}
}
- o = Symaddr(r.Sym) + r.Add
+ o = ldr.SymValue(rs) + 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
@@ -356,217 +356,198 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch
// 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 && 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)
+ err.Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", ldr.SymName(rs), uint64(o), ldr.SymValue(rs), r.Add())
errorexit()
}
case objabi.R_DWARFSECREF:
- if r.Sym.Sect == nil {
- Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
+ if ldr.SymSect(rs) == nil {
+ err.Errorf(s, "missing DWARF section for relocation target %s", ldr.SymName(rs))
}
- if target.IsExternal() {
- r.Done = false
-
- // On most platforms, the external linker needs to adjust DWARF references
- // as it combines DWARF sections. However, on Darwin, dsymutil does the
- // 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 target.IsDarwin() {
- r.Done = true
- }
-
- // PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
- // for R_DWARFSECREF relocations, while R_ADDR is replaced with
- // 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 !target.IsWindows() {
- r.Type = objabi.R_ADDR
- }
-
- r.Xsym = r.Sym.Sect.Sym
- r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
-
- o = r.Xadd
- if target.IsElf() && target.IsAMD64() {
- o = 0
- }
- break
- }
- o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
- case objabi.R_WEAKADDROFF:
- if !r.Sym.Attr.Reachable() {
+ //if target.IsExternal() {
+ // r.Done = false
+ //
+ // // On most platforms, the external linker needs to adjust DWARF references
+ // // as it combines DWARF sections. However, on Darwin, dsymutil does the
+ // // 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 target.IsDarwin() {
+ // r.Done = true
+ // }
+ //
+ // // PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
+ // // for R_DWARFSECREF relocations, while R_ADDR is replaced with
+ // // 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 !target.IsWindows() {
+ // r.Type = objabi.R_ADDR
+ // }
+ //
+ // r.Xsym = r.Sym.Sect.Sym
+ // r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
+ //
+ // o = r.Xadd
+ // if target.IsElf() && target.IsAMD64() {
+ // o = 0
+ // }
+ // break
+ //}
+ o = ldr.SymValue(rs) + r.Add() - int64(ldr.SymSect(rs).Vaddr)
+ case objabi.R_WEAKADDROFF, objabi.R_METHODOFF:
+ if !ldr.AttrReachable(rs) {
continue
}
fallthrough
case objabi.R_ADDROFF:
// The method offset tables using this relocation expect the offset to be relative
// to the start of the first text section, even if there are multiple.
- if r.Sym.Sect.Name == ".text" {
- o = Symaddr(r.Sym) - int64(Segtext.Sections[0].Vaddr) + r.Add
+ if ldr.SymSect(rs).Name == ".text" {
+ o = ldr.SymValue(rs) - int64(Segtext.Sections[0].Vaddr) + r.Add()
} else {
- o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
+ o = ldr.SymValue(rs) - int64(ldr.SymSect(rs).Vaddr) + r.Add()
}
case objabi.R_ADDRCUOFF:
// debug_range and debug_loc elements use this relocation type to get an
// offset from the start of the compile unit.
- o = Symaddr(r.Sym) + r.Add - Symaddr(ldr.Syms[r.Sym.Unit.Textp2[0]])
+ o = ldr.SymValue(rs) + r.Add() - ldr.SymValue(loader.Sym(ldr.SymUnit(rs).Textp2[0]))
- // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
+ // r.Sym() can be 0 when CALL $(constant) is transformed from absolute PC to relative PC call.
case objabi.R_GOTPCREL:
- 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
- r.Xsym = r.Sym
-
- o = r.Xadd
- o += int64(r.Siz)
- break
- }
+ //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
+ // r.Xsym = r.Sym
+ //
+ // o = r.Xadd
+ // o += int64(r.Siz)
+ // break
+ //}
fallthrough
case objabi.R_CALL, objabi.R_PCREL:
- if target.IsExternal() && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
- // pass through to the external linker.
- r.Done = false
- r.Xadd = 0
- if target.IsElf() {
- r.Xadd -= int64(r.Siz)
- }
- r.Xsym = r.Sym
- o = 0
- break
- }
- 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.
- 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 != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
- Errorf(s, "missing section for relocation target %s", rs.Name)
- }
- r.Xsym = rs
-
- o = r.Xadd
- if target.IsElf() {
- if target.IsAMD64() {
- o = 0
- }
- } else if target.IsDarwin() {
- if r.Type == objabi.R_CALL {
- if target.IsExternal() && rs.Type == sym.SDYNIMPORT {
- if target.IsAMD64() {
- // AMD64 dynamic relocations are relative to the end of the relocation.
- o += int64(r.Siz)
- }
- } else {
- if rs.Type != sym.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 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, target.HeadType)
- }
-
- break
- }
+ //if target.IsExternal() && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
+ // // pass through to the external linker.
+ // r.Done = false
+ // r.Xadd = 0
+ // if target.IsElf() {
+ // r.Xadd -= int64(r.Siz)
+ // }
+ // r.Xsym = r.Sym
+ // o = 0
+ // break
+ //}
+ //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.
+ // 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 != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
+ // Errorf(s, "missing section for relocation target %s", rs.Name)
+ // }
+ // r.Xsym = rs
+ //
+ // o = r.Xadd
+ // if target.IsElf() {
+ // if target.IsAMD64() {
+ // o = 0
+ // }
+ // } else if target.IsDarwin() {
+ // if r.Type == objabi.R_CALL {
+ // if target.IsExternal() && rs.Type == sym.SDYNIMPORT {
+ // if target.IsAMD64() {
+ // // AMD64 dynamic relocations are relative to the end of the relocation.
+ // o += int64(r.Siz)
+ // }
+ // } else {
+ // if rs.Type != sym.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 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, target.HeadType)
+ // }
+ //
+ // break
+ //}
o = 0
- if r.Sym != nil {
- o += Symaddr(r.Sym)
+ if rs != 0 {
+ o = ldr.SymValue(rs)
}
- o += r.Add - (s.Value + int64(r.Off) + int64(r.Siz))
+ o += r.Add() - (ldr.SymValue(s) + int64(off) + int64(siz))
case objabi.R_SIZE:
- o = r.Sym.Size + r.Add
+ o = ldr.SymSize(rs) + r.Add()
case objabi.R_XCOFFREF:
if !target.IsAIX() {
- Errorf(s, "find XCOFF R_REF on non-XCOFF files")
+ err.Errorf(s, "find XCOFF R_REF on non-XCOFF files")
}
if !target.IsExternal() {
- Errorf(s, "find XCOFF R_REF with internal linking")
+ err.Errorf(s, "find XCOFF R_REF with internal linking")
}
- r.Xsym = r.Sym
- r.Xadd = r.Add
- r.Done = false
+ //r.Xsym = r.Sym
+ //r.Xadd = r.Add
+ //r.Done = false
// This isn't a real relocation so it must not update
// its offset value.
continue
case objabi.R_DWARFFILEREF:
- // The final file index is saved in r.Add in dwarf.go:writelines.
- o = r.Add
+ // We don't renumber files in dwarf.go:writelines anymore.
+ continue
}
- if target.IsPPC64() || target.IsS390X() {
- r.InitExt()
- if r.Variant != sym.RV_NONE {
- o = thearch.Archrelocvariant(target, syms, r, s, o)
- }
- }
+ //if target.IsPPC64() || target.IsS390X() {
+ // r.InitExt()
+ // if r.Variant != sym.RV_NONE {
+ // o = thearch.Archrelocvariant(ldr, target, syms, &r, s, o)
+ // }
+ //}
- if false {
- nam := "<nil>"
- var addr int64
- if r.Sym != nil {
- nam = r.Sym.Name
- addr = Symaddr(r.Sym)
- }
- xnam := "<nil>"
- 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(target.Arch, r.Type), r.Variant, o)
- }
switch siz {
default:
- Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
- fallthrough
-
- // TODO(rsc): Remove.
+ err.Errorf(s, "bad reloc size %#x for %s", uint32(siz), ldr.SymName(rs))
case 1:
- s.P[off] = byte(int8(o))
+ P[off] = byte(int8(o))
case 2:
if o != int64(int16(o)) {
- Errorf(s, "relocation address for %s is too big: %#x", r.Sym.Name, o)
+ err.Errorf(s, "relocation address for %s is too big: %#x", ldr.SymName(rs), o)
}
- i16 := int16(o)
- target.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
+ target.Arch.ByteOrder.PutUint16(P[off:], uint16(o))
case 4:
- if r.Type == objabi.R_PCREL || r.Type == objabi.R_CALL {
+ if rt == objabi.R_PCREL || rt == objabi.R_CALL {
if o != int64(int32(o)) {
- Errorf(s, "pc-relative relocation address for %s is too big: %#x", r.Sym.Name, o)
+ err.Errorf(s, "pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), o)
}
} else {
if o != int64(int32(o)) && o != int64(uint32(o)) {
- Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", r.Sym.Name, uint64(o))
+ err.Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), uint64(o))
}
}
-
- fl := int32(o)
- target.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
+ target.Arch.ByteOrder.PutUint32(P[off:], uint32(o))
case 8:
- target.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
+ target.Arch.ByteOrder.PutUint64(P[off:], uint64(o))
}
}
}
@@ -579,21 +560,23 @@ func (ctxt *Link) reloc() {
syms := &ctxt.ArchSyms
wg.Add(3)
go func() {
- for _, s := range ctxt.Textp {
- relocsym(target, ldr, reporter, syms, s)
+ if !ctxt.IsWasm() { // On Wasm, text relocations are applied in Asmb2.
+ for _, s := range ctxt.Textp2 {
+ relocsym(target, ldr, reporter, syms, s, ldr.OutData(s))
+ }
}
wg.Done()
}()
go func() {
- for _, s := range ctxt.datap {
- relocsym(target, ldr, reporter, syms, s)
+ for _, s := range ctxt.datap2 {
+ relocsym(target, ldr, reporter, syms, s, ldr.OutData(s))
}
wg.Done()
}()
go func() {
- for _, si := range dwarfp {
+ for _, si := range dwarfp2 {
for _, s := range si.syms {
- relocsym(target, ldr, reporter, syms, s)
+ relocsym(target, ldr, reporter, syms, s, ldr.OutData(s))
}
}
wg.Done()
@@ -677,32 +660,34 @@ func (ctxt *Link) windynrelocsyms() {
ctxt.Textp2 = append(ctxt.Textp2, rel)
}
-func dynrelocsym(ctxt *Link, s *sym.Symbol) {
+func dynrelocsym2(ctxt *Link, s loader.Sym) {
target := &ctxt.Target
ldr := ctxt.loader
syms := &ctxt.ArchSyms
- for ri := range s.R {
- r := &s.R[ri]
+ relocs := ldr.Relocs(s)
+ for ri := 0; ri < relocs.Count(); ri++ {
+ r := relocs.At2(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(target, ldr, syms, s, r)
+ thearch.Adddynrel2(target, ldr, syms, s, &r, ri)
continue
}
- if r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT || r.Type >= objabi.ElfRelocOffset {
- if r.Sym != nil && !r.Sym.Attr.Reachable() {
- Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name)
+ rSym := r.Sym()
+ if rSym != 0 && ldr.SymType(rSym) == sym.SDYNIMPORT || r.Type() >= objabi.ElfRelocOffset {
+ if rSym != 0 && !ldr.AttrReachable(rSym) {
+ ctxt.Errorf(s, "dynamic relocation to unreachable symbol %s", ldr.SymName(rSym))
}
- 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)
+ if !thearch.Adddynrel2(target, ldr, syms, s, &r, ri) {
+ ctxt.Errorf(s, "unsupported dynamic relocation for symbol %s (type=%d (%s) stype=%d (%s))", ldr.SymName(rSym), r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymType(rSym), ldr.SymType(rSym))
}
}
}
}
-func (state *dodataState) dynreloc(ctxt *Link) {
+func (state *dodataState) dynreloc2(ctxt *Link) {
if ctxt.HeadType == objabi.Hwindows {
return
}
@@ -712,16 +697,16 @@ func (state *dodataState) dynreloc(ctxt *Link) {
return
}
- for _, s := range ctxt.Textp {
- dynrelocsym(ctxt, s)
+ for _, s := range ctxt.Textp2 {
+ dynrelocsym2(ctxt, s)
}
- for _, syms := range state.data {
+ for _, syms := range state.data2 {
for _, s := range syms {
- dynrelocsym(ctxt, s)
+ dynrelocsym2(ctxt, s)
}
}
if ctxt.IsELF {
- elfdynhash(ctxt)
+ elfdynhash2(ctxt)
}
}
@@ -730,66 +715,7 @@ func Codeblk(ctxt *Link, out *OutBuf, addr int64, size int64) {
}
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())
- }
-
- writeBlocks(out, ctxt.outSem, ctxt.Textp, addr, size, pad)
-
- /* again for printing */
- if !*flagA {
- return
- }
-
- syms := ctxt.Textp
- for i, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if s.Value >= addr {
- syms = syms[i:]
- break
- }
- }
-
- eaddr := addr + size
- for _, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if s.Value >= eaddr {
- break
- }
-
- if addr < s.Value {
- ctxt.Logf("%-20s %.8x|", "_", uint64(addr))
- for ; addr < s.Value; addr++ {
- ctxt.Logf(" %.2x", 0)
- }
- ctxt.Logf("\n")
- }
-
- ctxt.Logf("%.6x\t%-20s\n", uint64(addr), s.Name)
- q := s.P
-
- for len(q) >= 16 {
- ctxt.Logf("%.6x\t% x\n", uint64(addr), q[:16])
- addr += 16
- q = q[16:]
- }
-
- if len(q) > 0 {
- ctxt.Logf("%.6x\t% x\n", uint64(addr), q)
- addr += int64(len(q))
- }
- }
-
- if addr < eaddr {
- ctxt.Logf("%-20s %.8x|", "_", uint64(addr))
- for ; addr < eaddr; addr++ {
- ctxt.Logf(" %.2x", 0)
- }
- }
+ writeBlocks(out, ctxt.outSem, ctxt.loader, ctxt.Textp2, addr, size, pad)
}
const blockSize = 1 << 20 // 1MB chunks written at a time.
@@ -799,9 +725,9 @@ const blockSize = 1 << 20 // 1MB chunks written at a time.
// 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) {
+func writeBlocks(out *OutBuf, sem chan int, ldr *loader.Loader, syms []loader.Sym, addr, size int64, pad []byte) {
for i, s := range syms {
- if s.Value >= addr && !s.Attr.SubSymbol() {
+ if ldr.SymValue(s) >= addr && !ldr.AttrSubSymbol(s) {
syms = syms[i:]
break
}
@@ -813,13 +739,14 @@ func writeBlocks(out *OutBuf, sem chan int, syms []*sym.Symbol, addr, size int64
// Find the last symbol we'd write.
idx := -1
for i, s := range syms {
- if s.Attr.SubSymbol() {
+ if ldr.AttrSubSymbol(s) {
continue
}
// If the next symbol's size would put us out of bounds on the total length,
// stop looking.
- if s.Value+s.Size > lastAddr {
+ end := ldr.SymValue(s) + ldr.SymSize(s)
+ if end > lastAddr {
break
}
@@ -827,7 +754,7 @@ func writeBlocks(out *OutBuf, sem chan int, syms []*sym.Symbol, addr, size int64
idx = i
// If we cross over the max size, we've got enough symbols.
- if s.Value+s.Size > addr+max {
+ if end > addr+max {
break
}
}
@@ -848,11 +775,11 @@ func writeBlocks(out *OutBuf, sem chan int, syms []*sym.Symbol, addr, size int64
// Skip over sub symbols so we won't split a containter symbol
// into two blocks.
next := syms[idx+1]
- for next.Attr.SubSymbol() {
+ for ldr.AttrSubSymbol(next) {
idx++
next = syms[idx+1]
}
- length = next.Value - addr
+ length = ldr.SymValue(next) - addr
}
if length == 0 || length > lastAddr-addr {
length = lastAddr - addr
@@ -862,13 +789,13 @@ func writeBlocks(out *OutBuf, sem chan int, syms []*sym.Symbol, addr, size int64
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)
+ go func(o *OutBuf, ldr *loader.Loader, syms []loader.Sym, addr, size int64, pad []byte) {
+ writeBlock(o, ldr, syms, addr, size, pad)
wg.Done()
<-sem
- }(o, syms, addr, length, pad)
+ }(o, ldr, syms, addr, length, pad)
} else { // output not mmaped, don't parallelize.
- writeBlock(out, syms, addr, length, pad)
+ writeBlock(out, ldr, syms, addr, length, pad)
}
// Prepare for the next loop.
@@ -881,9 +808,9 @@ func writeBlocks(out *OutBuf, sem chan int, syms []*sym.Symbol, addr, size int64
wg.Wait()
}
-func writeBlock(out *OutBuf, syms []*sym.Symbol, addr, size int64, pad []byte) {
+func writeBlock(out *OutBuf, ldr *loader.Loader, syms []loader.Sym, addr, size int64, pad []byte) {
for i, s := range syms {
- if s.Value >= addr && !s.Attr.SubSymbol() {
+ if ldr.SymValue(s) >= addr && !ldr.AttrSubSymbol(s) {
syms = syms[i:]
break
}
@@ -895,31 +822,33 @@ func writeBlock(out *OutBuf, syms []*sym.Symbol, addr, size int64, pad []byte) {
// so dwarfcompress will fix this up later if necessary.
eaddr := addr + size
for _, s := range syms {
- if s.Attr.SubSymbol() {
+ if ldr.AttrSubSymbol(s) {
continue
}
- if s.Value >= eaddr {
+ val := ldr.SymValue(s)
+ if val >= eaddr {
break
}
- if s.Value < addr {
- Errorf(s, "phase error: addr=%#x but sym=%#x type=%d", addr, s.Value, s.Type)
+ if val < addr {
+ ldr.Errorf(s, "phase error: addr=%#x but sym=%#x type=%d", addr, val, ldr.SymType(s))
errorexit()
}
- if addr < s.Value {
- out.WriteStringPad("", int(s.Value-addr), pad)
- addr = s.Value
+ if addr < val {
+ out.WriteStringPad("", int(val-addr), pad)
+ addr = val
}
- out.WriteSym(s)
- addr += int64(len(s.P))
- if addr < s.Value+s.Size {
- out.WriteStringPad("", int(s.Value+s.Size-addr), pad)
- addr = s.Value + s.Size
+ out.WriteSym(ldr, s)
+ addr += int64(len(ldr.Data(s)))
+ siz := ldr.SymSize(s)
+ if addr < val+siz {
+ out.WriteStringPad("", int(val+siz-addr), pad)
+ addr = val + siz
}
- if addr != s.Value+s.Size {
- Errorf(s, "phase error: addr=%#x value+size=%#x", addr, s.Value+s.Size)
+ if addr != val+siz {
+ ldr.Errorf(s, "phase error: addr=%#x value+size=%#x", addr, val+siz)
errorexit()
}
- if s.Value+s.Size >= eaddr {
+ if val+siz >= eaddr {
break
}
}
@@ -958,84 +887,10 @@ func DatblkBytes(ctxt *Link, addr int64, size int64) []byte {
}
func writeDatblkToOutBuf(ctxt *Link, out *OutBuf, addr int64, size int64) {
- if *flagA {
- ctxt.Logf("datblk [%#x,%#x) at offset %#x\n", addr, addr+size, ctxt.Out.Offset())
- }
-
- writeBlocks(out, ctxt.outSem, ctxt.datap, addr, size, zeros[:])
-
- /* again for printing */
- if !*flagA {
- return
- }
-
- syms := ctxt.datap
- for i, sym := range syms {
- if sym.Value >= addr {
- syms = syms[i:]
- break
- }
- }
-
- eaddr := addr + size
- for _, sym := range syms {
- if sym.Value >= eaddr {
- break
- }
- if addr < sym.Value {
- ctxt.Logf("\t%.8x| 00 ...\n", uint64(addr))
- addr = sym.Value
- }
-
- ctxt.Logf("%s\n\t%.8x|", sym.Name, uint64(addr))
- for i, b := range sym.P {
- if i > 0 && i%16 == 0 {
- ctxt.Logf("\n\t%.8x|", uint64(addr)+uint64(i))
- }
- ctxt.Logf(" %.2x", b)
- }
-
- addr += int64(len(sym.P))
- for ; addr < sym.Value+sym.Size; addr++ {
- ctxt.Logf(" %.2x", 0)
- }
- ctxt.Logf("\n")
-
- if ctxt.LinkMode != LinkExternal {
- continue
- }
- for i := range sym.R {
- r := &sym.R[i] // Copying sym.Reloc has measurable impact on performance
- rsname := ""
- rsval := int64(0)
- if r.Sym != nil {
- rsname = r.Sym.Name
- rsval = r.Sym.Value
- }
- typ := "?"
- switch r.Type {
- case objabi.R_ADDR:
- typ = "addr"
- case objabi.R_PCREL:
- typ = "pcrel"
- case objabi.R_CALL:
- typ = "call"
- }
- ctxt.Logf("\treloc %.8x/%d %s %s+%#x [%#x]\n", uint(sym.Value+int64(r.Off)), r.Siz, typ, rsname, r.Add, rsval+r.Add)
- }
- }
-
- if addr < eaddr {
- ctxt.Logf("\t%.8x| 00 ...\n", uint(addr))
- }
- ctxt.Logf("\t%.8x|\n", uint(eaddr))
+ writeBlocks(out, ctxt.outSem, ctxt.loader, ctxt.datap2, addr, size, zeros[:])
}
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())
- }
-
// Concatenate the section symbol lists into a single list to pass
// to writeBlocks.
//
@@ -1043,14 +898,14 @@ func Dwarfblk(ctxt *Link, out *OutBuf, addr int64, size int64) {
// section, but this would run the risk of undoing any file offset
// adjustments made during layout.
n := 0
- for i := range dwarfp {
- n += len(dwarfp[i].syms)
+ for i := range dwarfp2 {
+ n += len(dwarfp2[i].syms)
}
- syms := make([]*sym.Symbol, 0, n)
- for i := range dwarfp {
- syms = append(syms, dwarfp[i].syms...)
+ syms := make([]loader.Sym, 0, n)
+ for i := range dwarfp2 {
+ syms = append(syms, dwarfp2[i].syms...)
}
- writeBlocks(out, ctxt.outSem, syms, addr, size, zeros[:])
+ writeBlocks(out, ctxt.outSem, ctxt.loader, syms, addr, size, zeros[:])
}
var zeros [512]byte
@@ -1120,21 +975,6 @@ func (ctxt *Link) dostrdata() {
}
}
-func Addstring(s *sym.Symbol, str string) int64 {
- if s.Type == 0 {
- s.Type = sym.SNOPTRDATA
- }
- s.Attr |= sym.AttrReachable
- r := s.Size
- if s.Name == ".shstrtab" {
- elfsetstring(s, str, int(r))
- }
- s.P = append(s.P, str...)
- s.P = append(s.P, 0)
- s.Size = int64(len(s.P))
- return 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(ctxt *Link, ldr *loader.Loader, s *loader.SymbolBuilder, symname, str string) {
@@ -1161,102 +1001,37 @@ func addinitarrdata(ctxt *Link, ldr *loader.Loader, s loader.Sym) {
}
// symalign returns the required alignment for the given symbol s.
-func symalign(s *sym.Symbol) int32 {
+func (state *dodataState) symalign2(s loader.Sym) int32 {
min := int32(thearch.Minalign)
- if s.Align >= min {
- return s.Align
- } else if s.Align != 0 {
+ ldr := state.ctxt.loader
+ align := ldr.SymAlign(s)
+ if align >= min {
+ return align
+ } else if align != 0 {
return min
}
- if strings.HasPrefix(s.Name, "go.string.") || strings.HasPrefix(s.Name, "type..namedata.") {
+ // FIXME: figure out a way to avoid checking by name here.
+ sname := ldr.SymName(s)
+ if strings.HasPrefix(sname, "go.string.") || strings.HasPrefix(sname, "type..namedata.") {
// String data is just bytes.
// If we align it, we waste a lot of space to padding.
return min
}
- align := int32(thearch.Maxalign)
- for int64(align) > s.Size && align > min {
+ align = int32(thearch.Maxalign)
+ ssz := ldr.SymSize(s)
+ for int64(align) > ssz && align > min {
align >>= 1
}
- s.Align = align
+ ldr.SetSymAlign(s, align)
return align
}
-func aligndatsize(datsize int64, s *sym.Symbol) int64 {
- return Rnd(datsize, int64(symalign(s)))
+func aligndatsize2(state *dodataState, datsize int64, s loader.Sym) int64 {
+ return Rnd(datsize, int64(state.symalign2(s)))
}
const debugGCProg = false
-type GCProg struct {
- ctxt *Link
- sym *sym.Symbol
- w gcprog.Writer
-}
-
-func (p *GCProg) Init(ctxt *Link, name string) {
- p.ctxt = ctxt
- p.sym = ctxt.Syms.Lookup(name, 0)
- p.w.Init(p.writeByte(ctxt))
- if debugGCProg {
- fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name)
- p.w.Debug(os.Stderr)
- }
-}
-
-func (p *GCProg) writeByte(ctxt *Link) func(x byte) {
- return func(x byte) {
- p.sym.AddUint8(x)
- }
-}
-
-func (p *GCProg) End(size int64) {
- p.w.ZeroUntil(size / int64(p.ctxt.Arch.PtrSize))
- p.w.End()
- if debugGCProg {
- fmt.Fprintf(os.Stderr, "ld: end GCProg\n")
- }
-}
-
-func (p *GCProg) AddSym(s *sym.Symbol) {
- typ := s.Gotype
- // Things without pointers should be in sym.SNOPTRDATA or sym.SNOPTRBSS;
- // everything we see should have pointers and should therefore have a type.
- if typ == nil {
- switch s.Name {
- case "runtime.data", "runtime.edata", "runtime.bss", "runtime.ebss":
- // Ignore special symbols that are sometimes laid out
- // as real symbols. See comment about dyld on darwin in
- // the address function.
- return
- }
- Errorf(s, "missing Go type information for global symbol: size %d", s.Size)
- return
- }
-
- ptrsize := int64(p.ctxt.Arch.PtrSize)
- nptr := decodetypePtrdata(p.ctxt.Arch, typ.P) / 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 decodetypeUsegcprog(p.ctxt.Arch, typ.P) == 0 {
- // Copy pointers from mask into program.
- mask := decodetypeGcmask(p.ctxt, 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 := decodetypeGcprog(p.ctxt, typ)
- p.w.ZeroUntil(s.Value / ptrsize)
- p.w.Append(prog[4:], nptr)
-}
-
type GCProg2 struct {
ctxt *Link
sym *loader.SymbolBuilder
@@ -1295,14 +1070,14 @@ func (p *GCProg2) AddSym(s loader.Sym) {
// Things without pointers should be in sym.SNOPTRDATA or sym.SNOPTRBSS;
// everything we see should have pointers and should therefore have a type.
if typ == 0 {
- switch p.sym.Name() {
+ switch ldr.SymName(s) {
case "runtime.data", "runtime.edata", "runtime.bss", "runtime.ebss":
// Ignore special symbols that are sometimes laid out
// as real symbols. See comment about dyld on darwin in
// the address function.
return
}
- p.ctxt.Errorf(p.sym.Sym(), "missing Go type information for global symbol: size %d", ldr.SymSize(s))
+ p.ctxt.Errorf(p.sym.Sym(), "missing Go type information for global symbol %s: size %d", ldr.SymName(s), ldr.SymSize(s))
return
}
@@ -1332,26 +1107,6 @@ func (p *GCProg2) AddSym(s loader.Sym) {
p.w.Append(prog[4:], nptr)
}
-// dataSortKey is used to sort a slice of data symbol *sym.Symbol pointers.
-// The sort keys are kept inline to improve cache behavior while sorting.
-type dataSortKey struct {
- size int64
- name string
- sym *sym.Symbol
-}
-
-type bySizeAndName []dataSortKey
-
-func (d bySizeAndName) Len() int { return len(d) }
-func (d bySizeAndName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
-func (d bySizeAndName) Less(i, j int) bool {
- s1, s2 := d[i], d[j]
- if s1.size != s2.size {
- return s1.size < s2.size
- }
- return s1.name < s2.name
-}
-
// cutoff is the maximum data section size permitted by the linker
// (see issue #9862).
const cutoff = 2e9 // 2 GB (or so; looks better in errors than 2^31)
@@ -1363,7 +1118,7 @@ func (state *dodataState) checkdatsize(symn sym.SymKind) {
}
// fixZeroSizedSymbols gives a few special symbols with zero size some space.
-func fixZeroSizedSymbols(ctxt *Link) {
+func fixZeroSizedSymbols2(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
@@ -1391,44 +1146,48 @@ func fixZeroSizedSymbols(ctxt *Link) {
return
}
- bss := ctxt.Syms.Lookup("runtime.bss", 0)
- bss.Size = 8
- bss.Attr.Set(sym.AttrSpecial, false)
+ ldr := ctxt.loader
+ bss := ldr.CreateSymForUpdate("runtime.bss", 0)
+ bss.SetSize(8)
+ ldr.SetAttrSpecial(bss.Sym(), false)
+
+ ebss := ldr.CreateSymForUpdate("runtime.ebss", 0)
+ ldr.SetAttrSpecial(ebss.Sym(), false)
- ctxt.Syms.Lookup("runtime.ebss", 0).Attr.Set(sym.AttrSpecial, false)
+ data := ldr.CreateSymForUpdate("runtime.data", 0)
+ data.SetSize(8)
+ ldr.SetAttrSpecial(data.Sym(), false)
- data := ctxt.Syms.Lookup("runtime.data", 0)
- data.Size = 8
- data.Attr.Set(sym.AttrSpecial, false)
+ edata := ldr.CreateSymForUpdate("runtime.edata", 0)
+ ldr.SetAttrSpecial(edata.Sym(), 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
+ edata.SetType(sym.SXCOFFTOC)
}
- types := ctxt.Syms.Lookup("runtime.types", 0)
- types.Type = sym.STYPE
- types.Size = 8
- types.Attr.Set(sym.AttrSpecial, false)
+ types := ldr.CreateSymForUpdate("runtime.types", 0)
+ types.SetType(sym.STYPE)
+ types.SetSize(8)
+ ldr.SetAttrSpecial(types.Sym(), false)
- etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
- etypes.Type = sym.SFUNCTAB
- etypes.Attr.Set(sym.AttrSpecial, false)
+ etypes := ldr.CreateSymForUpdate("runtime.etypes", 0)
+ etypes.SetType(sym.SFUNCTAB)
+ ldr.SetAttrSpecial(etypes.Sym(), 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)
+ rodata := ldr.CreateSymForUpdate("runtime.rodata", 0)
+ rodata.SetType(sym.SSTRING)
+ rodata.SetSize(8)
+ ldr.SetAttrSpecial(rodata.Sym(), false)
- ctxt.Syms.Lookup("runtime.erodata", 0).Attr.Set(sym.AttrSpecial, false)
+ erodata := ldr.CreateSymForUpdate("runtime.erodata", 0)
+ ldr.SetAttrSpecial(erodata.Sym(), false)
}
}
// makeRelroForSharedLib creates a section of readonly data if necessary.
-func (state *dodataState) makeRelroForSharedLib(target *Link) {
+func (state *dodataState) makeRelroForSharedLib2(target *Link) {
if !target.UseRelro() {
return
}
@@ -1436,31 +1195,33 @@ func (state *dodataState) makeRelroForSharedLib(target *Link) {
// "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.
+ ldr := target.loader
for _, symnro := range sym.ReadOnly {
symnrelro := sym.RelROMap[symnro]
- ro := []*sym.Symbol{}
- relro := state.data[symnrelro]
+ ro := []loader.Sym{}
+ relro := state.data2[symnrelro]
- for _, s := range state.data[symnro] {
- isRelro := len(s.R) > 0
- switch s.Type {
+ for _, s := range state.data2[symnro] {
+ relocs := ldr.Relocs(s)
+ isRelro := relocs.Count() > 0
+ switch state.symType(s) {
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" {
+ if target.IsAIX() && ldr.SymName(s) == "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
+ state.setSymType(s, symnrelro)
+ if outer := ldr.OuterSym(s); outer != 0 {
+ state.setSymType(outer, symnrelro)
}
relro = append(relro, s)
} else {
@@ -1473,14 +1234,18 @@ func (state *dodataState) makeRelroForSharedLib(target *Link) {
// 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)
+ if outer := ldr.OuterSym(s); outer != 0 {
+ st := state.symType(s)
+ ost := state.symType(outer)
+ if st != ost {
+ state.ctxt.Errorf(s, "inconsistent types for symbol and its Outer %s (%v != %v)",
+ ldr.SymName(outer), st, ost)
+ }
}
}
- state.data[symnro] = ro
- state.data[symnrelro] = relro
+ state.data2[symnro] = ro
+ state.data2[symnrelro] = relro
}
}
@@ -1492,26 +1257,76 @@ type dodataState struct {
ctxt *Link
// Data symbols bucketed by type.
data [sym.SXREF][]*sym.Symbol
+ // Data symbols bucketed by type.
+ data2 [sym.SXREF][]loader.Sym
// Max alignment for each flavor of data symbol.
dataMaxAlign [sym.SXREF]int32
+ // Overridden sym type
+ symGroupType []sym.SymKind
// Current data size so far.
datsize int64
}
-func (ctxt *Link) dodata() {
+// A note on symType/setSymType below:
+//
+// In the legacy linker, the types of symbols (notably data symbols) are
+// changed during the symtab() phase so as to insure that similar symbols
+// are bucketed together, then their types are changed back again during
+// dodata. Symbol to section assignment also plays tricks along these lines
+// in the case where a relro segment is needed.
+//
+// The value returned from setType() below reflects the effects of
+// any overrides made by symtab and/or dodata.
+
+// symType returns the (possibly overridden) type of 's'.
+func (state *dodataState) symType(s loader.Sym) sym.SymKind {
+ if int(s) < len(state.symGroupType) {
+ if override := state.symGroupType[s]; override != 0 {
+ return override
+ }
+ }
+ return state.ctxt.loader.SymType(s)
+}
+
+// setSymType sets a new override type for 's'.
+func (state *dodataState) setSymType(s loader.Sym, kind sym.SymKind) {
+ if s == 0 {
+ panic("bad")
+ }
+ if int(s) < len(state.symGroupType) {
+ state.symGroupType[s] = kind
+ } else {
+ su := state.ctxt.loader.MakeSymbolUpdater(s)
+ su.SetType(kind)
+ }
+}
+
+func (ctxt *Link) dodata2(symGroupType []sym.SymKind) {
+
// Give zeros sized symbols space if necessary.
- fixZeroSizedSymbols(ctxt)
+ fixZeroSizedSymbols2(ctxt)
// Collect data symbols by type into data.
- state := dodataState{ctxt: ctxt}
- for _, s := range ctxt.Syms.Allsym {
- if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() {
+ state := dodataState{ctxt: ctxt, symGroupType: symGroupType}
+ ldr := ctxt.loader
+ for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
+ if !ldr.AttrReachable(s) || ldr.AttrSpecial(s) || ldr.AttrSubSymbol(s) ||
+ !ldr.TopLevelSym(s) {
continue
}
- if s.Type <= sym.STEXT || s.Type >= sym.SXREF {
+
+ st := state.symType(s)
+
+ if st <= sym.STEXT || st >= sym.SXREF {
continue
}
- state.data[s.Type] = append(state.data[s.Type], s)
+ state.data2[st] = append(state.data2[st], s)
+
+ // Similarly with checking the onlist attr.
+ if ldr.AttrOnList(s) {
+ log.Fatalf("symbol %s listed multiple times", ldr.SymName(s))
+ }
+ ldr.SetAttrOnList(s, true)
}
// Now that we have the data symbols, but before we start
@@ -1523,37 +1338,83 @@ func (ctxt *Link) dodata() {
if ctxt.HeadType == objabi.Hdarwin {
machosymorder(ctxt)
}
- state.dynreloc(ctxt)
+ state.dynreloc2(ctxt)
// Move any RO data with relocations to a separate section.
- state.makeRelroForSharedLib(ctxt)
+ state.makeRelroForSharedLib2(ctxt)
+
+ // Set explicit alignment here, so as to avoid having to update
+ // symbol alignment in doDataSect2, which would cause a concurrent
+ // map read/write violation.
+ // NOTE: this needs to be done after dynreloc2, where symbol size
+ // may change.
+ for _, list := range state.data2 {
+ for _, s := range list {
+ state.symalign2(s)
+ }
+ }
// Sort symbols.
var wg sync.WaitGroup
- for symn := range state.data {
+ for symn := range state.data2 {
symn := sym.SymKind(symn)
wg.Add(1)
go func() {
- state.data[symn], state.dataMaxAlign[symn] = dodataSect(ctxt, symn, state.data[symn])
+ state.data2[symn], state.dataMaxAlign[symn] = state.dodataSect2(ctxt, symn, state.data2[symn])
wg.Done()
}()
}
wg.Wait()
+ if ctxt.IsELF {
+ // Make .rela and .rela.plt contiguous, the ELF ABI requires this
+ // and Solaris actually cares.
+ syms := state.data2[sym.SELFROSECT]
+ reli, plti := -1, -1
+ for i, s := range syms {
+ switch ldr.SymName(s) {
+ case ".rel.plt", ".rela.plt":
+ plti = i
+ case ".rel", ".rela":
+ reli = i
+ }
+ }
+ if reli >= 0 && plti >= 0 && plti != reli+1 {
+ var first, second int
+ if plti > reli {
+ first, second = reli, plti
+ } else {
+ first, second = plti, reli
+ }
+ rel, plt := syms[reli], syms[plti]
+ copy(syms[first+2:], syms[first+1:second])
+ syms[first+0] = rel
+ syms[first+1] = plt
+
+ // Make sure alignment doesn't introduce a gap.
+ // Setting the alignment explicitly prevents
+ // symalign from basing it on the size and
+ // getting it wrong.
+ ldr.SetSymAlign(rel, int32(ctxt.Arch.RegSize))
+ ldr.SetSymAlign(plt, int32(ctxt.Arch.RegSize))
+ }
+ state.data2[sym.SELFROSECT] = syms
+ }
+
if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
// These symbols must have the same alignment as their section.
// Otherwize, ld might change the layout of Go sections.
- ctxt.Syms.ROLookup("runtime.data", 0).Align = state.dataMaxAlign[sym.SDATA]
- ctxt.Syms.ROLookup("runtime.bss", 0).Align = state.dataMaxAlign[sym.SBSS]
+ ldr.SetSymAlign(ldr.Lookup("runtime.data", 0), state.dataMaxAlign[sym.SDATA])
+ ldr.SetSymAlign(ldr.Lookup("runtime.bss", 0), state.dataMaxAlign[sym.SBSS])
}
// Create *sym.Section objects and assign symbols to sections for
// data/rodata (and related) symbols.
- state.allocateDataSections(ctxt)
+ state.allocateDataSections2(ctxt)
// Create *sym.Section objects and assign symbols to sections for
// DWARF symbols.
- state.allocateDwarfSections(ctxt)
+ state.allocateDwarfSections2(ctxt)
/* number the sections */
n := int16(1)
@@ -1584,9 +1445,11 @@ func (ctxt *Link) dodata() {
// single symbol will be placed. Here "seg" is the segment into which
// the section will go, "s" is the symbol to be placed into the new
// section, and "rwx" contains permissions for the section.
-func (state *dodataState) allocateDataSectionForSym(seg *sym.Segment, s *sym.Symbol, rwx int) *sym.Section {
- sect := addsection(state.ctxt.loader, state.ctxt.Arch, seg, s.Name, rwx)
- sect.Align = symalign(s)
+func (state *dodataState) allocateDataSectionForSym2(seg *sym.Segment, s loader.Sym, rwx int) *sym.Section {
+ ldr := state.ctxt.loader
+ sname := ldr.SymName(s)
+ sect := addsection(ldr, state.ctxt.Arch, seg, sname, rwx)
+ sect.Align = state.symalign2(s)
state.datsize = Rnd(state.datsize, int64(sect.Align))
sect.Vaddr = uint64(state.datsize)
return sect
@@ -1622,21 +1485,22 @@ func (state *dodataState) allocateNamedDataSection(seg *sym.Segment, sName strin
// "forceType" (if non-zero) contains a new sym type to apply to each
// sym during the assignment, and "aligner" is a hook to call to
// handle alignment during the assignment process.
-func (state *dodataState) assignDsymsToSection(sect *sym.Section, syms []*sym.Symbol, forceType sym.SymKind, aligner func(datsize int64, s *sym.Symbol) int64) {
+func (state *dodataState) assignDsymsToSection2(sect *sym.Section, syms []loader.Sym, forceType sym.SymKind, aligner func(state *dodataState, datsize int64, s loader.Sym) int64) {
+ ldr := state.ctxt.loader
for _, s := range syms {
- state.datsize = aligner(state.datsize, s)
- s.Sect = sect
+ state.datsize = aligner(state, state.datsize, s)
+ ldr.SetSymSect(s, sect)
if forceType != sym.Sxxx {
- s.Type = forceType
+ state.setSymType(s, forceType)
}
- s.Value = int64(uint64(state.datsize) - sect.Vaddr)
- state.datsize += s.Size
+ ldr.SetSymValue(s, int64(uint64(state.datsize)-sect.Vaddr))
+ state.datsize += ldr.SymSize(s)
}
sect.Length = uint64(state.datsize) - sect.Vaddr
}
-func (state *dodataState) assignToSection(sect *sym.Section, symn sym.SymKind, forceType sym.SymKind) {
- state.assignDsymsToSection(sect, state.data[symn], forceType, aligndatsize)
+func (state *dodataState) assignToSection2(sect *sym.Section, symn sym.SymKind, forceType sym.SymKind) {
+ state.assignDsymsToSection2(sect, state.data2[symn], forceType, aligndatsize2)
state.checkdatsize(symn)
}
@@ -1646,13 +1510,14 @@ func (state *dodataState) assignToSection(sect *sym.Section, symn sym.SymKind, f
// symbol name. "Seg" is the segment into which to place the new
// section, "forceType" is the new sym.SymKind to assign to the symbol
// within the section, and "rwx" holds section permissions.
-func (state *dodataState) allocateSingleSymSections(seg *sym.Segment, symn sym.SymKind, forceType sym.SymKind, rwx int) {
- for _, s := range state.data[symn] {
- sect := state.allocateDataSectionForSym(seg, s, rwx)
- s.Sect = sect
- s.Type = forceType
- s.Value = int64(uint64(state.datsize) - sect.Vaddr)
- state.datsize += s.Size
+func (state *dodataState) allocateSingleSymSections2(seg *sym.Segment, symn sym.SymKind, forceType sym.SymKind, rwx int) {
+ ldr := state.ctxt.loader
+ for _, s := range state.data2[symn] {
+ sect := state.allocateDataSectionForSym2(seg, s, rwx)
+ ldr.SetSymSect(s, sect)
+ state.setSymType(s, forceType)
+ ldr.SetSymValue(s, int64(uint64(state.datsize)-sect.Vaddr))
+ state.datsize += ldr.SymSize(s)
sect.Length = uint64(state.datsize) - sect.Vaddr
}
state.checkdatsize(symn)
@@ -1665,16 +1530,16 @@ func (state *dodataState) allocateSingleSymSections(seg *sym.Segment, symn sym.S
// name to give to the new section, "forceType" (if non-zero) contains
// a new sym type to apply to each sym during the assignment, and
// "rwx" holds section permissions.
-func (state *dodataState) allocateNamedSectionAndAssignSyms(seg *sym.Segment, secName string, symn sym.SymKind, forceType sym.SymKind, rwx int) *sym.Section {
+func (state *dodataState) allocateNamedSectionAndAssignSyms2(seg *sym.Segment, secName string, symn sym.SymKind, forceType sym.SymKind, rwx int) *sym.Section {
sect := state.allocateNamedDataSection(seg, secName, []sym.SymKind{symn}, rwx)
- state.assignDsymsToSection(sect, state.data[symn], forceType, aligndatsize)
+ state.assignDsymsToSection2(sect, state.data2[symn], forceType, aligndatsize2)
return sect
}
// allocateDataSections allocates sym.Section objects for data/rodata
// (and related) symbols, and then assigns symbols to those sections.
-func (state *dodataState) allocateDataSections(ctxt *Link) {
+func (state *dodataState) allocateDataSections2(ctxt *Link) {
// Allocate sections.
// Data is processed before segtext, because we need
// to see all symbols in the .data and .bss sections in order
@@ -1689,32 +1554,31 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
sym.SWINDOWS,
}
for _, symn := range writable {
- state.allocateSingleSymSections(&Segdata, symn, sym.SDATA, 06)
+ state.allocateSingleSymSections2(&Segdata, symn, sym.SDATA, 06)
}
+ ldr := ctxt.loader
// .got (and .toc on ppc64)
- if len(state.data[sym.SELFGOT]) > 0 {
- sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
+ if len(state.data2[sym.SELFGOT]) > 0 {
+ sect := state.allocateNamedSectionAndAssignSyms2(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
if ctxt.IsPPC64() {
- for _, s := range state.data[sym.SELFGOT] {
+ for _, s := range state.data2[sym.SELFGOT] {
// Resolve .TOC. symbol for this object file (ppc64)
- toc := ctxt.Syms.ROLookup(".TOC.", int(s.Version))
- if toc != nil {
- toc.Sect = sect
- toc.Outer = s
- toc.Sub = s.Sub
- s.Sub = toc
- toc.Value = 0x8000
+ toc := ldr.Lookup(".TOC.", int(ldr.SymVersion(s)))
+ if toc != 0 {
+ ldr.SetSymSect(toc, sect)
+ ldr.PrependSub(s, toc)
+ ldr.SetSymValue(toc, 0x8000)
}
}
}
}
/* pointer-free data */
- sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrdata", sym.SNOPTRDATA, sym.SDATA, 06)
- ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.enoptrdata", 0).Sect = sect
+ sect := state.allocateNamedSectionAndAssignSyms2(&Segdata, ".noptrdata", sym.SNOPTRDATA, sym.SDATA, 06)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.noptrdata", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.enoptrdata", 0), sect)
hasinitarr := ctxt.linkShared
@@ -1725,31 +1589,31 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
}
if ctxt.HeadType == objabi.Haix {
- if len(state.data[sym.SINITARR]) > 0 {
+ if len(state.data2[sym.SINITARR]) > 0 {
Errorf(nil, "XCOFF format doesn't allow .init_array section")
}
}
- if hasinitarr && len(state.data[sym.SINITARR]) > 0 {
- state.allocateNamedSectionAndAssignSyms(&Segdata, ".init_array", sym.SINITARR, sym.Sxxx, 06)
+ if hasinitarr && len(state.data2[sym.SINITARR]) > 0 {
+ state.allocateNamedSectionAndAssignSyms2(&Segdata, ".init_array", sym.SINITARR, sym.Sxxx, 06)
}
/* data */
- sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".data", sym.SDATA, sym.SDATA, 06)
- ctxt.Syms.Lookup("runtime.data", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.edata", 0).Sect = sect
+ sect = state.allocateNamedSectionAndAssignSyms2(&Segdata, ".data", sym.SDATA, sym.SDATA, 06)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.data", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.edata", 0), sect)
dataGcEnd := state.datsize - int64(sect.Vaddr)
// On AIX, TOC entries must be the last of .data
// These aren't part of gc as they won't change during the runtime.
- state.assignToSection(sect, sym.SXCOFFTOC, sym.SDATA)
+ state.assignToSection2(sect, sym.SXCOFFTOC, sym.SDATA)
state.checkdatsize(sym.SDATA)
sect.Length = uint64(state.datsize) - sect.Vaddr
/* bss */
- sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".bss", sym.SBSS, sym.Sxxx, 06)
- ctxt.Syms.Lookup("runtime.bss", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.ebss", 0).Sect = sect
+ sect = state.allocateNamedSectionAndAssignSyms2(&Segdata, ".bss", sym.SBSS, sym.Sxxx, 06)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.bss", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.ebss", 0), sect)
bssGcEnd := state.datsize - int64(sect.Vaddr)
// Emit gcdata for bcc symbols now that symbol values have been assigned.
@@ -1762,41 +1626,43 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
{"runtime.gcbss", sym.SBSS, bssGcEnd},
}
for _, g := range gcsToEmit {
- var gc GCProg
+ var gc GCProg2
gc.Init(ctxt, g.symName)
- for _, s := range state.data[g.symKind] {
+ for _, s := range state.data2[g.symKind] {
gc.AddSym(s)
}
gc.End(g.gcEnd)
}
/* pointer-free bss */
- sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrbss", sym.SNOPTRBSS, sym.Sxxx, 06)
- ctxt.Syms.Lookup("runtime.noptrbss", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.enoptrbss", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.end", 0).Sect = sect
+ sect = state.allocateNamedSectionAndAssignSyms2(&Segdata, ".noptrbss", sym.SNOPTRBSS, sym.Sxxx, 06)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.noptrbss", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.enoptrbss", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.end", 0), sect)
// Coverage instrumentation counters for libfuzzer.
if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
- state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
+ state.allocateNamedSectionAndAssignSyms2(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
}
- if len(state.data[sym.STLSBSS]) > 0 {
+ if len(state.data2[sym.STLSBSS]) > 0 {
var sect *sym.Section
// FIXME: not clear why it is sometimes necessary to suppress .tbss section creation.
if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && (ctxt.LinkMode == LinkExternal || !*FlagD) {
- sect = addsection(ctxt.loader, ctxt.Arch, &Segdata, ".tbss", 06)
+ sect = addsection(ldr, ctxt.Arch, &Segdata, ".tbss", 06)
sect.Align = int32(ctxt.Arch.PtrSize)
// FIXME: why does this need to be set to zero?
sect.Vaddr = 0
}
state.datsize = 0
- for _, s := range state.data[sym.STLSBSS] {
- state.datsize = aligndatsize(state.datsize, s)
- s.Sect = sect
- s.Value = state.datsize
- state.datsize += s.Size
+ for _, s := range state.data2[sym.STLSBSS] {
+ state.datsize = aligndatsize2(state, state.datsize, s)
+ if sect != nil {
+ ldr.SetSymSect(s, sect)
+ }
+ ldr.SetSymValue(s, state.datsize)
+ state.datsize += ldr.SymSize(s)
}
state.checkdatsize(sym.STLSBSS)
@@ -1826,34 +1692,35 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
state.datsize = 0
/* read-only executable ELF, Mach-O sections */
- if len(state.data[sym.STEXT]) != 0 {
- Errorf(nil, "dodata found an sym.STEXT symbol: %s", state.data[sym.STEXT][0].Name)
+ if len(state.data2[sym.STEXT]) != 0 {
+ culprit := ldr.SymName(state.data2[sym.STEXT][0])
+ Errorf(nil, "dodata found an sym.STEXT symbol: %s", culprit)
}
- state.allocateSingleSymSections(&Segtext, sym.SELFRXSECT, sym.SRODATA, 04)
+ state.allocateSingleSymSections2(&Segtext, sym.SELFRXSECT, sym.SRODATA, 04)
/* read-only data */
sect = state.allocateNamedDataSection(segro, ".rodata", sym.ReadOnly, 04)
- ctxt.Syms.Lookup("runtime.rodata", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.erodata", 0).Sect = sect
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.rodata", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.erodata", 0), sect)
if !ctxt.UseRelro() {
- ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.types", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.etypes", 0), sect)
}
for _, symn := range sym.ReadOnly {
symnStartValue := state.datsize
- state.assignToSection(sect, symn, sym.SRODATA)
+ state.assignToSection2(sect, symn, sym.SRODATA)
if ctxt.HeadType == objabi.Haix {
// Read-only symbols might be wrapped inside their outer
// symbol.
// XCOFF symbol table needs to know the size of
// these outer symbols.
- xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
+ xcoffUpdateOuterSize2(ctxt, state.datsize-symnStartValue, symn)
}
}
/* read-only ELF, Mach-O sections */
- state.allocateSingleSymSections(segro, sym.SELFROSECT, sym.SRODATA, 04)
- state.allocateSingleSymSections(segro, sym.SMACHOPLT, sym.SRODATA, 04)
+ state.allocateSingleSymSections2(segro, sym.SELFROSECT, sym.SRODATA, 04)
+ state.allocateSingleSymSections2(segro, sym.SMACHOPLT, sym.SRODATA, 04)
// 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
@@ -1902,8 +1769,8 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
/* data only written by relocations */
sect = state.allocateNamedDataSection(segrelro, genrelrosecname(""), relroReadOnly, relroSecPerm)
- ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.types", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.etypes", 0), sect)
for i, symnro := range sym.ReadOnly {
if i == 0 && symnro == sym.STYPE && ctxt.HeadType != objabi.Haix {
@@ -1917,18 +1784,19 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
symn := sym.RelROMap[symnro]
symnStartValue := state.datsize
- for _, s := range state.data[symn] {
- if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
- Errorf(s, "s.Outer (%s) in different section from s, %s != %s", s.Outer.Name, s.Outer.Sect.Name, sect.Name)
+ for _, s := range state.data2[symn] {
+ outer := ldr.OuterSym(s)
+ if s != 0 && ldr.SymSect(outer) != nil && ldr.SymSect(outer) != sect {
+ ctxt.Errorf(s, "s.Outer (%s) in different section from s, %s != %s", ldr.SymName(outer), ldr.SymSect(outer).Name, sect.Name)
}
}
- state.assignToSection(sect, symn, sym.SRODATA)
+ state.assignToSection2(sect, symn, sym.SRODATA)
if ctxt.HeadType == objabi.Haix {
// Read-only symbols might be wrapped inside their outer
// symbol.
// XCOFF symbol table needs to know the size of
// these outer symbols.
- xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
+ xcoffUpdateOuterSize2(ctxt, state.datsize-symnStartValue, symn)
}
}
@@ -1937,32 +1805,33 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
/* typelink */
sect = state.allocateNamedDataSection(seg, genrelrosecname(".typelink"), []sym.SymKind{sym.STYPELINK}, relroSecPerm)
- typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
- typelink.Sect = sect
- typelink.Type = sym.SRODATA
- state.datsize += typelink.Size
+
+ typelink := ldr.CreateSymForUpdate("runtime.typelink", 0)
+ ldr.SetSymSect(typelink.Sym(), sect)
+ typelink.SetType(sym.SRODATA)
+ state.datsize += typelink.Size()
state.checkdatsize(sym.STYPELINK)
sect.Length = uint64(state.datsize) - sect.Vaddr
/* itablink */
- sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".itablink"), sym.SITABLINK, sym.Sxxx, relroSecPerm)
- ctxt.Syms.Lookup("runtime.itablink", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.eitablink", 0).Sect = sect
+ sect = state.allocateNamedSectionAndAssignSyms2(seg, genrelrosecname(".itablink"), sym.SITABLINK, sym.Sxxx, relroSecPerm)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.itablink", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.eitablink", 0), sect)
if ctxt.HeadType == objabi.Haix {
// Store .itablink size because its symbols are wrapped
// under an outer symbol: runtime.itablink.
- xcoffUpdateOuterSize(ctxt, int64(sect.Length), sym.SITABLINK)
+ xcoffUpdateOuterSize2(ctxt, int64(sect.Length), sym.SITABLINK)
}
/* gosymtab */
- sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".gosymtab"), sym.SSYMTAB, sym.SRODATA, relroSecPerm)
- ctxt.Syms.Lookup("runtime.symtab", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.esymtab", 0).Sect = sect
+ sect = state.allocateNamedSectionAndAssignSyms2(seg, genrelrosecname(".gosymtab"), sym.SSYMTAB, sym.SRODATA, relroSecPerm)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.symtab", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.esymtab", 0), sect)
/* gopclntab */
- sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".gopclntab"), sym.SPCLNTAB, sym.SRODATA, relroSecPerm)
- ctxt.Syms.Lookup("runtime.pclntab", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.epclntab", 0).Sect = sect
+ sect = state.allocateNamedSectionAndAssignSyms2(seg, genrelrosecname(".gopclntab"), sym.SPCLNTAB, sym.SRODATA, relroSecPerm)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.pclntab", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.epclntab", 0), sect)
// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
if state.datsize != int64(uint32(state.datsize)) {
@@ -1970,37 +1839,38 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
}
for symn := sym.SELFRXSECT; symn < sym.SXREF; symn++ {
- ctxt.datap = append(ctxt.datap, state.data[symn]...)
+ ctxt.datap2 = append(ctxt.datap2, state.data2[symn]...)
}
}
// allocateDwarfSections allocates sym.Section objects for DWARF
// symbols, and assigns symbols to sections.
-func (state *dodataState) allocateDwarfSections(ctxt *Link) {
+func (state *dodataState) allocateDwarfSections2(ctxt *Link) {
- alignOne := func(datsize int64, s *sym.Symbol) int64 { return datsize }
+ alignOne := func(state *dodataState, datsize int64, s loader.Sym) int64 { return datsize }
- for i := 0; i < len(dwarfp); i++ {
+ ldr := ctxt.loader
+ for i := 0; i < len(dwarfp2); i++ {
// First the section symbol.
- s := dwarfp[i].secSym()
- sect := state.allocateNamedDataSection(&Segdwarf, s.Name, []sym.SymKind{}, 04)
- sect.Sym = s
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(state.datsize) - sect.Vaddr)
- state.datsize += s.Size
- curType := s.Type
+ s := dwarfp2[i].secSym()
+ sect := state.allocateNamedDataSection(&Segdwarf, ldr.SymName(s), []sym.SymKind{}, 04)
+ ldr.SetSymSect(s, sect)
+ sect.Sym2 = sym.LoaderSym(s)
+ curType := ldr.SymType(s)
+ state.setSymType(s, sym.SRODATA)
+ ldr.SetSymValue(s, int64(uint64(state.datsize)-sect.Vaddr))
+ state.datsize += ldr.SymSize(s)
// Then any sub-symbols for the section symbol.
- subSyms := dwarfp[i].subSyms()
- state.assignDsymsToSection(sect, subSyms, sym.SRODATA, alignOne)
+ subSyms := dwarfp2[i].subSyms()
+ state.assignDsymsToSection2(sect, subSyms, sym.SRODATA, alignOne)
for j := 0; j < len(subSyms); j++ {
s := subSyms[j]
if ctxt.HeadType == objabi.Haix && curType == sym.SDWARFLOC {
// Update the size of .debug_loc for this symbol's
// package.
- addDwsectCUSize(".debug_loc", s.File, uint64(s.Size))
+ addDwsectCUSize(".debug_loc", ldr.SymPkg(s), uint64(ldr.SymSize(s)))
}
}
sect.Length = uint64(state.datsize) - sect.Vaddr
@@ -2008,40 +1878,26 @@ func (state *dodataState) allocateDwarfSections(ctxt *Link) {
}
}
-func dodataSect(ctxt *Link, symn sym.SymKind, syms []*sym.Symbol) (result []*sym.Symbol, maxAlign int32) {
- if ctxt.HeadType == objabi.Hdarwin {
- // Some symbols may no longer belong in syms
- // due to movement in machosymorder.
- newSyms := make([]*sym.Symbol, 0, len(syms))
- for _, s := range syms {
- if s.Type == symn {
- newSyms = append(newSyms, s)
- }
- }
- syms = newSyms
- }
-
- var head, tail *sym.Symbol
- symsSort := make([]dataSortKey, 0, len(syms))
+func (state *dodataState) dodataSect2(ctxt *Link, symn sym.SymKind, syms []loader.Sym) (result []loader.Sym, maxAlign int32) {
+ var head, tail loader.Sym
+ ldr := ctxt.loader
for _, s := range syms {
- if s.Attr.OnList() {
- log.Fatalf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
+ ss := ldr.SymSize(s)
+ ds := int64(len(ldr.Data(s)))
switch {
- case s.Size < int64(len(s.P)):
- Errorf(s, "initialize bounds (%d < %d)", s.Size, len(s.P))
- case s.Size < 0:
- Errorf(s, "negative size (%d bytes)", s.Size)
- case s.Size > cutoff:
- Errorf(s, "symbol too large (%d bytes)", s.Size)
+ case ss < ds:
+ ctxt.Errorf(s, "initialize bounds (%d < %d)", ss, ds)
+ case ss < 0:
+ ctxt.Errorf(s, "negative size (%d bytes)", ss)
+ case ss > cutoff:
+ ctxt.Errorf(s, "symbol too large (%d bytes)", ss)
}
// If the usually-special section-marker symbols are being laid
// out as regular symbols, put them either at the beginning or
// end of their section.
if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- switch s.Name {
+ switch ldr.SymName(s) {
case "runtime.text", "runtime.bss", "runtime.data", "runtime.types", "runtime.rodata":
head = s
continue
@@ -2050,73 +1906,46 @@ func dodataSect(ctxt *Link, symn sym.SymKind, syms []*sym.Symbol) (result []*sym
continue
}
}
-
- key := dataSortKey{
- size: s.Size,
- name: s.Name,
- sym: s,
- }
-
- switch s.Type {
- case sym.SELFGOT:
- // For ppc64, we want to interleave the .got and .toc sections
- // from input files. Both are type sym.SELFGOT, so in that case
- // we skip size comparison and fall through to the name
- // comparison (conveniently, .got sorts before .toc).
- key.size = 0
- }
-
- symsSort = append(symsSort, key)
}
- sort.Sort(bySizeAndName(symsSort))
+ // For ppc64, we want to interleave the .got and .toc sections
+ // from input files. Both are type sym.SELFGOT, so in that case
+ // we skip size comparison and fall through to the name
+ // comparison (conveniently, .got sorts before .toc).
+ checkSize := symn != sym.SELFGOT
- off := 0
- if head != nil {
- syms[0] = head
- off++
- }
- for i, symSort := range symsSort {
- syms[i+off] = symSort.sym
- align := symalign(symSort.sym)
- if maxAlign < align {
- maxAlign = align
+ // Perform the sort.
+ sort.Slice(syms, func(i, j int) bool {
+ si, sj := syms[i], syms[j]
+ switch {
+ case si == head, sj == tail:
+ return true
+ case sj == head, si == tail:
+ return false
}
- }
- if tail != nil {
- syms[len(syms)-1] = tail
- }
-
- if ctxt.IsELF && symn == sym.SELFROSECT {
- // Make .rela and .rela.plt contiguous, the ELF ABI requires this
- // and Solaris actually cares.
- reli, plti := -1, -1
- for i, s := range syms {
- switch s.Name {
- case ".rel.plt", ".rela.plt":
- plti = i
- case ".rel", ".rela":
- reli = i
+ if checkSize {
+ isz := ldr.SymSize(si)
+ jsz := ldr.SymSize(sj)
+ if isz != jsz {
+ return isz < jsz
}
}
- if reli >= 0 && plti >= 0 && plti != reli+1 {
- var first, second int
- if plti > reli {
- first, second = reli, plti
- } else {
- first, second = plti, reli
- }
- rel, plt := syms[reli], syms[plti]
- copy(syms[first+2:], syms[first+1:second])
- syms[first+0] = rel
- syms[first+1] = plt
+ iname := ldr.SymName(si)
+ jname := ldr.SymName(sj)
+ if iname != jname {
+ return iname < jname
+ }
+ return si < sj
+ })
- // Make sure alignment doesn't introduce a gap.
- // Setting the alignment explicitly prevents
- // symalign from basing it on the size and
- // getting it wrong.
- rel.Align = int32(ctxt.Arch.RegSize)
- plt.Align = int32(ctxt.Arch.RegSize)
+ // Reap alignment.
+ for k := range syms {
+ s := syms[k]
+ if s != head && s != tail {
+ align := state.symalign2(s)
+ if maxAlign < align {
+ maxAlign = align
+ }
}
}
@@ -2462,13 +2291,14 @@ func (ctxt *Link) address() []*sym.Segment {
Segdwarf.Length = va - Segdwarf.Vaddr
}
+ ldr := ctxt.loader
var (
text = Segtext.Sections[0]
- rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect
- itablink = ctxt.Syms.Lookup("runtime.itablink", 0).Sect
- symtab = ctxt.Syms.Lookup("runtime.symtab", 0).Sect
- pclntab = ctxt.Syms.Lookup("runtime.pclntab", 0).Sect
- types = ctxt.Syms.Lookup("runtime.types", 0).Sect
+ rodata = ldr.SymSect(ldr.LookupOrCreateSym("runtime.rodata", 0))
+ itablink = ldr.SymSect(ldr.LookupOrCreateSym("runtime.itablink", 0))
+ symtab = ldr.SymSect(ldr.LookupOrCreateSym("runtime.symtab", 0))
+ pclntab = ldr.SymSect(ldr.LookupOrCreateSym("runtime.pclntab", 0))
+ types = ldr.SymSect(ldr.LookupOrCreateSym("runtime.types", 0))
)
lasttext := text
// Could be multiple .text sections
@@ -2478,38 +2308,41 @@ func (ctxt *Link) address() []*sym.Segment {
}
}
- for _, s := range ctxt.datap {
- if s.Sect != nil {
- s.Value += int64(s.Sect.Vaddr)
+ for _, s := range ctxt.datap2 {
+ if sect := ldr.SymSect(s); sect != nil {
+ ldr.AddToSymValue(s, int64(sect.Vaddr))
}
- for sub := s.Sub; sub != nil; sub = sub.Sub {
- sub.Value += s.Value
+ v := ldr.SymValue(s)
+ for sub := ldr.SubSym(s); sub != 0; sub = ldr.SubSym(sub) {
+ ldr.AddToSymValue(sub, v)
}
}
- for _, si := range dwarfp {
+ for _, si := range dwarfp2 {
for _, s := range si.syms {
- if s.Sect != nil {
- s.Value += int64(s.Sect.Vaddr)
+ if sect := ldr.SymSect(s); sect != nil {
+ ldr.AddToSymValue(s, int64(sect.Vaddr))
}
- if s.Sub != nil {
- panic(fmt.Sprintf("unexpected sub-sym for %s %s", s.Name, s.Type.String()))
+ sub := ldr.SubSym(s)
+ if sub != 0 {
+ panic(fmt.Sprintf("unexpected sub-sym for %s %s", ldr.SymName(s), ldr.SymType(s).String()))
}
- for sub := s.Sub; sub != nil; sub = sub.Sub {
- sub.Value += s.Value
+ v := ldr.SymValue(s)
+ for ; sub != 0; sub = ldr.SubSym(sub) {
+ ldr.AddToSymValue(s, v)
}
}
}
if ctxt.BuildMode == BuildModeShared {
- s := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
- sectSym := ctxt.Syms.Lookup(".note.go.abihash", 0)
- s.Sect = sectSym.Sect
- s.Value = int64(sectSym.Sect.Vaddr + 16)
+ s := ldr.LookupOrCreateSym("go.link.abihashbytes", 0)
+ sect := ldr.SymSect(ldr.LookupOrCreateSym(".note.go.abihash", 0))
+ ldr.SetSymSect(s, sect)
+ ldr.SetSymValue(s, int64(sect.Vaddr+16))
}
- ctxt.xdefine("runtime.text", sym.STEXT, int64(text.Vaddr))
- ctxt.xdefine("runtime.etext", sym.STEXT, int64(lasttext.Vaddr+lasttext.Length))
+ ctxt.xdefine2("runtime.text", sym.STEXT, int64(text.Vaddr))
+ ctxt.xdefine2("runtime.etext", sym.STEXT, int64(lasttext.Vaddr+lasttext.Length))
// If there are multiple text sections, create runtime.text.n for
// their section Vaddr, using n for index
@@ -2522,58 +2355,58 @@ func (ctxt *Link) address() []*sym.Segment {
if ctxt.HeadType != objabi.Haix || ctxt.LinkMode != LinkExternal {
// Addresses are already set on AIX with external linker
// because these symbols are part of their sections.
- ctxt.xdefine(symname, sym.STEXT, int64(sect.Vaddr))
+ ctxt.xdefine2(symname, sym.STEXT, int64(sect.Vaddr))
}
n++
}
- ctxt.xdefine("runtime.rodata", sym.SRODATA, int64(rodata.Vaddr))
- ctxt.xdefine("runtime.erodata", sym.SRODATA, int64(rodata.Vaddr+rodata.Length))
- ctxt.xdefine("runtime.types", sym.SRODATA, int64(types.Vaddr))
- ctxt.xdefine("runtime.etypes", sym.SRODATA, int64(types.Vaddr+types.Length))
- ctxt.xdefine("runtime.itablink", sym.SRODATA, int64(itablink.Vaddr))
- ctxt.xdefine("runtime.eitablink", sym.SRODATA, int64(itablink.Vaddr+itablink.Length))
+ ctxt.xdefine2("runtime.rodata", sym.SRODATA, int64(rodata.Vaddr))
+ ctxt.xdefine2("runtime.erodata", sym.SRODATA, int64(rodata.Vaddr+rodata.Length))
+ ctxt.xdefine2("runtime.types", sym.SRODATA, int64(types.Vaddr))
+ ctxt.xdefine2("runtime.etypes", sym.SRODATA, int64(types.Vaddr+types.Length))
+ ctxt.xdefine2("runtime.itablink", sym.SRODATA, int64(itablink.Vaddr))
+ ctxt.xdefine2("runtime.eitablink", sym.SRODATA, int64(itablink.Vaddr+itablink.Length))
- s := ctxt.Syms.Lookup("runtime.gcdata", 0)
- s.Attr |= sym.AttrLocal
- ctxt.xdefine("runtime.egcdata", sym.SRODATA, Symaddr(s)+s.Size)
- ctxt.Syms.Lookup("runtime.egcdata", 0).Sect = s.Sect
+ s := ldr.Lookup("runtime.gcdata", 0)
+ ldr.SetAttrLocal(s, true)
+ ctxt.xdefine2("runtime.egcdata", sym.SRODATA, ldr.SymAddr(s)+ldr.SymSize(s))
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.egcdata", 0), ldr.SymSect(s))
- s = ctxt.Syms.Lookup("runtime.gcbss", 0)
- s.Attr |= sym.AttrLocal
- ctxt.xdefine("runtime.egcbss", sym.SRODATA, Symaddr(s)+s.Size)
- ctxt.Syms.Lookup("runtime.egcbss", 0).Sect = s.Sect
+ s = ldr.LookupOrCreateSym("runtime.gcbss", 0)
+ ldr.SetAttrLocal(s, true)
+ ctxt.xdefine2("runtime.egcbss", sym.SRODATA, ldr.SymAddr(s)+ldr.SymSize(s))
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.egcbss", 0), ldr.SymSect(s))
- ctxt.xdefine("runtime.symtab", sym.SRODATA, int64(symtab.Vaddr))
- ctxt.xdefine("runtime.esymtab", sym.SRODATA, int64(symtab.Vaddr+symtab.Length))
- ctxt.xdefine("runtime.pclntab", sym.SRODATA, int64(pclntab.Vaddr))
- ctxt.xdefine("runtime.epclntab", sym.SRODATA, int64(pclntab.Vaddr+pclntab.Length))
- ctxt.xdefine("runtime.noptrdata", sym.SNOPTRDATA, int64(noptr.Vaddr))
- ctxt.xdefine("runtime.enoptrdata", sym.SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
- ctxt.xdefine("runtime.bss", sym.SBSS, int64(bss.Vaddr))
- ctxt.xdefine("runtime.ebss", sym.SBSS, int64(bss.Vaddr+bss.Length))
- ctxt.xdefine("runtime.data", sym.SDATA, int64(data.Vaddr))
- ctxt.xdefine("runtime.edata", sym.SDATA, int64(data.Vaddr+data.Length))
- ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr))
- ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
- ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
+ ctxt.xdefine2("runtime.symtab", sym.SRODATA, int64(symtab.Vaddr))
+ ctxt.xdefine2("runtime.esymtab", sym.SRODATA, int64(symtab.Vaddr+symtab.Length))
+ ctxt.xdefine2("runtime.pclntab", sym.SRODATA, int64(pclntab.Vaddr))
+ ctxt.xdefine2("runtime.epclntab", sym.SRODATA, int64(pclntab.Vaddr+pclntab.Length))
+ ctxt.xdefine2("runtime.noptrdata", sym.SNOPTRDATA, int64(noptr.Vaddr))
+ ctxt.xdefine2("runtime.enoptrdata", sym.SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
+ ctxt.xdefine2("runtime.bss", sym.SBSS, int64(bss.Vaddr))
+ ctxt.xdefine2("runtime.ebss", sym.SBSS, int64(bss.Vaddr+bss.Length))
+ ctxt.xdefine2("runtime.data", sym.SDATA, int64(data.Vaddr))
+ ctxt.xdefine2("runtime.edata", sym.SDATA, int64(data.Vaddr+data.Length))
+ ctxt.xdefine2("runtime.noptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr))
+ ctxt.xdefine2("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
+ ctxt.xdefine2("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
+ etext := ldr.Lookup("runtime.etext", 0)
+ edata := ldr.Lookup("runtime.edata", 0)
+ end := ldr.Lookup("runtime.end", 0)
+ ldr.SetSymExtname(etext, "runtime.etext")
+ ldr.SetSymExtname(edata, "runtime.edata")
+ ldr.SetSymExtname(end, "runtime.end")
+ ctxt.xdefine2("_etext", ldr.SymType(etext), ldr.SymValue(etext))
+ ctxt.xdefine2("_edata", ldr.SymType(edata), ldr.SymValue(edata))
+ ctxt.xdefine2("_end", ldr.SymType(end), ldr.SymValue(end))
+ ldr.SetSymSect(ldr.Lookup("_etext", 0), ldr.SymSect(etext))
+ ldr.SetSymSect(ldr.Lookup("_edata", 0), ldr.SymSect(edata))
+ ldr.SetSymSect(ldr.Lookup("_end", 0), ldr.SymSect(end))
}
return order
@@ -2626,10 +2459,11 @@ func (ctxt *Link) AddTramp(s *loader.SymbolBuilder) {
// compressSyms compresses syms and returns the contents of the
// compressed section. If the section would get larger, it returns nil.
-func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte {
+func compressSyms(ctxt *Link, syms []loader.Sym) []byte {
+ ldr := ctxt.loader
var total int64
for _, sym := range syms {
- total += sym.Size
+ total += ldr.SymSize(sym)
}
var buf bytes.Buffer
@@ -2649,25 +2483,22 @@ func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte {
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
+ // Symbol data 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 {
- 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)
+ P := ldr.Data(s)
+ relocs := ldr.Relocs(s)
+ if relocs.Count() != 0 {
+ relocbuf = append(relocbuf[:0], P...)
+ P = relocbuf
}
- relocsym(target, ldr, reporter, archSyms, s)
- if _, err := z.Write(s.P); err != nil {
+ relocsym(target, ldr, reporter, archSyms, s, P)
+ if _, err := z.Write(P); err != nil {
log.Fatalf("compression failed: %s", err)
}
- for i := s.Size - int64(len(s.P)); i > 0; {
+ for i := ldr.SymSize(s) - int64(len(P)); i > 0; {
b := zeros[:]
if i < int64(len(b)) {
b = b[:i]
@@ -2678,16 +2509,6 @@ func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte {
}
i -= int64(n)
}
- // Restore s.P if a temporary buffer was used. If compression
- // is not beneficial, we'll go back to use the uncompressed
- // contents, in which case we still need s.P.
- if len(s.R) != 0 && wasReadOnly {
- s.P = oldP
- s.Attr.Set(sym.AttrReadOnly, wasReadOnly)
- for i := range s.R {
- s.R[i].Done = false
- }
- }
}
if err := z.Close(); err != nil {
log.Fatalf("compression failed: %s", err)
diff --git a/src/cmd/link/internal/ld/data2.go b/src/cmd/link/internal/ld/data2.go
new file mode 100644
index 0000000000..d4503a4b0a
--- /dev/null
+++ b/src/cmd/link/internal/ld/data2.go
@@ -0,0 +1,518 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ld
+
+import (
+ "cmd/internal/objabi"
+ "cmd/link/internal/loader"
+ "cmd/link/internal/sym"
+ "fmt"
+ "log"
+ "strings"
+ "sync"
+)
+
+// Temporary dumping around for sym.Symbol version of helper
+// functions in dodata(), still being used for some archs/oses.
+// FIXME: get rid of this file when dodata() is completely
+// converted.
+
+func Addstring(s *sym.Symbol, str string) int64 {
+ if s.Type == 0 {
+ s.Type = sym.SNOPTRDATA
+ }
+ s.Attr |= sym.AttrReachable
+ r := s.Size
+ if s.Name == ".shstrtab" {
+ elfsetstring(s, str, int(r))
+ }
+ s.P = append(s.P, str...)
+ s.P = append(s.P, 0)
+ s.Size = int64(len(s.P))
+ return r
+}
+
+// symalign returns the required alignment for the given symbol s.
+func symalign(s *sym.Symbol) 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, "type..namedata.") {
+ // String data is just bytes.
+ // If we align it, we waste a lot of space to padding.
+ return min
+ }
+ align := int32(thearch.Maxalign)
+ for int64(align) > s.Size && align > min {
+ align >>= 1
+ }
+ s.Align = align
+ return align
+}
+
+func relocsym2(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *ArchSyms, s *sym.Symbol) {
+ if len(s.R) == 0 {
+ return
+ }
+ for ri := int32(0); ri < int32(len(s.R)); ri++ {
+ r := &s.R[ri]
+ if r.Done {
+ // Relocation already processed by an earlier phase.
+ continue
+ }
+ r.Done = true
+ off := r.Off
+ siz := int32(r.Siz)
+ if off < 0 || off+siz > int32(len(s.P)) {
+ rname := ""
+ if r.Sym != nil {
+ rname = r.Sym.Name
+ }
+ Errorf(s, "invalid relocation %s: %d+%d not in [%d,%d)", rname, off, siz, 0, len(s.P))
+ continue
+ }
+
+ 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 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
+ // DWARF info between the compiler and linker.
+ continue
+ }
+ } else {
+ err.errorUnresolved2(s, r)
+ continue
+ }
+ }
+
+ if r.Type >= objabi.ElfRelocOffset {
+ 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, Darwin and AIX need it always
+ 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 target.IsExternal() {
+ r.InitExt()
+ }
+
+ // TODO(mundaym): remove this special case - see issue 14218.
+ if target.IsS390X() {
+ switch r.Type {
+ case objabi.R_PCRELDBL:
+ r.InitExt()
+ r.Type = objabi.R_PCREL
+ r.Variant = sym.RV_390_DBL
+ case objabi.R_CALL:
+ r.InitExt()
+ r.Variant = sym.RV_390_DBL
+ }
+ }
+
+ var o int64
+ switch r.Type {
+ default:
+ switch siz {
+ default:
+ Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
+ case 1:
+ o = int64(s.P[off])
+ case 2:
+ o = int64(target.Arch.ByteOrder.Uint16(s.P[off:]))
+ case 4:
+ o = int64(target.Arch.ByteOrder.Uint32(s.P[off:]))
+ case 8:
+ o = int64(target.Arch.ByteOrder.Uint64(s.P[off:]))
+ }
+ 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(target.Arch, r.Type))
+ }
+ case objabi.R_TLS_LE:
+ if target.IsExternal() && target.IsElf() {
+ r.Done = false
+ if r.Sym == nil {
+ r.Sym = syms.Tlsg
+ }
+ r.Xsym = r.Sym
+ r.Xadd = r.Add
+ o = 0
+ if !target.IsAMD64() {
+ o = r.Add
+ }
+ break
+ }
+
+ 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).
+ // 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 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", target.HeadType)
+ }
+ case objabi.R_TLS_IE:
+ if target.IsExternal() && target.IsElf() {
+ r.Done = false
+ if r.Sym == nil {
+ r.Sym = syms.Tlsg
+ }
+ r.Xsym = r.Sym
+ r.Xadd = r.Add
+ o = 0
+ if !target.IsAMD64() {
+ o = r.Add
+ }
+ break
+ }
+ 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", target.Arch.Family)
+ }
+ thearch.TLSIEtoLE(s.P, int(off), int(r.Siz))
+ 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 target.IsExternal() && r.Sym.Type != sym.SCONST {
+ r.Done = false
+
+ // 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 != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
+ Errorf(s, "missing section for relocation target %s", rs.Name)
+ }
+ r.Xsym = rs
+
+ o = r.Xadd
+ if target.IsElf() {
+ if target.IsAMD64() {
+ o = 0
+ }
+ } else if target.IsDarwin() {
+ if rs.Type != sym.SHOSTOBJ {
+ o += Symaddr(rs)
+ }
+ } else if target.IsWindows() {
+ // nothing to do
+ } else if target.IsAIX() {
+ o = Symaddr(r.Sym) + r.Add
+ } else {
+ Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
+ }
+
+ break
+ }
+
+ // On AIX, a second relocation must be done by the loader,
+ // 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 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(target, ldr, s, r)
+ }
+ }
+
+ 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 && 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()
+ }
+ case objabi.R_DWARFSECREF:
+ if r.Sym.Sect == nil {
+ Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
+ }
+
+ if target.IsExternal() {
+ r.Done = false
+
+ // On most platforms, the external linker needs to adjust DWARF references
+ // as it combines DWARF sections. However, on Darwin, dsymutil does the
+ // 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 target.IsDarwin() {
+ r.Done = true
+ }
+
+ // PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
+ // for R_DWARFSECREF relocations, while R_ADDR is replaced with
+ // 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 !target.IsWindows() {
+ r.Type = objabi.R_ADDR
+ }
+
+ r.Xsym = r.Sym.Sect.Sym
+ r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
+
+ o = r.Xadd
+ if target.IsElf() && target.IsAMD64() {
+ o = 0
+ }
+ break
+ }
+ o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
+ case objabi.R_WEAKADDROFF:
+ if !r.Sym.Attr.Reachable() {
+ continue
+ }
+ fallthrough
+ case objabi.R_ADDROFF:
+ // The method offset tables using this relocation expect the offset to be relative
+ // to the start of the first text section, even if there are multiple.
+ if r.Sym.Sect.Name == ".text" {
+ o = Symaddr(r.Sym) - int64(Segtext.Sections[0].Vaddr) + r.Add
+ } else {
+ o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
+ }
+
+ case objabi.R_ADDRCUOFF:
+ // debug_range and debug_loc elements use this relocation type to get an
+ // offset from the start of the compile unit.
+ u := ldr.SymUnit(loader.Sym(r.Sym.SymIdx))
+ o = Symaddr(r.Sym) + r.Add - Symaddr(ldr.Syms[u.Textp2[0]])
+
+ // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
+ case objabi.R_GOTPCREL:
+ 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
+ r.Xsym = r.Sym
+
+ o = r.Xadd
+ o += int64(r.Siz)
+ break
+ }
+ fallthrough
+ case objabi.R_CALL, objabi.R_PCREL:
+ if target.IsExternal() && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
+ // pass through to the external linker.
+ r.Done = false
+ r.Xadd = 0
+ if target.IsElf() {
+ r.Xadd -= int64(r.Siz)
+ }
+ r.Xsym = r.Sym
+ o = 0
+ break
+ }
+ 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.
+ 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 != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
+ Errorf(s, "missing section for relocation target %s", rs.Name)
+ }
+ r.Xsym = rs
+
+ o = r.Xadd
+ if target.IsElf() {
+ if target.IsAMD64() {
+ o = 0
+ }
+ } else if target.IsDarwin() {
+ if r.Type == objabi.R_CALL {
+ if target.IsExternal() && rs.Type == sym.SDYNIMPORT {
+ if target.IsAMD64() {
+ // AMD64 dynamic relocations are relative to the end of the relocation.
+ o += int64(r.Siz)
+ }
+ } else {
+ if rs.Type != sym.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 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, target.HeadType)
+ }
+
+ break
+ }
+
+ o = 0
+ if r.Sym != nil {
+ o += Symaddr(r.Sym)
+ }
+
+ o += r.Add - (s.Value + int64(r.Off) + int64(r.Siz))
+ case objabi.R_SIZE:
+ o = r.Sym.Size + r.Add
+
+ case objabi.R_XCOFFREF:
+ if !target.IsAIX() {
+ Errorf(s, "find XCOFF R_REF on non-XCOFF files")
+ }
+ if !target.IsExternal() {
+ Errorf(s, "find XCOFF R_REF with internal linking")
+ }
+ r.Xsym = r.Sym
+ r.Xadd = r.Add
+ r.Done = false
+
+ // This isn't a real relocation so it must not update
+ // its offset value.
+ continue
+
+ case objabi.R_DWARFFILEREF:
+ // The final file index is saved in r.Add in dwarf.go:writelines.
+ o = r.Add
+ }
+
+ if target.IsPPC64() || target.IsS390X() {
+ r.InitExt()
+ if r.Variant != sym.RV_NONE {
+ o = thearch.Archrelocvariant(target, syms, r, s, o)
+ }
+ }
+
+ if false {
+ nam := "<nil>"
+ var addr int64
+ if r.Sym != nil {
+ nam = r.Sym.Name
+ addr = Symaddr(r.Sym)
+ }
+ xnam := "<nil>"
+ 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(target.Arch, r.Type), r.Variant, o)
+ }
+ switch siz {
+ default:
+ Errorf(s, "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)) {
+ Errorf(s, "relocation address for %s is too big: %#x", r.Sym.Name, o)
+ }
+ i16 := int16(o)
+ 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)) {
+ Errorf(s, "pc-relative relocation address for %s is too big: %#x", r.Sym.Name, o)
+ }
+ } else {
+ if o != int64(int32(o)) && o != int64(uint32(o)) {
+ Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", r.Sym.Name, uint64(o))
+ }
+ }
+
+ fl := int32(o)
+ target.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
+ case 8:
+ target.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
+ }
+ }
+}
+
+func (ctxt *Link) reloc2() {
+ var wg sync.WaitGroup
+ target := &ctxt.Target
+ ldr := ctxt.loader
+ reporter := &ctxt.ErrorReporter
+ syms := &ctxt.ArchSyms
+ wg.Add(3)
+ go func() {
+ if !ctxt.IsWasm() { // On Wasm, text relocations are applied in Asmb2.
+ for _, s := range ctxt.Textp {
+ relocsym2(target, ldr, reporter, syms, s)
+ }
+ }
+ wg.Done()
+ }()
+ go func() {
+ for _, s := range ctxt.datap {
+ relocsym2(target, ldr, reporter, syms, s)
+ }
+ wg.Done()
+ }()
+ go func() {
+ for _, si := range dwarfp {
+ for _, s := range si.syms {
+ relocsym2(target, ldr, reporter, syms, s)
+ }
+ }
+ wg.Done()
+ }()
+ wg.Wait()
+}
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index 8e248fc982..9534464916 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -5,12 +5,9 @@
package ld
import (
- "bytes"
"cmd/internal/objabi"
"cmd/internal/sys"
- "cmd/link/internal/sym"
"debug/elf"
- "fmt"
)
// Decoding the type.* symbols. This has to be in sync with
@@ -29,23 +26,6 @@ const (
tflagExtraStar = 1 << 1
)
-func decodeReloc(s *sym.Symbol, off int32) *sym.Reloc {
- for i := range s.R {
- if s.R[i].Off == off {
- return &s.R[i]
- }
- }
- return nil
-}
-
-func decodeRelocSym(s *sym.Symbol, off int32) *sym.Symbol {
- r := decodeReloc(s, off)
- if r == nil {
- return nil
- }
- return r.Sym
-}
-
func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 {
switch sz {
case 2:
@@ -103,26 +83,6 @@ func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
return nil
}
-// Type.commonType.gc
-func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte {
- if s.Type == sym.SDYNIMPORT {
- addr := decodetypeGcprogShlib(ctxt, s.P)
- sect := findShlibSection(ctxt, s.File, addr)
- if sect != nil {
- // A gcprog is a 4-byte uint32 indicating length, followed by
- // the actual program.
- progsize := make([]byte, 4)
- sect.ReadAt(progsize, int64(addr-sect.Addr))
- progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
- sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
- return append(progsize, progbytes...)
- }
- Exitf("cannot find gcprog for %s", s.Name)
- return nil
- }
- return decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)).P
-}
-
func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
if ctxt.Arch.Family == sys.ARM64 {
return 0
@@ -130,51 +90,6 @@ func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
return decodeInuxi(ctxt.Arch, data[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
}
-func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
- if s.Type == sym.SDYNIMPORT {
- addr := decodetypeGcprogShlib(ctxt, s.P)
- ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
- sect := findShlibSection(ctxt, s.File, addr)
- if sect != nil {
- r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
- sect.ReadAt(r, int64(addr-sect.Addr))
- return r
- }
- Exitf("cannot find gcmask for %s", s.Name)
- return nil
- }
- mask := decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
- return mask.P
-}
-
-// Type.ArrayType.elem and Type.SliceType.Elem
-func decodetypeArrayElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
-}
-
-func decodetypeArrayLen(arch *sys.Arch, s *sym.Symbol) int64 {
- return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
-}
-
-// Type.PtrType.elem
-func decodetypePtrElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
-}
-
-// Type.MapType.key, elem
-func decodetypeMapKey(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
-}
-
-func decodetypeMapValue(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38
-}
-
-// Type.ChanType.elem
-func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
-}
-
// Type.FuncType.dotdotdot
func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
@@ -189,75 +104,6 @@ func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
}
-func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
- uadd := commonsize(arch) + 4
- if arch.PtrSize == 8 {
- uadd += 4
- }
- if decodetypeHasUncommon(arch, s.P) {
- uadd += uncommonSize()
- }
- return decodeRelocSym(s, int32(uadd+i*arch.PtrSize))
-}
-
-func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
- return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s.P))
-}
-
-// Type.StructType.fields.Slice::length
-func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int {
- return int(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
-}
-
-func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int {
- off := commonsize(arch) + 4*arch.PtrSize
- if decodetypeHasUncommon(arch, s.P) {
- off += uncommonSize()
- }
- off += i * structfieldSize(arch)
- return off
-}
-
-// decodetypeStr returns the contents of an rtype's str field (a nameOff).
-func decodetypeStr(arch *sys.Arch, s *sym.Symbol) string {
- str := decodetypeName(s, 4*arch.PtrSize+8)
- if s.P[2*arch.PtrSize+4]&tflagExtraStar != 0 {
- return str[1:]
- }
- return str
-}
-
-// decodetypeName decodes the name from a reflect.name.
-func decodetypeName(s *sym.Symbol, off int) string {
- r := decodeReloc(s, int32(off))
- if r == nil {
- return ""
- }
-
- data := r.Sym.P
- namelen := int(uint16(data[1])<<8 | uint16(data[2]))
- return string(data[3 : 3+namelen])
-}
-
-func decodetypeStructFieldName(arch *sys.Arch, s *sym.Symbol, i int) string {
- off := decodetypeStructFieldArrayOff(arch, s, i)
- return decodetypeName(s, off)
-}
-
-func decodetypeStructFieldType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
- off := decodetypeStructFieldArrayOff(arch, s, i)
- return decodeRelocSym(s, int32(off+arch.PtrSize))
-}
-
-func decodetypeStructFieldOffs(arch *sys.Arch, s *sym.Symbol, i int) int64 {
- return decodetypeStructFieldOffsAnon(arch, s, i) >> 1
-}
-
-func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 {
- off := decodetypeStructFieldArrayOff(arch, s, i)
- return int64(decodeInuxi(arch, s.P[off+2*arch.PtrSize:], arch.PtrSize))
-}
-
// InterfaceType.methods.length
func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
@@ -279,91 +125,3 @@ const (
kindStruct = 25
kindMask = (1 << 5) - 1
)
-
-// decodeMethodSig decodes an array of method signature information.
-// Each element of the array is size bytes. The first 4 bytes is a
-// nameOff for the method name, and the next 4 bytes is a typeOff for
-// the function type.
-//
-// Conveniently this is the layout of both runtime.method and runtime.imethod.
-func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []methodsig {
- var buf bytes.Buffer
- var methods []methodsig
- for i := 0; i < count; i++ {
- buf.WriteString(decodetypeName(s, off))
- mtypSym := decodeRelocSym(s, int32(off+4))
-
- buf.WriteRune('(')
- inCount := decodetypeFuncInCount(arch, mtypSym.P)
- for i := 0; i < inCount; i++ {
- if i > 0 {
- buf.WriteString(", ")
- }
- buf.WriteString(decodetypeFuncInType(arch, mtypSym, i).Name)
- }
- buf.WriteString(") (")
- outCount := decodetypeFuncOutCount(arch, mtypSym.P)
- for i := 0; i < outCount; i++ {
- if i > 0 {
- buf.WriteString(", ")
- }
- buf.WriteString(decodetypeFuncOutType(arch, mtypSym, i).Name)
- }
- buf.WriteRune(')')
-
- off += size
- methods = append(methods, methodsig(buf.String()))
- buf.Reset()
- }
- return methods
-}
-
-func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
- if decodetypeKind(arch, s.P)&kindMask != kindInterface {
- panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
- }
- r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize))
- if r == nil {
- return nil
- }
- if r.Sym != s {
- panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
- }
- off := int(r.Add) // array of reflect.imethod values
- numMethods := int(decodetypeIfaceMethodCount(arch, s.P))
- sizeofIMethod := 4 + 4
- return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
-}
-
-func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
- if !decodetypeHasUncommon(arch, s.P) {
- panic(fmt.Sprintf("no methods on %q", s.Name))
- }
- off := commonsize(arch) // reflect.rtype
- switch decodetypeKind(arch, s.P) & kindMask {
- case kindStruct: // reflect.structType
- off += 4 * arch.PtrSize
- case kindPtr: // reflect.ptrType
- off += arch.PtrSize
- case kindFunc: // reflect.funcType
- off += arch.PtrSize // 4 bytes, pointer aligned
- case kindSlice: // reflect.sliceType
- off += arch.PtrSize
- case kindArray: // reflect.arrayType
- off += 3 * arch.PtrSize
- case kindChan: // reflect.chanType
- off += 2 * arch.PtrSize
- case kindMap: // reflect.mapType
- off += 4*arch.PtrSize + 8
- case kindInterface: // reflect.interfaceType
- off += 3 * arch.PtrSize
- default:
- // just Sizeof(rtype)
- }
-
- mcount := int(decodeInuxi(arch, s.P[off+4:], 2))
- moff := int(decodeInuxi(arch, s.P[off+4+2+2:], 4))
- off += moff // offset to array of reflect.method values
- const sizeofMethod = 4 * 4 // sizeof reflect.method in program
- return decodeMethodSig(arch, s, off, sizeofMethod, mcount)
-}
diff --git a/src/cmd/link/internal/ld/dwarf2.go b/src/cmd/link/internal/ld/dwarf2.go
index 4bd52f5105..336122800b 100644
--- a/src/cmd/link/internal/ld/dwarf2.go
+++ b/src/cmd/link/internal/ld/dwarf2.go
@@ -101,20 +101,20 @@ func dwarfcompress(ctxt *Link) {
type compressedSect struct {
index int
compressed []byte
- syms []*sym.Symbol
+ syms []loader.Sym
}
- supported := ctxt.IsELF || ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Hdarwin
- if !ctxt.compressDWARF || !supported || ctxt.LinkMode != LinkInternal {
+ supported := ctxt.IsELF || ctxt.IsWindows() || ctxt.IsDarwin()
+ if !ctxt.compressDWARF || !supported || ctxt.IsExternal() {
return
}
var compressedCount int
resChannel := make(chan compressedSect)
- for i := range dwarfp {
- go func(resIndex int, syms []*sym.Symbol) {
+ for i := range dwarfp2 {
+ go func(resIndex int, syms []loader.Sym) {
resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms}
- }(compressedCount, dwarfp[i].syms)
+ }(compressedCount, dwarfp2[i].syms)
compressedCount++
}
res := make([]compressedSect, compressedCount)
@@ -123,46 +123,55 @@ func dwarfcompress(ctxt *Link) {
res[r.index] = r
}
- var newDwarfp []dwarfSecInfo2
+ ldr := ctxt.loader
+ var newDwarfp []dwarfSecInfo
Segdwarf.Sections = Segdwarf.Sections[:0]
for _, z := range res {
s := z.syms[0]
if z.compressed == nil {
// Compression didn't help.
- ds := dwarfSecInfo2{syms: z.syms}
+ ds := dwarfSecInfo{syms: z.syms}
newDwarfp = append(newDwarfp, ds)
- Segdwarf.Sections = append(Segdwarf.Sections, s.Sect)
+ Segdwarf.Sections = append(Segdwarf.Sections, ldr.SymSect(s))
} else {
- compressedSegName := ".zdebug_" + s.Sect.Name[len(".debug_"):]
+ compressedSegName := ".zdebug_" + ldr.SymSect(s).Name[len(".debug_"):]
sect := addsection(ctxt.loader, ctxt.Arch, &Segdwarf, compressedSegName, 04)
+ sect.Align = 1
sect.Length = uint64(len(z.compressed))
- newSym := ctxt.Syms.Lookup(compressedSegName, 0)
- newSym.P = z.compressed
- newSym.Size = int64(len(z.compressed))
- newSym.Sect = sect
- ds := dwarfSecInfo2{syms: []*sym.Symbol{newSym}}
+ newSym := ldr.CreateSymForUpdate(compressedSegName, 0)
+ newSym.SetReachable(true)
+ newSym.SetData(z.compressed)
+ newSym.SetSize(int64(len(z.compressed)))
+ ldr.SetSymSect(newSym.Sym(), sect)
+ ds := dwarfSecInfo{syms: []loader.Sym{newSym.Sym()}}
newDwarfp = append(newDwarfp, ds)
+
+ // compressed symbols are no longer needed.
+ for _, s := range z.syms {
+ ldr.SetAttrReachable(s, false)
+ }
}
}
- dwarfp = newDwarfp
+ dwarfp2 = newDwarfp
// Re-compute the locations of the compressed DWARF symbols
// and sections, since the layout of these within the file is
// based on Section.Vaddr and Symbol.Value.
pos := Segdwarf.Vaddr
var prevSect *sym.Section
- for _, si := range dwarfp {
+ for _, si := range dwarfp2 {
for _, s := range si.syms {
- s.Value = int64(pos)
- if s.Sect != prevSect {
- s.Sect.Vaddr = uint64(s.Value)
- prevSect = s.Sect
+ ldr.SetSymValue(s, int64(pos))
+ sect := ldr.SymSect(s)
+ if sect != prevSect {
+ sect.Vaddr = uint64(pos)
+ prevSect = sect
}
- if s.Sub != nil {
- log.Fatalf("%s: unexpected sub-symbols", s)
+ if ldr.SubSym(s) != 0 {
+ log.Fatalf("%s: unexpected sub-symbols", ldr.SymName(s))
}
- pos += uint64(s.Size)
- if ctxt.HeadType == objabi.Hwindows {
+ pos += uint64(ldr.SymSize(s))
+ if ctxt.IsWindows() {
pos = uint64(Rnd(int64(pos), PEFILEALIGN))
}
}
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index fa7221ffb1..3be3f99171 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -628,9 +628,9 @@ func elfwriteshdrs(out *OutBuf) uint32 {
return uint32(ehdr.shnum) * ELF32SHDRSIZE
}
-func elfsetstring(s *sym.Symbol, str string, off int) {
+func elfsetstring2(ctxt *Link, s loader.Sym, str string, off int) {
if nelfstr >= len(elfstr) {
- Errorf(s, "too many elf strings")
+ ctxt.Errorf(s, "too many elf strings")
errorexit()
}
@@ -753,8 +753,8 @@ func elfWriteDynEnt(arch *sys.Arch, s *sym.Symbol, tag int, val uint64) {
}
}
-func elfWriteDynEntSym(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol) {
- Elfwritedynentsymplus(arch, s, tag, t, 0)
+func elfWriteDynEntSym2(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
+ Elfwritedynentsymplus2(ctxt, s, tag, t, 0)
}
func Elfwritedynentsymplus(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol, add int64) {
@@ -1057,15 +1057,16 @@ havelib:
return aux
}
-func elfdynhash(ctxt *Link) {
+func elfdynhash2(ctxt *Link) {
if !ctxt.IsELF {
return
}
nsym := Nelfsym
- s := ctxt.Syms.Lookup(".hash", 0)
- s.Type = sym.SELFROSECT
- s.Attr |= sym.AttrReachable
+ ldr := ctxt.loader
+ s := ldr.CreateSymForUpdate(".hash", 0)
+ s.SetType(sym.SELFROSECT)
+ s.SetReachable(true)
i := nsym
nbucket := 1
@@ -1079,21 +1080,19 @@ func elfdynhash(ctxt *Link) {
chain := make([]uint32, nsym)
buckets := make([]uint32, nbucket)
- for _, sy := range ctxt.Syms.Allsym {
- if sy.Dynid <= 0 {
- continue
- }
+ for _, sy := range ldr.DynidSyms() {
- if sy.Dynimpvers() != "" {
- need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib(), sy.Dynimpvers())
+ dynid := ldr.SymDynid(sy)
+ if ldr.SymDynimpvers(sy) != "" {
+ need[dynid] = addelflib(&needlib, ldr.SymDynimplib(sy), ldr.SymDynimpvers(sy))
}
- name := sy.Extname()
+ name := ldr.SymExtname(sy)
hc := elfhash(name)
b := hc % uint32(nbucket)
- chain[sy.Dynid] = buckets[b]
- buckets[b] = uint32(sy.Dynid)
+ chain[dynid] = buckets[b]
+ buckets[b] = uint32(dynid)
}
// s390x (ELF64) hash table entries are 8 bytes
@@ -1117,10 +1116,11 @@ func elfdynhash(ctxt *Link) {
}
}
- // version symbols
- dynstr := ctxt.Syms.Lookup(".dynstr", 0)
+ dynstr := ldr.CreateSymForUpdate(".dynstr", 0)
- s = ctxt.Syms.Lookup(".gnu.version_r", 0)
+ // version symbols
+ gnuVersionR := ldr.CreateSymForUpdate(".gnu.version_r", 0)
+ s = gnuVersionR
i = 2
nfile := 0
for l := needlib; l != nil; l = l.next {
@@ -1132,9 +1132,9 @@ func elfdynhash(ctxt *Link) {
for x := l.aux; x != nil; x = x.next {
j++
}
- s.AddUint16(ctxt.Arch, uint16(j)) // aux count
- s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, l.file))) // file string offset
- s.AddUint32(ctxt.Arch, 16) // offset from header to first aux
+ s.AddUint16(ctxt.Arch, uint16(j)) // aux count
+ s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(l.file))) // file string offset
+ s.AddUint32(ctxt.Arch, 16) // offset from header to first aux
if l.next != nil {
s.AddUint32(ctxt.Arch, 16+uint32(j)*16) // offset from this header to next
} else {
@@ -1146,10 +1146,10 @@ func elfdynhash(ctxt *Link) {
i++
// aux struct
- s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash
- s.AddUint16(ctxt.Arch, 0) // flags
- s.AddUint16(ctxt.Arch, uint16(x.num)) // other - index we refer to this by
- s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, x.vers))) // version string offset
+ s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash
+ s.AddUint16(ctxt.Arch, 0) // flags
+ s.AddUint16(ctxt.Arch, uint16(x.num)) // other - index we refer to this by
+ s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(x.vers))) // version string offset
if x.next != nil {
s.AddUint32(ctxt.Arch, 16) // offset from this aux to next
} else {
@@ -1159,7 +1159,8 @@ func elfdynhash(ctxt *Link) {
}
// version references
- s = ctxt.Syms.Lookup(".gnu.version", 0)
+ gnuVersion := ldr.CreateSymForUpdate(".gnu.version", 0)
+ s = gnuVersion
for i := 0; i < nsym; i++ {
if i == 0 {
@@ -1171,26 +1172,26 @@ func elfdynhash(ctxt *Link) {
}
}
- s = ctxt.Syms.Lookup(".dynamic", 0)
+ s = ldr.CreateSymForUpdate(".dynamic", 0)
elfverneed = nfile
if elfverneed != 0 {
- elfWriteDynEntSym(ctxt.Arch, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
- elfWriteDynEnt(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
- elfWriteDynEntSym(ctxt.Arch, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
+ elfWriteDynEntSym2(ctxt, s, DT_VERNEED, gnuVersionR.Sym())
+ Elfwritedynent2(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
+ elfWriteDynEntSym2(ctxt, s, DT_VERSYM, gnuVersion.Sym())
}
- sy := ctxt.Syms.Lookup(elfRelType+".plt", 0)
- if sy.Size > 0 {
+ sy := ldr.CreateSymForUpdate(elfRelType+".plt", 0)
+ if sy.Size() > 0 {
if elfRelType == ".rela" {
- elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_RELA)
+ Elfwritedynent2(ctxt.Arch, s, DT_PLTREL, DT_RELA)
} else {
- elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_REL)
+ Elfwritedynent2(ctxt.Arch, s, DT_PLTREL, DT_REL)
}
- elfWriteDynEntSymSize(ctxt.Arch, s, DT_PLTRELSZ, sy)
- elfWriteDynEntSym(ctxt.Arch, s, DT_JMPREL, sy)
+ elfwritedynentsymsize2(ctxt, s, DT_PLTRELSZ, sy.Sym())
+ elfWriteDynEntSym2(ctxt, s, DT_JMPREL, sy.Sym())
}
- elfWriteDynEnt(ctxt.Arch, s, DT_NULL, 0)
+ Elfwritedynent2(ctxt.Arch, s, DT_NULL, 0)
}
func elfphload(seg *sym.Segment) *ElfPhdr {
@@ -1410,7 +1411,8 @@ func elfrelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
Errorf(s, "missing xsym in relocation %#v %#v", r.Sym.Name, s)
continue
}
- if r.Xsym.ElfsymForReloc() == 0 {
+ esr := ElfSymForReloc(ctxt, r.Xsym)
+ if esr == 0 {
Errorf(s, "reloc %d (%s) to non-elf symbol %s (outer=%s) %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Name, r.Xsym.Name, r.Sym.Type, r.Sym.Type)
}
if !r.Xsym.Attr.Reachable() {
@@ -2342,93 +2344,6 @@ elfobj:
}
}
-func elfadddynsym(target *Target, syms *ArchSyms, s *sym.Symbol) {
- if elf64 {
- s.Dynid = int32(Nelfsym)
- Nelfsym++
-
- d := syms.DynSym
-
- name := s.Extname()
- d.AddUint32(target.Arch, uint32(Addstring(syms.DynStr, name)))
-
- /* type */
- t := STB_GLOBAL << 4
-
- if s.Attr.CgoExport() && s.Type == sym.STEXT {
- t |= STT_FUNC
- } else {
- t |= STT_OBJECT
- }
- d.AddUint8(uint8(t))
-
- /* reserved */
- d.AddUint8(0)
-
- /* section where symbol is defined */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint16(target.Arch, SHN_UNDEF)
- } else {
- d.AddUint16(target.Arch, 1)
- }
-
- /* value */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint64(target.Arch, 0)
- } else {
- d.AddAddr(target.Arch, s)
- }
-
- /* size of object */
- d.AddUint64(target.Arch, uint64(s.Size))
-
- if target.Arch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib() != "" && !seenlib[s.Dynimplib()] {
- elfWriteDynEnt(target.Arch, syms.Dynamic, DT_NEEDED, uint64(Addstring(syms.DynStr, s.Dynimplib())))
- }
- } else {
- s.Dynid = int32(Nelfsym)
- Nelfsym++
-
- d := syms.DynSym
-
- /* name */
- name := s.Extname()
-
- d.AddUint32(target.Arch, uint32(Addstring(syms.DynStr, name)))
-
- /* value */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint32(target.Arch, 0)
- } else {
- d.AddAddr(target.Arch, s)
- }
-
- /* size of object */
- d.AddUint32(target.Arch, uint32(s.Size))
-
- /* type */
- t := STB_GLOBAL << 4
-
- // TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
- if target.Arch.Family == sys.I386 && s.Attr.CgoExport() && s.Type == sym.STEXT {
- t |= STT_FUNC
- } else if target.Arch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type == sym.STEXT {
- t |= STT_FUNC
- } else {
- t |= STT_OBJECT
- }
- d.AddUint8(uint8(t))
- d.AddUint8(0)
-
- /* shndx */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint16(target.Arch, SHN_UNDEF)
- } else {
- d.AddUint16(target.Arch, 1)
- }
- }
-}
-
func elfadddynsym2(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
ldr.SetSymDynid(s, int32(Nelfsym))
Nelfsym++
diff --git a/src/cmd/link/internal/ld/elf2.go b/src/cmd/link/internal/ld/elf2.go
new file mode 100644
index 0000000000..3f7d72b310
--- /dev/null
+++ b/src/cmd/link/internal/ld/elf2.go
@@ -0,0 +1,25 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ld
+
+import (
+ "cmd/link/internal/sym"
+)
+
+// Temporary dumping around for sym.Symbol version of helper
+// functions in elf.go, still being used for some archs/oses.
+// FIXME: get rid of this file when dodata() is completely
+// converted and the sym.Symbol functions are not needed.
+
+func elfsetstring(s *sym.Symbol, str string, off int) {
+ if nelfstr >= len(elfstr) {
+ Errorf(s, "too many elf strings")
+ errorexit()
+ }
+
+ elfstr[nelfstr].s = str
+ elfstr[nelfstr].off = off
+ nelfstr++
+}
diff --git a/src/cmd/link/internal/ld/errors.go b/src/cmd/link/internal/ld/errors.go
index e66c518b85..c2c191d058 100644
--- a/src/cmd/link/internal/ld/errors.go
+++ b/src/cmd/link/internal/ld/errors.go
@@ -7,12 +7,15 @@ import (
"cmd/internal/obj"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
- "fmt"
- "os"
"sync"
)
type unresolvedSymKey struct {
+ from loader.Sym // Symbol that referenced unresolved "to"
+ to loader.Sym // Unresolved symbol referenced by "from"
+}
+
+type unresolvedSymKey2 struct {
from *sym.Symbol // Symbol that referenced unresolved "to"
to *sym.Symbol // Unresolved symbol referenced by "from"
}
@@ -22,22 +25,62 @@ type symNameFn func(s loader.Sym) string
// ErrorReporter is used to make error reporting thread safe.
type ErrorReporter struct {
+ loader.ErrorReporter
unresOnce sync.Once
unresSyms map[unresolvedSymKey]bool
+ unresSyms2 map[unresolvedSymKey2]bool
unresMutex sync.Mutex
lookup lookupFn
SymName symNameFn
}
-// errorUnresolved prints unresolved symbol error for r.Sym that is referenced from s.
-func (reporter *ErrorReporter) errorUnresolved(s *sym.Symbol, r *sym.Reloc) {
+// errorUnresolved prints unresolved symbol error for rs that is referenced from s.
+func (reporter *ErrorReporter) errorUnresolved(ldr *loader.Loader, s, rs loader.Sym) {
reporter.unresOnce.Do(func() { reporter.unresSyms = make(map[unresolvedSymKey]bool) })
- k := unresolvedSymKey{from: s, to: r.Sym}
+ k := unresolvedSymKey{from: s, to: rs}
reporter.unresMutex.Lock()
defer reporter.unresMutex.Unlock()
if !reporter.unresSyms[k] {
reporter.unresSyms[k] = true
+ name := ldr.SymName(rs)
+
+ // Try to find symbol under another ABI.
+ var reqABI, haveABI obj.ABI
+ haveABI = ^obj.ABI(0)
+ reqABI, ok := sym.VersionToABI(ldr.SymVersion(rs))
+ if ok {
+ for abi := obj.ABI(0); abi < obj.ABICount; abi++ {
+ v := sym.ABIToVersion(abi)
+ if v == -1 {
+ continue
+ }
+ if rs1 := ldr.Lookup(name, v); rs1 != 0 && ldr.SymType(rs1) != sym.Sxxx && ldr.SymType(rs1) != sym.SXREF {
+ haveABI = abi
+ }
+ }
+ }
+
+ // Give a special error message for main symbol (see #24809).
+ if name == "main.main" {
+ reporter.Errorf(s, "function main is undeclared in the main package")
+ } else if haveABI != ^obj.ABI(0) {
+ reporter.Errorf(s, "relocation target %s not defined for %s (but is defined for %s)", name, reqABI, haveABI)
+ } else {
+ reporter.Errorf(s, "relocation target %s not defined", name)
+ }
+ }
+}
+
+// errorUnresolved2 prints unresolved symbol error for r.Sym that is referenced from s.
+func (reporter *ErrorReporter) errorUnresolved2(s *sym.Symbol, r *sym.Reloc) {
+ reporter.unresOnce.Do(func() { reporter.unresSyms2 = make(map[unresolvedSymKey2]bool) })
+
+ k := unresolvedSymKey2{from: s, to: r.Sym}
+ reporter.unresMutex.Lock()
+ defer reporter.unresMutex.Unlock()
+ if !reporter.unresSyms2[k] {
+ reporter.unresSyms2[k] = true
// Try to find symbol under another ABI.
var reqABI, haveABI obj.ABI
@@ -65,23 +108,3 @@ func (reporter *ErrorReporter) errorUnresolved(s *sym.Symbol, r *sym.Reloc) {
}
}
}
-
-// Errorf method logs an error message.
-//
-// If more than 20 errors have been printed, exit with an error.
-//
-// Logging an error means that on exit cmd/link will delete any
-// output file and return a non-zero error code.
-// TODO: consolidate the various different versions of Errorf (
-// function, Link method, and ErrorReporter method).
-func (reporter *ErrorReporter) Errorf(s loader.Sym, format string, args ...interface{}) {
- if s != 0 && reporter.SymName != nil {
- sn := reporter.SymName(s)
- format = sn + ": " + format
- } else {
- format = fmt.Sprintf("sym %d: %s", s, format)
- }
- format += "\n"
- fmt.Fprintf(os.Stderr, format, args...)
- afterErrorAction()
-}
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index 8474cefa39..9a63a3a0bb 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -331,7 +331,7 @@ func adddynlib(ctxt *Link, lib string) {
}
}
-func Adddynsym2(ldr *loader.Loader, reporter *ErrorReporter, target *Target, syms *ArchSyms, s loader.Sym) {
+func Adddynsym2(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
if ldr.SymDynid(s) >= 0 || target.LinkMode == LinkExternal {
return
}
@@ -339,27 +339,11 @@ func Adddynsym2(ldr *loader.Loader, reporter *ErrorReporter, target *Target, sym
if target.IsELF {
elfadddynsym2(ldr, target, syms, s)
} else if target.HeadType == objabi.Hdarwin {
- reporter.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s))
+ ldr.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s))
} else if target.HeadType == objabi.Hwindows {
// already taken care of
} else {
- reporter.Errorf(s, "adddynsym: unsupported binary format")
- }
-}
-
-func Adddynsym(target *Target, syms *ArchSyms, s *sym.Symbol) {
- if s.Dynid >= 0 || target.LinkMode == LinkExternal {
- return
- }
-
- if target.IsELF {
- elfadddynsym(target, syms, s)
- } else if target.HeadType == objabi.Hdarwin {
- Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname())
- } else if target.HeadType == objabi.Hwindows {
- // already taken care of
- } else {
- Errorf(s, "adddynsym: unsupported binary format")
+ ldr.Errorf(s, "adddynsym: unsupported binary format")
}
}
@@ -425,7 +409,7 @@ func (ctxt *Link) addexport() {
}
for _, exp := range ctxt.dynexp2 {
- Adddynsym2(ctxt.loader, &ctxt.ErrorReporter, &ctxt.Target, &ctxt.ArchSyms, exp)
+ Adddynsym2(ctxt.loader, &ctxt.Target, &ctxt.ArchSyms, exp)
}
for _, lib := range dynlib {
adddynlib(ctxt, lib)
diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go
index 85038f3ad2..c913a519a1 100644
--- a/src/cmd/link/internal/ld/ld.go
+++ b/src/cmd/link/internal/ld/ld.go
@@ -32,6 +32,7 @@
package ld
import (
+ "cmd/internal/goobj2"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"io/ioutil"
@@ -155,11 +156,12 @@ func findlib(ctxt *Link, lib string) (string, bool) {
return pname, isshlib
}
-func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
+func addlib(ctxt *Link, src, obj, lib string, fingerprint goobj2.FingerprintType) *sym.Library {
pkg := pkgname(ctxt, lib)
// already loaded?
if l := ctxt.LibraryByPkg[pkg]; l != nil {
+ checkFingerprint(l, l.Fingerprint, src, fingerprint)
return l
}
@@ -170,9 +172,9 @@ func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
}
if isshlib {
- return addlibpath(ctxt, src, obj, "", pkg, pname)
+ return addlibpath(ctxt, src, obj, "", pkg, pname, fingerprint)
}
- return addlibpath(ctxt, src, obj, pname, pkg, "")
+ return addlibpath(ctxt, src, obj, pname, pkg, "", fingerprint)
}
/*
@@ -182,14 +184,16 @@ func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
* pkg: package import path, e.g. container/vector
* shlib: path to shared library, or .shlibname file holding path
+ * fingerprint: if not 0, expected fingerprint for import from srcref
+ * fingerprint is 0 if the library is not imported (e.g. main)
*/
-func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlib string) *sym.Library {
+func addlibpath(ctxt *Link, srcref, objref, file, pkg, shlib string, fingerprint goobj2.FingerprintType) *sym.Library {
if l := ctxt.LibraryByPkg[pkg]; l != nil {
return l
}
if ctxt.Debugvlog > 1 {
- ctxt.Logf("addlibpath: srcref: %s objref: %s file: %s pkg: %s shlib: %s\n", srcref, objref, file, pkg, shlib)
+ ctxt.Logf("addlibpath: srcref: %s objref: %s file: %s pkg: %s shlib: %s fingerprint: %x\n", srcref, objref, file, pkg, shlib, fingerprint)
}
l := &sym.Library{}
@@ -199,6 +203,7 @@ func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg strin
l.Srcref = srcref
l.File = file
l.Pkg = pkg
+ l.Fingerprint = fingerprint
if shlib != "" {
if strings.HasSuffix(shlib, ".shlibname") {
data, err := ioutil.ReadFile(shlib)
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 429c2641fb..618faf2233 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -33,6 +33,7 @@ package ld
import (
"bytes"
"cmd/internal/bio"
+ "cmd/internal/goobj2"
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
@@ -232,6 +233,7 @@ type Arch struct {
Dragonflydynld string
Solarisdynld string
Adddynrel func(*Target, *loader.Loader, *ArchSyms, *sym.Symbol, *sym.Reloc) bool
+ Adddynrel2 func(*Target, *loader.Loader, *ArchSyms, loader.Sym, *loader.Reloc2, int) bool
Archinit func(*Link)
// Archreloc is an arch-specific hook that assists in
// relocation processing (invoked by 'relocsym'); it handles
@@ -263,7 +265,7 @@ type Arch struct {
// file. Typically, Asmb writes most of the content (sections and
// segments), for which we have computed the size and offset. Asmb2
// writes the rest.
- Asmb func(*Link)
+ Asmb func(*Link, *loader.Loader)
Asmb2 func(*Link)
Elfreloc1 func(*Link, *sym.Reloc, int64) bool
@@ -280,7 +282,7 @@ type Arch struct {
// This is possible when a TLS IE relocation refers to a local
// symbol in an executable, which is typical when internally
// linking PIE binaries.
- TLSIEtoLE func(s *sym.Symbol, off, size int)
+ TLSIEtoLE func(P []byte, off, size int)
// optional override for assignAddress
AssignAddress func(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64)
@@ -424,14 +426,15 @@ func errorexit() {
}
func loadinternal(ctxt *Link, name string) *sym.Library {
+ zerofp := goobj2.FingerprintType{}
if ctxt.linkShared && ctxt.PackageShlib != nil {
if shlib := ctxt.PackageShlib[name]; shlib != "" {
- return addlibpath(ctxt, "internal", "internal", "", name, shlib)
+ return addlibpath(ctxt, "internal", "internal", "", name, shlib, zerofp)
}
}
if ctxt.PackageFile != nil {
if pname := ctxt.PackageFile[name]; pname != "" {
- return addlibpath(ctxt, "internal", "internal", pname, name, "")
+ return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
}
ctxt.Logf("loadinternal: cannot find %s\n", name)
return nil
@@ -444,7 +447,7 @@ func loadinternal(ctxt *Link, name string) *sym.Library {
ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
}
if _, err := os.Stat(shlibname); err == nil {
- return addlibpath(ctxt, "internal", "internal", "", name, shlibname)
+ return addlibpath(ctxt, "internal", "internal", "", name, shlibname, zerofp)
}
}
pname := filepath.Join(libdir, name+".a")
@@ -452,7 +455,7 @@ func loadinternal(ctxt *Link, name string) *sym.Library {
ctxt.Logf("searching for %s.a in %s\n", name, pname)
}
if _, err := os.Stat(pname); err == nil {
- return addlibpath(ctxt, "internal", "internal", pname, name, "")
+ return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
}
}
@@ -503,7 +506,7 @@ func (ctxt *Link) loadlib() {
default:
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
}
- ctxt.loader = loader.NewLoader(flags, elfsetstring)
+ ctxt.loader = loader.NewLoader(flags, elfsetstring, &ctxt.ErrorReporter.ErrorReporter)
ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
return ctxt.loader.SymName(s)
}
@@ -1984,11 +1987,29 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
f.MustSeek(import1, 0)
- ctxt.loader.Preload(ctxt.Syms, f, lib, unit, eof-f.Offset(), 0)
+ fingerprint := ctxt.loader.Preload(ctxt.Syms, f, lib, unit, eof-f.Offset())
+ if !fingerprint.IsZero() { // Assembly objects don't have fingerprints. Ignore them.
+ // Check fingerprint, to ensure the importing and imported packages
+ // have consistent view of symbol indices.
+ // Normally the go command should ensure this. But in case something
+ // goes wrong, it could lead to obscure bugs like run-time crash.
+ // Check it here to be sure.
+ if lib.Fingerprint.IsZero() { // Not yet imported. Update its fingerprint.
+ lib.Fingerprint = fingerprint
+ }
+ checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
+ }
+
addImports(ctxt, lib, pn)
return nil
}
+func checkFingerprint(lib *sym.Library, libfp goobj2.FingerprintType, src string, srcfp goobj2.FingerprintType) {
+ if libfp != srcfp {
+ Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
+ }
+}
+
func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
data := make([]byte, sym.Size)
sect := f.Sections[sym.Section]
@@ -2472,7 +2493,7 @@ const (
DeletedAutoSym = 'x'
)
-func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int64, *sym.Symbol)) {
+func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int64)) {
// These symbols won't show up in the first loop below because we
// skip sym.STEXT symbols. Normal sym.STEXT symbols are emitted by walking textp.
s := ctxt.Syms.Lookup("runtime.text", 0)
@@ -2482,7 +2503,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
// on AIX with external linker.
// See data.go:/textaddress
if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- put(ctxt, s, s.Name, TextSym, s.Value, nil)
+ put(ctxt, s, s.Name, TextSym, s.Value)
}
}
@@ -2503,7 +2524,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
break
}
if s.Type == sym.STEXT {
- put(ctxt, s, s.Name, TextSym, s.Value, nil)
+ put(ctxt, s, s.Name, TextSym, s.Value)
}
n++
}
@@ -2515,7 +2536,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
// on AIX with external linker.
// See data.go:/textaddress
if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- put(ctxt, s, s.Name, TextSym, s.Value, nil)
+ put(ctxt, s, s.Name, TextSym, s.Value)
}
}
@@ -2534,7 +2555,10 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
return true
}
- for _, s := range ctxt.Syms.Allsym {
+ for _, s := range ctxt.loader.Syms {
+ if s == nil {
+ continue
+ }
if !shouldBeInSymbolTable(s) {
continue
}
@@ -2565,7 +2589,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
if !s.Attr.Reachable() {
continue
}
- put(ctxt, s, s.Name, DataSym, Symaddr(s), s.Gotype)
+ put(ctxt, s, s.Name, DataSym, Symaddr(s))
case sym.SBSS, sym.SNOPTRBSS, sym.SLIBFUZZER_EXTRA_COUNTER:
if !s.Attr.Reachable() {
@@ -2574,11 +2598,11 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
if len(s.P) > 0 {
Errorf(s, "should not be bss (size=%d type=%v special=%v)", len(s.P), s.Type, s.Attr.Special())
}
- put(ctxt, s, s.Name, BSSSym, Symaddr(s), s.Gotype)
+ put(ctxt, s, s.Name, BSSSym, Symaddr(s))
case sym.SUNDEFEXT:
if ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Haix || ctxt.IsELF {
- put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
+ put(ctxt, s, s.Name, UndefinedSym, s.Value)
}
case sym.SHOSTOBJ:
@@ -2586,24 +2610,24 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
continue
}
if ctxt.HeadType == objabi.Hwindows || ctxt.IsELF {
- put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
+ put(ctxt, s, s.Name, UndefinedSym, s.Value)
}
case sym.SDYNIMPORT:
if !s.Attr.Reachable() {
continue
}
- put(ctxt, s, s.Extname(), UndefinedSym, 0, nil)
+ put(ctxt, s, s.Extname(), UndefinedSym, 0)
case sym.STLSBSS:
if ctxt.LinkMode == LinkExternal {
- put(ctxt, s, s.Name, TLSSym, Symaddr(s), s.Gotype)
+ put(ctxt, s, s.Name, TLSSym, Symaddr(s))
}
}
}
for _, s := range ctxt.Textp {
- put(ctxt, s, s.Name, TextSym, s.Value, s.Gotype)
+ put(ctxt, s, s.Name, TextSym, s.Value)
}
if ctxt.Debugvlog != 0 || *flagN {
@@ -2800,10 +2824,9 @@ func addToTextp(ctxt *Link) {
ctxt.Textp = textp
}
-func (ctxt *Link) loadlibfull() {
-
+func (ctxt *Link) loadlibfull(symGroupType []sym.SymKind, needReloc bool) {
// Load full symbol contents, resolve indexed references.
- ctxt.loader.LoadFull(ctxt.Arch, ctxt.Syms)
+ ctxt.loader.LoadFull(ctxt.Arch, ctxt.Syms, needReloc)
// Convert ctxt.Moduledata2 to ctxt.Moduledata, etc
if ctxt.Moduledata2 != 0 {
@@ -2841,12 +2864,41 @@ func (ctxt *Link) loadlibfull() {
dwarfp = append(dwarfp, dwarfSecInfo2{syms: syms})
}
+ // Populate datap from datap2
+ ctxt.datap = make([]*sym.Symbol, len(ctxt.datap2))
+ for i, symIdx := range ctxt.datap2 {
+ s := ctxt.loader.Syms[symIdx]
+ if s == nil {
+ panic(fmt.Sprintf("nil sym for datap2 element %d", symIdx))
+ }
+ ctxt.datap[i] = s
+ }
+
+ // Populate the sym.Section 'Sym' fields based on their 'Sym2'
+ // fields.
+ allSegments := []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf}
+ for _, seg := range allSegments {
+ for _, sect := range seg.Sections {
+ if sect.Sym2 != 0 {
+ s := ctxt.loader.Syms[sect.Sym2]
+ if s == nil {
+ panic(fmt.Sprintf("nil sym for sect %s sym %d", sect.Name, sect.Sym2))
+ }
+ sect.Sym = s
+ }
+ }
+ }
+
// For now, overwrite symbol type with its "group" type, as dodata
// expected. Once we converted dodata, this will probably not be
// needed.
for i, t := range symGroupType {
if t != sym.Sxxx {
- ctxt.loader.Syms[i].Type = t
+ s := ctxt.loader.Syms[i]
+ if s == nil {
+ continue // in dwarfcompress we drop compressed DWARF symbols
+ }
+ s.Type = t
}
}
symGroupType = nil
@@ -2858,8 +2910,29 @@ func (ctxt *Link) loadlibfull() {
}
}
+func symPkg(ctxt *Link, s *sym.Symbol) string {
+ if s == nil {
+ return ""
+ }
+ return ctxt.loader.SymPkg(loader.Sym(s.SymIdx))
+}
+
+func ElfSymForReloc(ctxt *Link, s *sym.Symbol) int32 {
+ // If putelfsym created a local version of this symbol, use that in all
+ // relocations.
+ les := ctxt.loader.SymLocalElfSym(loader.Sym(s.SymIdx))
+ if les != 0 {
+ return les
+ } else {
+ return ctxt.loader.SymElfSym(loader.Sym(s.SymIdx))
+ }
+}
+
func (ctxt *Link) dumpsyms() {
- for _, s := range ctxt.Syms.Allsym {
+ for _, s := range ctxt.loader.Syms {
+ if s == nil {
+ continue
+ }
fmt.Printf("%s %s reachable=%v onlist=%v outer=%v sub=%v\n", s, s.Type, s.Attr.Reachable(), s.Attr.OnList(), s.Outer, s.Sub)
for i := range s.R {
fmt.Println("\t", s.R[i].Type, s.R[i].Sym)
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index f6441a5b65..84b1f9121e 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -66,7 +66,6 @@ type Link struct {
compressDWARF bool
- Tlsg2 loader.Sym
Libdir []string
Library []*sym.Library
LibraryByPkg map[string]*sym.Library
@@ -92,6 +91,7 @@ type Link struct {
cgo_export_dynamic map[string]bool
datap []*sym.Symbol
+ datap2 []loader.Sym
dynexp2 []loader.Sym
// Elf symtab variables.
@@ -129,11 +129,11 @@ func (ctxt *Link) Logf(format string, args ...interface{}) {
func addImports(ctxt *Link, l *sym.Library, pn string) {
pkg := objabi.PathToPrefix(l.Pkg)
- for _, importStr := range l.ImportStrings {
- lib := addlib(ctxt, pkg, pn, importStr)
+ for _, imp := range l.Autolib {
+ lib := addlib(ctxt, pkg, pn, imp.Pkg, imp.Fingerprint)
if lib != nil {
l.Imports = append(l.Imports, lib)
}
}
- l.ImportStrings = nil
+ l.Autolib = nil
}
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index baa1f4094a..4dc7f819eb 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -8,6 +8,7 @@ import (
"bytes"
"cmd/internal/objabi"
"cmd/internal/sys"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/macho"
"encoding/binary"
@@ -216,7 +217,7 @@ const (
var nkind [NumSymKind]int
-var sortsym []*sym.Symbol
+var sortsym []loader.Sym
var nsortsym int
@@ -743,106 +744,125 @@ func Asmbmacho(ctxt *Link) {
}
}
-func symkind(s *sym.Symbol) int {
- if s.Type == sym.SDYNIMPORT {
+func symkind(ldr *loader.Loader, s loader.Sym) int {
+ if ldr.SymType(s) == sym.SDYNIMPORT {
return SymKindUndef
}
- if s.Attr.CgoExport() {
+ if ldr.AttrCgoExport(s) {
return SymKindExtdef
}
return SymKindLocal
}
-func addsym(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) {
- if s == nil {
- return
- }
-
- switch type_ {
- default:
- return
+func collectmachosyms(ctxt *Link) {
+ ldr := ctxt.loader
- case DataSym, BSSSym, TextSym:
- break
+ addsym := func(s loader.Sym) {
+ sortsym = append(sortsym, s)
+ nkind[symkind(ldr, s)]++
}
- if sortsym != nil {
- sortsym[nsortsym] = s
- nkind[symkind(s)]++
+ // Add special runtime.text and runtime.etext symbols.
+ // We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
+ // See data.go:/textaddress
+ if !ctxt.DynlinkingGo() {
+ s := ldr.Lookup("runtime.text", 0)
+ if ldr.SymType(s) == sym.STEXT {
+ addsym(s)
+ }
+ s = ldr.Lookup("runtime.etext", 0)
+ if ldr.SymType(s) == sym.STEXT {
+ addsym(s)
+ }
}
- nsortsym++
-}
-
-type machoscmp []*sym.Symbol
-
-func (x machoscmp) Len() int {
- return len(x)
-}
-
-func (x machoscmp) Swap(i, j int) {
- x[i], x[j] = x[j], x[i]
-}
-
-func (x machoscmp) Less(i, j int) bool {
- s1 := x[i]
- s2 := x[j]
+ // Add text symbols.
+ for _, s := range ctxt.Textp2 {
+ addsym(s)
+ }
- k1 := symkind(s1)
- k2 := symkind(s2)
- if k1 != k2 {
- return k1 < k2
+ shouldBeInSymbolTable := func(s loader.Sym) bool {
+ if ldr.AttrNotInSymbolTable(s) {
+ return false
+ }
+ name := ldr.RawSymName(s) // TODO: try not to read the name
+ if name == "" || name[0] == '.' {
+ return false
+ }
+ return true
}
- return s1.Extname() < s2.Extname()
-}
+ // Add data symbols and external references.
+ for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
+ if !ldr.AttrReachable(s) {
+ continue
+ }
+ t := ldr.SymType(s)
+ if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
+ if t == sym.STLSBSS {
+ // TLSBSS is not used on darwin. See data.go:allocateDataSections
+ continue
+ }
+ if !shouldBeInSymbolTable(s) {
+ continue
+ }
+ addsym(s)
+ }
+
+ switch t {
+ case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT, sym.SCONST:
+ addsym(s)
+ }
-func machogenasmsym(ctxt *Link) {
- genasmsym(ctxt, addsym)
- for _, s := range ctxt.Syms.Allsym {
// Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
- if s.Type == sym.SDYNIMPORT && s.Dynimplib() == "/usr/lib/libSystem.B.dylib" {
+ if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
// But only on macOS.
if machoPlatform == PLATFORM_MACOS {
- switch n := s.Extname(); n {
+ switch n := ldr.SymExtname(s); n {
case "fdopendir":
switch objabi.GOARCH {
case "amd64":
- s.SetExtname(n + "$INODE64")
+ ldr.SetSymExtname(s, n+"$INODE64")
case "386":
- s.SetExtname(n + "$INODE64$UNIX2003")
+ ldr.SetSymExtname(s, n+"$INODE64$UNIX2003")
}
case "readdir_r", "getfsstat":
switch objabi.GOARCH {
case "amd64", "386":
- s.SetExtname(n + "$INODE64")
+ ldr.SetSymExtname(s, n+"$INODE64")
}
}
}
}
-
- if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ || s.Type == sym.SUNDEFEXT {
- if s.Attr.Reachable() {
- addsym(ctxt, s, "", DataSym, 0, nil)
- }
- }
}
+
+ nsortsym = len(sortsym)
}
func machosymorder(ctxt *Link) {
+ ldr := ctxt.loader
+
// On Mac OS X Mountain Lion, we must sort exported symbols
// So we sort them here and pre-allocate dynid for them
// See https://golang.org/issue/4029
- for i := range dynexp {
- dynexp[i].Attr |= sym.AttrReachable
+ for _, s := range ctxt.dynexp2 {
+ if !ldr.AttrReachable(s) {
+ panic("dynexp symbol is not reachable")
+ }
}
- machogenasmsym(ctxt)
- sortsym = make([]*sym.Symbol, nsortsym)
- nsortsym = 0
- machogenasmsym(ctxt)
- sort.Sort(machoscmp(sortsym[:nsortsym]))
- for i := 0; i < nsortsym; i++ {
- sortsym[i].Dynid = int32(i)
+ collectmachosyms(ctxt)
+ sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
+ s1 := sortsym[i]
+ s2 := sortsym[j]
+ k1 := symkind(ldr, s1)
+ k2 := symkind(ldr, s2)
+ if k1 != k2 {
+ return k1 < k2
+ }
+ return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms
+ })
+ for i, s := range sortsym {
+ ldr.SetSymDynid(s, int32(i))
}
}
@@ -877,7 +897,7 @@ func machosymtab(ctxt *Link) {
symstr := ctxt.Syms.Lookup(".machosymstr", 0)
for i := 0; i < nsortsym; i++ {
- s := sortsym[i]
+ s := ctxt.loader.Syms[sortsym[i]]
symtab.AddUint32(ctxt.Arch, uint32(symstr.Size))
export := machoShouldExport(ctxt, s)
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 91656170b8..84f40d9b81 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -32,6 +32,7 @@ package ld
import (
"bufio"
+ "cmd/internal/goobj2"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/benchmark"
@@ -74,7 +75,7 @@ var (
flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker")
flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive")
- flagA = flag.Bool("a", false, "disassemble output")
+ flagA = flag.Bool("a", false, "no-op (deprecated)")
FlagC = flag.Bool("c", false, "dump call graph")
FlagD = flag.Bool("d", false, "disable dynamic executable")
flagF = flag.Bool("f", false, "ignore version mismatch")
@@ -154,6 +155,9 @@ func Main(arch *sys.Arch, theArch Arch) {
usage()
}
}
+ if ctxt.HeadType == objabi.Hunknown {
+ ctxt.HeadType.Set(objabi.GOOS)
+ }
checkStrictDups = *FlagStrictDups
@@ -190,11 +194,6 @@ func Main(arch *sys.Arch, theArch Arch) {
bench.Start("libinit")
libinit(ctxt) // creates outfile
-
- if ctxt.HeadType == objabi.Hunknown {
- ctxt.HeadType.Set(objabi.GOOS)
- }
-
bench.Start("computeTLSOffset")
ctxt.computeTLSOffset()
bench.Start("Archinit")
@@ -208,6 +207,7 @@ func Main(arch *sys.Arch, theArch Arch) {
ctxt.Logf("HEADER = -H%d -T0x%x -R0x%x\n", ctxt.HeadType, uint64(*FlagTextAddr), uint32(*FlagRound))
}
+ zerofp := goobj2.FingerprintType{}
switch ctxt.BuildMode {
case BuildModeShared:
for i := 0; i < flag.NArg(); i++ {
@@ -221,12 +221,12 @@ func Main(arch *sys.Arch, theArch Arch) {
}
pkglistfornote = append(pkglistfornote, pkgpath...)
pkglistfornote = append(pkglistfornote, '\n')
- addlibpath(ctxt, "command line", "command line", file, pkgpath, "")
+ addlibpath(ctxt, "command line", "command line", file, pkgpath, "", zerofp)
}
case BuildModePlugin:
- addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "")
+ addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "", zerofp)
default:
- addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "")
+ addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "", zerofp)
}
bench.Start("loadlib")
ctxt.loadlib()
@@ -297,11 +297,9 @@ func Main(arch *sys.Arch, theArch Arch) {
bench.Start("dwarfGenerateDebugSyms")
dwarfGenerateDebugSyms(ctxt)
bench.Start("symtab")
- ctxt.symtab()
- bench.Start("loadlibfull")
- ctxt.loadlibfull() // XXX do it here for now
+ symGroupType := ctxt.symtab()
bench.Start("dodata")
- ctxt.dodata()
+ ctxt.dodata2(symGroupType)
bench.Start("address")
order := ctxt.address()
bench.Start("dwarfcompress")
@@ -321,19 +319,27 @@ func Main(arch *sys.Arch, theArch Arch) {
if err := ctxt.Out.Mmap(filesize); err != nil {
panic(err)
}
- // Asmb will redirect symbols to the output file mmap, and relocations
- // will be applied directly there.
- bench.Start("Asmb")
- thearch.Asmb(ctxt)
+ }
+ // Asmb will redirect symbols to the output file mmap, and relocations
+ // will be applied directly there.
+ bench.Start("Asmb")
+ ctxt.loader.InitOutData()
+ thearch.Asmb(ctxt, ctxt.loader)
+
+ newreloc := ctxt.IsInternal() && ctxt.IsAMD64()
+ if newreloc {
bench.Start("reloc")
ctxt.reloc()
+ bench.Start("loadlibfull")
+ // We don't need relocations at this point.
+ // An exception is Windows, see pe.go:addPEBaseRelocSym
+ needReloc := ctxt.IsWindows()
+ ctxt.loadlibfull(symGroupType, needReloc) // XXX do it here for now
} else {
- // If we don't mmap, we need to apply relocations before
- // writing out.
+ bench.Start("loadlibfull")
+ ctxt.loadlibfull(symGroupType, true) // XXX do it here for now
bench.Start("reloc")
- ctxt.reloc()
- bench.Start("Asmb")
- thearch.Asmb(ctxt)
+ ctxt.reloc2()
}
bench.Start("Asmb2")
thearch.Asmb2(ctxt)
@@ -346,7 +352,7 @@ func Main(arch *sys.Arch, theArch Arch) {
bench.Start("hostlink")
ctxt.hostlink()
if ctxt.Debugvlog != 0 {
- ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym))
+ ctxt.Logf("%d symbols, %d reachable\n", len(ctxt.loader.Syms), ctxt.loader.NReachableSym())
ctxt.Logf("%d liveness data\n", liveness)
}
bench.Start("Flush")
diff --git a/src/cmd/link/internal/ld/outbuf.go b/src/cmd/link/internal/ld/outbuf.go
index cee589fc05..4ce211172c 100644
--- a/src/cmd/link/internal/ld/outbuf.go
+++ b/src/cmd/link/internal/ld/outbuf.go
@@ -6,7 +6,7 @@ package ld
import (
"cmd/internal/sys"
- "cmd/link/internal/sym"
+ "cmd/link/internal/loader"
"encoding/binary"
"errors"
"log"
@@ -285,11 +285,11 @@ func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) {
// to point to the output buffer that we just wrote, so we can apply further
// edit to the symbol content.
// If the output file is not Mmap'd, just writes the content.
-func (out *OutBuf) WriteSym(s *sym.Symbol) {
- n := int64(len(s.P))
+func (out *OutBuf) WriteSym(ldr *loader.Loader, s loader.Sym) {
+ P := ldr.Data(s)
+ n := int64(len(P))
pos, buf := out.writeLoc(n)
- copy(buf[pos:], s.P)
+ copy(buf[pos:], P)
out.off += n
- s.P = buf[pos : pos+n]
- s.Attr.Set(sym.AttrReadOnly, false)
+ ldr.SetOutData(s, buf[pos:pos+n])
}
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index fda5590700..547200fbee 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -646,7 +646,7 @@ func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int
// writeSymbols writes all COFF symbol table records.
func (f *peFile) writeSymbols(ctxt *Link) {
- put := func(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) {
+ put := func(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64) {
if s == nil {
return
}
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index 6a8b3dbed1..7a6c4e43e9 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -34,19 +34,22 @@ package ld
import (
"cmd/internal/objabi"
"cmd/internal/sys"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"log"
"runtime"
)
func linknew(arch *sys.Arch) *Link {
+ ler := loader.ErrorReporter{AfterErrorAction: afterErrorAction}
ctxt := &Link{
- Target: Target{Arch: arch},
- Syms: sym.NewSymbols(),
- outSem: make(chan int, 2*runtime.GOMAXPROCS(0)),
- Out: NewOutBuf(arch),
- LibraryByPkg: make(map[string]*sym.Library),
- numelfsym: 1,
+ Target: Target{Arch: arch},
+ Syms: sym.NewSymbols(),
+ outSem: make(chan int, 2*runtime.GOMAXPROCS(0)),
+ Out: NewOutBuf(arch),
+ LibraryByPkg: make(map[string]*sym.Library),
+ numelfsym: 1,
+ ErrorReporter: ErrorReporter{ErrorReporter: ler},
}
if objabi.GOARCH != arch.Name {
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index 9aca0ded3b..f9eb05146f 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -74,7 +74,7 @@ func putelfsyment(out *OutBuf, off int, addr int64, size int64, info int, shndx
}
}
-func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go_ *sym.Symbol) {
+func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64) {
var typ int
switch t {
@@ -185,7 +185,7 @@ func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go
// ELF linker -Bsymbolic-functions option, but that is buggy on
// several platforms.
putelfsyment(ctxt.Out, putelfstr("local."+s), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other)
- x.LocalElfsym = int32(ctxt.numelfsym)
+ ctxt.loader.SetSymLocalElfSym(loader.Sym(x.SymIdx), int32(ctxt.numelfsym))
ctxt.numelfsym++
return
} else if bind != ctxt.elfbind {
@@ -193,13 +193,13 @@ func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go
}
putelfsyment(ctxt.Out, putelfstr(s), addr, size, bind<<4|typ&0xf, elfshnum, other)
- x.Elfsym = int32(ctxt.numelfsym)
+ ctxt.loader.SetSymElfSym(loader.Sym(x.SymIdx), int32(ctxt.numelfsym))
ctxt.numelfsym++
}
func putelfsectionsym(ctxt *Link, out *OutBuf, s *sym.Symbol, shndx int) {
putelfsyment(out, 0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
- s.Elfsym = int32(ctxt.numelfsym)
+ ctxt.loader.SetSymElfSym(loader.Sym(s.SymIdx), int32(ctxt.numelfsym))
ctxt.numelfsym++
}
@@ -224,7 +224,7 @@ func Asmelfsym(ctxt *Link) {
genasmsym(ctxt, putelfsym)
}
-func putplan9sym(ctxt *Link, x *sym.Symbol, s string, typ SymbolType, addr int64, go_ *sym.Symbol) {
+func putplan9sym(ctxt *Link, x *sym.Symbol, s string, typ SymbolType, addr int64) {
t := int(typ)
switch typ {
case TextSym, DataSym, BSSSym:
@@ -327,9 +327,7 @@ func textsectionmap(ctxt *Link) (loader.Sym, uint32) {
return t.Sym(), uint32(n)
}
-var symGroupType []sym.SymKind // temporarily assign a symbol's "group" type
-
-func (ctxt *Link) symtab() {
+func (ctxt *Link) symtab() []sym.SymKind {
ldr := ctxt.loader
if !ctxt.IsAIX() {
@@ -441,7 +439,7 @@ func (ctxt *Link) symtab() {
// just defined above will be first.
// hide the specific symbols.
nsym := loader.Sym(ldr.NSym())
- symGroupType = make([]sym.SymKind, nsym)
+ symGroupType := make([]sym.SymKind, nsym)
for s := loader.Sym(1); s < nsym; s++ {
name := ldr.SymName(s)
if !ctxt.IsExternal() && isStaticTemp(name) {
@@ -709,6 +707,7 @@ func (ctxt *Link) symtab() {
lastmoduledatap.SetData(nil)
lastmoduledatap.AddAddr(ctxt.Arch, moduledata.Sym())
}
+ return symGroupType
}
func isStaticTemp(name string) bool {
diff --git a/src/cmd/link/internal/ld/target.go b/src/cmd/link/internal/ld/target.go
index 7aa2c1ccd0..102b6c5436 100644
--- a/src/cmd/link/internal/ld/target.go
+++ b/src/cmd/link/internal/ld/target.go
@@ -61,6 +61,7 @@ func (t *Target) CanUsePlugins() bool {
}
func (t *Target) IsElf() bool {
+ t.mustSetHeadType()
return t.IsELF
}
@@ -91,14 +92,30 @@ func (t *Target) IsARM() bool {
return t.Arch.Family == sys.ARM
}
+func (t *Target) IsARM64() bool {
+ return t.Arch.Family == sys.ARM64
+}
+
func (t *Target) IsAMD64() bool {
return t.Arch.Family == sys.AMD64
}
+func (t *Target) IsMIPS() bool {
+ return t.Arch.Family == sys.MIPS
+}
+
+func (t *Target) IsMIPS64() bool {
+ return t.Arch.Family == sys.MIPS64
+}
+
func (t *Target) IsPPC64() bool {
return t.Arch.Family == sys.PPC64
}
+func (t *Target) IsRISCV64() bool {
+ return t.Arch.Family == sys.RISCV64
+}
+
func (t *Target) IsS390X() bool {
return t.Arch.Family == sys.S390X
}
@@ -112,37 +129,51 @@ func (t *Target) IsWasm() bool {
//
func (t *Target) IsLinux() bool {
+ t.mustSetHeadType()
return t.HeadType == objabi.Hlinux
}
func (t *Target) IsDarwin() bool {
+ t.mustSetHeadType()
return t.HeadType == objabi.Hdarwin
}
func (t *Target) IsWindows() bool {
+ t.mustSetHeadType()
return t.HeadType == objabi.Hwindows
}
func (t *Target) IsPlan9() bool {
+ t.mustSetHeadType()
return t.HeadType == objabi.Hplan9
}
func (t *Target) IsAIX() bool {
+ t.mustSetHeadType()
return t.HeadType == objabi.Haix
}
func (t *Target) IsSolaris() bool {
+ t.mustSetHeadType()
return t.HeadType == objabi.Hsolaris
}
func (t *Target) IsNetbsd() bool {
+ t.mustSetHeadType()
return t.HeadType == objabi.Hnetbsd
}
func (t *Target) IsOpenbsd() bool {
+ t.mustSetHeadType()
return t.HeadType == objabi.Hopenbsd
}
+func (t *Target) mustSetHeadType() {
+ if t.HeadType == objabi.Hunknown {
+ panic("HeadType is not set")
+ }
+}
+
//
// MISC
//
diff --git a/src/cmd/link/internal/ld/util.go b/src/cmd/link/internal/ld/util.go
index 9f257b8fc0..2186503f0c 100644
--- a/src/cmd/link/internal/ld/util.go
+++ b/src/cmd/link/internal/ld/util.go
@@ -73,12 +73,12 @@ func Errorf(s *sym.Symbol, format string, args ...interface{}) {
// Logging an error means that on exit cmd/link will delete any
// output file and return a non-zero error code.
func (ctxt *Link) Errorf(s loader.Sym, format string, args ...interface{}) {
- if s != 0 && ctxt.loader != nil {
- sn := ctxt.loader.SymName(s)
- format = sn + ": " + format
- } else {
- format = fmt.Sprintf("sym %d: %s", s, format)
+ if ctxt.loader != nil {
+ ctxt.loader.Errorf(s, format, args...)
+ return
}
+ // Note: this is not expected to happen very often.
+ format = fmt.Sprintf("sym %d: %s", s, format)
format += "\n"
fmt.Fprintf(os.Stderr, format, args...)
afterErrorAction()
diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go
index 94920f4457..bb039884af 100644
--- a/src/cmd/link/internal/ld/xcoff.go
+++ b/src/cmd/link/internal/ld/xcoff.go
@@ -360,7 +360,8 @@ type XcoffLdRel64 struct {
// xcoffLoaderReloc holds information about a relocation made by the loader.
type xcoffLoaderReloc struct {
sym *sym.Symbol
- rel *sym.Reloc
+ sym2 loader.Sym
+ roff int32
rtype uint16
symndx int32
}
@@ -567,11 +568,12 @@ var (
// xcoffUpdateOuterSize stores the size of outer symbols in order to have it
// in the symbol table.
-func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
+func xcoffUpdateOuterSize2(ctxt *Link, size int64, stype sym.SymKind) {
if size == 0 {
return
}
+ ldr := ctxt.loader
switch stype {
default:
Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String())
@@ -580,14 +582,16 @@ func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
case sym.STYPERELRO:
if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
// runtime.types size must be removed, as it's a real symbol.
- outerSymSize["typerel.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
+ tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
+ outerSymSize["typerel.*"] = size - tsize
return
}
fallthrough
case sym.STYPE:
if !ctxt.DynlinkingGo() {
// runtime.types size must be removed, as it's a real symbol.
- outerSymSize["type.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
+ tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
+ outerSymSize["type.*"] = size - tsize
}
case sym.SGOSTRING:
outerSymSize["go.string.*"] = size
@@ -603,7 +607,6 @@ func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
outerSymSize["runtime.itablink"] = size
}
-
}
// addSymbol writes a symbol or an auxiliary symbol entry on ctxt.out.
@@ -780,19 +783,19 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
// Trampoline don't have a FILE so there are considered
// in the current file.
// Same goes for runtime.text.X symbols.
- } else if x.File == "" { // Undefined global symbol
+ } else if symPkg(ctxt, x) == "" { // Undefined global symbol
// If this happens, the algorithm must be redone.
if currSymSrcFile.name != "" {
Exitf("undefined global symbol found inside another file")
}
} else {
// Current file has changed. New C_FILE, C_DWARF, etc must be generated.
- if currSymSrcFile.name != x.File {
+ if currSymSrcFile.name != symPkg(ctxt, x) {
if ctxt.LinkMode == LinkInternal {
// update previous file values
xfile.updatePreviousFile(ctxt, false)
- currSymSrcFile.name = x.File
- f.writeSymbolNewFile(ctxt, x.File, uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
+ currSymSrcFile.name = symPkg(ctxt, x)
+ f.writeSymbolNewFile(ctxt, symPkg(ctxt, x), uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
} else {
// With external linking, ld will crash if there is several
// .FILE and DWARF debugging enable, somewhere during
@@ -802,7 +805,7 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
// TODO(aix); remove once ld has been fixed or the triggering
// relocation has been found and fixed.
if currSymSrcFile.name == "" {
- currSymSrcFile.name = x.File
+ currSymSrcFile.name = symPkg(ctxt, x)
f.writeSymbolNewFile(ctxt, "go_functions", uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
}
}
@@ -852,7 +855,7 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
}
// put function used by genasmsym to write symbol table
-func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, go_ *sym.Symbol) {
+func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64) {
// All XCOFF symbols generated by this GO symbols
// Can be a symbol entry or a auxiliary entry
@@ -863,7 +866,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64,
return
case TextSym:
- if x.File != "" || strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
+ if symPkg(ctxt, x) != "" || strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
// Function within a file
syms = xfile.writeSymbolFunc(ctxt, x)
} else {
@@ -1106,51 +1109,55 @@ func (f *xcoffFile) adddynimpsym(ctxt *Link, s loader.Sym) {
// Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
// This relocation will be made by the loader.
-func Xcoffadddynrel(target *Target, ldr *loader.Loader, s *sym.Symbol, r *sym.Reloc) bool {
+func Xcoffadddynrel2(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
if target.IsExternal() {
return true
}
- if s.Type <= sym.SPCLNTAB {
- Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name)
+ if ldr.SymType(s) <= sym.SPCLNTAB {
+ ldr.Errorf(s, "cannot have a relocation to %s in a text section symbol", ldr.SymName(r.Sym()))
return false
}
xldr := &xcoffLoaderReloc{
- sym: s,
- rel: r,
+ sym2: s,
+ roff: r.Off(),
+ }
+ targ := r.Sym()
+ var targType sym.SymKind
+ if targ != 0 {
+ targType = ldr.SymType(targ)
}
- switch r.Type {
+ switch r.Type() {
default:
- Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", r.Sym.Name, r.Type.String())
+ ldr.Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", ldr.SymName(targ), r.Type().String())
return false
case objabi.R_ADDR:
- if s.Type == sym.SXCOFFTOC && r.Sym.Type == sym.SDYNIMPORT {
+ if ldr.SymType(s) == sym.SXCOFFTOC && targType == sym.SDYNIMPORT {
// Imported symbol relocation
for i, dynsym := range xfile.loaderSymbols {
- if ldr.Syms[dynsym.sym].Name == r.Sym.Name {
+ if ldr.SymName(dynsym.sym) == ldr.SymName(targ) {
xldr.symndx = int32(i + 3) // +3 because of 3 section symbols
break
}
}
- } else if s.Type == sym.SDATA {
- switch r.Sym.Sect.Seg {
+ } else if t := ldr.SymType(s); t == sym.SDATA || t == sym.SNOPTRDATA || t == sym.SBUILDINFO || t == sym.SXCOFFTOC {
+ switch ldr.SymSect(targ).Seg {
default:
- Errorf(s, "unknown segment for .loader relocation with symbol %s", r.Sym.Name)
+ ldr.Errorf(s, "unknown segment for .loader relocation with symbol %s", ldr.SymName(targ))
case &Segtext:
case &Segrodata:
xldr.symndx = 0 // .text
case &Segdata:
- if r.Sym.Type == sym.SBSS || r.Sym.Type == sym.SNOPTRBSS {
+ if targType == sym.SBSS || targType == sym.SNOPTRBSS {
xldr.symndx = 2 // .bss
} else {
xldr.symndx = 1 // .data
}
-
}
} else {
- Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", r.Sym.Name, s.Type, r.Sym.Type)
+ ldr.Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", ldr.SymName(targ), ldr.SymType(s), ldr.SymType(targ))
return false
}
@@ -1301,14 +1308,18 @@ func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
off += uint64(16 * len(f.loaderReloc))
for _, r := range f.loaderReloc {
+ symp := r.sym
+ if symp == nil {
+ symp = ctxt.loader.Syms[r.sym2]
+ }
xldr = &XcoffLdRel64{
- Lvaddr: uint64(r.sym.Value + int64(r.rel.Off)),
+ Lvaddr: uint64(symp.Value + int64(r.roff)),
Lrtype: r.rtype,
Lsymndx: r.symndx,
}
- if r.sym.Sect != nil {
- xldr.Lrsecnm = f.getXCOFFscnum(r.sym.Sect)
+ if symp.Sect != nil {
+ xldr.Lrsecnm = f.getXCOFFscnum(symp.Sect)
}
reloctab = append(reloctab, xldr)
@@ -1389,45 +1400,6 @@ func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
}
f.loaderSize = off + uint64(stlen)
-
- /* again for printing */
- if !*flagA {
- return
- }
-
- ctxt.Logf("\n.loader section")
- // write in buf
- var buf bytes.Buffer
-
- binary.Write(&buf, ctxt.Arch.ByteOrder, hdr)
- for _, s := range symtab {
- binary.Write(&buf, ctxt.Arch.ByteOrder, s)
-
- }
- for _, f := range importtab {
- buf.WriteString(f.Limpidpath)
- buf.WriteByte(0)
- buf.WriteString(f.Limpidbase)
- buf.WriteByte(0)
- buf.WriteString(f.Limpidmem)
- buf.WriteByte(0)
- }
- for _, s := range strtab {
- binary.Write(&buf, ctxt.Arch.ByteOrder, s.size)
- buf.WriteString(s.name)
- buf.WriteByte(0) // null terminator
- }
-
- // Log buffer
- ctxt.Logf("\n\t%.8x|", globalOff)
- for i, b := range buf.Bytes() {
- if i > 0 && i%16 == 0 {
- ctxt.Logf("\n\t%.8x|", uint64(globalOff)+uint64(i))
- }
- ctxt.Logf(" %.2x", b)
- }
- ctxt.Logf("\n")
-
}
// XCOFF assembling and writing file
@@ -1683,7 +1655,10 @@ func xcoffCreateExportFile(ctxt *Link) (fname string) {
fname = filepath.Join(*flagTmpdir, "export_file.exp")
var buf bytes.Buffer
- for _, s := range ctxt.Syms.Allsym {
+ for _, s := range ctxt.loader.Syms {
+ if s == nil {
+ continue
+ }
if !s.Attr.CgoExport() {
continue
}
diff --git a/src/cmd/link/internal/ld/xcoff2.go b/src/cmd/link/internal/ld/xcoff2.go
new file mode 100644
index 0000000000..27edbcb22d
--- /dev/null
+++ b/src/cmd/link/internal/ld/xcoff2.go
@@ -0,0 +1,113 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ld
+
+import (
+ "cmd/internal/objabi"
+ "cmd/link/internal/loader"
+ "cmd/link/internal/sym"
+)
+
+// Temporary dumping around for sym.Symbol version of helper
+// functions in xcoff.go, still being used for some archs/oses.
+// FIXME: get rid of this file when dodata() is completely
+// converted.
+
+// xcoffUpdateOuterSize stores the size of outer symbols in order to have it
+// in the symbol table.
+func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
+ if size == 0 {
+ return
+ }
+
+ switch stype {
+ default:
+ Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String())
+ case sym.SRODATA, sym.SRODATARELRO, sym.SFUNCTAB, sym.SSTRING:
+ // Nothing to do
+ case sym.STYPERELRO:
+ if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
+ // runtime.types size must be removed, as it's a real symbol.
+ outerSymSize["typerel.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
+ return
+ }
+ fallthrough
+ case sym.STYPE:
+ if !ctxt.DynlinkingGo() {
+ // runtime.types size must be removed, as it's a real symbol.
+ outerSymSize["type.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
+ }
+ case sym.SGOSTRING:
+ outerSymSize["go.string.*"] = size
+ case sym.SGOFUNC:
+ if !ctxt.DynlinkingGo() {
+ outerSymSize["go.func.*"] = size
+ }
+ case sym.SGOFUNCRELRO:
+ outerSymSize["go.funcrel.*"] = size
+ case sym.SGCBITS:
+ outerSymSize["runtime.gcbits.*"] = size
+ case sym.SITABLINK:
+ outerSymSize["runtime.itablink"] = size
+
+ }
+}
+
+// Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
+// This relocation will be made by the loader.
+func Xcoffadddynrel(target *Target, ldr *loader.Loader, s *sym.Symbol, r *sym.Reloc) bool {
+ if target.IsExternal() {
+ return true
+ }
+ if s.Type <= sym.SPCLNTAB {
+ Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name)
+ return false
+ }
+
+ xldr := &xcoffLoaderReloc{
+ sym: s,
+ roff: r.Off,
+ }
+
+ switch r.Type {
+ default:
+ Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", r.Sym.Name, r.Type.String())
+ return false
+ case objabi.R_ADDR:
+ if s.Type == sym.SXCOFFTOC && r.Sym.Type == sym.SDYNIMPORT {
+ // Imported symbol relocation
+ for i, dynsym := range xfile.loaderSymbols {
+ if ldr.Syms[dynsym.sym].Name == r.Sym.Name {
+ xldr.symndx = int32(i + 3) // +3 because of 3 section symbols
+ break
+ }
+ }
+ } else if s.Type == sym.SDATA || s.Type == sym.SNOPTRDATA || s.Type == sym.SBUILDINFO || s.Type == sym.SXCOFFTOC {
+ switch r.Sym.Sect.Seg {
+ default:
+ Errorf(s, "unknown segment for .loader relocation with symbol %s", r.Sym.Name)
+ case &Segtext:
+ case &Segrodata:
+ xldr.symndx = 0 // .text
+ case &Segdata:
+ if r.Sym.Type == sym.SBSS || r.Sym.Type == sym.SNOPTRBSS {
+ xldr.symndx = 2 // .bss
+ } else {
+ xldr.symndx = 1 // .data
+ }
+
+ }
+
+ } else {
+ Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", r.Sym.Name, s.Type, r.Sym.Type)
+ return false
+ }
+
+ xldr.rtype = 0x3F<<8 + XCOFF_R_POS
+ }
+
+ xfile.loaderReloc = append(xfile.loaderReloc, xldr)
+ return true
+}
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 987feeb284..2abd0e60e1 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -58,7 +58,7 @@ type Reloc2 struct {
// External reloc types may not fit into a uint8 which the Go object file uses.
// Store it here, instead of in the byte of goobj2.Reloc2.
- // For Go symbols this will always be 0.
+ // For Go symbols this will always be zero.
// goobj2.Reloc2.Type() + typ is always the right type, for both Go and external
// symbols.
typ objabi.RelocType
@@ -73,6 +73,10 @@ func (rel Reloc2) SetType(t objabi.RelocType) {
panic("SetType: type doesn't fit into Reloc2")
}
rel.Reloc.SetType(uint8(t))
+ if rel.typ != 0 {
+ // should use SymbolBuilder.SetRelocType
+ panic("wrong method to set reloc type")
+ }
}
// Aux2 holds a "handle" to access an aux symbol record from an
@@ -143,6 +147,16 @@ func (bm Bitmap) Has(i Sym) bool {
func (bm Bitmap) Len() int {
return len(bm) * 32
}
+
+// return the number of bits set.
+func (bm Bitmap) Count() int {
+ s := 0
+ for _, x := range bm {
+ s += bits.OnesCount32(x)
+ }
+ return s
+}
+
func MakeBitmap(n int) Bitmap {
return make(Bitmap, (n+31)/32)
}
@@ -202,6 +216,8 @@ type Loader struct {
sects []*sym.Section // sections
symSects []uint16 // symbol's section, index to sects array
+ outdata [][]byte // symbol's data in the output buffer
+
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
objByPkg map[string]*oReader // map package path to its Go object reader
@@ -241,15 +257,17 @@ type Loader struct {
align map[Sym]int32 // stores alignment for symbols
- dynimplib map[Sym]string // stores Dynimplib symbol attribute
- dynimpvers map[Sym]string // stores Dynimpvers symbol attribute
- localentry map[Sym]uint8 // stores Localentry symbol attribute
- extname map[Sym]string // stores Extname symbol attribute
- elfType map[Sym]elf.SymType // stores elf type symbol property
- symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms
- plt map[Sym]int32 // stores dynimport for pe objects
- got map[Sym]int32 // stores got for pe objects
- dynid map[Sym]int32 // stores Dynid for symbol
+ dynimplib map[Sym]string // stores Dynimplib symbol attribute
+ dynimpvers map[Sym]string // stores Dynimpvers symbol attribute
+ localentry map[Sym]uint8 // stores Localentry symbol attribute
+ extname map[Sym]string // stores Extname symbol attribute
+ elfType map[Sym]elf.SymType // stores elf type symbol property
+ elfSym map[Sym]int32 // stores elf sym symbol property
+ localElfSym map[Sym]int32 // stores "local" elf sym symbol property
+ symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms
+ plt map[Sym]int32 // stores dynimport for pe objects
+ got map[Sym]int32 // stores got for pe objects
+ dynid map[Sym]int32 // stores Dynid for symbol
relocVariant map[relocId]sym.RelocVariant // stores variant relocs
@@ -266,6 +284,8 @@ type Loader struct {
elfsetstring elfsetstringFunc
+ errorReporter *ErrorReporter
+
SymLookup func(name string, ver int) *sym.Symbol
}
@@ -297,9 +317,9 @@ const (
FlagStrictDups = 1 << iota
)
-func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
+func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
nbuiltin := goobj2.NBuiltin()
- return &Loader{
+ ldr := &Loader{
start: make(map[*oReader]Sym),
objs: []objIdx{{}}, // reserve index 0 for nil symbol
objSyms: []objSym{{}}, // reserve index 0 for nil symbol
@@ -315,6 +335,8 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
extname: make(map[Sym]string),
attrReadOnly: make(map[Sym]bool),
elfType: make(map[Sym]elf.SymType),
+ elfSym: make(map[Sym]int32),
+ localElfSym: make(map[Sym]int32),
symPkg: make(map[Sym]string),
plt: make(map[Sym]int32),
got: make(map[Sym]int32),
@@ -328,8 +350,11 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
builtinSyms: make([]Sym, nbuiltin),
flags: flags,
elfsetstring: elfsetstring,
+ errorReporter: reporter,
sects: []*sym.Section{nil}, // reserve index 0 for nil section
}
+ reporter.ldr = ldr
+ return ldr
}
// Add object file r, return the start index.
@@ -616,6 +641,11 @@ func (l *Loader) NDef() int {
return int(l.extStart)
}
+// Number of reachable symbols.
+func (l *Loader) NReachableSym() int {
+ return l.attrReachable.Count()
+}
+
// Returns the raw (unpatched) name of the i-th symbol.
func (l *Loader) RawSymName(i Sym) string {
if l.IsExternal(i) {
@@ -732,6 +762,14 @@ func (l *Loader) SetAttrLocal(i Sym, v bool) {
}
}
+// SymAddr checks that a symbol is reachable, and returns its value.
+func (l *Loader) SymAddr(i Sym) int64 {
+ if !l.AttrReachable(i) {
+ panic("unreachable symbol in symaddr")
+ }
+ return l.values[i]
+}
+
// AttrNotInSymbolTable returns true for symbols that should not be
// added to the symbol table of the final generated load module.
func (l *Loader) AttrNotInSymbolTable(i Sym) bool {
@@ -1026,6 +1064,11 @@ func (l *Loader) SetSymValue(i Sym, val int64) {
l.values[i] = val
}
+// AddToSymValue adds to the value of the i-th symbol. i is the global index.
+func (l *Loader) AddToSymValue(i Sym, val int64) {
+ l.values[i] += val
+}
+
// Returns the symbol content of the i-th symbol. i is global index.
func (l *Loader) Data(i Sym) []byte {
if l.IsExternal(i) {
@@ -1039,6 +1082,32 @@ func (l *Loader) Data(i Sym) []byte {
return r.Data(li)
}
+// Returns the data of the i-th symbol in the output buffer.
+func (l *Loader) OutData(i Sym) []byte {
+ if int(i) < len(l.outdata) && l.outdata[i] != nil {
+ return l.outdata[i]
+ }
+ return l.Data(i)
+}
+
+// SetOutData sets the position of the data of the i-th symbol in the output buffer.
+// i is global index.
+func (l *Loader) SetOutData(i Sym, data []byte) {
+ if l.IsExternal(i) {
+ pp := l.getPayload(i)
+ if pp != nil {
+ pp.data = data
+ return
+ }
+ }
+ l.outdata[i] = data
+}
+
+// InitOutData initializes the slice used to store symbol output data.
+func (l *Loader) InitOutData() {
+ l.outdata = make([][]byte, l.extStart)
+}
+
// SymAlign returns the alignment for a symbol.
func (l *Loader) SymAlign(i Sym) int32 {
// If an alignment has been recorded, return that.
@@ -1075,6 +1144,12 @@ func (l *Loader) SetSymAlign(i Sym, align int32) {
// SymValue returns the section of the i-th symbol. i is global index.
func (l *Loader) SymSect(i Sym) *sym.Section {
+ if int(i) >= len(l.symSects) {
+ // symSects is extended lazily -- it the sym in question is
+ // outside the range of the existing slice, then we assume its
+ // section has not yet been set.
+ return nil
+ }
return l.sects[l.symSects[i]]
}
@@ -1192,6 +1267,42 @@ func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
}
}
+// SymElfSym returns the ELF symbol index for a given loader
+// symbol, assigned during ELF symtab generation.
+func (l *Loader) SymElfSym(i Sym) int32 {
+ return l.elfSym[i]
+}
+
+// SetSymElfSym sets the elf symbol index for a symbol.
+func (l *Loader) SetSymElfSym(i Sym, es int32) {
+ if i == 0 {
+ panic("bad sym index")
+ }
+ if es == 0 {
+ delete(l.elfSym, i)
+ } else {
+ l.elfSym[i] = es
+ }
+}
+
+// SymLocalElfSym returns the "local" ELF symbol index for a given loader
+// symbol, assigned during ELF symtab generation.
+func (l *Loader) SymLocalElfSym(i Sym) int32 {
+ return l.localElfSym[i]
+}
+
+// SetSymLocalElfSym sets the "local" elf symbol index for a symbol.
+func (l *Loader) SetSymLocalElfSym(i Sym, es int32) {
+ if i == 0 {
+ panic("bad sym index")
+ }
+ if es == 0 {
+ delete(l.localElfSym, i)
+ } else {
+ l.localElfSym[i] = es
+ }
+}
+
// SymPlt returns the plt value for pe symbols.
func (l *Loader) SymPlt(s Sym) int32 {
if v, ok := l.plt[s]; ok {
@@ -1253,6 +1364,18 @@ func (l *Loader) SetSymDynid(i Sym, val int32) {
}
}
+// DynIdSyms returns the set of symbols for which dynID is set to an
+// interesting (non-default) value. This is expected to be a fairly
+// small set.
+func (l *Loader) DynidSyms() []Sym {
+ sl := make([]Sym, 0, len(l.dynid))
+ for s := range l.dynid {
+ sl = append(sl, s)
+ }
+ sort.Slice(sl, func(i, j int) bool { return sl[i] < sl[j] })
+ return sl
+}
+
// SymGoType returns the 'Gotype' property for a given symbol (set by
// the Go compiler for variable symbols). This version relies on
// reading aux symbols for the target sym -- it could be that a faster
@@ -1734,7 +1857,8 @@ func (l *Loader) FuncInfo(i Sym) FuncInfo {
// Preload a package: add autolibs, add defined package symbols to the symbol table.
// Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
// Does not read symbol data.
-func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, flags int) {
+// Returns the fingerprint of the object.
+func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj2.FingerprintType {
roObject, readonly, err := f.Slice(uint64(length))
if err != nil {
log.Fatal("cannot read object file:", err)
@@ -1753,7 +1877,7 @@ func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, uni
or := &oReader{r, unit, localSymVersion, r.Flags(), pkgprefix, make([]Sym, ndef+nnonpkgdef+r.NNonpkgref()), ndef, uint32(len(l.objs))}
// Autolib
- lib.ImportStrings = append(lib.ImportStrings, r.Autolib()...)
+ lib.Autolib = append(lib.Autolib, r.Autolib()...)
// DWARF file table
nfile := r.NDwarfFile()
@@ -1767,6 +1891,8 @@ func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, uni
// The caller expects us consuming all the data
f.MustSeek(length, os.SEEK_CUR)
+
+ return r.Fingerprint()
}
// Preload symbols of given kind from an object.
@@ -1890,7 +2016,7 @@ func (l *Loader) preprocess(arch *sys.Arch, s Sym, name string) {
}
// Load full contents.
-func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
+func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
// create all Symbols first.
l.growSyms(l.NSym())
l.growSects(l.NSym())
@@ -1923,7 +2049,9 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
}
// allocate a single large slab of relocations for all live symbols
- l.relocBatch = make([]sym.Reloc, nr)
+ if needReloc {
+ l.relocBatch = make([]sym.Reloc, nr)
+ }
// convert payload-based external symbols into sym.Symbol-based
for _, i := range toConvert {
@@ -1934,21 +2062,15 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
s.Version = int16(pp.ver)
s.Type = pp.kind
s.Size = pp.size
- if pp.gotype != 0 {
- s.Gotype = l.Syms[pp.gotype]
- }
- if f, ok := l.symPkg[i]; ok {
- s.File = f
- } else if pp.objidx != 0 {
- s.File = l.objs[pp.objidx].r.unit.Lib.Pkg
- }
// Copy relocations
- batch := l.relocBatch
- s.R = batch[:len(pp.relocs):len(pp.relocs)]
- l.relocBatch = batch[len(pp.relocs):]
- relocs := l.Relocs(i)
- l.convertRelocations(i, &relocs, s, false)
+ if needReloc {
+ batch := l.relocBatch
+ s.R = batch[:len(pp.relocs):len(pp.relocs)]
+ l.relocBatch = batch[len(pp.relocs):]
+ relocs := l.Relocs(i)
+ l.convertRelocations(i, &relocs, s, false)
+ }
// Copy data
s.P = pp.data
@@ -1959,7 +2081,7 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
// load contents of defined symbols
for _, o := range l.objs[1:] {
- loadObjFull(l, o.r)
+ loadObjFull(l, o.r, needReloc)
}
// Note: resolution of ABI aliases is now also handled in
@@ -2103,22 +2225,7 @@ func (l *Loader) PropagateLoaderChangesToSymbols(toconvert []Sym, anonVerReplace
relfix = true
}
- // For 'new' symbols, copy other content (such as Gotype,
- // sym file, relocations, etc).
- if isnew {
- if gt := l.SymGoType(cand); gt != 0 {
- s.Gotype = l.Syms[gt]
- }
- if f, ok := l.symPkg[cand]; ok {
- s.File = f
- } else {
- r, _ := l.toLocal(cand)
- if r != nil && r != l.extReader {
- s.File = l.SymPkg(cand)
- }
- }
- }
-
+ // For 'new' symbols, copy other content.
if relfix {
relocfixup = append(relocfixup, cand)
}
@@ -2165,7 +2272,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
if s == nil {
continue
}
- syms.Allsym = append(syms.Allsym, s) // XXX still add to Allsym for now, as there are code looping through Allsym
if s.Version < 0 {
s.Version = int16(anonVerReplacement)
}
@@ -2179,7 +2285,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
}
s := l.allocSym(name, ver)
l.installSym(i, s)
- syms.Allsym = append(syms.Allsym, s) // XXX see above
return s
}
syms.Lookup = l.SymLookup
@@ -2191,7 +2296,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
i := l.newExtSym(name, ver)
s := l.allocSym(name, ver)
l.installSym(i, s)
- syms.Allsym = append(syms.Allsym, s) // XXX see above
return s
}
}
@@ -2221,6 +2325,7 @@ func (l *Loader) installSym(i Sym, s *sym.Symbol) {
panic("sym already present in installSym")
}
l.Syms[i] = s
+ s.SymIdx = sym.LoaderSym(i)
}
// addNewSym adds a new sym.Symbol to the i-th index in the list of symbols.
@@ -2234,12 +2339,35 @@ func (l *Loader) addNewSym(i Sym, name string, ver int, unit *sym.CompilationUni
t = s.Type
}
s.Type = t
- s.Unit = unit
l.growSyms(int(i))
l.installSym(i, s)
return s
}
+// TopLevelSym tests a symbol (by name and kind) to determine whether
+// the symbol first class sym (participating in the link) or is an
+// anonymous aux or sub-symbol containing some sub-part or payload of
+// another symbol.
+func (l *Loader) TopLevelSym(s Sym) bool {
+ return topLevelSym(l.RawSymName(s), l.SymType(s))
+}
+
+// topLevelSym tests a symbol name and kind to determine whether
+// the symbol first class sym (participating in the link) or is an
+// anonymous aux or sub-symbol containing some sub-part or payload of
+// another symbol.
+func topLevelSym(sname string, skind sym.SymKind) bool {
+ if sname != "" {
+ return true
+ }
+ switch skind {
+ case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES, sym.SGOFUNC:
+ return true
+ default:
+ return false
+ }
+}
+
// loadObjSyms creates sym.Symbol objects for the live Syms in the
// object corresponding to object reader "r". Return value is the
// number of sym.Reloc entries required for all the new symbols.
@@ -2253,16 +2381,11 @@ func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
osym := r.Sym(i)
name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
t := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
- // NB: for the test below, we can skip most anonymous symbols
- // since they will never be turned into sym.Symbols (eg:
- // funcdata). DWARF symbols are an exception however -- we
- // want to include all reachable but nameless DWARF symbols.
- if name == "" {
- switch t {
- case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES:
- default:
- continue
- }
+
+ // Skip non-dwarf anonymous symbols (e.g. funcdata),
+ // since they will never be turned into sym.Symbols.
+ if !topLevelSym(name, t) {
+ continue
}
ver := abiToVer(osym.ABI(), r.version)
if t == sym.SXREF {
@@ -2479,12 +2602,7 @@ func (l *Loader) CreateStaticSym(name string) Sym {
return l.newExtSym(name, l.anonVersion)
}
-func loadObjFull(l *Loader, r *oReader) {
- resolveSymRef := func(s goobj2.SymRef) *sym.Symbol {
- i := l.resolve(r, s)
- return l.Syms[i]
- }
-
+func loadObjFull(l *Loader, r *oReader, needReloc bool) {
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
// A symbol may be a dup or overwritten. In this case, its
// content will actually be provided by a different object
@@ -2506,27 +2624,23 @@ func loadObjFull(l *Loader, r *oReader) {
size := osym.Siz()
// Symbol data
- s.P = r.Data(i)
- s.Attr.Set(sym.AttrReadOnly, r.ReadOnly())
+ s.P = l.OutData(gi)
// Relocs
- relocs := l.relocs(r, i)
- batch := l.relocBatch
- s.R = batch[:relocs.Count():relocs.Count()]
- l.relocBatch = batch[relocs.Count():]
- l.convertRelocations(gi, &relocs, s, false)
+ if needReloc {
+ relocs := l.relocs(r, i)
+ batch := l.relocBatch
+ s.R = batch[:relocs.Count():relocs.Count()]
+ l.relocBatch = batch[relocs.Count():]
+ l.convertRelocations(gi, &relocs, s, false)
+ }
// Aux symbol info
auxs := r.Auxs(i)
for j := range auxs {
a := &auxs[j]
switch a.Type() {
- case goobj2.AuxGotype:
- typ := resolveSymRef(a.Sym())
- if typ != nil {
- s.Gotype = typ
- }
- case goobj2.AuxFuncInfo, goobj2.AuxFuncdata:
+ case goobj2.AuxFuncInfo, goobj2.AuxFuncdata, goobj2.AuxGotype:
// already handled
case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines:
// ignored for now
@@ -2535,7 +2649,6 @@ func loadObjFull(l *Loader, r *oReader) {
}
}
- s.File = r.pkgprefix[:len(r.pkgprefix)-1]
if s.Size < int64(size) {
s.Size = int64(size)
}
@@ -2744,6 +2857,42 @@ func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, exts
return textp2
}
+// ErrorReporter is a helper class for reporting errors.
+type ErrorReporter struct {
+ ldr *Loader
+ AfterErrorAction func()
+}
+
+// Errorf method logs an error message.
+//
+// After each error, the error actions function will be invoked; this
+// will either terminate the link immediately (if -h option given)
+// or it will keep a count and exit if more than 20 errors have been printed.
+//
+// Logging an error means that on exit cmd/link will delete any
+// output file and return a non-zero error code.
+//
+func (reporter *ErrorReporter) Errorf(s Sym, format string, args ...interface{}) {
+ if s != 0 && reporter.ldr.SymName(s) != "" {
+ format = reporter.ldr.SymName(s) + ": " + format
+ } else {
+ format = fmt.Sprintf("sym %d: %s", s, format)
+ }
+ format += "\n"
+ fmt.Fprintf(os.Stderr, format, args...)
+ reporter.AfterErrorAction()
+}
+
+// GetErrorReporter returns the loader's associated error reporter.
+func (l *Loader) GetErrorReporter() *ErrorReporter {
+ return l.errorReporter
+}
+
+// Errorf method logs an error message. See ErrorReporter.Errorf for details.
+func (l *Loader) Errorf(s Sym, format string, args ...interface{}) {
+ l.errorReporter.Errorf(s, format, args...)
+}
+
// For debugging.
func (l *Loader) Dump() {
fmt.Println("objs")
diff --git a/src/cmd/link/internal/loader/loader_test.go b/src/cmd/link/internal/loader/loader_test.go
index b2f823d17e..60ef69afb9 100644
--- a/src/cmd/link/internal/loader/loader_test.go
+++ b/src/cmd/link/internal/loader/loader_test.go
@@ -27,9 +27,16 @@ func addDummyObjSym(t *testing.T, ldr *Loader, or *oReader, name string) Sym {
return s
}
-func TestAddMaterializedSymbol(t *testing.T) {
+func mkLoader() *Loader {
edummy := func(s *sym.Symbol, str string, off int) {}
- ldr := NewLoader(0, edummy)
+ er := ErrorReporter{}
+ ldr := NewLoader(0, edummy, &er)
+ er.ldr = ldr
+ return ldr
+}
+
+func TestAddMaterializedSymbol(t *testing.T) {
+ ldr := mkLoader()
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
or := &dummyOreader
@@ -229,8 +236,7 @@ func sameRelocSlice(s1 *Relocs, s2 []Reloc) bool {
type addFunc func(l *Loader, s Sym, s2 Sym) Sym
func TestAddDataMethods(t *testing.T) {
- edummy := func(s *sym.Symbol, str string, off int) {}
- ldr := NewLoader(0, edummy)
+ ldr := mkLoader()
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
or := &dummyOreader
@@ -352,8 +358,7 @@ func TestAddDataMethods(t *testing.T) {
}
func TestOuterSub(t *testing.T) {
- edummy := func(s *sym.Symbol, str string, off int) {}
- ldr := NewLoader(0, edummy)
+ ldr := mkLoader()
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
or := &dummyOreader
diff --git a/src/cmd/link/internal/loader/symbolbuilder.go b/src/cmd/link/internal/loader/symbolbuilder.go
index f5db69856b..70adb369a4 100644
--- a/src/cmd/link/internal/loader/symbolbuilder.go
+++ b/src/cmd/link/internal/loader/symbolbuilder.go
@@ -143,6 +143,22 @@ func (sb *SymbolBuilder) SetRelocs(rslice []Reloc) {
}
}
+// SetRelocType sets the type of the 'i'-th relocation on this sym to 't'
+func (sb *SymbolBuilder) SetRelocType(i int, t objabi.RelocType) {
+ sb.relocs[i].SetType(0)
+ sb.reltypes[i] = t
+}
+
+// SetRelocSym sets the target sym of the 'i'-th relocation on this sym to 's'
+func (sb *SymbolBuilder) SetRelocSym(i int, tgt Sym) {
+ sb.relocs[i].SetSym(goobj2.SymRef{PkgIdx: 0, SymIdx: uint32(tgt)})
+}
+
+// SetRelocAdd sets the addend of the 'i'-th relocation on this sym to 'a'
+func (sb *SymbolBuilder) SetRelocAdd(i int, a int64) {
+ sb.relocs[i].SetAdd(a)
+}
+
// Add n relocations, return a handle to the relocations.
func (sb *SymbolBuilder) AddRelocs(n int) Relocs {
sb.relocs = append(sb.relocs, make([]goobj2.Reloc, n)...)
@@ -431,3 +447,10 @@ func GenAddAddrPlusFunc(internalExec bool) func(s *SymbolBuilder, arch *sys.Arch
return (*SymbolBuilder).AddAddrPlus
}
}
+
+func (sb *SymbolBuilder) MakeWritable() {
+ if sb.ReadOnly() {
+ sb.data = append([]byte(nil), sb.data...)
+ sb.l.SetAttrReadOnly(sb.symIdx, false)
+ }
+}
diff --git a/src/cmd/link/internal/mips/asm.go b/src/cmd/link/internal/mips/asm.go
index 21a57ccbb0..53032a7e33 100644
--- a/src/cmd/link/internal/mips/asm.go
+++ b/src/cmd/link/internal/mips/asm.go
@@ -54,7 +54,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write32(uint32(sectoff))
- elfsym := r.Xsym.ElfsymForReloc()
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type {
default:
return false
@@ -164,7 +164,7 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
return -1
}
-func asmb(ctxt *ld.Link) {
+func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF {
ld.Asmbelfsetup()
}
diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go
index 0a2a3c11f3..33f8b33509 100644
--- a/src/cmd/link/internal/mips64/asm.go
+++ b/src/cmd/link/internal/mips64/asm.go
@@ -61,7 +61,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write64(uint64(sectoff))
- elfsym := r.Xsym.ElfsymForReloc()
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
ctxt.Out.Write32(uint32(elfsym))
ctxt.Out.Write8(0)
ctxt.Out.Write8(0)
@@ -170,7 +170,7 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
return -1
}
-func asmb(ctxt *ld.Link) {
+func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF {
ld.Asmbelfsetup()
}
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index 0e3a691432..dfc55a30fd 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -267,120 +267,134 @@ func gencallstub2(ctxt *ld.Link, ldr *loader.Loader, abicase int, stub *loader.S
stub.AddUint32(ctxt.Arch, 0x4e800420) // bctr
}
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
+func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
if target.IsElf() {
- return addelfdynrel(target, syms, s, r)
+ return addelfdynrel2(target, ldr, syms, s, r, rIdx)
} else if target.IsAIX() {
- return ld.Xcoffadddynrel(target, ldr, s, r)
+ return ld.Xcoffadddynrel2(target, ldr, syms, s, r, rIdx)
}
return false
}
-func addelfdynrel(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
- r.InitExt()
+func addelfdynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
+ targ := r.Sym()
+ var targType sym.SymKind
+ if targ != 0 {
+ targType = ldr.SymType(targ)
+ }
- switch r.Type {
+ switch r.Type() {
default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
+ if r.Type() >= objabi.ElfRelocOffset {
+ ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false
}
// Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL24):
- r.Type = objabi.R_CALLPOWER
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CALLPOWER)
// This is a local call, so the caller isn't setting
// up r12 and r2 is the same for the caller and
// callee. Hence, we need to go to the local entry
// point. (If we don't do this, the callee will try
// to use r12 to compute r2.)
- r.Add += int64(r.Sym.Localentry()) * 4
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymLocalentry(targ))*4)
- if targ.Type == sym.SDYNIMPORT {
+ if targType == sym.SDYNIMPORT {
// Should have been handled in elfsetupplt
- ld.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
+ ldr.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
}
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC_REL32):
- r.Type = objabi.R_PCREL
- r.Add += 4
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+4)
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
}
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_ADDR64):
- r.Type = objabi.R_ADDR
- if targ.Type == sym.SDYNIMPORT {
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ADDR)
+ if targType == sym.SDYNIMPORT {
// These happen in .toc sections
- ld.Adddynsym(target, syms, targ)
+ ld.Adddynsym2(ldr, target, syms, targ)
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, s, int64(r.Off))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_PPC64_ADDR64)))
- rela.AddUint64(target.Arch, uint64(r.Add))
- r.Type = objabi.ElfRelocOffset // ignore during relocsym
+ rela := ldr.MakeSymbolUpdater(syms.Rela2)
+ rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
+ rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_PPC64_ADDR64)))
+ rela.AddUint64(target.Arch, uint64(r.Add()))
+ su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
}
-
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_LO | sym.RV_CHECK_OVERFLOW
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_POWER_TOC)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_LO|sym.RV_CHECK_OVERFLOW)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_LO
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_POWER_TOC)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_LO)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HA):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_POWER_TOC)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HA|sym.RV_CHECK_OVERFLOW)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HI):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_POWER_TOC)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HI|sym.RV_CHECK_OVERFLOW)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_DS):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_DS | sym.RV_CHECK_OVERFLOW
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_POWER_TOC)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_DS|sym.RV_CHECK_OVERFLOW)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO_DS):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_DS
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_POWER_TOC)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_DS)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_LO):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_POWER_LO
- r.Add += 2 // Compensate for relocation size of 2
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_LO)
+ su.SetRelocAdd(rIdx, r.Add()+2) // Compensate for relocation size of 2
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HI):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
- r.Add += 2
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HI|sym.RV_CHECK_OVERFLOW)
+ su.SetRelocAdd(rIdx, r.Add()+2)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HA):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
- r.Add += 2
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HA|sym.RV_CHECK_OVERFLOW)
+ su.SetRelocAdd(rIdx, r.Add()+2)
return true
}
// Handle references to ELF symbols from our own object files.
- if targ.Type != sym.SDYNIMPORT {
+ if targType != sym.SDYNIMPORT {
return true
}
@@ -439,7 +453,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
}
ctxt.Out.Write64(uint64(sectoff))
- elfsym := r.Xsym.ElfsymForReloc()
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type {
default:
return false
@@ -972,7 +986,7 @@ func addpltsym2(ctxt *ld.Link, ldr *loader.Loader, s loader.Sym) {
return
}
- ld.Adddynsym2(ldr, &ctxt.ErrorReporter, &ctxt.Target, &ctxt.ArchSyms, s)
+ ld.Adddynsym2(ldr, &ctxt.Target, &ctxt.ArchSyms, s)
if ctxt.IsELF {
plt := ldr.MakeSymbolUpdater(ctxt.PLT2)
@@ -1068,7 +1082,7 @@ func ensureglinkresolver2(ctxt *ld.Link, ldr *loader.Loader) *loader.SymbolBuild
return glink
}
-func asmb(ctxt *ld.Link) {
+func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF {
ld.Asmbelfsetup()
}
diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go
index cff1e9cc73..67002bc719 100644
--- a/src/cmd/link/internal/ppc64/obj.go
+++ b/src/cmd/link/internal/ppc64/obj.go
@@ -49,7 +49,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
+ Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
diff --git a/src/cmd/link/internal/riscv64/asm.go b/src/cmd/link/internal/riscv64/asm.go
index 51cc5980c8..5183de8d6b 100644
--- a/src/cmd/link/internal/riscv64/asm.go
+++ b/src/cmd/link/internal/riscv64/asm.go
@@ -98,7 +98,7 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
return -1
}
-func asmb(ctxt *ld.Link) {
+func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF {
ld.Asmbelfsetup()
}
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
index 9b6be28421..a9cb79a1cc 100644
--- a/src/cmd/link/internal/s390x/asm.go
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -75,135 +75,146 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
initfunc.AddUint32(ctxt.Arch, 0)
}
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
- r.InitExt()
+func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
+ targ := r.Sym()
+ var targType sym.SymKind
+ if targ != 0 {
+ targType = ldr.SymType(targ)
+ }
- switch r.Type {
+ switch r.Type() {
default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d", r.Type)
+ if r.Type() >= objabi.ElfRelocOffset {
+ ldr.Errorf(s, "unexpected relocation type %d", r.Type())
return false
}
// Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_12),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT12):
- ld.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type-objabi.ElfRelocOffset)
+ ldr.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type()-objabi.ElfRelocOffset)
return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_8),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_16),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ADDR
+
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ADDR)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", ldr.SymName(targ))
}
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly.
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
+ if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
+ ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
}
- r.Type = objabi.R_PCREL
- r.Add += int64(r.Siz)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT16),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT64):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
+ ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT16DBL),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32DBL):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- r.Add += int64(r.Siz)
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
+ su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ r.SetSym(syms.PLT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
}
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT64):
- r.Type = objabi.R_PCREL
- r.Add += int64(r.Siz)
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ r.SetSym(syms.PLT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
}
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_COPY):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
+ ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GLOB_DAT):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
+ ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_JMP_SLOT):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
+ ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_RELATIVE):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
+ ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTOFF):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_GOTOFF
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_GOTOFF)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPC):
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += int64(r.Siz)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ r.SetSym(syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16DBL),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32DBL):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- r.Add += int64(r.Siz)
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
+ su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", ldr.SymName(targ))
}
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPCDBL):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- r.Sym = syms.GOT
- r.Add += int64(r.Siz)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
+ r.SetSym(syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTENT):
- addgotsym(target, syms, targ)
-
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
- r.Add += int64(r.Siz)
+ addgotsym2(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
+ r.SetSym(syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ))+int64(r.Siz()))
return true
}
// Handle references to ELF symbols from our own object files.
- if targ.Type != sym.SDYNIMPORT {
+ if targType != sym.SDYNIMPORT {
return true
}
@@ -213,7 +224,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write64(uint64(sectoff))
- elfsym := r.Xsym.ElfsymForReloc()
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type {
default:
return false
@@ -388,28 +399,30 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
}
}
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
+func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymPlt(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
+ ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() {
- plt := syms.PLT
- got := syms.GOT
- rela := syms.RelaPLT
- if plt.Size == 0 {
+ plt := ldr.MakeSymbolUpdater(syms.PLT2)
+ got := ldr.MakeSymbolUpdater(syms.GOT2)
+ rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
+ if plt.Size() == 0 {
panic("plt is not set up")
}
// larl %r1,_GLOBAL_OFFSET_TABLE_+index
plt.AddUint8(0xc0)
plt.AddUint8(0x10)
- plt.AddPCRelPlus(target.Arch, got, got.Size+6) // need variant?
+ plt.AddPCRelPlus(target.Arch, got.Sym(), got.Size()+6)
+ pltrelocs := plt.Relocs()
+ ldr.SetRelocVariant(plt.Sym(), pltrelocs.Count()-1, sym.RV_390_DBL)
// add to got: pointer to current pos in plt
- got.AddAddrPlus(target.Arch, plt, plt.Size+8) // weird but correct
+ got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size()+8) // weird but correct
// lg %r1,0(%r1)
plt.AddUint8(0xe3)
plt.AddUint8(0x10)
@@ -434,44 +447,45 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
plt.AddUint8(0xc0)
plt.AddUint8(0xf4)
- plt.AddUint32(target.Arch, uint32(-((plt.Size - 2) >> 1))) // roll-your-own relocation
+ plt.AddUint32(target.Arch, uint32(-((plt.Size() - 2) >> 1))) // roll-your-own relocation
//.plt index
- plt.AddUint32(target.Arch, uint32(rela.Size)) // rela size before current entry
+ plt.AddUint32(target.Arch, uint32(rela.Size())) // rela size before current entry
// rela
- rela.AddAddrPlus(target.Arch, got, got.Size-8)
+ rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_JMP_SLOT)))
+ sDynid := ldr.SymDynid(s)
+ rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_390_JMP_SLOT)))
rela.AddUint64(target.Arch, 0)
- s.SetPlt(int32(plt.Size - 32))
+ ldr.SetPlt(s, int32(plt.Size()-32))
} else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
+ ldr.Errorf(s, "addpltsym: unsupported binary format")
}
}
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
+func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymGot(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
+ ld.Adddynsym2(ldr, target, syms, s)
+ got := ldr.MakeSymbolUpdater(syms.GOT2)
+ ldr.SetGot(s, int32(got.Size()))
got.AddUint64(target.Arch, 0)
if target.IsElf() {
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_GLOB_DAT)))
+ rela := ldr.MakeSymbolUpdater(syms.Rela2)
+ rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
+ rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_390_GLOB_DAT)))
rela.AddUint64(target.Arch, 0)
} else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
+ ldr.Errorf(s, "addgotsym: unsupported binary format")
}
}
-func asmb(ctxt *ld.Link) {
+func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF {
ld.Asmbelfsetup()
}
diff --git a/src/cmd/link/internal/s390x/obj.go b/src/cmd/link/internal/s390x/obj.go
index e463c5e727..129c6a7ee4 100644
--- a/src/cmd/link/internal/s390x/obj.go
+++ b/src/cmd/link/internal/s390x/obj.go
@@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
+ Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
diff --git a/src/cmd/link/internal/sym/library.go b/src/cmd/link/internal/sym/library.go
index bed16565ba..c9be3abb27 100644
--- a/src/cmd/link/internal/sym/library.go
+++ b/src/cmd/link/internal/sym/library.go
@@ -4,18 +4,21 @@
package sym
+import "cmd/internal/goobj2"
+
type Library struct {
- Objref string
- Srcref string
- File string
- Pkg string
- Shlib string
- Hash string
- ImportStrings []string
- Imports []*Library
- Main bool
- Safe bool
- Units []*CompilationUnit
+ Objref string
+ Srcref string
+ File string
+ Pkg string
+ Shlib string
+ Hash string
+ Fingerprint goobj2.FingerprintType
+ Autolib []goobj2.ImportedPkg
+ Imports []*Library
+ Main bool
+ Safe bool
+ Units []*CompilationUnit
Textp2 []LoaderSym // text syms defined in this library
DupTextSyms2 []LoaderSym // dupok text syms defined in this library
diff --git a/src/cmd/link/internal/sym/segment.go b/src/cmd/link/internal/sym/segment.go
index 5ca0228163..662e8e0c8f 100644
--- a/src/cmd/link/internal/sym/segment.go
+++ b/src/cmd/link/internal/sym/segment.go
@@ -55,6 +55,7 @@ type Section struct {
Elfsect interface{} // an *ld.ElfShdr
Reloff uint64
Rellen uint64
- Sym *Symbol // symbol for the section, if any
- Index uint16 // each section has a unique index, used internally
+ Sym *Symbol // symbol for the section, if any
+ Sym2 LoaderSym // symbol for the section, if any
+ Index uint16 // each section has a unique index, used internally
}
diff --git a/src/cmd/link/internal/sym/sizeof_test.go b/src/cmd/link/internal/sym/sizeof_test.go
index 3e97a833df..4cfca3b5a3 100644
--- a/src/cmd/link/internal/sym/sizeof_test.go
+++ b/src/cmd/link/internal/sym/sizeof_test.go
@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Symbol{}, 104, 168},
+ {Symbol{}, 84, 136},
}
for _, tt := range tests {
diff --git a/src/cmd/link/internal/sym/symbol.go b/src/cmd/link/internal/sym/symbol.go
index 9a6791e16f..546798fdf4 100644
--- a/src/cmd/link/internal/sym/symbol.go
+++ b/src/cmd/link/internal/sym/symbol.go
@@ -15,23 +15,19 @@ import (
// Symbol is an entry in the symbol table.
type Symbol struct {
- Name string
- Type SymKind
- Version int16
- Attr Attribute
- Dynid int32
- Align int32
- Elfsym int32
- LocalElfsym int32
- Value int64
- Size int64
- Sub *Symbol
- Outer *Symbol
- Gotype *Symbol
- File string // actually package!
- auxinfo *AuxSymbol
- Sect *Section
- Unit *CompilationUnit
+ Name string
+ Type SymKind
+ Version int16
+ Attr Attribute
+ Dynid int32
+ Align int32
+ Value int64
+ Size int64
+ Sub *Symbol
+ Outer *Symbol
+ SymIdx LoaderSym
+ auxinfo *AuxSymbol
+ Sect *Section
// P contains the raw symbol data.
P []byte
R []Reloc
@@ -88,16 +84,6 @@ func (s *Symbol) IsFileLocal() bool {
return s.Version >= SymVerStatic
}
-func (s *Symbol) ElfsymForReloc() int32 {
- // If putelfsym created a local version of this symbol, use that in all
- // relocations.
- if s.LocalElfsym != 0 {
- return s.LocalElfsym
- } else {
- return s.Elfsym
- }
-}
-
func (s *Symbol) Len() int64 {
return s.Size
}
@@ -444,80 +430,6 @@ func (s *Symbol) SetElfType(val elf.SymType) {
s.auxinfo.elftype = val
}
-// SortSub sorts a linked-list (by Sub) of *Symbol by Value.
-// Used for sub-symbols when loading host objects (see e.g. ldelf.go).
-func SortSub(l *Symbol) *Symbol {
- if l == nil || l.Sub == nil {
- return l
- }
-
- l1 := l
- l2 := l
- for {
- l2 = l2.Sub
- if l2 == nil {
- break
- }
- l2 = l2.Sub
- if l2 == nil {
- break
- }
- l1 = l1.Sub
- }
-
- l2 = l1.Sub
- l1.Sub = nil
- l1 = SortSub(l)
- l2 = SortSub(l2)
-
- /* set up lead element */
- if l1.Value < l2.Value {
- l = l1
- l1 = l1.Sub
- } else {
- l = l2
- l2 = l2.Sub
- }
-
- le := l
-
- for {
- if l1 == nil {
- for l2 != nil {
- le.Sub = l2
- le = l2
- l2 = l2.Sub
- }
-
- le.Sub = nil
- break
- }
-
- if l2 == nil {
- for l1 != nil {
- le.Sub = l1
- le = l1
- l1 = l1.Sub
- }
-
- break
- }
-
- if l1.Value < l2.Value {
- le.Sub = l1
- le = l1
- l1 = l1.Sub
- } else {
- le.Sub = l2
- le = l2
- l2 = l2.Sub
- }
- }
-
- le.Sub = nil
- return l
-}
-
type Pcdata struct {
P []byte
}
diff --git a/src/cmd/link/internal/sym/symbols.go b/src/cmd/link/internal/sym/symbols.go
index d36be11ee8..0d7b7e6a46 100644
--- a/src/cmd/link/internal/sym/symbols.go
+++ b/src/cmd/link/internal/sym/symbols.go
@@ -34,8 +34,6 @@ type Symbols struct {
// Symbol lookup based on name and indexed by version.
versions int
- Allsym []*Symbol
-
// Provided by the loader
// Look up the symbol with the given name and version, creating the
@@ -55,7 +53,6 @@ type Symbols struct {
func NewSymbols() *Symbols {
return &Symbols{
versions: SymVerStatic,
- Allsym: make([]*Symbol, 0, 100000),
}
}
diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go
index 7f8742d008..1eb3291db6 100644
--- a/src/cmd/link/internal/wasm/asm.go
+++ b/src/cmd/link/internal/wasm/asm.go
@@ -92,7 +92,30 @@ func assignAddress(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, v
return sect, n, va
}
-func asmb(ctxt *ld.Link) {} // dummy
+type wasmDataSect struct {
+ sect *sym.Section
+ data []byte
+}
+
+var dataSects []wasmDataSect
+
+func asmb(ctxt *ld.Link, ldr *loader.Loader) {
+ sections := []*sym.Section{
+ ldr.SymSect(ldr.Lookup("runtime.rodata", 0)),
+ ldr.SymSect(ldr.Lookup("runtime.typelink", 0)),
+ ldr.SymSect(ldr.Lookup("runtime.itablink", 0)),
+ ldr.SymSect(ldr.Lookup("runtime.symtab", 0)),
+ ldr.SymSect(ldr.Lookup("runtime.pclntab", 0)),
+ ldr.SymSect(ldr.Lookup("runtime.noptrdata", 0)),
+ ldr.SymSect(ldr.Lookup("runtime.data", 0)),
+ }
+
+ dataSects = make([]wasmDataSect, len(sections))
+ for i, sect := range sections {
+ data := ld.DatblkBytes(ctxt, int64(sect.Vaddr), int64(sect.Length))
+ dataSects[i] = wasmDataSect{sect, data}
+ }
+}
// asmb writes the final WebAssembly module binary.
// Spec: https://webassembly.github.io/spec/core/binary/modules.html
@@ -396,16 +419,6 @@ func writeCodeSec(ctxt *ld.Link, fns []*wasmFunc) {
func writeDataSec(ctxt *ld.Link) {
sizeOffset := writeSecHeader(ctxt, sectionData)
- sections := []*sym.Section{
- ctxt.Syms.Lookup("runtime.rodata", 0).Sect,
- ctxt.Syms.Lookup("runtime.typelink", 0).Sect,
- ctxt.Syms.Lookup("runtime.itablink", 0).Sect,
- ctxt.Syms.Lookup("runtime.symtab", 0).Sect,
- ctxt.Syms.Lookup("runtime.pclntab", 0).Sect,
- ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect,
- ctxt.Syms.Lookup("runtime.data", 0).Sect,
- }
-
type dataSegment struct {
offset int32
data []byte
@@ -420,9 +433,9 @@ func writeDataSec(ctxt *ld.Link) {
const maxNumSegments = 100000
var segments []*dataSegment
- for secIndex, sec := range sections {
- data := ld.DatblkBytes(ctxt, int64(sec.Vaddr), int64(sec.Length))
- offset := int32(sec.Vaddr)
+ for secIndex, ds := range dataSects {
+ data := ds.data
+ offset := int32(ds.sect.Vaddr)
// skip leading zeroes
for len(data) > 0 && data[0] == 0 {
@@ -433,7 +446,7 @@ func writeDataSec(ctxt *ld.Link) {
for len(data) > 0 {
dataLen := int32(len(data))
var segmentEnd, zeroEnd int32
- if len(segments)+(len(sections)-secIndex) == maxNumSegments {
+ if len(segments)+(len(dataSects)-secIndex) == maxNumSegments {
segmentEnd = dataLen
zeroEnd = dataLen
} else {
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index 650fe12f94..157e13496c 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -129,161 +129,189 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
o(0xc3)
}
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
+func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
+ targ := r.Sym()
+ var targType sym.SymKind
+ if targ != 0 {
+ targType = ldr.SymType(targ)
+ }
- switch r.Type {
+ switch r.Type() {
default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
+ if r.Type() >= objabi.ElfRelocOffset {
+ ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false
}
// Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", ldr.SymName(targ))
}
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly.
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
+ if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
+ ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
}
- r.Type = objabi.R_PCREL
- r.Add += 4
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+4)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32):
- r.Type = objabi.R_PCREL
- r.Add += 4
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocAdd(rIdx, r.Add()+4)
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
}
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
- if targ.Type != sym.SDYNIMPORT {
+ su := ldr.MakeSymbolUpdater(s)
+ if targType != sym.SDYNIMPORT {
// have symbol
- if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
- // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
- s.P[r.Off-2] = 0x8d
+ sData := ldr.Data(s)
- r.Type = objabi.R_GOTOFF
+ if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
+ su.MakeWritable()
+
+ // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
+ writeableData := su.Data()
+ writeableData[r.Off()-2] = 0x8d
+ su.SetRelocType(rIdx, objabi.R_GOTOFF)
return true
}
- if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
+ if r.Off() >= 2 && sData[r.Off()-2] == 0xff && sData[r.Off()-1] == 0xb3 {
+ su.MakeWritable()
// turn PUSHL of GOT entry into PUSHL of symbol itself.
// use unnecessary SS prefix to keep instruction same length.
- s.P[r.Off-2] = 0x36
-
- s.P[r.Off-1] = 0x68
- r.Type = objabi.R_ADDR
+ writeableData := su.Data()
+ writeableData[r.Off()-2] = 0x36
+ writeableData[r.Off()-1] = 0x68
+ su.SetRelocType(rIdx, objabi.R_ADDR)
return true
}
- ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+ ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
return false
}
- addgotsym(target, syms, targ)
- r.Type = objabi.R_CONST // write r->add during relocsym
- r.Sym = nil
- r.Add += int64(targ.Got())
+ addgotsym2(target, ldr, syms, targ)
+ su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
+ su.SetRelocSym(rIdx, 0)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF):
- r.Type = objabi.R_GOTOFF
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_GOTOFF)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += 4
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_PCREL)
+ su.SetRelocSym(rIdx, syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+4)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", ldr.SymName(targ))
}
- r.Type = objabi.R_ADDR
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ADDR)
return true
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
- r.Type = objabi.R_ADDR
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ADDR)
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
}
return true
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
- r.Type = objabi.R_PCREL
+ su := ldr.MakeSymbolUpdater(s)
+ if targType == sym.SDYNIMPORT {
+ addpltsym2(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
+ su.SetRelocType(rIdx, objabi.R_PCREL)
return true
}
- r.Type = objabi.R_PCREL
+ su.SetRelocType(rIdx, objabi.R_PCREL)
return true
case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
- if targ.Type != sym.SDYNIMPORT {
+ su := ldr.MakeSymbolUpdater(s)
+ if targType != sym.SDYNIMPORT {
// have symbol
// turn MOVL of GOT entry into LEAL of symbol itself
- if r.Off < 2 || s.P[r.Off-2] != 0x8b {
- ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+ sData := ldr.Data(s)
+ if r.Off() < 2 || sData[r.Off()-2] != 0x8b {
+ ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
return false
}
- s.P[r.Off-2] = 0x8d
- r.Type = objabi.R_PCREL
+ su.MakeWritable()
+ writeableData := su.Data()
+ writeableData[r.Off()-2] = 0x8d
+ su.SetRelocType(rIdx, objabi.R_PCREL)
return true
}
- addgotsym(target, syms, targ)
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
- r.Type = objabi.R_PCREL
+ addgotsym2(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.GOT2)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
+ su.SetRelocType(rIdx, objabi.R_PCREL)
return true
}
// Handle references to ELF symbols from our own object files.
- if targ.Type != sym.SDYNIMPORT {
+ if targType != sym.SDYNIMPORT {
return true
}
- switch r.Type {
+
+ // Reread the reloc to incorporate any changes in type above.
+ relocs := ldr.Relocs(s)
+ *r = relocs.At2(rIdx)
+
+ switch r.Type() {
case objabi.R_CALL,
objabi.R_PCREL:
if target.IsExternal() {
// External linker will do this relocation.
return true
}
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
+ addpltsym2(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.PLT2)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
return true
case objabi.R_ADDR:
- if s.Type != sym.SDATA {
+ if ldr.SymType(s) != sym.SDATA {
break
}
if target.IsElf() {
- ld.Adddynsym(target, syms, targ)
- rel := syms.Rel
- rel.AddAddrPlus(target.Arch, s, int64(r.Off))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32)))
- r.Type = objabi.R_CONST // write r->add during relocsym
- r.Sym = nil
+ ld.Adddynsym2(ldr, target, syms, targ)
+ rel := ldr.MakeSymbolUpdater(syms.Rel2)
+ rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
+ rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
+ su.SetRelocSym(rIdx, 0)
return true
}
- if target.IsDarwin() && s.Size == int64(target.Arch.PtrSize) && r.Off == 0 {
+ if target.IsDarwin() && ldr.SymSize(s) == int64(target.Arch.PtrSize) && r.Off() == 0 {
// Mach-O relocations are a royal pain to lay out.
// They use a compact stateful bytecode representation
// that is too much bother to deal with.
@@ -294,18 +322,17 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- ld.Adddynsym(target, syms, targ)
+ ld.Adddynsym2(ldr, target, syms, targ)
- got := syms.GOT
- s.Type = got.Type
- s.Attr |= sym.AttrSubSymbol
- s.Outer = got
- s.Sub = got.Sub
- got.Sub = s
- s.Value = got.Size
+ got := ldr.MakeSymbolUpdater(syms.GOT2)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetType(got.Type())
+ got.PrependSub(s)
+ su.SetValue(got.Size())
got.AddUint32(target.Arch, 0)
- syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid))
- r.Type = objabi.ElfRelocOffset // ignore during relocsym
+ leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
+ leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ)))
+ su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
return true
}
}
@@ -316,7 +343,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write32(uint32(sectoff))
- elfsym := r.Xsym.ElfsymForReloc()
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type {
default:
return false
@@ -452,18 +479,18 @@ func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.S
}
}
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
+func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymPlt(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
+ ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() {
- plt := syms.PLT
- got := syms.GOTPLT
- rel := syms.RelPLT
- if plt.Size == 0 {
+ plt := ldr.MakeSymbolUpdater(syms.PLT2)
+ got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
+ rel := ldr.MakeSymbolUpdater(syms.RelPLT2)
+ if plt.Size() == 0 {
panic("plt is not set up")
}
@@ -471,69 +498,73 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
plt.AddUint8(0xff)
plt.AddUint8(0x25)
- plt.AddAddrPlus(target.Arch, got, got.Size)
+ plt.AddAddrPlus(target.Arch, got.Sym(), got.Size())
// add to got: pointer to current pos in plt
- got.AddAddrPlus(target.Arch, plt, plt.Size)
+ got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
// pushl $x
plt.AddUint8(0x68)
- plt.AddUint32(target.Arch, uint32(rel.Size))
+ plt.AddUint32(target.Arch, uint32(rel.Size()))
// jmp .plt
plt.AddUint8(0xe9)
- plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
+ plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
// rel
- rel.AddAddrPlus(target.Arch, got, got.Size-4)
+ rel.AddAddrPlus(target.Arch, got.Sym(), got.Size()-4)
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT)))
+ sDynid := ldr.SymDynid(s)
+ rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(sDynid), uint32(elf.R_386_JMP_SLOT)))
- s.SetPlt(int32(plt.Size - 16))
+ ldr.SetPlt(s, int32(plt.Size()-16))
} else if target.IsDarwin() {
// Same laziness as in 6l.
- plt := syms.PLT
+ plt := ldr.MakeSymbolUpdater(syms.PLT2)
- addgotsym(target, syms, s)
+ addgotsym2(target, ldr, syms, s)
- syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid))
+ sDynid := ldr.SymDynid(s)
+ lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT2)
+ lep.AddUint32(target.Arch, uint32(sDynid))
// jmpq *got+size(IP)
- s.SetPlt(int32(plt.Size))
+ ldr.SetPlt(s, int32(plt.Size()))
plt.AddUint8(0xff)
plt.AddUint8(0x25)
- plt.AddAddrPlus(target.Arch, syms.GOT, int64(s.Got()))
+ plt.AddAddrPlus(target.Arch, syms.GOT2, int64(ldr.SymGot(s)))
} else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
+ ldr.Errorf(s, "addpltsym: unsupported binary format")
}
}
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
+func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymGot(s) >= 0 {
return
}
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
+ ld.Adddynsym2(ldr, target, syms, s)
+ got := ldr.MakeSymbolUpdater(syms.GOT2)
+ ldr.SetGot(s, int32(got.Size()))
got.AddUint32(target.Arch, 0)
if target.IsElf() {
- rel := syms.Rel
- rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT)))
+ rel := ldr.MakeSymbolUpdater(syms.Rel2)
+ rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
+ rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_386_GLOB_DAT)))
} else if target.IsDarwin() {
- syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid))
+ leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
+ leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
} else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
+ ldr.Errorf(s, "addgotsym: unsupported binary format")
}
}
-func asmb(ctxt *ld.Link) {
+func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF {
ld.Asmbelfsetup()
}
diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go
index 952113fbff..61e3077b5b 100644
--- a/src/cmd/link/internal/x86/obj.go
+++ b/src/cmd/link/internal/x86/obj.go
@@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
+ Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index bf097532de..1c9e177911 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -675,3 +675,61 @@ func TestTrampoline(t *testing.T) {
t.Errorf("unexpected output:\n%s", out)
}
}
+
+func TestIndexMismatch(t *testing.T) {
+ // Test that index mismatch will cause a link-time error (not run-time error).
+ // This shouldn't happen with "go build". We invoke the compiler and the linker
+ // manually, and try to "trick" the linker with an inconsistent object file.
+ testenv.MustHaveGoBuild(t)
+
+ tmpdir, err := ioutil.TempDir("", "TestIndexMismatch")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ aSrc := filepath.Join("testdata", "testIndexMismatch", "a.go")
+ bSrc := filepath.Join("testdata", "testIndexMismatch", "b.go")
+ mSrc := filepath.Join("testdata", "testIndexMismatch", "main.go")
+ aObj := filepath.Join(tmpdir, "a.o")
+ mObj := filepath.Join(tmpdir, "main.o")
+ exe := filepath.Join(tmpdir, "main.exe")
+
+ // Build a program with main package importing package a.
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, aSrc)
+ t.Log(cmd)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("compiling a.go failed: %v\n%s", err, out)
+ }
+ cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-I", tmpdir, "-o", mObj, mSrc)
+ t.Log(cmd)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("compiling main.go failed: %v\n%s", err, out)
+ }
+ cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
+ t.Log(cmd)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("linking failed: %v\n%s", err, out)
+ }
+
+ // Now, overwrite a.o with the object of b.go. This should
+ // result in an index mismatch.
+ cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, bSrc)
+ t.Log(cmd)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("compiling a.go failed: %v\n%s", err, out)
+ }
+ cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
+ t.Log(cmd)
+ out, err = cmd.CombinedOutput()
+ if err == nil {
+ t.Fatalf("linking didn't fail")
+ }
+ if !bytes.Contains(out, []byte("fingerprint mismatch")) {
+ t.Errorf("did not see expected error message. out:\n%s", out)
+ }
+}
diff --git a/src/cmd/link/testdata/testIndexMismatch/a.go b/src/cmd/link/testdata/testIndexMismatch/a.go
new file mode 100644
index 0000000000..1f3b2c52d2
--- /dev/null
+++ b/src/cmd/link/testdata/testIndexMismatch/a.go
@@ -0,0 +1,8 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+//go:noinline
+func A() { println("A") }
diff --git a/src/cmd/link/testdata/testIndexMismatch/b.go b/src/cmd/link/testdata/testIndexMismatch/b.go
new file mode 100644
index 0000000000..9b55dbf771
--- /dev/null
+++ b/src/cmd/link/testdata/testIndexMismatch/b.go
@@ -0,0 +1,8 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+//go:noinline
+func B() { println("B") }
diff --git a/src/cmd/link/testdata/testIndexMismatch/main.go b/src/cmd/link/testdata/testIndexMismatch/main.go
new file mode 100644
index 0000000000..bc15236f1e
--- /dev/null
+++ b/src/cmd/link/testdata/testIndexMismatch/main.go
@@ -0,0 +1,9 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "a"
+
+func main() { a.A() }