cmd: merge branch 'dev.link' into master

In the dev.link branch we continued developing the new object
file format support and the linker improvements described in
https://golang.org/s/better-linker . Since the last merge, more
progress has been made to improve the new linker.

This is a clean merge.

Change-Id: Ide5ad6fcec9cede99e9b21c4548929b4ba1f4185
This commit is contained in:
Cherry Zhang 2020-04-30 17:08:35 -04:00
commit d0754cfe4a
59 changed files with 3094 additions and 2446 deletions

View file

@ -35,6 +35,8 @@
// } // }
// } // }
// //
// Fingerprint [8]byte
//
// uvarint means a uint64 written out using uvarint encoding. // uvarint means a uint64 written out using uvarint encoding.
// //
// []T means a uvarint followed by that many T objects. In other // []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, &hdr)
io.Copy(out, &p.strings) io.Copy(out, &p.strings)
io.Copy(out, &p.data0) 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 // writeIndex writes out an object index. mainIndex indicates whether

View file

@ -10,6 +10,7 @@ package gc
import ( import (
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/goobj2"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
"encoding/binary" "encoding/binary"
@ -95,7 +96,7 @@ func (r *intReader) uint64() uint64 {
return i 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} ir := &intReader{in, pkg}
version := ir.uint64() version := ir.uint64()
@ -188,6 +189,14 @@ func iimport(pkg *types.Pkg, in *bio.Reader) {
inlineImporter[s] = iimporterAndOffset{p, off} 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 { type iimporter struct {

View file

@ -14,6 +14,7 @@ import (
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/dwarf" "cmd/internal/dwarf"
"cmd/internal/goobj2"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/src" "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: // In the importfile, if we find:
// $$\n (textual format): not supported anymore // $$\n (textual format): not supported anymore
// $$B\n (binary format) : import directly, then feed the lexer a dummy statement // $$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() c, _ = imp.ReadByte()
} }
var fingerprint goobj2.FingerprintType
switch c { switch c {
case '\n': case '\n':
yyerror("cannot import %s: old export format no longer supported (recompile library)", path_) 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) yyerror("import %s: unexpected package format byte: %v", file, c)
errorexit() errorexit()
} }
iimport(importpkg, imp) fingerprint = iimport(importpkg, imp)
default: default:
yyerror("no import in %q", path_) yyerror("no import in %q", path_)
errorexit() 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 { if importpkg.Height >= myheight {
myheight = importpkg.Height + 1 myheight = importpkg.Height + 1
} }

View file

@ -25,7 +25,11 @@ func (r *objReader) readNew() {
} }
// Imports // 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() pkglist := rr.Pkglist()

View file

@ -19,17 +19,21 @@ import (
// New object file format. // New object file format.
// //
// Header struct { // Header struct {
// Magic [...]byte // "\x00go115ld" // Magic [...]byte // "\x00go115ld"
// Flags uint32 // Fingerprint [8]byte
// // TODO: Fingerprint // Flags uint32
// Offsets [...]uint32 // byte offset of each block below // Offsets [...]uint32 // byte offset of each block below
// } // }
// //
// Strings [...]struct { // Strings [...]struct {
// Data [...]byte // 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 // PkgIndex [...]string // referenced packages by index
// //
// DwarfFiles [...]string // DwarfFiles [...]string
@ -119,6 +123,10 @@ import (
const stringRefSize = 8 // two uint32s const stringRefSize = 8 // two uint32s
type FingerprintType [8]byte
func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
// Package Index. // Package Index.
const ( const (
PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols
@ -149,15 +157,17 @@ const (
// File header. // File header.
// TODO: probably no need to export this. // TODO: probably no need to export this.
type Header struct { type Header struct {
Magic string Magic string
Flags uint32 Fingerprint FingerprintType
Offsets [NBlk]uint32 Flags uint32
Offsets [NBlk]uint32
} }
const Magic = "\x00go115ld" const Magic = "\x00go115ld"
func (h *Header) Write(w *Writer) { func (h *Header) Write(w *Writer) {
w.RawString(h.Magic) w.RawString(h.Magic)
w.Bytes(h.Fingerprint[:])
w.Uint32(h.Flags) w.Uint32(h.Flags)
for _, x := range h.Offsets { for _, x := range h.Offsets {
w.Uint32(x) w.Uint32(x)
@ -171,6 +181,8 @@ func (h *Header) Read(r *Reader) error {
return errors.New("wrong magic, not a Go object file") return errors.New("wrong magic, not a Go object file")
} }
off := uint32(len(h.Magic)) off := uint32(len(h.Magic))
copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
off += 8
h.Flags = r.uint32At(off) h.Flags = r.uint32At(off)
off += 4 off += 4
for i := range h.Offsets { for i := range h.Offsets {
@ -184,6 +196,19 @@ func (h *Header) Size() int {
return len(h.Magic) + 4 + 4*len(h.Offsets) 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. // Symbol definition.
// //
// Serialized format: // Serialized format:
@ -495,12 +520,18 @@ func (r *Reader) StringRef(off uint32) string {
return r.StringAt(r.uint32At(off+4), l) return r.StringAt(r.uint32At(off+4), l)
} }
func (r *Reader) Autolib() []string { func (r *Reader) Fingerprint() FingerprintType {
n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / stringRefSize return r.h.Fingerprint
s := make([]string, n) }
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 { for i := range s {
off := r.h.Offsets[BlkAutolib] + uint32(i)*stringRefSize s[i].Pkg = r.StringRef(off)
s[i] = r.StringRef(off) copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
off += importedPkgSize
} }
return s return s
} }
@ -508,9 +539,10 @@ func (r *Reader) Autolib() []string {
func (r *Reader) Pkglist() []string { func (r *Reader) Pkglist() []string {
n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
s := make([]string, n) s := make([]string, n)
off := r.h.Offsets[BlkPkgIdx]
for i := range s { for i := range s {
off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
s[i] = r.StringRef(off) s[i] = r.StringRef(off)
off += stringRefSize
} }
return s return s
} }

View file

@ -5,12 +5,13 @@
package obj package obj
import ( import (
"cmd/internal/goobj2"
"cmd/internal/src" "cmd/internal/src"
) )
// AddImport adds a package to the list of imported packages. // AddImport adds a package to the list of imported packages.
func (ctxt *Link) AddImport(pkg string) { func (ctxt *Link) AddImport(pkg string, fingerprint goobj2.FingerprintType) {
ctxt.Imports = append(ctxt.Imports, pkg) ctxt.Imports = append(ctxt.Imports, goobj2.ImportedPkg{Pkg: pkg, Fingerprint: fingerprint})
} }
func linkgetlineFromPos(ctxt *Link, xpos src.XPos) (f string, l int32) { func linkgetlineFromPos(ctxt *Link, xpos src.XPos) (f string, l int32) {

View file

@ -33,6 +33,7 @@ package obj
import ( import (
"bufio" "bufio"
"cmd/internal/dwarf" "cmd/internal/dwarf"
"cmd/internal/goobj2"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/src" "cmd/internal/src"
"cmd/internal/sys" "cmd/internal/sys"
@ -666,7 +667,7 @@ type Link struct {
PosTable src.PosTable PosTable src.PosTable
InlTree InlTree // global inlining tree used by gc/inl.go InlTree InlTree // global inlining tree used by gc/inl.go
DwFixups *DwarfFixupTable DwFixups *DwarfFixupTable
Imports []string Imports []goobj2.ImportedPkg
DiagFunc func(string, ...interface{}) DiagFunc func(string, ...interface{})
DiagFlush func() DiagFlush func()
DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node 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 defs []*LSym // list of defined symbols in the current package
nonpkgdefs []*LSym // list of defined non-package symbols nonpkgdefs []*LSym // list of defined non-package symbols
nonpkgrefs []*LSym // list of referenced 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{}) { func (ctxt *Link) Diag(format string, args ...interface{}) {

View file

@ -98,8 +98,9 @@ func WriteObjFile(ctxt *Link, bout *bio.Writer, pkgpath string) {
w.wr.WriteByte(1) w.wr.WriteByte(1)
// Autolib // Autolib
for _, pkg := range ctxt.Imports { for _, p := range ctxt.Imports {
w.writeString(pkg) w.writeString(p.Pkg)
// This object format ignores p.Fingerprint.
} }
w.writeString("") w.writeString("")

View file

@ -38,7 +38,11 @@ func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
if ctxt.Flag_shared { if ctxt.Flag_shared {
flags |= goobj2.ObjFlagShared 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) h.Write(w.Writer)
// String table // String table
@ -46,8 +50,8 @@ func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
// Autolib // Autolib
h.Offsets[goobj2.BlkAutolib] = w.Offset() h.Offsets[goobj2.BlkAutolib] = w.Offset()
for _, pkg := range ctxt.Imports { for i := range ctxt.Imports {
w.StringRef(pkg) ctxt.Imports[i].Write(w.Writer)
} }
// Package references // Package references
@ -180,8 +184,8 @@ func (w *writer) init() {
func (w *writer) StringTable() { func (w *writer) StringTable() {
w.AddString("") w.AddString("")
for _, pkg := range w.ctxt.Imports { for _, p := range w.ctxt.Imports {
w.AddString(pkg) w.AddString(p.Pkg)
} }
for _, pkg := range w.pkglist { for _, pkg := range w.pkglist {
w.AddString(pkg) w.AddString(pkg)

View file

@ -34,6 +34,7 @@ package obj
import ( import (
"cmd/internal/goobj2" "cmd/internal/goobj2"
"cmd/internal/objabi" "cmd/internal/objabi"
"crypto/md5"
"fmt" "fmt"
"log" "log"
"math" "math"
@ -241,6 +242,15 @@ func (ctxt *Link) NumberSyms(asm bool) {
ctxt.pkgIdx[pkg] = ipkg ctxt.pkgIdx[pkg] = ipkg
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 // Returns whether s is a non-package symbol, which needs to be referenced

View file

@ -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 { func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
targ := r.Sym targ := r.Sym()
var targType sym.SymKind
if targ != 0 {
targType = ldr.SymType(targ)
}
switch r.Type { switch r.Type() {
default: default:
if r.Type >= objabi.ElfRelocOffset { if r.Type() >= objabi.ElfRelocOffset {
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type)) ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false return false
} }
// Handle relocations found in ELF object files. // Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name) 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 // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly. // sense and should be removed when someone has thought about it properly.
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() { if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
} }
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += 4 su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocAdd(rIdx, r.Add()+4)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name) ldr.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", ldr.SymName(targ))
} }
if targ.Type == 0 || targ.Type == sym.SXREF { if targType == 0 || targType == sym.SXREF {
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
} }
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += 8 su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocAdd(rIdx, r.Add()+8)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += 4 su.SetRelocType(rIdx, objabi.R_PCREL)
if targ.Type == sym.SDYNIMPORT { su.SetRelocAdd(rIdx, r.Add()+4)
addpltsym(target, syms, targ) if targType == sym.SDYNIMPORT {
r.Sym = syms.PLT addpltsym2(target, ldr, syms, targ)
r.Add += int64(targ.Plt()) su.SetRelocSym(rIdx, syms.PLT2)
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
} }
return true 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), 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_GOTPCRELX),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_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 // have symbol
if r.Off >= 2 && s.P[r.Off-2] == 0x8b { sData := ldr.Data(s)
makeWritable(s) if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
su.MakeWritable()
// turn MOVQ of GOT entry into LEAQ of symbol itself // turn MOVQ of GOT entry into LEAQ of symbol itself
s.P[r.Off-2] = 0x8d writeableData := su.Data()
writeableData[r.Off()-2] = 0x8d
r.Type = objabi.R_PCREL su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += 4 su.SetRelocAdd(rIdx, r.Add()+4)
return true return true
} }
} }
// fall back to using GOT and hope for the best (CMOV*) // fall back to using GOT and hope for the best (CMOV*)
// TODO: just needs relocation, no need to put in .dynsym // TODO: just needs relocation, no need to put in .dynsym
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
r.Type = objabi.R_PCREL su.SetRelocType(rIdx, objabi.R_PCREL)
r.Sym = syms.GOT su.SetRelocSym(rIdx, syms.GOT2)
r.Add += 4 su.SetRelocAdd(rIdx, r.Add()+4+int64(ldr.SymGot(targ)))
r.Add += int64(targ.Got())
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name) 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() { if target.IsPIE() && target.IsInternal() {
// For internal linking PIE, this R_ADDR relocation cannot // For internal linking PIE, this R_ADDR relocation cannot
// be resolved statically. We need to generate a dynamic // 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_SIGNED*2 + 0,
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0: objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
// TODO: What is the difference between all these? // 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 { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name) ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
} }
return true return true
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1: case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
addpltsym(target, syms, targ) addpltsym2(target, ldr, syms, targ)
r.Sym = syms.PLT su := ldr.MakeSymbolUpdater(s)
r.Add = int64(targ.Plt()) su.SetRelocSym(rIdx, syms.PLT2)
r.Type = objabi.R_PCREL su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
return true return true
} }
fallthrough 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_1*2 + 1,
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1, objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*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 { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name) ldr.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", ldr.SymName(targ))
} }
return true return true
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1: case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
// have symbol // have symbol
// turn MOVQ of GOT entry into LEAQ of symbol itself // turn MOVQ of GOT entry into LEAQ of symbol itself
if r.Off < 2 || s.P[r.Off-2] != 0x8b { sdata := ldr.Data(s)
ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name) 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 return false
} }
makeWritable(s) su := ldr.MakeSymbolUpdater(s)
s.P[r.Off-2] = 0x8d su.MakeWritable()
r.Type = objabi.R_PCREL sdata = su.Data()
sdata[r.Off()-2] = 0x8d
su.SetRelocType(rIdx, objabi.R_PCREL)
return true return true
} }
fallthrough fallthrough
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1: case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
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))
} }
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Sym = syms.GOT su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += int64(targ.Got()) su.SetRelocSym(rIdx, syms.GOT2)
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true 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, case objabi.R_CALL,
objabi.R_PCREL: objabi.R_PCREL:
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
// nothing to do, the relocation will be laid out in reloc // nothing to do, the relocation will be laid out in reloc
return true 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. // Internal linking, for both ELF and Mach-O.
// Build a PLT entry and change the relocation target to that entry. // Build a PLT entry and change the relocation target to that entry.
addpltsym(target, syms, targ) addpltsym2(target, ldr, syms, targ)
r.Sym = syms.PLT su := ldr.MakeSymbolUpdater(s)
r.Add = int64(targ.Plt()) su.SetRelocSym(rIdx, syms.PLT2)
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
return true return true
case objabi.R_ADDR: 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() { if target.IsSolaris() {
addpltsym(target, syms, targ) addpltsym2(target, ldr, syms, targ)
r.Sym = syms.PLT su.SetRelocSym(rIdx, syms.PLT2)
r.Add += int64(targ.Plt()) su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
return true return true
} }
// The code is asking for the address of an external // The code is asking for the address of an external
// function. We provide it with the address of the // function. We provide it with the address of the
// correspondent GOT symbol. // correspondent GOT symbol.
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
r.Sym = syms.GOT su.SetRelocSym(rIdx, syms.GOT2)
r.Add += int64(targ.Got()) su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true 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 // symbol offset as determined by reloc(), not the
// final dynamically linked address as a dynamic // final dynamically linked address as a dynamic
// relocation would provide. // relocation would provide.
switch s.Name { switch ldr.SymName(s) {
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic": case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
return false 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 // linking, in which case the relocation will be
// prepared in the 'reloc' phase and passed to the // prepared in the 'reloc' phase and passed to the
// external linker in the 'asmb' phase. // 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 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 // AddAddrPlus is used for r_offset and r_addend to
// generate new R_ADDR relocations that will update // generate new R_ADDR relocations that will update
// these fields in the 'reloc' phase. // these fields in the 'reloc' phase.
rela := syms.Rela rela := ldr.MakeSymbolUpdater(syms.Rela2)
rela.AddAddrPlus(target.Arch, s, int64(r.Off)) rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
if r.Siz == 8 { if r.Siz() == 8 {
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE))) rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
} else { } 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, // Not mark r done here. So we still apply it statically,
// so in the file content we'll also have the right offset // so in the file content we'll also have the right offset
// to the relocation target. So it can be examined statically // 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 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. // Mach-O relocations are a royal pain to lay out.
// They use a compact stateful bytecode representation // They use a compact stateful bytecode representation
// that is too much bother to deal with. // 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, // just in case the C code assigns to the variable,
// and of course it only works for single pointers, // and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs. // 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 got := ldr.MakeSymbolUpdater(syms.GOT2)
s.Type = got.Type su := ldr.MakeSymbolUpdater(s)
s.Attr |= sym.AttrSubSymbol su.SetType(got.Type())
s.Outer = got got.PrependSub(s)
s.Sub = got.Sub su.SetValue(got.Size())
got.Sub = s
s.Value = got.Size
got.AddUint64(target.Arch, 0) got.AddUint64(target.Arch, 0)
syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid)) leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
r.Type = objabi.ElfRelocOffset // ignore during relocsym leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ)))
su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
return true 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 { func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write64(uint64(sectoff)) ctxt.Out.Write64(uint64(sectoff))
elfsym := r.Xsym.ElfsymForReloc() elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type { switch r.Type {
default: default:
return false 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) { func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Plt() >= 0 { if ldr.SymPlt(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() { if target.IsElf() {
plt := syms.PLT plt := ldr.MakeSymbolUpdater(syms.PLT2)
got := syms.GOTPLT got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
rela := syms.RelaPLT rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
if plt.Size == 0 { if plt.Size() == 0 {
panic("plt is not set up") 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(0xff)
plt.AddUint8(0x25) 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 // 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 // pushq $x
plt.AddUint8(0x68) 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 // jmpq .plt
plt.AddUint8(0xe9) plt.AddUint8(0xe9)
plt.AddUint32(target.Arch, uint32(-(plt.Size + 4))) plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
// rela // 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) rela.AddUint64(target.Arch, 0)
s.SetPlt(int32(plt.Size - 16)) ldr.SetPlt(s, int32(plt.Size()-16))
} else if target.IsDarwin() { } else if target.IsDarwin() {
// To do lazy symbol lookup right, we're supposed // To do lazy symbol lookup right, we're supposed
// to tell the dynamic loader which library each // 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 // https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
// has details about what we're avoiding. // has details about what we're avoiding.
addgotsym(target, syms, s) addgotsym2(target, ldr, syms, s)
plt := syms.PLT 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) // jmpq *got+size(IP)
s.SetPlt(int32(plt.Size)) ldr.SetPlt(s, int32(plt.Size()))
plt.AddUint8(0xff) plt.AddUint8(0xff)
plt.AddUint8(0x25) plt.AddUint8(0x25)
plt.AddPCRelPlus(target.Arch, syms.GOT, int64(s.Got())) plt.AddPCRelPlus(target.Arch, syms.GOT2, int64(ldr.SymGot(s)))
} else { } 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) { func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Got() >= 0 { if ldr.SymGot(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
got := syms.GOT got := ldr.MakeSymbolUpdater(syms.GOT2)
s.SetGot(int32(got.Size)) ldr.SetGot(s, int32(got.Size()))
got.AddUint64(target.Arch, 0) got.AddUint64(target.Arch, 0)
if target.IsElf() { if target.IsElf() {
rela := syms.Rela rela := ldr.MakeSymbolUpdater(syms.Rela2)
rela.AddAddrPlus(target.Arch, got, int64(s.Got())) rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT))) rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_X86_64_GLOB_DAT)))
rela.AddUint64(target.Arch, 0) rela.AddUint64(target.Arch, 0)
} else if target.IsDarwin() { } 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 { } 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 { if ctxt.IsELF {
ld.Asmbelfsetup() 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. // Transform the PC-relative instruction into a constant load.
// That is, // That is,
// //
@ -827,7 +852,7 @@ func tlsIEtoLE(s *sym.Symbol, off, size int) {
if off < 3 { if off < 3 {
log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction") 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 reg := op[2] >> 3
if op[1] == 0x8b || reg == 4 { if op[1] == 0x8b || reg == 4 {

View file

@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP, Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR, Dwarfreglr: dwarfRegLR,
Adddynrel: adddynrel, Adddynrel2: adddynrel2,
Archinit: archinit, Archinit: archinit,
Archreloc: archreloc, Archreloc: archreloc,
Archrelocvariant: archrelocvariant, Archrelocvariant: archrelocvariant,

View file

@ -103,24 +103,30 @@ func braddoff(a int32, b int32) int32 {
return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b)) 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 { func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
targ := r.Sym
switch r.Type { targ := r.Sym()
var targType sym.SymKind
if targ != 0 {
targType = ldr.SymType(targ)
}
switch r.Type() {
default: default:
if r.Type >= objabi.ElfRelocOffset { if r.Type() >= objabi.ElfRelocOffset {
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type)) ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false return false
} }
// Handle relocations found in ELF object files. // Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PLT32): 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 { if targType == sym.SDYNIMPORT {
addpltsym(target, syms, targ) addpltsym2(target, ldr, syms, targ)
r.Sym = syms.PLT su.SetRelocSym(rIdx, syms.PLT2)
r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4)))
} }
return true return true
@ -130,113 +136,112 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
return false return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT32): // R_ARM_GOT_BREL case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT32): // R_ARM_GOT_BREL
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
addgotsyminternal(target, syms, targ) addgotsyminternal2(target, ldr, syms, targ)
} else { } else {
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
} }
r.Type = objabi.R_CONST // write r->add during relocsym su := ldr.MakeSymbolUpdater(s)
r.Sym = nil su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
r.Add += int64(targ.Got()) su.SetRelocSym(rIdx, 0)
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT_PREL): // GOT(nil) + A - nil case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT_PREL): // GOT(nil) + A - nil
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
addgotsyminternal(target, syms, targ) addgotsyminternal2(target, ldr, syms, targ)
} else { } else {
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
} }
su := ldr.MakeSymbolUpdater(s)
r.Type = objabi.R_PCREL su.SetRelocType(rIdx, objabi.R_PCREL)
r.Sym = syms.GOT su.SetRelocSym(rIdx, syms.GOT2)
r.Add += int64(targ.Got()) + 4 su.SetRelocAdd(rIdx, r.Add()+4+int64(ldr.SymGot(targ)))
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTOFF): // R_ARM_GOTOFF32 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTPC): // R_ARM_BASE_PREL case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTPC): // R_ARM_BASE_PREL
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_PCREL)
r.Sym = syms.GOT su.SetRelocSym(rIdx, syms.GOT2)
r.Add += 4 su.SetRelocAdd(rIdx, r.Add()+4)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_CALL): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_CALL):
r.Type = objabi.R_CALLARM su := ldr.MakeSymbolUpdater(s)
if targ.Type == sym.SDYNIMPORT { su.SetRelocType(rIdx, objabi.R_CALLARM)
addpltsym(target, syms, targ) if targType == sym.SDYNIMPORT {
r.Sym = syms.PLT addpltsym2(target, ldr, syms, targ)
r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) su.SetRelocSym(rIdx, syms.PLT2)
su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4)))
} }
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_REL32): // R_ARM_REL32 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_REL32): // R_ARM_REL32
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += 4 su.SetRelocAdd(rIdx, r.Add()+4)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_ABS32): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_ABS32):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name) ldr.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", ldr.SymName(targ))
} }
r.Type = objabi.R_ADDR su := ldr.MakeSymbolUpdater(s)
return true su.SetRelocType(rIdx, objabi.R_ADDR)
// 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
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PC24), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PC24),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_JUMP24): objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_JUMP24):
r.Type = objabi.R_CALLARM su := ldr.MakeSymbolUpdater(s)
if targ.Type == sym.SDYNIMPORT { su.SetRelocType(rIdx, objabi.R_CALLARM)
addpltsym(target, syms, targ) if targType == sym.SDYNIMPORT {
r.Sym = syms.PLT addpltsym2(target, ldr, syms, targ)
r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) su.SetRelocSym(rIdx, syms.PLT2)
su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4)))
} }
return true return true
} }
// Handle references to ELF symbols from our own object files. // Handle references to ELF symbols from our own object files.
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
return true 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: case objabi.R_CALLARM:
if target.IsExternal() { if target.IsExternal() {
// External linker will do this relocation. // External linker will do this relocation.
return true return true
} }
addpltsym(target, syms, targ) addpltsym2(target, ldr, syms, targ)
r.Sym = syms.PLT su := ldr.MakeSymbolUpdater(s)
r.Add = int64(targ.Plt()) su.SetRelocSym(rIdx, syms.PLT2)
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
return true return true
case objabi.R_ADDR: case objabi.R_ADDR:
if s.Type != sym.SDATA { if ldr.SymType(s) != sym.SDATA {
break break
} }
if target.IsElf() { if target.IsElf() {
ld.Adddynsym(target, syms, targ) ld.Adddynsym2(ldr, target, syms, targ)
rel := syms.Rel rel := ldr.MakeSymbolUpdater(syms.Rel2)
rel.AddAddrPlus(target.Arch, s, int64(r.Off)) 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 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
r.Type = objabi.R_CONST // write r->add during relocsym su := ldr.MakeSymbolUpdater(s)
r.Sym = nil su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
su.SetRelocSym(rIdx, 0)
return true 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 { func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write32(uint32(sectoff)) ctxt.Out.Write32(uint32(sectoff))
elfsym := r.Xsym.ElfsymForReloc() elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type { switch r.Type {
default: default:
return false return false
@ -592,94 +597,92 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
return t return t
} }
func addpltreloc(plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, typ objabi.RelocType) { func addpltreloc2(ldr *loader.Loader, plt *loader.SymbolBuilder, got *loader.SymbolBuilder, s loader.Sym, typ objabi.RelocType) {
r := plt.AddRel() r, _ := plt.AddRel(typ)
r.Sym = got r.SetSym(got.Sym())
r.Off = int32(plt.Size) r.SetOff(int32(plt.Size()))
r.Siz = 4 r.SetSiz(4)
r.Type = typ r.SetAdd(int64(ldr.SymGot(s)) - 8)
r.Add = int64(s.Got()) - 8
plt.Attr |= sym.AttrReachable plt.SetReachable(true)
plt.Size += 4 plt.SetSize(plt.Size() + 4)
plt.Grow(plt.Size) plt.Grow(plt.Size())
} }
func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) { func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Plt() >= 0 { if ldr.SymPlt(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() { if target.IsElf() {
plt := syms.PLT plt := ldr.MakeSymbolUpdater(syms.PLT2)
got := syms.GOTPLT got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
rel := syms.RelPLT rel := ldr.MakeSymbolUpdater(syms.RelPLT2)
if plt.Size == 0 { if plt.Size() == 0 {
panic("plt is not set up") panic("plt is not set up")
} }
// .got entry // .got entry
s.SetGot(int32(got.Size)) ldr.SetGot(s, int32(got.Size()))
// In theory, all GOT should point to the first PLT entry, // 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 // 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. // 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 // .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 addpltreloc2(ldr, plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000
addpltreloc(plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000 addpltreloc2(ldr, 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_PLT2) // ldr pc, [lr, #0xZZZ]!
// rel // 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 { } 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) { func addgotsyminternal2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Got() >= 0 { if ldr.SymGot(s) >= 0 {
return return
} }
got := syms.GOT got := ldr.MakeSymbolUpdater(syms.GOT2)
s.SetGot(int32(got.Size)) ldr.SetGot(s, int32(got.Size()))
got.AddAddrPlus(target.Arch, s, 0) got.AddAddrPlus(target.Arch, s, 0)
if target.IsElf() { if target.IsElf() {
} else { } 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) { func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Got() >= 0 { if ldr.SymGot(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
got := syms.GOT got := ldr.MakeSymbolUpdater(syms.GOT2)
s.SetGot(int32(got.Size)) ldr.SetGot(s, int32(got.Size()))
got.AddUint32(target.Arch, 0) got.AddUint64(target.Arch, 0)
if target.IsElf() { if target.IsElf() {
rel := syms.Rel rel := ldr.MakeSymbolUpdater(syms.Rel2)
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_GLOB_DAT))) rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_GLOB_DAT)))
} else { } 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 { if ctxt.IsELF {
ld.Asmbelfsetup() ld.Asmbelfsetup()
} }

View file

@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP, Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR, Dwarfreglr: dwarfRegLR,
Adddynrel: adddynrel, Adddynrel2: adddynrel2,
Archinit: archinit, Archinit: archinit,
Archreloc: archreloc, Archreloc: archreloc,
Archrelocvariant: archrelocvariant, Archrelocvariant: archrelocvariant,

View file

@ -78,86 +78,97 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
initfunc.AddReloc(rel2) initfunc.AddReloc(rel2)
} }
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 {
targ := r.Sym
switch r.Type { targ := r.Sym()
var targType sym.SymKind
if targ != 0 {
targType = ldr.SymType(targ)
}
switch r.Type() {
default: default:
if r.Type >= objabi.ElfRelocOffset { if r.Type() >= objabi.ElfRelocOffset {
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type)) ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false return false
} }
// Handle relocations found in ELF object files. // Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL32): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL32):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", targ.Name) 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 // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly. // sense and should be removed when someone has thought about it properly.
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() { if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
} }
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += 4 su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocAdd(rIdx, r.Add()+4)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL64): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL64):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", targ.Name) ldr.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", ldr.SymName(targ))
} }
if targ.Type == 0 || targ.Type == sym.SXREF { if targType == 0 || targType == sym.SXREF {
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
} }
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += 8 su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocAdd(rIdx, r.Add()+8)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26): objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
addpltsym(target, syms, targ) addpltsym2(target, ldr, syms, targ)
r.Sym = syms.PLT su := ldr.MakeSymbolUpdater(s)
r.Add += int64(targ.Plt()) 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() { if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
ld.Errorf(s, "unknown symbol %s in callarm64", targ.Name) 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC): objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC):
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
// have symbol // have symbol
// TODO: turn LDR of GOT entry into ADR of symbol itself // TODO: turn LDR of GOT entry into ADR of symbol itself
} }
// fall back to using GOT // fall back to using GOT
// TODO: just needs relocation, no need to put in .dynsym // TODO: just needs relocation, no need to put in .dynsym
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
su := ldr.MakeSymbolUpdater(s)
r.Type = objabi.R_ARM64_GOT su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
r.Sym = syms.GOT su.SetRelocSym(rIdx, syms.GOT2)
r.Add += int64(targ.Got()) su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC): objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
} }
if targ.Type == 0 || targ.Type == sym.SXREF { if targType == 0 || targType == sym.SXREF {
ld.Errorf(s, "unknown symbol %s", targ.Name) 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", targ.Name) 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() { if target.IsPIE() && target.IsInternal() {
// For internal linking PIE, this R_ADDR relocation cannot // For internal linking PIE, this R_ADDR relocation cannot
// be resolved statically. We need to generate a dynamic // 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) 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 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, case objabi.R_CALL,
objabi.R_PCREL, objabi.R_PCREL,
objabi.R_CALLARM64: objabi.R_CALLARM64:
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
// nothing to do, the relocation will be laid out in reloc // nothing to do, the relocation will be laid out in reloc
return true return true
} }
@ -209,14 +229,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
} }
case objabi.R_ADDR: 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 // The code is asking for the address of an external
// function. We provide it with the address of the // function. We provide it with the address of the
// correspondent GOT symbol. // correspondent GOT symbol.
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
su := ldr.MakeSymbolUpdater(s)
r.Sym = syms.GOT su.SetRelocSym(rIdx, syms.GOT2)
r.Add += int64(targ.Got()) su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true 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 // symbol offset as determined by reloc(), not the
// final dynamically linked address as a dynamic // final dynamically linked address as a dynamic
// relocation would provide. // relocation would provide.
switch s.Name { switch ldr.SymName(s) {
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic": case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
return false 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 // linking, in which case the relocation will be
// prepared in the 'reloc' phase and passed to the // prepared in the 'reloc' phase and passed to the
// external linker in the 'asmb' phase. // 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 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 // AddAddrPlus is used for r_offset and r_addend to
// generate new R_ADDR relocations that will update // generate new R_ADDR relocations that will update
// these fields in the 'reloc' phase. // these fields in the 'reloc' phase.
rela := syms.Rela rela := ldr.MakeSymbolUpdater(syms.Rela2)
rela.AddAddrPlus(target.Arch, s, int64(r.Off)) rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
if r.Siz == 8 { if r.Siz() == 8 {
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_AARCH64_RELATIVE))) rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
} else { } 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, // Not mark r done here. So we still apply it statically,
// so in the file content we'll also have the right offset // so in the file content we'll also have the right offset
// to the relocation target. So it can be examined statically // 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 { func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write64(uint64(sectoff)) ctxt.Out.Write64(uint64(sectoff))
elfsym := r.Xsym.ElfsymForReloc() elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type { switch r.Type {
default: default:
return false 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) { func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Plt() >= 0 { if ldr.SymPlt(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() { if target.IsElf() {
plt := syms.PLT plt := ldr.MakeSymbolUpdater(syms.PLT2)
gotplt := syms.GOTPLT gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT2)
rela := syms.RelaPLT rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
if plt.Size == 0 { if plt.Size() == 0 {
panic("plt is not set up") panic("plt is not set up")
} }
// adrp x16, &got.plt[0] // adrp x16, &got.plt[0]
plt.AddAddrPlus4(gotplt, gotplt.Size) plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
plt.SetUint32(target.Arch, plt.Size-4, 0x90000010) plt.SetUint32(target.Arch, plt.Size()-4, 0x90000010)
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT relocs := plt.Relocs()
plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
// <offset> is the offset value of &got.plt[n] to &got.plt[0] // <offset> is the offset value of &got.plt[n] to &got.plt[0]
// ldr x17, [x16, <offset>] // ldr x17, [x16, <offset>]
plt.AddAddrPlus4(gotplt, gotplt.Size) plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
plt.SetUint32(target.Arch, plt.Size-4, 0xf9400211) plt.SetUint32(target.Arch, plt.Size()-4, 0xf9400211)
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT relocs = plt.Relocs()
plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
// add x16, x16, <offset> // add x16, x16, <offset>
plt.AddAddrPlus4(gotplt, gotplt.Size) plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
plt.SetUint32(target.Arch, plt.Size-4, 0x91000210) plt.SetUint32(target.Arch, plt.Size()-4, 0x91000210)
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL relocs = plt.Relocs()
plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_PCREL)
// br x17 // br x17
plt.AddUint32(target.Arch, 0xd61f0220) plt.AddUint32(target.Arch, 0xd61f0220)
// add to got.plt: pointer to plt[0] // add to got.plt: pointer to plt[0]
gotplt.AddAddrPlus(target.Arch, plt, 0) gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
// rela // rela
rela.AddAddrPlus(target.Arch, gotplt, gotplt.Size-8) rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_JUMP_SLOT))) 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) rela.AddUint64(target.Arch, 0)
s.SetPlt(int32(plt.Size - 16)) ldr.SetPlt(s, int32(plt.Size()-16))
} else { } 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) { func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Got() >= 0 { if ldr.SymGot(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
got := syms.GOT got := ldr.MakeSymbolUpdater(syms.GOT2)
s.SetGot(int32(got.Size)) ldr.SetGot(s, int32(got.Size()))
got.AddUint64(target.Arch, 0) got.AddUint64(target.Arch, 0)
if target.IsElf() { if target.IsElf() {
rela := syms.Rela rela := ldr.MakeSymbolUpdater(syms.Rela2)
rela.AddAddrPlus(target.Arch, got, int64(s.Got())) rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_GLOB_DAT))) rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_AARCH64_GLOB_DAT)))
rela.AddUint64(target.Arch, 0) rela.AddUint64(target.Arch, 0)
} else { } 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 { if ctxt.IsELF {
ld.Asmbelfsetup() ld.Asmbelfsetup()
} }

View file

@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP, Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR, Dwarfreglr: dwarfRegLR,
Adddynrel: adddynrel, Adddynrel2: adddynrel2,
Archinit: archinit, Archinit: archinit,
Archreloc: archreloc, Archreloc: archreloc,
Archrelocvariant: archrelocvariant, Archrelocvariant: archrelocvariant,

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,518 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ld
import (
"cmd/internal/objabi"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"fmt"
"log"
"strings"
"sync"
)
// Temporary dumping around for sym.Symbol version of helper
// functions in dodata(), still being used for some archs/oses.
// FIXME: get rid of this file when dodata() is completely
// converted.
func Addstring(s *sym.Symbol, str string) int64 {
if s.Type == 0 {
s.Type = sym.SNOPTRDATA
}
s.Attr |= sym.AttrReachable
r := s.Size
if s.Name == ".shstrtab" {
elfsetstring(s, str, int(r))
}
s.P = append(s.P, str...)
s.P = append(s.P, 0)
s.Size = int64(len(s.P))
return r
}
// symalign returns the required alignment for the given symbol s.
func symalign(s *sym.Symbol) int32 {
min := int32(thearch.Minalign)
if s.Align >= min {
return s.Align
} else if s.Align != 0 {
return min
}
if strings.HasPrefix(s.Name, "go.string.") || strings.HasPrefix(s.Name, "type..namedata.") {
// String data is just bytes.
// If we align it, we waste a lot of space to padding.
return min
}
align := int32(thearch.Maxalign)
for int64(align) > s.Size && align > min {
align >>= 1
}
s.Align = align
return align
}
func relocsym2(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *ArchSyms, s *sym.Symbol) {
if len(s.R) == 0 {
return
}
for ri := int32(0); ri < int32(len(s.R)); ri++ {
r := &s.R[ri]
if r.Done {
// Relocation already processed by an earlier phase.
continue
}
r.Done = true
off := r.Off
siz := int32(r.Siz)
if off < 0 || off+siz > int32(len(s.P)) {
rname := ""
if r.Sym != nil {
rname = r.Sym.Name
}
Errorf(s, "invalid relocation %s: %d+%d not in [%d,%d)", rname, off, siz, 0, len(s.P))
continue
}
if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) {
// When putting the runtime but not main into a shared library
// these symbols are undefined and that's OK.
if target.IsShared() || target.IsPlugin() {
if r.Sym.Name == "main.main" || (!target.IsPlugin() && r.Sym.Name == "main..inittask") {
r.Sym.Type = sym.SDYNIMPORT
} else if strings.HasPrefix(r.Sym.Name, "go.info.") {
// Skip go.info symbols. They are only needed to communicate
// DWARF info between the compiler and linker.
continue
}
} else {
err.errorUnresolved2(s, r)
continue
}
}
if r.Type >= objabi.ElfRelocOffset {
continue
}
if r.Siz == 0 { // informational relocation - no work to do
continue
}
// We need to be able to reference dynimport symbols when linking against
// shared libraries, and Solaris, Darwin and AIX need it always
if !target.IsSolaris() && !target.IsDarwin() && !target.IsAIX() && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !target.IsDynlinkingGo() && !r.Sym.Attr.SubSymbol() {
if !(target.IsPPC64() && target.IsExternal() && r.Sym.Name == ".TOC.") {
Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(target.Arch, r.Type))
}
}
if r.Sym != nil && r.Sym.Type != sym.STLSBSS && r.Type != objabi.R_WEAKADDROFF && !r.Sym.Attr.Reachable() {
Errorf(s, "unreachable sym in relocation: %s", r.Sym.Name)
}
if target.IsExternal() {
r.InitExt()
}
// TODO(mundaym): remove this special case - see issue 14218.
if target.IsS390X() {
switch r.Type {
case objabi.R_PCRELDBL:
r.InitExt()
r.Type = objabi.R_PCREL
r.Variant = sym.RV_390_DBL
case objabi.R_CALL:
r.InitExt()
r.Variant = sym.RV_390_DBL
}
}
var o int64
switch r.Type {
default:
switch siz {
default:
Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
case 1:
o = int64(s.P[off])
case 2:
o = int64(target.Arch.ByteOrder.Uint16(s.P[off:]))
case 4:
o = int64(target.Arch.ByteOrder.Uint32(s.P[off:]))
case 8:
o = int64(target.Arch.ByteOrder.Uint64(s.P[off:]))
}
if offset, ok := thearch.Archreloc(target, syms, r, s, o); ok {
o = offset
} else {
Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(target.Arch, r.Type))
}
case objabi.R_TLS_LE:
if target.IsExternal() && target.IsElf() {
r.Done = false
if r.Sym == nil {
r.Sym = syms.Tlsg
}
r.Xsym = r.Sym
r.Xadd = r.Add
o = 0
if !target.IsAMD64() {
o = r.Add
}
break
}
if target.IsElf() && target.IsARM() {
// On ELF ARM, the thread pointer is 8 bytes before
// the start of the thread-local data block, so add 8
// to the actual TLS offset (r->sym->value).
// This 8 seems to be a fundamental constant of
// ELF on ARM (or maybe Glibc on ARM); it is not
// related to the fact that our own TLS storage happens
// to take up 8 bytes.
o = 8 + r.Sym.Value
} else if target.IsElf() || target.IsPlan9() || target.IsDarwin() {
o = int64(syms.Tlsoffset) + r.Add
} else if target.IsWindows() {
o = r.Add
} else {
log.Fatalf("unexpected R_TLS_LE relocation for %v", target.HeadType)
}
case objabi.R_TLS_IE:
if target.IsExternal() && target.IsElf() {
r.Done = false
if r.Sym == nil {
r.Sym = syms.Tlsg
}
r.Xsym = r.Sym
r.Xadd = r.Add
o = 0
if !target.IsAMD64() {
o = r.Add
}
break
}
if target.IsPIE() && target.IsElf() {
// We are linking the final executable, so we
// can optimize any TLS IE relocation to LE.
if thearch.TLSIEtoLE == nil {
log.Fatalf("internal linking of TLS IE not supported on %v", target.Arch.Family)
}
thearch.TLSIEtoLE(s.P, int(off), int(r.Siz))
o = int64(syms.Tlsoffset)
// TODO: o += r.Add when !target.IsAmd64()?
// Why do we treat r.Add differently on AMD64?
// Is the external linker using Xadd at all?
} else {
log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", s.Name)
}
case objabi.R_ADDR:
if target.IsExternal() && r.Sym.Type != sym.SCONST {
r.Done = false
// set up addend for eventual relocation via outer symbol.
rs := r.Sym
r.Xadd = r.Add
for rs.Outer != nil {
r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
rs = rs.Outer
}
if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
Errorf(s, "missing section for relocation target %s", rs.Name)
}
r.Xsym = rs
o = r.Xadd
if target.IsElf() {
if target.IsAMD64() {
o = 0
}
} else if target.IsDarwin() {
if rs.Type != sym.SHOSTOBJ {
o += Symaddr(rs)
}
} else if target.IsWindows() {
// nothing to do
} else if target.IsAIX() {
o = Symaddr(r.Sym) + r.Add
} else {
Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
}
break
}
// On AIX, a second relocation must be done by the loader,
// as section addresses can change once loaded.
// The "default" symbol address is still needed by the loader so
// the current relocation can't be skipped.
if target.IsAIX() && r.Sym.Type != sym.SDYNIMPORT {
// It's not possible to make a loader relocation in a
// symbol which is not inside .data section.
// FIXME: It should be forbidden to have R_ADDR from a
// symbol which isn't in .data. However, as .text has the
// same address once loaded, this is possible.
if s.Sect.Seg == &Segdata {
Xcoffadddynrel(target, ldr, s, r)
}
}
o = Symaddr(r.Sym) + r.Add
// On amd64, 4-byte offsets will be sign-extended, so it is impossible to
// access more than 2GB of static data; fail at link time is better than
// fail at runtime. See https://golang.org/issue/7980.
// Instead of special casing only amd64, we treat this as an error on all
// 64-bit architectures so as to be future-proof.
if int32(o) < 0 && target.Arch.PtrSize > 4 && siz == 4 {
Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", r.Sym.Name, uint64(o), Symaddr(r.Sym), r.Add)
errorexit()
}
case objabi.R_DWARFSECREF:
if r.Sym.Sect == nil {
Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
}
if target.IsExternal() {
r.Done = false
// On most platforms, the external linker needs to adjust DWARF references
// as it combines DWARF sections. However, on Darwin, dsymutil does the
// DWARF linking, and it understands how to follow section offsets.
// Leaving in the relocation records confuses it (see
// https://golang.org/issue/22068) so drop them for Darwin.
if target.IsDarwin() {
r.Done = true
}
// PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
// for R_DWARFSECREF relocations, while R_ADDR is replaced with
// IMAGE_REL_I386_DIR32, IMAGE_REL_AMD64_ADDR64 and IMAGE_REL_AMD64_ADDR32.
// Do not replace R_DWARFSECREF with R_ADDR for windows -
// let PE code emit correct relocations.
if !target.IsWindows() {
r.Type = objabi.R_ADDR
}
r.Xsym = r.Sym.Sect.Sym
r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
o = r.Xadd
if target.IsElf() && target.IsAMD64() {
o = 0
}
break
}
o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
case objabi.R_WEAKADDROFF:
if !r.Sym.Attr.Reachable() {
continue
}
fallthrough
case objabi.R_ADDROFF:
// The method offset tables using this relocation expect the offset to be relative
// to the start of the first text section, even if there are multiple.
if r.Sym.Sect.Name == ".text" {
o = Symaddr(r.Sym) - int64(Segtext.Sections[0].Vaddr) + r.Add
} else {
o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
}
case objabi.R_ADDRCUOFF:
// debug_range and debug_loc elements use this relocation type to get an
// offset from the start of the compile unit.
u := ldr.SymUnit(loader.Sym(r.Sym.SymIdx))
o = Symaddr(r.Sym) + r.Add - Symaddr(ldr.Syms[u.Textp2[0]])
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
case objabi.R_GOTPCREL:
if target.IsDynlinkingGo() && target.IsDarwin() && r.Sym != nil && r.Sym.Type != sym.SCONST {
r.Done = false
r.Xadd = r.Add
r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
r.Xsym = r.Sym
o = r.Xadd
o += int64(r.Siz)
break
}
fallthrough
case objabi.R_CALL, objabi.R_PCREL:
if target.IsExternal() && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
// pass through to the external linker.
r.Done = false
r.Xadd = 0
if target.IsElf() {
r.Xadd -= int64(r.Siz)
}
r.Xsym = r.Sym
o = 0
break
}
if target.IsExternal() && r.Sym != nil && r.Sym.Type != sym.SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) {
r.Done = false
// set up addend for eventual relocation via outer symbol.
rs := r.Sym
r.Xadd = r.Add
for rs.Outer != nil {
r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
rs = rs.Outer
}
r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
Errorf(s, "missing section for relocation target %s", rs.Name)
}
r.Xsym = rs
o = r.Xadd
if target.IsElf() {
if target.IsAMD64() {
o = 0
}
} else if target.IsDarwin() {
if r.Type == objabi.R_CALL {
if target.IsExternal() && rs.Type == sym.SDYNIMPORT {
if target.IsAMD64() {
// AMD64 dynamic relocations are relative to the end of the relocation.
o += int64(r.Siz)
}
} else {
if rs.Type != sym.SHOSTOBJ {
o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr)
}
o -= int64(r.Off) // relative to section offset, not symbol
}
} else {
o += int64(r.Siz)
}
} else if target.IsWindows() && target.IsAMD64() { // only amd64 needs PCREL
// PE/COFF's PC32 relocation uses the address after the relocated
// bytes as the base. Compensate by skewing the addend.
o += int64(r.Siz)
} else {
Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
}
break
}
o = 0
if r.Sym != nil {
o += Symaddr(r.Sym)
}
o += r.Add - (s.Value + int64(r.Off) + int64(r.Siz))
case objabi.R_SIZE:
o = r.Sym.Size + r.Add
case objabi.R_XCOFFREF:
if !target.IsAIX() {
Errorf(s, "find XCOFF R_REF on non-XCOFF files")
}
if !target.IsExternal() {
Errorf(s, "find XCOFF R_REF with internal linking")
}
r.Xsym = r.Sym
r.Xadd = r.Add
r.Done = false
// This isn't a real relocation so it must not update
// its offset value.
continue
case objabi.R_DWARFFILEREF:
// The final file index is saved in r.Add in dwarf.go:writelines.
o = r.Add
}
if target.IsPPC64() || target.IsS390X() {
r.InitExt()
if r.Variant != sym.RV_NONE {
o = thearch.Archrelocvariant(target, syms, r, s, o)
}
}
if false {
nam := "<nil>"
var addr int64
if r.Sym != nil {
nam = r.Sym.Name
addr = Symaddr(r.Sym)
}
xnam := "<nil>"
if r.Xsym != nil {
xnam = r.Xsym.Name
}
fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x (xsym: %s +%#x) [type %d (%s)/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, addr, r.Add, xnam, r.Xadd, r.Type, sym.RelocName(target.Arch, r.Type), r.Variant, o)
}
switch siz {
default:
Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
fallthrough
// TODO(rsc): Remove.
case 1:
s.P[off] = byte(int8(o))
case 2:
if o != int64(int16(o)) {
Errorf(s, "relocation address for %s is too big: %#x", r.Sym.Name, o)
}
i16 := int16(o)
target.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
case 4:
if r.Type == objabi.R_PCREL || r.Type == objabi.R_CALL {
if o != int64(int32(o)) {
Errorf(s, "pc-relative relocation address for %s is too big: %#x", r.Sym.Name, o)
}
} else {
if o != int64(int32(o)) && o != int64(uint32(o)) {
Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", r.Sym.Name, uint64(o))
}
}
fl := int32(o)
target.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
case 8:
target.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
}
}
}
func (ctxt *Link) reloc2() {
var wg sync.WaitGroup
target := &ctxt.Target
ldr := ctxt.loader
reporter := &ctxt.ErrorReporter
syms := &ctxt.ArchSyms
wg.Add(3)
go func() {
if !ctxt.IsWasm() { // On Wasm, text relocations are applied in Asmb2.
for _, s := range ctxt.Textp {
relocsym2(target, ldr, reporter, syms, s)
}
}
wg.Done()
}()
go func() {
for _, s := range ctxt.datap {
relocsym2(target, ldr, reporter, syms, s)
}
wg.Done()
}()
go func() {
for _, si := range dwarfp {
for _, s := range si.syms {
relocsym2(target, ldr, reporter, syms, s)
}
}
wg.Done()
}()
wg.Wait()
}

View file

@ -5,12 +5,9 @@
package ld package ld
import ( import (
"bytes"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/sym"
"debug/elf" "debug/elf"
"fmt"
) )
// Decoding the type.* symbols. This has to be in sync with // Decoding the type.* symbols. This has to be in sync with
@ -29,23 +26,6 @@ const (
tflagExtraStar = 1 << 1 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 { func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 {
switch sz { switch sz {
case 2: case 2:
@ -103,26 +83,6 @@ func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
return nil 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 { func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
if ctxt.Arch.Family == sys.ARM64 { if ctxt.Arch.Family == sys.ARM64 {
return 0 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) 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 // Type.FuncType.dotdotdot
func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool { func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0 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)) 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 // InterfaceType.methods.length
func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 { func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize)) return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
@ -279,91 +125,3 @@ const (
kindStruct = 25 kindStruct = 25
kindMask = (1 << 5) - 1 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)
}

View file

@ -101,20 +101,20 @@ func dwarfcompress(ctxt *Link) {
type compressedSect struct { type compressedSect struct {
index int index int
compressed []byte compressed []byte
syms []*sym.Symbol syms []loader.Sym
} }
supported := ctxt.IsELF || ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Hdarwin supported := ctxt.IsELF || ctxt.IsWindows() || ctxt.IsDarwin()
if !ctxt.compressDWARF || !supported || ctxt.LinkMode != LinkInternal { if !ctxt.compressDWARF || !supported || ctxt.IsExternal() {
return return
} }
var compressedCount int var compressedCount int
resChannel := make(chan compressedSect) resChannel := make(chan compressedSect)
for i := range dwarfp { for i := range dwarfp2 {
go func(resIndex int, syms []*sym.Symbol) { go func(resIndex int, syms []loader.Sym) {
resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms} resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms}
}(compressedCount, dwarfp[i].syms) }(compressedCount, dwarfp2[i].syms)
compressedCount++ compressedCount++
} }
res := make([]compressedSect, compressedCount) res := make([]compressedSect, compressedCount)
@ -123,46 +123,55 @@ func dwarfcompress(ctxt *Link) {
res[r.index] = r res[r.index] = r
} }
var newDwarfp []dwarfSecInfo2 ldr := ctxt.loader
var newDwarfp []dwarfSecInfo
Segdwarf.Sections = Segdwarf.Sections[:0] Segdwarf.Sections = Segdwarf.Sections[:0]
for _, z := range res { for _, z := range res {
s := z.syms[0] s := z.syms[0]
if z.compressed == nil { if z.compressed == nil {
// Compression didn't help. // Compression didn't help.
ds := dwarfSecInfo2{syms: z.syms} ds := dwarfSecInfo{syms: z.syms}
newDwarfp = append(newDwarfp, ds) newDwarfp = append(newDwarfp, ds)
Segdwarf.Sections = append(Segdwarf.Sections, s.Sect) Segdwarf.Sections = append(Segdwarf.Sections, ldr.SymSect(s))
} else { } 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 := addsection(ctxt.loader, ctxt.Arch, &Segdwarf, compressedSegName, 04)
sect.Align = 1
sect.Length = uint64(len(z.compressed)) sect.Length = uint64(len(z.compressed))
newSym := ctxt.Syms.Lookup(compressedSegName, 0) newSym := ldr.CreateSymForUpdate(compressedSegName, 0)
newSym.P = z.compressed newSym.SetReachable(true)
newSym.Size = int64(len(z.compressed)) newSym.SetData(z.compressed)
newSym.Sect = sect newSym.SetSize(int64(len(z.compressed)))
ds := dwarfSecInfo2{syms: []*sym.Symbol{newSym}} ldr.SetSymSect(newSym.Sym(), sect)
ds := dwarfSecInfo{syms: []loader.Sym{newSym.Sym()}}
newDwarfp = append(newDwarfp, ds) 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 // Re-compute the locations of the compressed DWARF symbols
// and sections, since the layout of these within the file is // and sections, since the layout of these within the file is
// based on Section.Vaddr and Symbol.Value. // based on Section.Vaddr and Symbol.Value.
pos := Segdwarf.Vaddr pos := Segdwarf.Vaddr
var prevSect *sym.Section var prevSect *sym.Section
for _, si := range dwarfp { for _, si := range dwarfp2 {
for _, s := range si.syms { for _, s := range si.syms {
s.Value = int64(pos) ldr.SetSymValue(s, int64(pos))
if s.Sect != prevSect { sect := ldr.SymSect(s)
s.Sect.Vaddr = uint64(s.Value) if sect != prevSect {
prevSect = s.Sect sect.Vaddr = uint64(pos)
prevSect = sect
} }
if s.Sub != nil { if ldr.SubSym(s) != 0 {
log.Fatalf("%s: unexpected sub-symbols", s) log.Fatalf("%s: unexpected sub-symbols", ldr.SymName(s))
} }
pos += uint64(s.Size) pos += uint64(ldr.SymSize(s))
if ctxt.HeadType == objabi.Hwindows { if ctxt.IsWindows() {
pos = uint64(Rnd(int64(pos), PEFILEALIGN)) pos = uint64(Rnd(int64(pos), PEFILEALIGN))
} }
} }

View file

@ -628,9 +628,9 @@ func elfwriteshdrs(out *OutBuf) uint32 {
return uint32(ehdr.shnum) * ELF32SHDRSIZE 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) { if nelfstr >= len(elfstr) {
Errorf(s, "too many elf strings") ctxt.Errorf(s, "too many elf strings")
errorexit() 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) { func elfWriteDynEntSym2(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
Elfwritedynentsymplus(arch, s, tag, t, 0) Elfwritedynentsymplus2(ctxt, s, tag, t, 0)
} }
func Elfwritedynentsymplus(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol, add int64) { func Elfwritedynentsymplus(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol, add int64) {
@ -1057,15 +1057,16 @@ havelib:
return aux return aux
} }
func elfdynhash(ctxt *Link) { func elfdynhash2(ctxt *Link) {
if !ctxt.IsELF { if !ctxt.IsELF {
return return
} }
nsym := Nelfsym nsym := Nelfsym
s := ctxt.Syms.Lookup(".hash", 0) ldr := ctxt.loader
s.Type = sym.SELFROSECT s := ldr.CreateSymForUpdate(".hash", 0)
s.Attr |= sym.AttrReachable s.SetType(sym.SELFROSECT)
s.SetReachable(true)
i := nsym i := nsym
nbucket := 1 nbucket := 1
@ -1079,21 +1080,19 @@ func elfdynhash(ctxt *Link) {
chain := make([]uint32, nsym) chain := make([]uint32, nsym)
buckets := make([]uint32, nbucket) buckets := make([]uint32, nbucket)
for _, sy := range ctxt.Syms.Allsym { for _, sy := range ldr.DynidSyms() {
if sy.Dynid <= 0 {
continue dynid := ldr.SymDynid(sy)
if ldr.SymDynimpvers(sy) != "" {
need[dynid] = addelflib(&needlib, ldr.SymDynimplib(sy), ldr.SymDynimpvers(sy))
} }
if sy.Dynimpvers() != "" { name := ldr.SymExtname(sy)
need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib(), sy.Dynimpvers())
}
name := sy.Extname()
hc := elfhash(name) hc := elfhash(name)
b := hc % uint32(nbucket) b := hc % uint32(nbucket)
chain[sy.Dynid] = buckets[b] chain[dynid] = buckets[b]
buckets[b] = uint32(sy.Dynid) buckets[b] = uint32(dynid)
} }
// s390x (ELF64) hash table entries are 8 bytes // s390x (ELF64) hash table entries are 8 bytes
@ -1117,10 +1116,11 @@ func elfdynhash(ctxt *Link) {
} }
} }
// version symbols dynstr := ldr.CreateSymForUpdate(".dynstr", 0)
dynstr := ctxt.Syms.Lookup(".dynstr", 0)
s = ctxt.Syms.Lookup(".gnu.version_r", 0) // version symbols
gnuVersionR := ldr.CreateSymForUpdate(".gnu.version_r", 0)
s = gnuVersionR
i = 2 i = 2
nfile := 0 nfile := 0
for l := needlib; l != nil; l = l.next { 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 { for x := l.aux; x != nil; x = x.next {
j++ j++
} }
s.AddUint16(ctxt.Arch, uint16(j)) // aux count s.AddUint16(ctxt.Arch, uint16(j)) // aux count
s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, l.file))) // file string offset s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(l.file))) // file string offset
s.AddUint32(ctxt.Arch, 16) // offset from header to first aux s.AddUint32(ctxt.Arch, 16) // offset from header to first aux
if l.next != nil { if l.next != nil {
s.AddUint32(ctxt.Arch, 16+uint32(j)*16) // offset from this header to next s.AddUint32(ctxt.Arch, 16+uint32(j)*16) // offset from this header to next
} else { } else {
@ -1146,10 +1146,10 @@ func elfdynhash(ctxt *Link) {
i++ i++
// aux struct // aux struct
s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash
s.AddUint16(ctxt.Arch, 0) // flags s.AddUint16(ctxt.Arch, 0) // flags
s.AddUint16(ctxt.Arch, uint16(x.num)) // other - index we refer to this by 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, uint32(dynstr.Addstring(x.vers))) // version string offset
if x.next != nil { if x.next != nil {
s.AddUint32(ctxt.Arch, 16) // offset from this aux to next s.AddUint32(ctxt.Arch, 16) // offset from this aux to next
} else { } else {
@ -1159,7 +1159,8 @@ func elfdynhash(ctxt *Link) {
} }
// version references // version references
s = ctxt.Syms.Lookup(".gnu.version", 0) gnuVersion := ldr.CreateSymForUpdate(".gnu.version", 0)
s = gnuVersion
for i := 0; i < nsym; i++ { for i := 0; i < nsym; i++ {
if i == 0 { if i == 0 {
@ -1171,26 +1172,26 @@ func elfdynhash(ctxt *Link) {
} }
} }
s = ctxt.Syms.Lookup(".dynamic", 0) s = ldr.CreateSymForUpdate(".dynamic", 0)
elfverneed = nfile elfverneed = nfile
if elfverneed != 0 { if elfverneed != 0 {
elfWriteDynEntSym(ctxt.Arch, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0)) elfWriteDynEntSym2(ctxt, s, DT_VERNEED, gnuVersionR.Sym())
elfWriteDynEnt(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile)) Elfwritedynent2(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
elfWriteDynEntSym(ctxt.Arch, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0)) elfWriteDynEntSym2(ctxt, s, DT_VERSYM, gnuVersion.Sym())
} }
sy := ctxt.Syms.Lookup(elfRelType+".plt", 0) sy := ldr.CreateSymForUpdate(elfRelType+".plt", 0)
if sy.Size > 0 { if sy.Size() > 0 {
if elfRelType == ".rela" { if elfRelType == ".rela" {
elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_RELA) Elfwritedynent2(ctxt.Arch, s, DT_PLTREL, DT_RELA)
} else { } else {
elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_REL) Elfwritedynent2(ctxt.Arch, s, DT_PLTREL, DT_REL)
} }
elfWriteDynEntSymSize(ctxt.Arch, s, DT_PLTRELSZ, sy) elfwritedynentsymsize2(ctxt, s, DT_PLTRELSZ, sy.Sym())
elfWriteDynEntSym(ctxt.Arch, s, DT_JMPREL, sy) 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 { 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) Errorf(s, "missing xsym in relocation %#v %#v", r.Sym.Name, s)
continue 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) 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() { 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) { func elfadddynsym2(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
ldr.SetSymDynid(s, int32(Nelfsym)) ldr.SetSymDynid(s, int32(Nelfsym))
Nelfsym++ Nelfsym++

View file

@ -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++
}

View file

@ -7,12 +7,15 @@ import (
"cmd/internal/obj" "cmd/internal/obj"
"cmd/link/internal/loader" "cmd/link/internal/loader"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"fmt"
"os"
"sync" "sync"
) )
type unresolvedSymKey struct { 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" from *sym.Symbol // Symbol that referenced unresolved "to"
to *sym.Symbol // Unresolved symbol referenced by "from" 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. // ErrorReporter is used to make error reporting thread safe.
type ErrorReporter struct { type ErrorReporter struct {
loader.ErrorReporter
unresOnce sync.Once unresOnce sync.Once
unresSyms map[unresolvedSymKey]bool unresSyms map[unresolvedSymKey]bool
unresSyms2 map[unresolvedSymKey2]bool
unresMutex sync.Mutex unresMutex sync.Mutex
lookup lookupFn lookup lookupFn
SymName symNameFn SymName symNameFn
} }
// errorUnresolved prints unresolved symbol error for r.Sym that is referenced from s. // errorUnresolved prints unresolved symbol error for rs that is referenced from s.
func (reporter *ErrorReporter) errorUnresolved(s *sym.Symbol, r *sym.Reloc) { func (reporter *ErrorReporter) errorUnresolved(ldr *loader.Loader, s, rs loader.Sym) {
reporter.unresOnce.Do(func() { reporter.unresSyms = make(map[unresolvedSymKey]bool) }) 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() reporter.unresMutex.Lock()
defer reporter.unresMutex.Unlock() defer reporter.unresMutex.Unlock()
if !reporter.unresSyms[k] { if !reporter.unresSyms[k] {
reporter.unresSyms[k] = true 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. // Try to find symbol under another ABI.
var reqABI, haveABI obj.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()
}

View file

@ -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 { if ldr.SymDynid(s) >= 0 || target.LinkMode == LinkExternal {
return return
} }
@ -339,27 +339,11 @@ func Adddynsym2(ldr *loader.Loader, reporter *ErrorReporter, target *Target, sym
if target.IsELF { if target.IsELF {
elfadddynsym2(ldr, target, syms, s) elfadddynsym2(ldr, target, syms, s)
} else if target.HeadType == objabi.Hdarwin { } 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 { } else if target.HeadType == objabi.Hwindows {
// already taken care of // already taken care of
} else { } else {
reporter.Errorf(s, "adddynsym: unsupported binary format") ldr.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")
} }
} }
@ -425,7 +409,7 @@ func (ctxt *Link) addexport() {
} }
for _, exp := range ctxt.dynexp2 { 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 { for _, lib := range dynlib {
adddynlib(ctxt, lib) adddynlib(ctxt, lib)

View file

@ -32,6 +32,7 @@
package ld package ld
import ( import (
"cmd/internal/goobj2"
"cmd/link/internal/loader" "cmd/link/internal/loader"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"io/ioutil" "io/ioutil"
@ -155,11 +156,12 @@ func findlib(ctxt *Link, lib string) (string, bool) {
return pname, isshlib 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) pkg := pkgname(ctxt, lib)
// already loaded? // already loaded?
if l := ctxt.LibraryByPkg[pkg]; l != nil { if l := ctxt.LibraryByPkg[pkg]; l != nil {
checkFingerprint(l, l.Fingerprint, src, fingerprint)
return l return l
} }
@ -170,9 +172,9 @@ func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
} }
if isshlib { 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 * file: object file, e.g., /home/rsc/go/pkg/container/vector.a
* pkg: package import path, e.g. container/vector * pkg: package import path, e.g. container/vector
* shlib: path to shared library, or .shlibname file holding path * 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 { if l := ctxt.LibraryByPkg[pkg]; l != nil {
return l return l
} }
if ctxt.Debugvlog > 1 { 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{} l := &sym.Library{}
@ -199,6 +203,7 @@ func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg strin
l.Srcref = srcref l.Srcref = srcref
l.File = file l.File = file
l.Pkg = pkg l.Pkg = pkg
l.Fingerprint = fingerprint
if shlib != "" { if shlib != "" {
if strings.HasSuffix(shlib, ".shlibname") { if strings.HasSuffix(shlib, ".shlibname") {
data, err := ioutil.ReadFile(shlib) data, err := ioutil.ReadFile(shlib)

View file

@ -33,6 +33,7 @@ package ld
import ( import (
"bytes" "bytes"
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/goobj2"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
@ -232,6 +233,7 @@ type Arch struct {
Dragonflydynld string Dragonflydynld string
Solarisdynld string Solarisdynld string
Adddynrel func(*Target, *loader.Loader, *ArchSyms, *sym.Symbol, *sym.Reloc) bool 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) Archinit func(*Link)
// Archreloc is an arch-specific hook that assists in // Archreloc is an arch-specific hook that assists in
// relocation processing (invoked by 'relocsym'); it handles // relocation processing (invoked by 'relocsym'); it handles
@ -263,7 +265,7 @@ type Arch struct {
// file. Typically, Asmb writes most of the content (sections and // file. Typically, Asmb writes most of the content (sections and
// segments), for which we have computed the size and offset. Asmb2 // segments), for which we have computed the size and offset. Asmb2
// writes the rest. // writes the rest.
Asmb func(*Link) Asmb func(*Link, *loader.Loader)
Asmb2 func(*Link) Asmb2 func(*Link)
Elfreloc1 func(*Link, *sym.Reloc, int64) bool 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 // This is possible when a TLS IE relocation refers to a local
// symbol in an executable, which is typical when internally // symbol in an executable, which is typical when internally
// linking PIE binaries. // linking PIE binaries.
TLSIEtoLE func(s *sym.Symbol, off, size int) TLSIEtoLE func(P []byte, off, size int)
// optional override for assignAddress // 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) 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 { func loadinternal(ctxt *Link, name string) *sym.Library {
zerofp := goobj2.FingerprintType{}
if ctxt.linkShared && ctxt.PackageShlib != nil { if ctxt.linkShared && ctxt.PackageShlib != nil {
if shlib := ctxt.PackageShlib[name]; shlib != "" { 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 ctxt.PackageFile != nil {
if pname := ctxt.PackageFile[name]; pname != "" { 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) ctxt.Logf("loadinternal: cannot find %s\n", name)
return nil 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) ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
} }
if _, err := os.Stat(shlibname); err == nil { 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") 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) ctxt.Logf("searching for %s.a in %s\n", name, pname)
} }
if _, err := os.Stat(pname); err == nil { 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: default:
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups) 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 { ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
return ctxt.loader.SymName(s) 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 ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
f.MustSeek(import1, 0) 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) addImports(ctxt, lib, pn)
return nil 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 { func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
data := make([]byte, sym.Size) data := make([]byte, sym.Size)
sect := f.Sections[sym.Section] sect := f.Sections[sym.Section]
@ -2472,7 +2493,7 @@ const (
DeletedAutoSym = 'x' 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 // 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. // skip sym.STEXT symbols. Normal sym.STEXT symbols are emitted by walking textp.
s := ctxt.Syms.Lookup("runtime.text", 0) 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. // on AIX with external linker.
// See data.go:/textaddress // See data.go:/textaddress
if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) { 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 break
} }
if s.Type == sym.STEXT { if s.Type == sym.STEXT {
put(ctxt, s, s.Name, TextSym, s.Value, nil) put(ctxt, s, s.Name, TextSym, s.Value)
} }
n++ n++
} }
@ -2515,7 +2536,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
// on AIX with external linker. // on AIX with external linker.
// See data.go:/textaddress // See data.go:/textaddress
if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) { 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 return true
} }
for _, s := range ctxt.Syms.Allsym { for _, s := range ctxt.loader.Syms {
if s == nil {
continue
}
if !shouldBeInSymbolTable(s) { if !shouldBeInSymbolTable(s) {
continue continue
} }
@ -2565,7 +2589,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
if !s.Attr.Reachable() { if !s.Attr.Reachable() {
continue 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: case sym.SBSS, sym.SNOPTRBSS, sym.SLIBFUZZER_EXTRA_COUNTER:
if !s.Attr.Reachable() { 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 { 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()) 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: case sym.SUNDEFEXT:
if ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Haix || ctxt.IsELF { 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: case sym.SHOSTOBJ:
@ -2586,24 +2610,24 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
continue continue
} }
if ctxt.HeadType == objabi.Hwindows || ctxt.IsELF { 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: case sym.SDYNIMPORT:
if !s.Attr.Reachable() { if !s.Attr.Reachable() {
continue continue
} }
put(ctxt, s, s.Extname(), UndefinedSym, 0, nil) put(ctxt, s, s.Extname(), UndefinedSym, 0)
case sym.STLSBSS: case sym.STLSBSS:
if ctxt.LinkMode == LinkExternal { 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 { 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 { if ctxt.Debugvlog != 0 || *flagN {
@ -2800,10 +2824,9 @@ func addToTextp(ctxt *Link) {
ctxt.Textp = textp ctxt.Textp = textp
} }
func (ctxt *Link) loadlibfull() { func (ctxt *Link) loadlibfull(symGroupType []sym.SymKind, needReloc bool) {
// Load full symbol contents, resolve indexed references. // 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 // Convert ctxt.Moduledata2 to ctxt.Moduledata, etc
if ctxt.Moduledata2 != 0 { if ctxt.Moduledata2 != 0 {
@ -2841,12 +2864,41 @@ func (ctxt *Link) loadlibfull() {
dwarfp = append(dwarfp, dwarfSecInfo2{syms: syms}) 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 // For now, overwrite symbol type with its "group" type, as dodata
// expected. Once we converted dodata, this will probably not be // expected. Once we converted dodata, this will probably not be
// needed. // needed.
for i, t := range symGroupType { for i, t := range symGroupType {
if t != sym.Sxxx { 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 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() { 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) 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 { for i := range s.R {
fmt.Println("\t", s.R[i].Type, s.R[i].Sym) fmt.Println("\t", s.R[i].Type, s.R[i].Sym)

View file

@ -66,7 +66,6 @@ type Link struct {
compressDWARF bool compressDWARF bool
Tlsg2 loader.Sym
Libdir []string Libdir []string
Library []*sym.Library Library []*sym.Library
LibraryByPkg map[string]*sym.Library LibraryByPkg map[string]*sym.Library
@ -92,6 +91,7 @@ type Link struct {
cgo_export_dynamic map[string]bool cgo_export_dynamic map[string]bool
datap []*sym.Symbol datap []*sym.Symbol
datap2 []loader.Sym
dynexp2 []loader.Sym dynexp2 []loader.Sym
// Elf symtab variables. // Elf symtab variables.
@ -129,11 +129,11 @@ func (ctxt *Link) Logf(format string, args ...interface{}) {
func addImports(ctxt *Link, l *sym.Library, pn string) { func addImports(ctxt *Link, l *sym.Library, pn string) {
pkg := objabi.PathToPrefix(l.Pkg) pkg := objabi.PathToPrefix(l.Pkg)
for _, importStr := range l.ImportStrings { for _, imp := range l.Autolib {
lib := addlib(ctxt, pkg, pn, importStr) lib := addlib(ctxt, pkg, pn, imp.Pkg, imp.Fingerprint)
if lib != nil { if lib != nil {
l.Imports = append(l.Imports, lib) l.Imports = append(l.Imports, lib)
} }
} }
l.ImportStrings = nil l.Autolib = nil
} }

View file

@ -8,6 +8,7 @@ import (
"bytes" "bytes"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"debug/macho" "debug/macho"
"encoding/binary" "encoding/binary"
@ -216,7 +217,7 @@ const (
var nkind [NumSymKind]int var nkind [NumSymKind]int
var sortsym []*sym.Symbol var sortsym []loader.Sym
var nsortsym int var nsortsym int
@ -743,106 +744,125 @@ func Asmbmacho(ctxt *Link) {
} }
} }
func symkind(s *sym.Symbol) int { func symkind(ldr *loader.Loader, s loader.Sym) int {
if s.Type == sym.SDYNIMPORT { if ldr.SymType(s) == sym.SDYNIMPORT {
return SymKindUndef return SymKindUndef
} }
if s.Attr.CgoExport() { if ldr.AttrCgoExport(s) {
return SymKindExtdef return SymKindExtdef
} }
return SymKindLocal return SymKindLocal
} }
func addsym(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) { func collectmachosyms(ctxt *Link) {
if s == nil { ldr := ctxt.loader
return
addsym := func(s loader.Sym) {
sortsym = append(sortsym, s)
nkind[symkind(ldr, s)]++
} }
switch type_ { // Add special runtime.text and runtime.etext symbols.
default: // We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
return // See data.go:/textaddress
if !ctxt.DynlinkingGo() {
case DataSym, BSSSym, TextSym: s := ldr.Lookup("runtime.text", 0)
break 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 { // Add text symbols.
sortsym[nsortsym] = s for _, s := range ctxt.Textp2 {
nkind[symkind(s)]++ addsym(s)
} }
nsortsym++ shouldBeInSymbolTable := func(s loader.Sym) bool {
} if ldr.AttrNotInSymbolTable(s) {
return false
type machoscmp []*sym.Symbol }
name := ldr.RawSymName(s) // TODO: try not to read the name
func (x machoscmp) Len() int { if name == "" || name[0] == '.' {
return len(x) return false
} }
return true
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
} }
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. // 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. // But only on macOS.
if machoPlatform == PLATFORM_MACOS { if machoPlatform == PLATFORM_MACOS {
switch n := s.Extname(); n { switch n := ldr.SymExtname(s); n {
case "fdopendir": case "fdopendir":
switch objabi.GOARCH { switch objabi.GOARCH {
case "amd64": case "amd64":
s.SetExtname(n + "$INODE64") ldr.SetSymExtname(s, n+"$INODE64")
case "386": case "386":
s.SetExtname(n + "$INODE64$UNIX2003") ldr.SetSymExtname(s, n+"$INODE64$UNIX2003")
} }
case "readdir_r", "getfsstat": case "readdir_r", "getfsstat":
switch objabi.GOARCH { switch objabi.GOARCH {
case "amd64", "386": 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) { func machosymorder(ctxt *Link) {
ldr := ctxt.loader
// On Mac OS X Mountain Lion, we must sort exported symbols // On Mac OS X Mountain Lion, we must sort exported symbols
// So we sort them here and pre-allocate dynid for them // So we sort them here and pre-allocate dynid for them
// See https://golang.org/issue/4029 // See https://golang.org/issue/4029
for i := range dynexp { for _, s := range ctxt.dynexp2 {
dynexp[i].Attr |= sym.AttrReachable if !ldr.AttrReachable(s) {
panic("dynexp symbol is not reachable")
}
} }
machogenasmsym(ctxt) collectmachosyms(ctxt)
sortsym = make([]*sym.Symbol, nsortsym) sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
nsortsym = 0 s1 := sortsym[i]
machogenasmsym(ctxt) s2 := sortsym[j]
sort.Sort(machoscmp(sortsym[:nsortsym])) k1 := symkind(ldr, s1)
for i := 0; i < nsortsym; i++ { k2 := symkind(ldr, s2)
sortsym[i].Dynid = int32(i) 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) symstr := ctxt.Syms.Lookup(".machosymstr", 0)
for i := 0; i < nsortsym; i++ { for i := 0; i < nsortsym; i++ {
s := sortsym[i] s := ctxt.loader.Syms[sortsym[i]]
symtab.AddUint32(ctxt.Arch, uint32(symstr.Size)) symtab.AddUint32(ctxt.Arch, uint32(symstr.Size))
export := machoShouldExport(ctxt, s) export := machoShouldExport(ctxt, s)

View file

@ -32,6 +32,7 @@ package ld
import ( import (
"bufio" "bufio"
"cmd/internal/goobj2"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/benchmark" "cmd/link/internal/benchmark"
@ -74,7 +75,7 @@ var (
flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker") flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker")
flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive") 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") FlagC = flag.Bool("c", false, "dump call graph")
FlagD = flag.Bool("d", false, "disable dynamic executable") FlagD = flag.Bool("d", false, "disable dynamic executable")
flagF = flag.Bool("f", false, "ignore version mismatch") flagF = flag.Bool("f", false, "ignore version mismatch")
@ -154,6 +155,9 @@ func Main(arch *sys.Arch, theArch Arch) {
usage() usage()
} }
} }
if ctxt.HeadType == objabi.Hunknown {
ctxt.HeadType.Set(objabi.GOOS)
}
checkStrictDups = *FlagStrictDups checkStrictDups = *FlagStrictDups
@ -190,11 +194,6 @@ func Main(arch *sys.Arch, theArch Arch) {
bench.Start("libinit") bench.Start("libinit")
libinit(ctxt) // creates outfile libinit(ctxt) // creates outfile
if ctxt.HeadType == objabi.Hunknown {
ctxt.HeadType.Set(objabi.GOOS)
}
bench.Start("computeTLSOffset") bench.Start("computeTLSOffset")
ctxt.computeTLSOffset() ctxt.computeTLSOffset()
bench.Start("Archinit") 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)) ctxt.Logf("HEADER = -H%d -T0x%x -R0x%x\n", ctxt.HeadType, uint64(*FlagTextAddr), uint32(*FlagRound))
} }
zerofp := goobj2.FingerprintType{}
switch ctxt.BuildMode { switch ctxt.BuildMode {
case BuildModeShared: case BuildModeShared:
for i := 0; i < flag.NArg(); i++ { 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, pkgpath...)
pkglistfornote = append(pkglistfornote, '\n') pkglistfornote = append(pkglistfornote, '\n')
addlibpath(ctxt, "command line", "command line", file, pkgpath, "") addlibpath(ctxt, "command line", "command line", file, pkgpath, "", zerofp)
} }
case BuildModePlugin: case BuildModePlugin:
addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "") addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "", zerofp)
default: 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") bench.Start("loadlib")
ctxt.loadlib() ctxt.loadlib()
@ -297,11 +297,9 @@ func Main(arch *sys.Arch, theArch Arch) {
bench.Start("dwarfGenerateDebugSyms") bench.Start("dwarfGenerateDebugSyms")
dwarfGenerateDebugSyms(ctxt) dwarfGenerateDebugSyms(ctxt)
bench.Start("symtab") bench.Start("symtab")
ctxt.symtab() symGroupType := ctxt.symtab()
bench.Start("loadlibfull")
ctxt.loadlibfull() // XXX do it here for now
bench.Start("dodata") bench.Start("dodata")
ctxt.dodata() ctxt.dodata2(symGroupType)
bench.Start("address") bench.Start("address")
order := ctxt.address() order := ctxt.address()
bench.Start("dwarfcompress") bench.Start("dwarfcompress")
@ -321,19 +319,27 @@ func Main(arch *sys.Arch, theArch Arch) {
if err := ctxt.Out.Mmap(filesize); err != nil { if err := ctxt.Out.Mmap(filesize); err != nil {
panic(err) panic(err)
} }
// Asmb will redirect symbols to the output file mmap, and relocations }
// will be applied directly there. // Asmb will redirect symbols to the output file mmap, and relocations
bench.Start("Asmb") // will be applied directly there.
thearch.Asmb(ctxt) bench.Start("Asmb")
ctxt.loader.InitOutData()
thearch.Asmb(ctxt, ctxt.loader)
newreloc := ctxt.IsInternal() && ctxt.IsAMD64()
if newreloc {
bench.Start("reloc") bench.Start("reloc")
ctxt.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 { } else {
// If we don't mmap, we need to apply relocations before bench.Start("loadlibfull")
// writing out. ctxt.loadlibfull(symGroupType, true) // XXX do it here for now
bench.Start("reloc") bench.Start("reloc")
ctxt.reloc() ctxt.reloc2()
bench.Start("Asmb")
thearch.Asmb(ctxt)
} }
bench.Start("Asmb2") bench.Start("Asmb2")
thearch.Asmb2(ctxt) thearch.Asmb2(ctxt)
@ -346,7 +352,7 @@ func Main(arch *sys.Arch, theArch Arch) {
bench.Start("hostlink") bench.Start("hostlink")
ctxt.hostlink() ctxt.hostlink()
if ctxt.Debugvlog != 0 { 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) ctxt.Logf("%d liveness data\n", liveness)
} }
bench.Start("Flush") bench.Start("Flush")

View file

@ -6,7 +6,7 @@ package ld
import ( import (
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/sym" "cmd/link/internal/loader"
"encoding/binary" "encoding/binary"
"errors" "errors"
"log" "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 // to point to the output buffer that we just wrote, so we can apply further
// edit to the symbol content. // edit to the symbol content.
// If the output file is not Mmap'd, just writes the content. // If the output file is not Mmap'd, just writes the content.
func (out *OutBuf) WriteSym(s *sym.Symbol) { func (out *OutBuf) WriteSym(ldr *loader.Loader, s loader.Sym) {
n := int64(len(s.P)) P := ldr.Data(s)
n := int64(len(P))
pos, buf := out.writeLoc(n) pos, buf := out.writeLoc(n)
copy(buf[pos:], s.P) copy(buf[pos:], P)
out.off += n out.off += n
s.P = buf[pos : pos+n] ldr.SetOutData(s, buf[pos:pos+n])
s.Attr.Set(sym.AttrReadOnly, false)
} }

View file

@ -646,7 +646,7 @@ func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int
// writeSymbols writes all COFF symbol table records. // writeSymbols writes all COFF symbol table records.
func (f *peFile) writeSymbols(ctxt *Link) { 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 { if s == nil {
return return
} }

View file

@ -34,19 +34,22 @@ package ld
import ( import (
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"log" "log"
"runtime" "runtime"
) )
func linknew(arch *sys.Arch) *Link { func linknew(arch *sys.Arch) *Link {
ler := loader.ErrorReporter{AfterErrorAction: afterErrorAction}
ctxt := &Link{ ctxt := &Link{
Target: Target{Arch: arch}, Target: Target{Arch: arch},
Syms: sym.NewSymbols(), Syms: sym.NewSymbols(),
outSem: make(chan int, 2*runtime.GOMAXPROCS(0)), outSem: make(chan int, 2*runtime.GOMAXPROCS(0)),
Out: NewOutBuf(arch), Out: NewOutBuf(arch),
LibraryByPkg: make(map[string]*sym.Library), LibraryByPkg: make(map[string]*sym.Library),
numelfsym: 1, numelfsym: 1,
ErrorReporter: ErrorReporter{ErrorReporter: ler},
} }
if objabi.GOARCH != arch.Name { if objabi.GOARCH != arch.Name {

View file

@ -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 var typ int
switch t { 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 // ELF linker -Bsymbolic-functions option, but that is buggy on
// several platforms. // several platforms.
putelfsyment(ctxt.Out, putelfstr("local."+s), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other) 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++ ctxt.numelfsym++
return return
} else if bind != ctxt.elfbind { } 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) 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++ ctxt.numelfsym++
} }
func putelfsectionsym(ctxt *Link, out *OutBuf, s *sym.Symbol, shndx int) { func putelfsectionsym(ctxt *Link, out *OutBuf, s *sym.Symbol, shndx int) {
putelfsyment(out, 0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0) 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++ ctxt.numelfsym++
} }
@ -224,7 +224,7 @@ func Asmelfsym(ctxt *Link) {
genasmsym(ctxt, putelfsym) 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) t := int(typ)
switch typ { switch typ {
case TextSym, DataSym, BSSSym: case TextSym, DataSym, BSSSym:
@ -327,9 +327,7 @@ func textsectionmap(ctxt *Link) (loader.Sym, uint32) {
return t.Sym(), uint32(n) return t.Sym(), uint32(n)
} }
var symGroupType []sym.SymKind // temporarily assign a symbol's "group" type func (ctxt *Link) symtab() []sym.SymKind {
func (ctxt *Link) symtab() {
ldr := ctxt.loader ldr := ctxt.loader
if !ctxt.IsAIX() { if !ctxt.IsAIX() {
@ -441,7 +439,7 @@ func (ctxt *Link) symtab() {
// just defined above will be first. // just defined above will be first.
// hide the specific symbols. // hide the specific symbols.
nsym := loader.Sym(ldr.NSym()) nsym := loader.Sym(ldr.NSym())
symGroupType = make([]sym.SymKind, nsym) symGroupType := make([]sym.SymKind, nsym)
for s := loader.Sym(1); s < nsym; s++ { for s := loader.Sym(1); s < nsym; s++ {
name := ldr.SymName(s) name := ldr.SymName(s)
if !ctxt.IsExternal() && isStaticTemp(name) { if !ctxt.IsExternal() && isStaticTemp(name) {
@ -709,6 +707,7 @@ func (ctxt *Link) symtab() {
lastmoduledatap.SetData(nil) lastmoduledatap.SetData(nil)
lastmoduledatap.AddAddr(ctxt.Arch, moduledata.Sym()) lastmoduledatap.AddAddr(ctxt.Arch, moduledata.Sym())
} }
return symGroupType
} }
func isStaticTemp(name string) bool { func isStaticTemp(name string) bool {

View file

@ -61,6 +61,7 @@ func (t *Target) CanUsePlugins() bool {
} }
func (t *Target) IsElf() bool { func (t *Target) IsElf() bool {
t.mustSetHeadType()
return t.IsELF return t.IsELF
} }
@ -91,14 +92,30 @@ func (t *Target) IsARM() bool {
return t.Arch.Family == sys.ARM return t.Arch.Family == sys.ARM
} }
func (t *Target) IsARM64() bool {
return t.Arch.Family == sys.ARM64
}
func (t *Target) IsAMD64() bool { func (t *Target) IsAMD64() bool {
return t.Arch.Family == sys.AMD64 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 { func (t *Target) IsPPC64() bool {
return t.Arch.Family == sys.PPC64 return t.Arch.Family == sys.PPC64
} }
func (t *Target) IsRISCV64() bool {
return t.Arch.Family == sys.RISCV64
}
func (t *Target) IsS390X() bool { func (t *Target) IsS390X() bool {
return t.Arch.Family == sys.S390X return t.Arch.Family == sys.S390X
} }
@ -112,37 +129,51 @@ func (t *Target) IsWasm() bool {
// //
func (t *Target) IsLinux() bool { func (t *Target) IsLinux() bool {
t.mustSetHeadType()
return t.HeadType == objabi.Hlinux return t.HeadType == objabi.Hlinux
} }
func (t *Target) IsDarwin() bool { func (t *Target) IsDarwin() bool {
t.mustSetHeadType()
return t.HeadType == objabi.Hdarwin return t.HeadType == objabi.Hdarwin
} }
func (t *Target) IsWindows() bool { func (t *Target) IsWindows() bool {
t.mustSetHeadType()
return t.HeadType == objabi.Hwindows return t.HeadType == objabi.Hwindows
} }
func (t *Target) IsPlan9() bool { func (t *Target) IsPlan9() bool {
t.mustSetHeadType()
return t.HeadType == objabi.Hplan9 return t.HeadType == objabi.Hplan9
} }
func (t *Target) IsAIX() bool { func (t *Target) IsAIX() bool {
t.mustSetHeadType()
return t.HeadType == objabi.Haix return t.HeadType == objabi.Haix
} }
func (t *Target) IsSolaris() bool { func (t *Target) IsSolaris() bool {
t.mustSetHeadType()
return t.HeadType == objabi.Hsolaris return t.HeadType == objabi.Hsolaris
} }
func (t *Target) IsNetbsd() bool { func (t *Target) IsNetbsd() bool {
t.mustSetHeadType()
return t.HeadType == objabi.Hnetbsd return t.HeadType == objabi.Hnetbsd
} }
func (t *Target) IsOpenbsd() bool { func (t *Target) IsOpenbsd() bool {
t.mustSetHeadType()
return t.HeadType == objabi.Hopenbsd return t.HeadType == objabi.Hopenbsd
} }
func (t *Target) mustSetHeadType() {
if t.HeadType == objabi.Hunknown {
panic("HeadType is not set")
}
}
// //
// MISC // MISC
// //

View file

@ -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 // Logging an error means that on exit cmd/link will delete any
// output file and return a non-zero error code. // output file and return a non-zero error code.
func (ctxt *Link) Errorf(s loader.Sym, format string, args ...interface{}) { func (ctxt *Link) Errorf(s loader.Sym, format string, args ...interface{}) {
if s != 0 && ctxt.loader != nil { if ctxt.loader != nil {
sn := ctxt.loader.SymName(s) ctxt.loader.Errorf(s, format, args...)
format = sn + ": " + format return
} else {
format = fmt.Sprintf("sym %d: %s", s, format)
} }
// Note: this is not expected to happen very often.
format = fmt.Sprintf("sym %d: %s", s, format)
format += "\n" format += "\n"
fmt.Fprintf(os.Stderr, format, args...) fmt.Fprintf(os.Stderr, format, args...)
afterErrorAction() afterErrorAction()

View file

@ -360,7 +360,8 @@ type XcoffLdRel64 struct {
// xcoffLoaderReloc holds information about a relocation made by the loader. // xcoffLoaderReloc holds information about a relocation made by the loader.
type xcoffLoaderReloc struct { type xcoffLoaderReloc struct {
sym *sym.Symbol sym *sym.Symbol
rel *sym.Reloc sym2 loader.Sym
roff int32
rtype uint16 rtype uint16
symndx int32 symndx int32
} }
@ -567,11 +568,12 @@ var (
// xcoffUpdateOuterSize stores the size of outer symbols in order to have it // xcoffUpdateOuterSize stores the size of outer symbols in order to have it
// in the symbol table. // 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 { if size == 0 {
return return
} }
ldr := ctxt.loader
switch stype { switch stype {
default: default:
Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String()) 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: case sym.STYPERELRO:
if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) { if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
// runtime.types size must be removed, as it's a real symbol. // 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 return
} }
fallthrough fallthrough
case sym.STYPE: case sym.STYPE:
if !ctxt.DynlinkingGo() { if !ctxt.DynlinkingGo() {
// runtime.types size must be removed, as it's a real symbol. // 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: case sym.SGOSTRING:
outerSymSize["go.string.*"] = size outerSymSize["go.string.*"] = size
@ -603,7 +607,6 @@ func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
outerSymSize["runtime.itablink"] = size outerSymSize["runtime.itablink"] = size
} }
} }
// addSymbol writes a symbol or an auxiliary symbol entry on ctxt.out. // 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 // Trampoline don't have a FILE so there are considered
// in the current file. // in the current file.
// Same goes for runtime.text.X symbols. // 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 this happens, the algorithm must be redone.
if currSymSrcFile.name != "" { if currSymSrcFile.name != "" {
Exitf("undefined global symbol found inside another file") Exitf("undefined global symbol found inside another file")
} }
} else { } else {
// Current file has changed. New C_FILE, C_DWARF, etc must be generated. // 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 { if ctxt.LinkMode == LinkInternal {
// update previous file values // update previous file values
xfile.updatePreviousFile(ctxt, false) xfile.updatePreviousFile(ctxt, false)
currSymSrcFile.name = x.File currSymSrcFile.name = symPkg(ctxt, x)
f.writeSymbolNewFile(ctxt, x.File, uint64(x.Value), xfile.getXCOFFscnum(x.Sect)) f.writeSymbolNewFile(ctxt, symPkg(ctxt, x), uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
} else { } else {
// With external linking, ld will crash if there is several // With external linking, ld will crash if there is several
// .FILE and DWARF debugging enable, somewhere during // .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 // TODO(aix); remove once ld has been fixed or the triggering
// relocation has been found and fixed. // relocation has been found and fixed.
if currSymSrcFile.name == "" { if currSymSrcFile.name == "" {
currSymSrcFile.name = x.File currSymSrcFile.name = symPkg(ctxt, x)
f.writeSymbolNewFile(ctxt, "go_functions", uint64(x.Value), xfile.getXCOFFscnum(x.Sect)) 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 // 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 // All XCOFF symbols generated by this GO symbols
// Can be a symbol entry or a auxiliary entry // 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 return
case TextSym: 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 // Function within a file
syms = xfile.writeSymbolFunc(ctxt, x) syms = xfile.writeSymbolFunc(ctxt, x)
} else { } else {
@ -1106,51 +1109,55 @@ func (f *xcoffFile) adddynimpsym(ctxt *Link, s loader.Sym) {
// Xcoffadddynrel adds a dynamic relocation in a XCOFF file. // Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
// This relocation will be made by the loader. // 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() { if target.IsExternal() {
return true return true
} }
if s.Type <= sym.SPCLNTAB { if ldr.SymType(s) <= sym.SPCLNTAB {
Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name) ldr.Errorf(s, "cannot have a relocation to %s in a text section symbol", ldr.SymName(r.Sym()))
return false return false
} }
xldr := &xcoffLoaderReloc{ xldr := &xcoffLoaderReloc{
sym: s, sym2: s,
rel: r, roff: r.Off(),
}
targ := r.Sym()
var targType sym.SymKind
if targ != 0 {
targType = ldr.SymType(targ)
} }
switch r.Type { switch r.Type() {
default: 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 return false
case objabi.R_ADDR: 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 // Imported symbol relocation
for i, dynsym := range xfile.loaderSymbols { 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 xldr.symndx = int32(i + 3) // +3 because of 3 section symbols
break break
} }
} }
} else if s.Type == sym.SDATA { } else if t := ldr.SymType(s); t == sym.SDATA || t == sym.SNOPTRDATA || t == sym.SBUILDINFO || t == sym.SXCOFFTOC {
switch r.Sym.Sect.Seg { switch ldr.SymSect(targ).Seg {
default: 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 &Segtext:
case &Segrodata: case &Segrodata:
xldr.symndx = 0 // .text xldr.symndx = 0 // .text
case &Segdata: case &Segdata:
if r.Sym.Type == sym.SBSS || r.Sym.Type == sym.SNOPTRBSS { if targType == sym.SBSS || targType == sym.SNOPTRBSS {
xldr.symndx = 2 // .bss xldr.symndx = 2 // .bss
} else { } else {
xldr.symndx = 1 // .data xldr.symndx = 1 // .data
} }
} }
} else { } 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 return false
} }
@ -1301,14 +1308,18 @@ func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
off += uint64(16 * len(f.loaderReloc)) off += uint64(16 * len(f.loaderReloc))
for _, r := range f.loaderReloc { for _, r := range f.loaderReloc {
symp := r.sym
if symp == nil {
symp = ctxt.loader.Syms[r.sym2]
}
xldr = &XcoffLdRel64{ xldr = &XcoffLdRel64{
Lvaddr: uint64(r.sym.Value + int64(r.rel.Off)), Lvaddr: uint64(symp.Value + int64(r.roff)),
Lrtype: r.rtype, Lrtype: r.rtype,
Lsymndx: r.symndx, Lsymndx: r.symndx,
} }
if r.sym.Sect != nil { if symp.Sect != nil {
xldr.Lrsecnm = f.getXCOFFscnum(r.sym.Sect) xldr.Lrsecnm = f.getXCOFFscnum(symp.Sect)
} }
reloctab = append(reloctab, xldr) reloctab = append(reloctab, xldr)
@ -1389,45 +1400,6 @@ func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
} }
f.loaderSize = off + uint64(stlen) 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 // XCOFF assembling and writing file
@ -1683,7 +1655,10 @@ func xcoffCreateExportFile(ctxt *Link) (fname string) {
fname = filepath.Join(*flagTmpdir, "export_file.exp") fname = filepath.Join(*flagTmpdir, "export_file.exp")
var buf bytes.Buffer var buf bytes.Buffer
for _, s := range ctxt.Syms.Allsym { for _, s := range ctxt.loader.Syms {
if s == nil {
continue
}
if !s.Attr.CgoExport() { if !s.Attr.CgoExport() {
continue continue
} }

View file

@ -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
}

View file

@ -58,7 +58,7 @@ type Reloc2 struct {
// External reloc types may not fit into a uint8 which the Go object file uses. // 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. // 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 // goobj2.Reloc2.Type() + typ is always the right type, for both Go and external
// symbols. // symbols.
typ objabi.RelocType typ objabi.RelocType
@ -73,6 +73,10 @@ func (rel Reloc2) SetType(t objabi.RelocType) {
panic("SetType: type doesn't fit into Reloc2") panic("SetType: type doesn't fit into Reloc2")
} }
rel.Reloc.SetType(uint8(t)) 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 // 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 { func (bm Bitmap) Len() int {
return len(bm) * 32 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 { func MakeBitmap(n int) Bitmap {
return make(Bitmap, (n+31)/32) return make(Bitmap, (n+31)/32)
} }
@ -202,6 +216,8 @@ type Loader struct {
sects []*sym.Section // sections sects []*sym.Section // sections
symSects []uint16 // symbol's section, index to sects array 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.* itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
objByPkg map[string]*oReader // map package path to its Go object reader 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 align map[Sym]int32 // stores alignment for symbols
dynimplib map[Sym]string // stores Dynimplib symbol attribute dynimplib map[Sym]string // stores Dynimplib symbol attribute
dynimpvers map[Sym]string // stores Dynimpvers symbol attribute dynimpvers map[Sym]string // stores Dynimpvers symbol attribute
localentry map[Sym]uint8 // stores Localentry symbol attribute localentry map[Sym]uint8 // stores Localentry symbol attribute
extname map[Sym]string // stores Extname symbol attribute extname map[Sym]string // stores Extname symbol attribute
elfType map[Sym]elf.SymType // stores elf type symbol property elfType map[Sym]elf.SymType // stores elf type symbol property
symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms elfSym map[Sym]int32 // stores elf sym symbol property
plt map[Sym]int32 // stores dynimport for pe objects localElfSym map[Sym]int32 // stores "local" elf sym symbol property
got map[Sym]int32 // stores got for pe objects symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms
dynid map[Sym]int32 // stores Dynid for symbol 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 relocVariant map[relocId]sym.RelocVariant // stores variant relocs
@ -266,6 +284,8 @@ type Loader struct {
elfsetstring elfsetstringFunc elfsetstring elfsetstringFunc
errorReporter *ErrorReporter
SymLookup func(name string, ver int) *sym.Symbol SymLookup func(name string, ver int) *sym.Symbol
} }
@ -297,9 +317,9 @@ const (
FlagStrictDups = 1 << iota FlagStrictDups = 1 << iota
) )
func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader { func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
nbuiltin := goobj2.NBuiltin() nbuiltin := goobj2.NBuiltin()
return &Loader{ ldr := &Loader{
start: make(map[*oReader]Sym), start: make(map[*oReader]Sym),
objs: []objIdx{{}}, // reserve index 0 for nil symbol objs: []objIdx{{}}, // reserve index 0 for nil symbol
objSyms: []objSym{{}}, // 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), extname: make(map[Sym]string),
attrReadOnly: make(map[Sym]bool), attrReadOnly: make(map[Sym]bool),
elfType: make(map[Sym]elf.SymType), elfType: make(map[Sym]elf.SymType),
elfSym: make(map[Sym]int32),
localElfSym: make(map[Sym]int32),
symPkg: make(map[Sym]string), symPkg: make(map[Sym]string),
plt: make(map[Sym]int32), plt: make(map[Sym]int32),
got: make(map[Sym]int32), got: make(map[Sym]int32),
@ -328,8 +350,11 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
builtinSyms: make([]Sym, nbuiltin), builtinSyms: make([]Sym, nbuiltin),
flags: flags, flags: flags,
elfsetstring: elfsetstring, elfsetstring: elfsetstring,
errorReporter: reporter,
sects: []*sym.Section{nil}, // reserve index 0 for nil section sects: []*sym.Section{nil}, // reserve index 0 for nil section
} }
reporter.ldr = ldr
return ldr
} }
// Add object file r, return the start index. // Add object file r, return the start index.
@ -616,6 +641,11 @@ func (l *Loader) NDef() int {
return int(l.extStart) 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. // Returns the raw (unpatched) name of the i-th symbol.
func (l *Loader) RawSymName(i Sym) string { func (l *Loader) RawSymName(i Sym) string {
if l.IsExternal(i) { 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 // AttrNotInSymbolTable returns true for symbols that should not be
// added to the symbol table of the final generated load module. // added to the symbol table of the final generated load module.
func (l *Loader) AttrNotInSymbolTable(i Sym) bool { func (l *Loader) AttrNotInSymbolTable(i Sym) bool {
@ -1026,6 +1064,11 @@ func (l *Loader) SetSymValue(i Sym, val int64) {
l.values[i] = val 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. // Returns the symbol content of the i-th symbol. i is global index.
func (l *Loader) Data(i Sym) []byte { func (l *Loader) Data(i Sym) []byte {
if l.IsExternal(i) { if l.IsExternal(i) {
@ -1039,6 +1082,32 @@ func (l *Loader) Data(i Sym) []byte {
return r.Data(li) 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. // SymAlign returns the alignment for a symbol.
func (l *Loader) SymAlign(i Sym) int32 { func (l *Loader) SymAlign(i Sym) int32 {
// If an alignment has been recorded, return that. // 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. // SymValue returns the section of the i-th symbol. i is global index.
func (l *Loader) SymSect(i Sym) *sym.Section { 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]] 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. // SymPlt returns the plt value for pe symbols.
func (l *Loader) SymPlt(s Sym) int32 { func (l *Loader) SymPlt(s Sym) int32 {
if v, ok := l.plt[s]; ok { 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 // SymGoType returns the 'Gotype' property for a given symbol (set by
// the Go compiler for variable symbols). This version relies on // the Go compiler for variable symbols). This version relies on
// reading aux symbols for the target sym -- it could be that a faster // 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. // 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 add non-package symbols yet, which will be done in LoadNonpkgSyms.
// Does not read symbol data. // 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)) roObject, readonly, err := f.Slice(uint64(length))
if err != nil { if err != nil {
log.Fatal("cannot read object file:", err) 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))} or := &oReader{r, unit, localSymVersion, r.Flags(), pkgprefix, make([]Sym, ndef+nnonpkgdef+r.NNonpkgref()), ndef, uint32(len(l.objs))}
// Autolib // Autolib
lib.ImportStrings = append(lib.ImportStrings, r.Autolib()...) lib.Autolib = append(lib.Autolib, r.Autolib()...)
// DWARF file table // DWARF file table
nfile := r.NDwarfFile() 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 // The caller expects us consuming all the data
f.MustSeek(length, os.SEEK_CUR) f.MustSeek(length, os.SEEK_CUR)
return r.Fingerprint()
} }
// Preload symbols of given kind from an object. // 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. // 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. // create all Symbols first.
l.growSyms(l.NSym()) l.growSyms(l.NSym())
l.growSects(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 // 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 // convert payload-based external symbols into sym.Symbol-based
for _, i := range toConvert { for _, i := range toConvert {
@ -1934,21 +2062,15 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
s.Version = int16(pp.ver) s.Version = int16(pp.ver)
s.Type = pp.kind s.Type = pp.kind
s.Size = pp.size 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 // Copy relocations
batch := l.relocBatch if needReloc {
s.R = batch[:len(pp.relocs):len(pp.relocs)] batch := l.relocBatch
l.relocBatch = batch[len(pp.relocs):] s.R = batch[:len(pp.relocs):len(pp.relocs)]
relocs := l.Relocs(i) l.relocBatch = batch[len(pp.relocs):]
l.convertRelocations(i, &relocs, s, false) relocs := l.Relocs(i)
l.convertRelocations(i, &relocs, s, false)
}
// Copy data // Copy data
s.P = pp.data s.P = pp.data
@ -1959,7 +2081,7 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
// load contents of defined symbols // load contents of defined symbols
for _, o := range l.objs[1:] { 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 // Note: resolution of ABI aliases is now also handled in
@ -2103,22 +2225,7 @@ func (l *Loader) PropagateLoaderChangesToSymbols(toconvert []Sym, anonVerReplace
relfix = true relfix = true
} }
// For 'new' symbols, copy other content (such as Gotype, // For 'new' symbols, copy other content.
// 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)
}
}
}
if relfix { if relfix {
relocfixup = append(relocfixup, cand) relocfixup = append(relocfixup, cand)
} }
@ -2165,7 +2272,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
if s == nil { if s == nil {
continue 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 { if s.Version < 0 {
s.Version = int16(anonVerReplacement) s.Version = int16(anonVerReplacement)
} }
@ -2179,7 +2285,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
} }
s := l.allocSym(name, ver) s := l.allocSym(name, ver)
l.installSym(i, s) l.installSym(i, s)
syms.Allsym = append(syms.Allsym, s) // XXX see above
return s return s
} }
syms.Lookup = l.SymLookup syms.Lookup = l.SymLookup
@ -2191,7 +2296,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
i := l.newExtSym(name, ver) i := l.newExtSym(name, ver)
s := l.allocSym(name, ver) s := l.allocSym(name, ver)
l.installSym(i, s) l.installSym(i, s)
syms.Allsym = append(syms.Allsym, s) // XXX see above
return s return s
} }
} }
@ -2221,6 +2325,7 @@ func (l *Loader) installSym(i Sym, s *sym.Symbol) {
panic("sym already present in installSym") panic("sym already present in installSym")
} }
l.Syms[i] = s 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. // 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 t = s.Type
} }
s.Type = t s.Type = t
s.Unit = unit
l.growSyms(int(i)) l.growSyms(int(i))
l.installSym(i, s) l.installSym(i, s)
return 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 // loadObjSyms creates sym.Symbol objects for the live Syms in the
// object corresponding to object reader "r". Return value is the // object corresponding to object reader "r". Return value is the
// number of sym.Reloc entries required for all the new symbols. // 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) osym := r.Sym(i)
name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1) name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
t := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())] 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: // Skip non-dwarf anonymous symbols (e.g. funcdata),
// funcdata). DWARF symbols are an exception however -- we // since they will never be turned into sym.Symbols.
// want to include all reachable but nameless DWARF symbols. if !topLevelSym(name, t) {
if name == "" { continue
switch t {
case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES:
default:
continue
}
} }
ver := abiToVer(osym.ABI(), r.version) ver := abiToVer(osym.ABI(), r.version)
if t == sym.SXREF { if t == sym.SXREF {
@ -2479,12 +2602,7 @@ func (l *Loader) CreateStaticSym(name string) Sym {
return l.newExtSym(name, l.anonVersion) return l.newExtSym(name, l.anonVersion)
} }
func loadObjFull(l *Loader, r *oReader) { func loadObjFull(l *Loader, r *oReader, needReloc bool) {
resolveSymRef := func(s goobj2.SymRef) *sym.Symbol {
i := l.resolve(r, s)
return l.Syms[i]
}
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ { for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
// A symbol may be a dup or overwritten. In this case, its // A symbol may be a dup or overwritten. In this case, its
// content will actually be provided by a different object // content will actually be provided by a different object
@ -2506,27 +2624,23 @@ func loadObjFull(l *Loader, r *oReader) {
size := osym.Siz() size := osym.Siz()
// Symbol data // Symbol data
s.P = r.Data(i) s.P = l.OutData(gi)
s.Attr.Set(sym.AttrReadOnly, r.ReadOnly())
// Relocs // Relocs
relocs := l.relocs(r, i) if needReloc {
batch := l.relocBatch relocs := l.relocs(r, i)
s.R = batch[:relocs.Count():relocs.Count()] batch := l.relocBatch
l.relocBatch = batch[relocs.Count():] s.R = batch[:relocs.Count():relocs.Count()]
l.convertRelocations(gi, &relocs, s, false) l.relocBatch = batch[relocs.Count():]
l.convertRelocations(gi, &relocs, s, false)
}
// Aux symbol info // Aux symbol info
auxs := r.Auxs(i) auxs := r.Auxs(i)
for j := range auxs { for j := range auxs {
a := &auxs[j] a := &auxs[j]
switch a.Type() { switch a.Type() {
case goobj2.AuxGotype: case goobj2.AuxFuncInfo, goobj2.AuxFuncdata, goobj2.AuxGotype:
typ := resolveSymRef(a.Sym())
if typ != nil {
s.Gotype = typ
}
case goobj2.AuxFuncInfo, goobj2.AuxFuncdata:
// already handled // already handled
case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines: case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines:
// ignored for now // 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) { if s.Size < int64(size) {
s.Size = int64(size) s.Size = int64(size)
} }
@ -2744,6 +2857,42 @@ func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, exts
return textp2 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. // For debugging.
func (l *Loader) Dump() { func (l *Loader) Dump() {
fmt.Println("objs") fmt.Println("objs")

View file

@ -27,9 +27,16 @@ func addDummyObjSym(t *testing.T, ldr *Loader, or *oReader, name string) Sym {
return s return s
} }
func TestAddMaterializedSymbol(t *testing.T) { func mkLoader() *Loader {
edummy := func(s *sym.Symbol, str string, off int) {} 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)} dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
or := &dummyOreader or := &dummyOreader
@ -229,8 +236,7 @@ func sameRelocSlice(s1 *Relocs, s2 []Reloc) bool {
type addFunc func(l *Loader, s Sym, s2 Sym) Sym type addFunc func(l *Loader, s Sym, s2 Sym) Sym
func TestAddDataMethods(t *testing.T) { func TestAddDataMethods(t *testing.T) {
edummy := func(s *sym.Symbol, str string, off int) {} ldr := mkLoader()
ldr := NewLoader(0, edummy)
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)} dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
or := &dummyOreader or := &dummyOreader
@ -352,8 +358,7 @@ func TestAddDataMethods(t *testing.T) {
} }
func TestOuterSub(t *testing.T) { func TestOuterSub(t *testing.T) {
edummy := func(s *sym.Symbol, str string, off int) {} ldr := mkLoader()
ldr := NewLoader(0, edummy)
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)} dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
or := &dummyOreader or := &dummyOreader

View file

@ -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. // Add n relocations, return a handle to the relocations.
func (sb *SymbolBuilder) AddRelocs(n int) Relocs { func (sb *SymbolBuilder) AddRelocs(n int) Relocs {
sb.relocs = append(sb.relocs, make([]goobj2.Reloc, n)...) 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 return (*SymbolBuilder).AddAddrPlus
} }
} }
func (sb *SymbolBuilder) MakeWritable() {
if sb.ReadOnly() {
sb.data = append([]byte(nil), sb.data...)
sb.l.SetAttrReadOnly(sb.symIdx, false)
}
}

View file

@ -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 { func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write32(uint32(sectoff)) ctxt.Out.Write32(uint32(sectoff))
elfsym := r.Xsym.ElfsymForReloc() elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type { switch r.Type {
default: default:
return false return false
@ -164,7 +164,7 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
return -1 return -1
} }
func asmb(ctxt *ld.Link) { func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF { if ctxt.IsELF {
ld.Asmbelfsetup() ld.Asmbelfsetup()
} }

View file

@ -61,7 +61,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write64(uint64(sectoff)) ctxt.Out.Write64(uint64(sectoff))
elfsym := r.Xsym.ElfsymForReloc() elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
ctxt.Out.Write32(uint32(elfsym)) ctxt.Out.Write32(uint32(elfsym))
ctxt.Out.Write8(0) ctxt.Out.Write8(0)
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 return -1
} }
func asmb(ctxt *ld.Link) { func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF { if ctxt.IsELF {
ld.Asmbelfsetup() ld.Asmbelfsetup()
} }

View file

@ -267,120 +267,134 @@ func gencallstub2(ctxt *ld.Link, ldr *loader.Loader, abicase int, stub *loader.S
stub.AddUint32(ctxt.Arch, 0x4e800420) // bctr 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() { if target.IsElf() {
return addelfdynrel(target, syms, s, r) return addelfdynrel2(target, ldr, syms, s, r, rIdx)
} else if target.IsAIX() { } else if target.IsAIX() {
return ld.Xcoffadddynrel(target, ldr, s, r) return ld.Xcoffadddynrel2(target, ldr, syms, s, r, rIdx)
} }
return false return false
} }
func addelfdynrel(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool { func addelfdynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
targ := r.Sym targ := r.Sym()
r.InitExt() var targType sym.SymKind
if targ != 0 {
targType = ldr.SymType(targ)
}
switch r.Type { switch r.Type() {
default: default:
if r.Type >= objabi.ElfRelocOffset { if r.Type() >= objabi.ElfRelocOffset {
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type)) ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false return false
} }
// Handle relocations found in ELF object files. // Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL24): 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 // This is a local call, so the caller isn't setting
// up r12 and r2 is the same for the caller and // up r12 and r2 is the same for the caller and
// callee. Hence, we need to go to the local entry // callee. Hence, we need to go to the local entry
// point. (If we don't do this, the callee will try // point. (If we don't do this, the callee will try
// to use r12 to compute r2.) // 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 // 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC_REL32): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC_REL32):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += 4 su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocAdd(rIdx, r.Add()+4)
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_PPC_REL32 for dyn import") ldr.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
} }
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_ADDR64): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_ADDR64):
r.Type = objabi.R_ADDR su := ldr.MakeSymbolUpdater(s)
if targ.Type == sym.SDYNIMPORT { su.SetRelocType(rIdx, objabi.R_ADDR)
if targType == sym.SDYNIMPORT {
// These happen in .toc sections // These happen in .toc sections
ld.Adddynsym(target, syms, targ) ld.Adddynsym2(ldr, target, syms, targ)
rela := syms.Rela rela := ldr.MakeSymbolUpdater(syms.Rela2)
rela.AddAddrPlus(target.Arch, s, int64(r.Off)) 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, ld.ELF64_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_PPC64_ADDR64)))
rela.AddUint64(target.Arch, uint64(r.Add)) rela.AddUint64(target.Arch, uint64(r.Add()))
r.Type = objabi.ElfRelocOffset // ignore during relocsym su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
} }
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16):
r.Type = objabi.R_POWER_TOC su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_POWER_LO | sym.RV_CHECK_OVERFLOW su.SetRelocType(rIdx, objabi.R_POWER_TOC)
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_LO|sym.RV_CHECK_OVERFLOW)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO):
r.Type = objabi.R_POWER_TOC su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_POWER_LO su.SetRelocType(rIdx, objabi.R_POWER_TOC)
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_LO)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HA): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HA):
r.Type = objabi.R_POWER_TOC su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW su.SetRelocType(rIdx, objabi.R_POWER_TOC)
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HA|sym.RV_CHECK_OVERFLOW)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HI): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HI):
r.Type = objabi.R_POWER_TOC su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW su.SetRelocType(rIdx, objabi.R_POWER_TOC)
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HI|sym.RV_CHECK_OVERFLOW)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_DS): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_DS):
r.Type = objabi.R_POWER_TOC su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_POWER_DS | sym.RV_CHECK_OVERFLOW su.SetRelocType(rIdx, objabi.R_POWER_TOC)
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_DS|sym.RV_CHECK_OVERFLOW)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO_DS): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO_DS):
r.Type = objabi.R_POWER_TOC su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_POWER_DS su.SetRelocType(rIdx, objabi.R_POWER_TOC)
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_DS)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_LO): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_LO):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_POWER_LO su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += 2 // Compensate for relocation size of 2 ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_LO)
su.SetRelocAdd(rIdx, r.Add()+2) // Compensate for relocation size of 2
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HI): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HI):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += 2 ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HI|sym.RV_CHECK_OVERFLOW)
su.SetRelocAdd(rIdx, r.Add()+2)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HA): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HA):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += 2 ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HA|sym.RV_CHECK_OVERFLOW)
su.SetRelocAdd(rIdx, r.Add()+2)
return true return true
} }
// Handle references to ELF symbols from our own object files. // Handle references to ELF symbols from our own object files.
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
return true return true
} }
@ -439,7 +453,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
} }
ctxt.Out.Write64(uint64(sectoff)) ctxt.Out.Write64(uint64(sectoff))
elfsym := r.Xsym.ElfsymForReloc() elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type { switch r.Type {
default: default:
return false return false
@ -972,7 +986,7 @@ func addpltsym2(ctxt *ld.Link, ldr *loader.Loader, s loader.Sym) {
return return
} }
ld.Adddynsym2(ldr, &ctxt.ErrorReporter, &ctxt.Target, &ctxt.ArchSyms, s) ld.Adddynsym2(ldr, &ctxt.Target, &ctxt.ArchSyms, s)
if ctxt.IsELF { if ctxt.IsELF {
plt := ldr.MakeSymbolUpdater(ctxt.PLT2) plt := ldr.MakeSymbolUpdater(ctxt.PLT2)
@ -1068,7 +1082,7 @@ func ensureglinkresolver2(ctxt *ld.Link, ldr *loader.Loader) *loader.SymbolBuild
return glink return glink
} }
func asmb(ctxt *ld.Link) { func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF { if ctxt.IsELF {
ld.Asmbelfsetup() ld.Asmbelfsetup()
} }

View file

@ -49,7 +49,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP, Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR, Dwarfreglr: dwarfRegLR,
Adddynrel: adddynrel, Adddynrel2: adddynrel2,
Archinit: archinit, Archinit: archinit,
Archreloc: archreloc, Archreloc: archreloc,
Archrelocvariant: archrelocvariant, Archrelocvariant: archrelocvariant,

View file

@ -98,7 +98,7 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
return -1 return -1
} }
func asmb(ctxt *ld.Link) { func asmb(ctxt *ld.Link, _ *loader.Loader) {
if ctxt.IsELF { if ctxt.IsELF {
ld.Asmbelfsetup() ld.Asmbelfsetup()
} }

View file

@ -75,135 +75,146 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
initfunc.AddUint32(ctxt.Arch, 0) initfunc.AddUint32(ctxt.Arch, 0)
} }
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 {
targ := r.Sym targ := r.Sym()
r.InitExt() var targType sym.SymKind
if targ != 0 {
targType = ldr.SymType(targ)
}
switch r.Type { switch r.Type() {
default: default:
if r.Type >= objabi.ElfRelocOffset { if r.Type() >= objabi.ElfRelocOffset {
ld.Errorf(s, "unexpected relocation type %d", r.Type) ldr.Errorf(s, "unexpected relocation type %d", r.Type())
return false return false
} }
// Handle relocations found in ELF object files. // Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_12), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_12),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT12): 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 return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_8), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_8),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_16), objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_16),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_32), objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_64): objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_64):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", targ.Name) 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32), objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC64): objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC64):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", targ.Name) 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 // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly. // sense and should be removed when someone has thought about it properly.
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() { if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
} }
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += int64(r.Siz) su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT16), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT16),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT32), objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT64): 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT16DBL), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT16DBL),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32DBL): objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32DBL):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_390_DBL su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += int64(r.Siz) ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
if targ.Type == sym.SDYNIMPORT { su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
addpltsym(target, syms, targ) if targType == sym.SDYNIMPORT {
r.Sym = syms.PLT addpltsym2(target, ldr, syms, targ)
r.Add += int64(targ.Plt()) r.SetSym(syms.PLT2)
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
} }
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT64): objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT64):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += int64(r.Siz) su.SetRelocType(rIdx, objabi.R_PCREL)
if targ.Type == sym.SDYNIMPORT { su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
addpltsym(target, syms, targ) if targType == sym.SDYNIMPORT {
r.Sym = syms.PLT addpltsym2(target, ldr, syms, targ)
r.Add += int64(targ.Plt()) r.SetSym(syms.PLT2)
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
} }
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_COPY): 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 return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GLOB_DAT): 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 return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_JMP_SLOT): 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 return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_RELATIVE): 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 return false
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTOFF): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTOFF):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name) 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPC): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPC):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Sym = syms.GOT su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += int64(r.Siz) r.SetSym(syms.GOT2)
su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16DBL), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16DBL),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32DBL): objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32DBL):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_390_DBL su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += int64(r.Siz) ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
if targ.Type == sym.SDYNIMPORT { su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
ld.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name) if targType == sym.SDYNIMPORT {
ldr.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", ldr.SymName(targ))
} }
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPCDBL): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPCDBL):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Variant = sym.RV_390_DBL su.SetRelocType(rIdx, objabi.R_PCREL)
r.Sym = syms.GOT ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
r.Add += int64(r.Siz) r.SetSym(syms.GOT2)
su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTENT): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTENT):
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
su := ldr.MakeSymbolUpdater(s)
r.Type = objabi.R_PCREL su.SetRelocType(rIdx, objabi.R_PCREL)
r.Variant = sym.RV_390_DBL ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
r.Sym = syms.GOT r.SetSym(syms.GOT2)
r.Add += int64(targ.Got()) su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ))+int64(r.Siz()))
r.Add += int64(r.Siz)
return true return true
} }
// Handle references to ELF symbols from our own object files. // Handle references to ELF symbols from our own object files.
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
return true 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 { func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write64(uint64(sectoff)) ctxt.Out.Write64(uint64(sectoff))
elfsym := r.Xsym.ElfsymForReloc() elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type { switch r.Type {
default: default:
return false 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) { func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Plt() >= 0 { if ldr.SymPlt(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() { if target.IsElf() {
plt := syms.PLT plt := ldr.MakeSymbolUpdater(syms.PLT2)
got := syms.GOT got := ldr.MakeSymbolUpdater(syms.GOT2)
rela := syms.RelaPLT rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
if plt.Size == 0 { if plt.Size() == 0 {
panic("plt is not set up") panic("plt is not set up")
} }
// larl %r1,_GLOBAL_OFFSET_TABLE_+index // larl %r1,_GLOBAL_OFFSET_TABLE_+index
plt.AddUint8(0xc0) plt.AddUint8(0xc0)
plt.AddUint8(0x10) 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 // 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) // lg %r1,0(%r1)
plt.AddUint8(0xe3) plt.AddUint8(0xe3)
plt.AddUint8(0x10) plt.AddUint8(0x10)
@ -434,44 +447,45 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
plt.AddUint8(0xc0) plt.AddUint8(0xc0)
plt.AddUint8(0xf4) 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 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
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) rela.AddUint64(target.Arch, 0)
s.SetPlt(int32(plt.Size - 32)) ldr.SetPlt(s, int32(plt.Size()-32))
} else { } 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) { func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Got() >= 0 { if ldr.SymGot(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
got := syms.GOT got := ldr.MakeSymbolUpdater(syms.GOT2)
s.SetGot(int32(got.Size)) ldr.SetGot(s, int32(got.Size()))
got.AddUint64(target.Arch, 0) got.AddUint64(target.Arch, 0)
if target.IsElf() { if target.IsElf() {
rela := syms.Rela rela := ldr.MakeSymbolUpdater(syms.Rela2)
rela.AddAddrPlus(target.Arch, got, int64(s.Got())) rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_GLOB_DAT))) rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_390_GLOB_DAT)))
rela.AddUint64(target.Arch, 0) rela.AddUint64(target.Arch, 0)
} else { } 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 { if ctxt.IsELF {
ld.Asmbelfsetup() ld.Asmbelfsetup()
} }

View file

@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP, Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR, Dwarfreglr: dwarfRegLR,
Adddynrel: adddynrel, Adddynrel2: adddynrel2,
Archinit: archinit, Archinit: archinit,
Archreloc: archreloc, Archreloc: archreloc,
Archrelocvariant: archrelocvariant, Archrelocvariant: archrelocvariant,

View file

@ -4,18 +4,21 @@
package sym package sym
import "cmd/internal/goobj2"
type Library struct { type Library struct {
Objref string Objref string
Srcref string Srcref string
File string File string
Pkg string Pkg string
Shlib string Shlib string
Hash string Hash string
ImportStrings []string Fingerprint goobj2.FingerprintType
Imports []*Library Autolib []goobj2.ImportedPkg
Main bool Imports []*Library
Safe bool Main bool
Units []*CompilationUnit Safe bool
Units []*CompilationUnit
Textp2 []LoaderSym // text syms defined in this library Textp2 []LoaderSym // text syms defined in this library
DupTextSyms2 []LoaderSym // dupok text syms defined in this library DupTextSyms2 []LoaderSym // dupok text syms defined in this library

View file

@ -55,6 +55,7 @@ type Section struct {
Elfsect interface{} // an *ld.ElfShdr Elfsect interface{} // an *ld.ElfShdr
Reloff uint64 Reloff uint64
Rellen uint64 Rellen uint64
Sym *Symbol // symbol for the section, if any Sym *Symbol // symbol for the section, if any
Index uint16 // each section has a unique index, used internally Sym2 LoaderSym // symbol for the section, if any
Index uint16 // each section has a unique index, used internally
} }

View file

@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms _32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms _64bit uintptr // size on 64bit platforms
}{ }{
{Symbol{}, 104, 168}, {Symbol{}, 84, 136},
} }
for _, tt := range tests { for _, tt := range tests {

View file

@ -15,23 +15,19 @@ import (
// Symbol is an entry in the symbol table. // Symbol is an entry in the symbol table.
type Symbol struct { type Symbol struct {
Name string Name string
Type SymKind Type SymKind
Version int16 Version int16
Attr Attribute Attr Attribute
Dynid int32 Dynid int32
Align int32 Align int32
Elfsym int32 Value int64
LocalElfsym int32 Size int64
Value int64 Sub *Symbol
Size int64 Outer *Symbol
Sub *Symbol SymIdx LoaderSym
Outer *Symbol auxinfo *AuxSymbol
Gotype *Symbol Sect *Section
File string // actually package!
auxinfo *AuxSymbol
Sect *Section
Unit *CompilationUnit
// P contains the raw symbol data. // P contains the raw symbol data.
P []byte P []byte
R []Reloc R []Reloc
@ -88,16 +84,6 @@ func (s *Symbol) IsFileLocal() bool {
return s.Version >= SymVerStatic 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 { func (s *Symbol) Len() int64 {
return s.Size return s.Size
} }
@ -444,80 +430,6 @@ func (s *Symbol) SetElfType(val elf.SymType) {
s.auxinfo.elftype = val 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 { type Pcdata struct {
P []byte P []byte
} }

View file

@ -34,8 +34,6 @@ type Symbols struct {
// Symbol lookup based on name and indexed by version. // Symbol lookup based on name and indexed by version.
versions int versions int
Allsym []*Symbol
// Provided by the loader // Provided by the loader
// Look up the symbol with the given name and version, creating the // Look up the symbol with the given name and version, creating the
@ -55,7 +53,6 @@ type Symbols struct {
func NewSymbols() *Symbols { func NewSymbols() *Symbols {
return &Symbols{ return &Symbols{
versions: SymVerStatic, versions: SymVerStatic,
Allsym: make([]*Symbol, 0, 100000),
} }
} }

View file

@ -92,7 +92,30 @@ func assignAddress(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, v
return sect, n, va 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. // asmb writes the final WebAssembly module binary.
// Spec: https://webassembly.github.io/spec/core/binary/modules.html // 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) { func writeDataSec(ctxt *ld.Link) {
sizeOffset := writeSecHeader(ctxt, sectionData) 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 { type dataSegment struct {
offset int32 offset int32
data []byte data []byte
@ -420,9 +433,9 @@ func writeDataSec(ctxt *ld.Link) {
const maxNumSegments = 100000 const maxNumSegments = 100000
var segments []*dataSegment var segments []*dataSegment
for secIndex, sec := range sections { for secIndex, ds := range dataSects {
data := ld.DatblkBytes(ctxt, int64(sec.Vaddr), int64(sec.Length)) data := ds.data
offset := int32(sec.Vaddr) offset := int32(ds.sect.Vaddr)
// skip leading zeroes // skip leading zeroes
for len(data) > 0 && data[0] == 0 { for len(data) > 0 && data[0] == 0 {
@ -433,7 +446,7 @@ func writeDataSec(ctxt *ld.Link) {
for len(data) > 0 { for len(data) > 0 {
dataLen := int32(len(data)) dataLen := int32(len(data))
var segmentEnd, zeroEnd int32 var segmentEnd, zeroEnd int32
if len(segments)+(len(sections)-secIndex) == maxNumSegments { if len(segments)+(len(dataSects)-secIndex) == maxNumSegments {
segmentEnd = dataLen segmentEnd = dataLen
zeroEnd = dataLen zeroEnd = dataLen
} else { } else {

View file

@ -129,161 +129,189 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
o(0xc3) o(0xc3)
} }
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 {
targ := r.Sym targ := r.Sym()
var targType sym.SymKind
if targ != 0 {
targType = ldr.SymType(targ)
}
switch r.Type { switch r.Type() {
default: default:
if r.Type >= objabi.ElfRelocOffset { if r.Type() >= objabi.ElfRelocOffset {
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type)) ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false return false
} }
// Handle relocations found in ELF object files. // Handle relocations found in ELF object files.
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name) 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 // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly. // sense and should be removed when someone has thought about it properly.
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() { if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
} }
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += 4 su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocAdd(rIdx, r.Add()+4)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Add += 4 su.SetRelocType(rIdx, objabi.R_PCREL)
if targ.Type == sym.SDYNIMPORT { su.SetRelocAdd(rIdx, r.Add()+4)
addpltsym(target, syms, targ) if targType == sym.SDYNIMPORT {
r.Sym = syms.PLT addpltsym2(target, ldr, syms, targ)
r.Add += int64(targ.Plt()) su.SetRelocSym(rIdx, syms.PLT2)
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
} }
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32), case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32),
objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X): objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
if targ.Type != sym.SDYNIMPORT { su := ldr.MakeSymbolUpdater(s)
if targType != sym.SDYNIMPORT {
// have symbol // have symbol
if r.Off >= 2 && s.P[r.Off-2] == 0x8b { sData := ldr.Data(s)
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
s.P[r.Off-2] = 0x8d
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 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. // turn PUSHL of GOT entry into PUSHL of symbol itself.
// use unnecessary SS prefix to keep instruction same length. // use unnecessary SS prefix to keep instruction same length.
s.P[r.Off-2] = 0x36 writeableData := su.Data()
writeableData[r.Off()-2] = 0x36
s.P[r.Off-1] = 0x68 writeableData[r.Off()-1] = 0x68
r.Type = objabi.R_ADDR su.SetRelocType(rIdx, objabi.R_ADDR)
return true 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 return false
} }
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
r.Type = objabi.R_CONST // write r->add during relocsym su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
r.Sym = nil su.SetRelocSym(rIdx, 0)
r.Add += int64(targ.Got()) su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF): 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 return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
r.Type = objabi.R_PCREL su := ldr.MakeSymbolUpdater(s)
r.Sym = syms.GOT su.SetRelocType(rIdx, objabi.R_PCREL)
r.Add += 4 su.SetRelocSym(rIdx, syms.GOT2)
su.SetRelocAdd(rIdx, r.Add()+4)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
if targ.Type == sym.SDYNIMPORT { if targType == sym.SDYNIMPORT {
ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name) 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 return true
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0: case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
r.Type = objabi.R_ADDR su := ldr.MakeSymbolUpdater(s)
if targ.Type == sym.SDYNIMPORT { su.SetRelocType(rIdx, objabi.R_ADDR)
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 return true
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1: case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
if targ.Type == sym.SDYNIMPORT { su := ldr.MakeSymbolUpdater(s)
addpltsym(target, syms, targ) if targType == sym.SDYNIMPORT {
r.Sym = syms.PLT addpltsym2(target, ldr, syms, targ)
r.Add = int64(targ.Plt()) su.SetRelocSym(rIdx, syms.PLT2)
r.Type = objabi.R_PCREL su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
su.SetRelocType(rIdx, objabi.R_PCREL)
return true return true
} }
r.Type = objabi.R_PCREL su.SetRelocType(rIdx, objabi.R_PCREL)
return true return true
case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL: case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
if targ.Type != sym.SDYNIMPORT { su := ldr.MakeSymbolUpdater(s)
if targType != sym.SDYNIMPORT {
// have symbol // have symbol
// turn MOVL of GOT entry into LEAL of symbol itself // turn MOVL of GOT entry into LEAL of symbol itself
if r.Off < 2 || s.P[r.Off-2] != 0x8b { sData := ldr.Data(s)
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name) 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 return false
} }
s.P[r.Off-2] = 0x8d su.MakeWritable()
r.Type = objabi.R_PCREL writeableData := su.Data()
writeableData[r.Off()-2] = 0x8d
su.SetRelocType(rIdx, objabi.R_PCREL)
return true return true
} }
addgotsym(target, syms, targ) addgotsym2(target, ldr, syms, targ)
r.Sym = syms.GOT su.SetRelocSym(rIdx, syms.GOT2)
r.Add += int64(targ.Got()) su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
r.Type = objabi.R_PCREL su.SetRelocType(rIdx, objabi.R_PCREL)
return true return true
} }
// Handle references to ELF symbols from our own object files. // Handle references to ELF symbols from our own object files.
if targ.Type != sym.SDYNIMPORT { if targType != sym.SDYNIMPORT {
return true 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, case objabi.R_CALL,
objabi.R_PCREL: objabi.R_PCREL:
if target.IsExternal() { if target.IsExternal() {
// External linker will do this relocation. // External linker will do this relocation.
return true return true
} }
addpltsym(target, syms, targ) addpltsym2(target, ldr, syms, targ)
r.Sym = syms.PLT su := ldr.MakeSymbolUpdater(s)
r.Add = int64(targ.Plt()) su.SetRelocSym(rIdx, syms.PLT2)
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
return true return true
case objabi.R_ADDR: case objabi.R_ADDR:
if s.Type != sym.SDATA { if ldr.SymType(s) != sym.SDATA {
break break
} }
if target.IsElf() { if target.IsElf() {
ld.Adddynsym(target, syms, targ) ld.Adddynsym2(ldr, target, syms, targ)
rel := syms.Rel rel := ldr.MakeSymbolUpdater(syms.Rel2)
rel.AddAddrPlus(target.Arch, s, int64(r.Off)) rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32))) rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
r.Type = objabi.R_CONST // write r->add during relocsym su := ldr.MakeSymbolUpdater(s)
r.Sym = nil su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
su.SetRelocSym(rIdx, 0)
return true 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. // Mach-O relocations are a royal pain to lay out.
// They use a compact stateful bytecode representation // They use a compact stateful bytecode representation
// that is too much bother to deal with. // 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, // just in case the C code assigns to the variable,
// and of course it only works for single pointers, // and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs. // 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 got := ldr.MakeSymbolUpdater(syms.GOT2)
s.Type = got.Type su := ldr.MakeSymbolUpdater(s)
s.Attr |= sym.AttrSubSymbol su.SetType(got.Type())
s.Outer = got got.PrependSub(s)
s.Sub = got.Sub su.SetValue(got.Size())
got.Sub = s
s.Value = got.Size
got.AddUint32(target.Arch, 0) got.AddUint32(target.Arch, 0)
syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid)) leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
r.Type = objabi.ElfRelocOffset // ignore during relocsym leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ)))
su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
return true 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 { func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
ctxt.Out.Write32(uint32(sectoff)) ctxt.Out.Write32(uint32(sectoff))
elfsym := r.Xsym.ElfsymForReloc() elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
switch r.Type { switch r.Type {
default: default:
return false 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) { func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Plt() >= 0 { if ldr.SymPlt(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
if target.IsElf() { if target.IsElf() {
plt := syms.PLT plt := ldr.MakeSymbolUpdater(syms.PLT2)
got := syms.GOTPLT got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
rel := syms.RelPLT rel := ldr.MakeSymbolUpdater(syms.RelPLT2)
if plt.Size == 0 { if plt.Size() == 0 {
panic("plt is not set up") 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(0xff)
plt.AddUint8(0x25) 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 // 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 // pushl $x
plt.AddUint8(0x68) plt.AddUint8(0x68)
plt.AddUint32(target.Arch, uint32(rel.Size)) plt.AddUint32(target.Arch, uint32(rel.Size()))
// jmp .plt // jmp .plt
plt.AddUint8(0xe9) plt.AddUint8(0xe9)
plt.AddUint32(target.Arch, uint32(-(plt.Size + 4))) plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
// rel // 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() { } else if target.IsDarwin() {
// Same laziness as in 6l. // 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) // jmpq *got+size(IP)
s.SetPlt(int32(plt.Size)) ldr.SetPlt(s, int32(plt.Size()))
plt.AddUint8(0xff) plt.AddUint8(0xff)
plt.AddUint8(0x25) plt.AddUint8(0x25)
plt.AddAddrPlus(target.Arch, syms.GOT, int64(s.Got())) plt.AddAddrPlus(target.Arch, syms.GOT2, int64(ldr.SymGot(s)))
} else { } 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) { func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
if s.Got() >= 0 { if ldr.SymGot(s) >= 0 {
return return
} }
ld.Adddynsym(target, syms, s) ld.Adddynsym2(ldr, target, syms, s)
got := syms.GOT got := ldr.MakeSymbolUpdater(syms.GOT2)
s.SetGot(int32(got.Size)) ldr.SetGot(s, int32(got.Size()))
got.AddUint32(target.Arch, 0) got.AddUint32(target.Arch, 0)
if target.IsElf() { if target.IsElf() {
rel := syms.Rel rel := ldr.MakeSymbolUpdater(syms.Rel2)
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_386_GLOB_DAT))) rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_386_GLOB_DAT)))
} else if target.IsDarwin() { } 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 { } 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 { if ctxt.IsELF {
ld.Asmbelfsetup() ld.Asmbelfsetup()
} }

View file

@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
Dwarfregsp: dwarfRegSP, Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR, Dwarfreglr: dwarfRegLR,
Adddynrel: adddynrel, Adddynrel2: adddynrel2,
Archinit: archinit, Archinit: archinit,
Archreloc: archreloc, Archreloc: archreloc,
Archrelocvariant: archrelocvariant, Archrelocvariant: archrelocvariant,

View file

@ -675,3 +675,61 @@ func TestTrampoline(t *testing.T) {
t.Errorf("unexpected output:\n%s", out) 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)
}
}

View file

@ -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") }

View file

@ -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") }

View file

@ -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() }