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) // is the offset value of &got.plt[n] to &got.plt[0] // ldr x17, [x16, ] - 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, - 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 := "" - var addr int64 - if r.Sym != nil { - nam = r.Sym.Name - addr = Symaddr(r.Sym) - } - xnam := "" - 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) - ctxt.Syms.Lookup("runtime.ebss", 0).Attr.Set(sym.AttrSpecial, false) + ebss := ldr.CreateSymForUpdate("runtime.ebss", 0) + ldr.SetAttrSpecial(ebss.Sym(), false) - data := ctxt.Syms.Lookup("runtime.data", 0) - data.Size = 8 - data.Attr.Set(sym.AttrSpecial, false) + data := ldr.CreateSymForUpdate("runtime.data", 0) + data.SetSize(8) + ldr.SetAttrSpecial(data.Sym(), 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, + // 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 + + // 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 } - - 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)) - - 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 - } - } - 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 := "" + var addr int64 + if r.Sym != nil { + nam = r.Sym.Name + addr = Symaddr(r.Sym) + } + xnam := "" + 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() { + + dynid := ldr.SymDynid(sy) + if ldr.SymDynimpvers(sy) != "" { + need[dynid] = addelflib(&needlib, ldr.SymDynimplib(sy), ldr.SymDynimpvers(sy)) } - if sy.Dynimpvers() != "" { - need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib(), sy.Dynimpvers()) - } - - 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 +func collectmachosyms(ctxt *Link) { + ldr := ctxt.loader + + addsym := func(s loader.Sym) { + sortsym = append(sortsym, s) + nkind[symkind(ldr, s)]++ } - switch type_ { - default: - return - - case DataSym, BSSSym, TextSym: - break + // 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) + } } - if sortsym != nil { - sortsym[nsortsym] = s - nkind[symkind(s)]++ + // Add text symbols. + for _, s := range ctxt.Textp2 { + 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] - - 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() }