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

@ -20,8 +20,8 @@ import (
// //
// Header struct { // Header struct {
// Magic [...]byte // "\x00go115ld" // Magic [...]byte // "\x00go115ld"
// Fingerprint [8]byte
// Flags uint32 // Flags uint32
// // TODO: Fingerprint
// Offsets [...]uint32 // byte offset of each block below // Offsets [...]uint32 // byte offset of each block below
// } // }
// //
@ -29,7 +29,11 @@ import (
// 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
@ -150,6 +158,7 @@ const (
// TODO: probably no need to export this. // TODO: probably no need to export this.
type Header struct { type Header struct {
Magic string Magic string
Fingerprint FingerprintType
Flags uint32 Flags uint32
Offsets [NBlk]uint32 Offsets [NBlk]uint32
} }
@ -158,6 +167,7 @@ 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 {
@ -1133,7 +1133,7 @@ func elfdynhash(ctxt *Link) {
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
@ -1149,7 +1149,7 @@ func elfdynhash(ctxt *Link) {
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 { nsortsym = len(sortsym)
if s.Attr.Reachable() {
addsym(ctxt, s, "", DataSym, 0, nil)
}
}
}
} }
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) }
sortsym = make([]*sym.Symbol, nsortsym) collectmachosyms(ctxt)
nsortsym = 0 sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
machogenasmsym(ctxt) s1 := sortsym[i]
sort.Sort(machoscmp(sortsym[:nsortsym])) s2 := sortsym[j]
for i := 0; i < nsortsym; i++ { k1 := symkind(ldr, s1)
sortsym[i].Dynid = int32(i) k2 := symkind(ldr, s2)
if k1 != k2 {
return k1 < k2
}
return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms
})
for i, s := range sortsym {
ldr.SetSymDynid(s, int32(i))
} }
} }
@ -877,7 +897,7 @@ func machosymtab(ctxt *Link) {
symstr := ctxt.Syms.Lookup(".machosymstr", 0) 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 // Asmb will redirect symbols to the output file mmap, and relocations
// will be applied directly there. // will be applied directly there.
bench.Start("Asmb") bench.Start("Asmb")
thearch.Asmb(ctxt) 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,12 +34,14 @@ 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(),
@ -47,6 +49,7 @@ func linknew(arch *sys.Arch) *Link {
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
@ -246,6 +262,8 @@ type Loader struct {
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
elfSym map[Sym]int32 // stores elf sym symbol property
localElfSym map[Sym]int32 // stores "local" elf sym symbol property
symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms
plt map[Sym]int32 // stores dynimport for pe objects plt map[Sym]int32 // stores dynimport for pe objects
got map[Sym]int32 // stores got for pe objects got map[Sym]int32 // stores got for pe objects
@ -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
if needReloc {
l.relocBatch = make([]sym.Reloc, nr) 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
if needReloc {
batch := l.relocBatch batch := l.relocBatch
s.R = batch[:len(pp.relocs):len(pp.relocs)] s.R = batch[:len(pp.relocs):len(pp.relocs)]
l.relocBatch = batch[len(pp.relocs):] l.relocBatch = batch[len(pp.relocs):]
relocs := l.Relocs(i) relocs := l.Relocs(i)
l.convertRelocations(i, &relocs, s, false) 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,17 +2381,12 @@ 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 == "" {
switch t {
case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES:
default:
continue continue
} }
}
ver := abiToVer(osym.ABI(), r.version) ver := abiToVer(osym.ABI(), r.version)
if t == sym.SXREF { if t == sym.SXREF {
log.Fatalf("bad sxref") log.Fatalf("bad 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
if needReloc {
relocs := l.relocs(r, i) relocs := l.relocs(r, i)
batch := l.relocBatch batch := l.relocBatch
s.R = batch[:relocs.Count():relocs.Count()] s.R = batch[:relocs.Count():relocs.Count()]
l.relocBatch = batch[relocs.Count():] l.relocBatch = batch[relocs.Count():]
l.convertRelocations(gi, &relocs, s, false) 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,6 +4,8 @@
package sym package sym
import "cmd/internal/goobj2"
type Library struct { type Library struct {
Objref string Objref string
Srcref string Srcref string
@ -11,7 +13,8 @@ type Library struct {
Pkg string Pkg string
Shlib string Shlib string
Hash string Hash string
ImportStrings []string Fingerprint goobj2.FingerprintType
Autolib []goobj2.ImportedPkg
Imports []*Library Imports []*Library
Main bool Main bool
Safe bool Safe bool

View file

@ -56,5 +56,6 @@ type Section struct {
Reloff uint64 Reloff uint64
Rellen uint64 Rellen uint64
Sym *Symbol // symbol for the section, if any Sym *Symbol // symbol for the section, if any
Sym2 LoaderSym // symbol for the section, if any
Index uint16 // each section has a unique index, used internally 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

@ -21,17 +21,13 @@ type Symbol struct {
Attr Attribute Attr Attribute
Dynid int32 Dynid int32
Align int32 Align int32
Elfsym int32
LocalElfsym int32
Value int64 Value int64
Size int64 Size int64
Sub *Symbol Sub *Symbol
Outer *Symbol Outer *Symbol
Gotype *Symbol SymIdx LoaderSym
File string // actually package!
auxinfo *AuxSymbol auxinfo *AuxSymbol
Sect *Section 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() }