mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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:
commit
d0754cfe4a
59 changed files with 3094 additions and 2446 deletions
|
|
@ -35,6 +35,8 @@
|
|||
// }
|
||||
// }
|
||||
//
|
||||
// Fingerprint [8]byte
|
||||
//
|
||||
// uvarint means a uint64 written out using uvarint encoding.
|
||||
//
|
||||
// []T means a uvarint followed by that many T objects. In other
|
||||
|
|
@ -296,6 +298,10 @@ func iexport(out *bufio.Writer) {
|
|||
io.Copy(out, &hdr)
|
||||
io.Copy(out, &p.strings)
|
||||
io.Copy(out, &p.data0)
|
||||
|
||||
// Add fingerprint (used by linker object file).
|
||||
// Attach this to the end, so tools (e.g. gcimporter) don't care.
|
||||
out.Write(Ctxt.Fingerprint[:])
|
||||
}
|
||||
|
||||
// writeIndex writes out an object index. mainIndex indicates whether
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package gc
|
|||
import (
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/src"
|
||||
"encoding/binary"
|
||||
|
|
@ -95,7 +96,7 @@ func (r *intReader) uint64() uint64 {
|
|||
return i
|
||||
}
|
||||
|
||||
func iimport(pkg *types.Pkg, in *bio.Reader) {
|
||||
func iimport(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj2.FingerprintType) {
|
||||
ir := &intReader{in, pkg}
|
||||
|
||||
version := ir.uint64()
|
||||
|
|
@ -188,6 +189,14 @@ func iimport(pkg *types.Pkg, in *bio.Reader) {
|
|||
inlineImporter[s] = iimporterAndOffset{p, off}
|
||||
}
|
||||
}
|
||||
|
||||
// Fingerprint
|
||||
n, err := in.Read(fingerprint[:])
|
||||
if err != nil || n != len(fingerprint) {
|
||||
yyerror("import %s: error reading fingerprint", pkg.Path)
|
||||
errorexit()
|
||||
}
|
||||
return fingerprint
|
||||
}
|
||||
|
||||
type iimporter struct {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"cmd/compile/internal/types"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/src"
|
||||
|
|
@ -1254,15 +1255,6 @@ func importfile(f *Val) *types.Pkg {
|
|||
}
|
||||
}
|
||||
|
||||
// assume files move (get installed) so don't record the full path
|
||||
if packageFile != nil {
|
||||
// If using a packageFile map, assume path_ can be recorded directly.
|
||||
Ctxt.AddImport(path_)
|
||||
} else {
|
||||
// For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
|
||||
Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):])
|
||||
}
|
||||
|
||||
// In the importfile, if we find:
|
||||
// $$\n (textual format): not supported anymore
|
||||
// $$B\n (binary format) : import directly, then feed the lexer a dummy statement
|
||||
|
|
@ -1287,6 +1279,7 @@ func importfile(f *Val) *types.Pkg {
|
|||
c, _ = imp.ReadByte()
|
||||
}
|
||||
|
||||
var fingerprint goobj2.FingerprintType
|
||||
switch c {
|
||||
case '\n':
|
||||
yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
|
||||
|
|
@ -1310,13 +1303,22 @@ func importfile(f *Val) *types.Pkg {
|
|||
yyerror("import %s: unexpected package format byte: %v", file, c)
|
||||
errorexit()
|
||||
}
|
||||
iimport(importpkg, imp)
|
||||
fingerprint = iimport(importpkg, imp)
|
||||
|
||||
default:
|
||||
yyerror("no import in %q", path_)
|
||||
errorexit()
|
||||
}
|
||||
|
||||
// assume files move (get installed) so don't record the full path
|
||||
if packageFile != nil {
|
||||
// If using a packageFile map, assume path_ can be recorded directly.
|
||||
Ctxt.AddImport(path_, fingerprint)
|
||||
} else {
|
||||
// For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
|
||||
Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):], fingerprint)
|
||||
}
|
||||
|
||||
if importpkg.Height >= myheight {
|
||||
myheight = importpkg.Height + 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,11 @@ func (r *objReader) readNew() {
|
|||
}
|
||||
|
||||
// Imports
|
||||
r.p.Imports = rr.Autolib()
|
||||
autolib := rr.Autolib()
|
||||
for _, p := range autolib {
|
||||
r.p.Imports = append(r.p.Imports, p.Pkg)
|
||||
// Ignore fingerprint (for tools like objdump which only reads one object).
|
||||
}
|
||||
|
||||
pkglist := rr.Pkglist()
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import (
|
|||
//
|
||||
// Header struct {
|
||||
// Magic [...]byte // "\x00go115ld"
|
||||
// Fingerprint [8]byte
|
||||
// Flags uint32
|
||||
// // TODO: Fingerprint
|
||||
// Offsets [...]uint32 // byte offset of each block below
|
||||
// }
|
||||
//
|
||||
|
|
@ -29,7 +29,11 @@ import (
|
|||
// Data [...]byte
|
||||
// }
|
||||
//
|
||||
// Autolib [...]string // imported packages (for file loading) // TODO: add fingerprints
|
||||
// Autolib [...]struct { // imported packages (for file loading)
|
||||
// Pkg string
|
||||
// Fingerprint [8]byte
|
||||
// }
|
||||
//
|
||||
// PkgIndex [...]string // referenced packages by index
|
||||
//
|
||||
// DwarfFiles [...]string
|
||||
|
|
@ -119,6 +123,10 @@ import (
|
|||
|
||||
const stringRefSize = 8 // two uint32s
|
||||
|
||||
type FingerprintType [8]byte
|
||||
|
||||
func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
|
||||
|
||||
// Package Index.
|
||||
const (
|
||||
PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols
|
||||
|
|
@ -150,6 +158,7 @@ const (
|
|||
// TODO: probably no need to export this.
|
||||
type Header struct {
|
||||
Magic string
|
||||
Fingerprint FingerprintType
|
||||
Flags uint32
|
||||
Offsets [NBlk]uint32
|
||||
}
|
||||
|
|
@ -158,6 +167,7 @@ const Magic = "\x00go115ld"
|
|||
|
||||
func (h *Header) Write(w *Writer) {
|
||||
w.RawString(h.Magic)
|
||||
w.Bytes(h.Fingerprint[:])
|
||||
w.Uint32(h.Flags)
|
||||
for _, x := range h.Offsets {
|
||||
w.Uint32(x)
|
||||
|
|
@ -171,6 +181,8 @@ func (h *Header) Read(r *Reader) error {
|
|||
return errors.New("wrong magic, not a Go object file")
|
||||
}
|
||||
off := uint32(len(h.Magic))
|
||||
copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
|
||||
off += 8
|
||||
h.Flags = r.uint32At(off)
|
||||
off += 4
|
||||
for i := range h.Offsets {
|
||||
|
|
@ -184,6 +196,19 @@ func (h *Header) Size() int {
|
|||
return len(h.Magic) + 4 + 4*len(h.Offsets)
|
||||
}
|
||||
|
||||
// Autolib
|
||||
type ImportedPkg struct {
|
||||
Pkg string
|
||||
Fingerprint FingerprintType
|
||||
}
|
||||
|
||||
const importedPkgSize = stringRefSize + 8
|
||||
|
||||
func (p *ImportedPkg) Write(w *Writer) {
|
||||
w.StringRef(p.Pkg)
|
||||
w.Bytes(p.Fingerprint[:])
|
||||
}
|
||||
|
||||
// Symbol definition.
|
||||
//
|
||||
// Serialized format:
|
||||
|
|
@ -495,12 +520,18 @@ func (r *Reader) StringRef(off uint32) string {
|
|||
return r.StringAt(r.uint32At(off+4), l)
|
||||
}
|
||||
|
||||
func (r *Reader) Autolib() []string {
|
||||
n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / stringRefSize
|
||||
s := make([]string, n)
|
||||
func (r *Reader) Fingerprint() FingerprintType {
|
||||
return r.h.Fingerprint
|
||||
}
|
||||
|
||||
func (r *Reader) Autolib() []ImportedPkg {
|
||||
n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
|
||||
s := make([]ImportedPkg, n)
|
||||
off := r.h.Offsets[BlkAutolib]
|
||||
for i := range s {
|
||||
off := r.h.Offsets[BlkAutolib] + uint32(i)*stringRefSize
|
||||
s[i] = r.StringRef(off)
|
||||
s[i].Pkg = r.StringRef(off)
|
||||
copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
|
||||
off += importedPkgSize
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
@ -508,9 +539,10 @@ func (r *Reader) Autolib() []string {
|
|||
func (r *Reader) Pkglist() []string {
|
||||
n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
|
||||
s := make([]string, n)
|
||||
off := r.h.Offsets[BlkPkgIdx]
|
||||
for i := range s {
|
||||
off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
|
||||
s[i] = r.StringRef(off)
|
||||
off += stringRefSize
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@
|
|||
package obj
|
||||
|
||||
import (
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/src"
|
||||
)
|
||||
|
||||
// AddImport adds a package to the list of imported packages.
|
||||
func (ctxt *Link) AddImport(pkg string) {
|
||||
ctxt.Imports = append(ctxt.Imports, pkg)
|
||||
func (ctxt *Link) AddImport(pkg string, fingerprint goobj2.FingerprintType) {
|
||||
ctxt.Imports = append(ctxt.Imports, goobj2.ImportedPkg{Pkg: pkg, Fingerprint: fingerprint})
|
||||
}
|
||||
|
||||
func linkgetlineFromPos(ctxt *Link, xpos src.XPos) (f string, l int32) {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ package obj
|
|||
import (
|
||||
"bufio"
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/src"
|
||||
"cmd/internal/sys"
|
||||
|
|
@ -666,7 +667,7 @@ type Link struct {
|
|||
PosTable src.PosTable
|
||||
InlTree InlTree // global inlining tree used by gc/inl.go
|
||||
DwFixups *DwarfFixupTable
|
||||
Imports []string
|
||||
Imports []goobj2.ImportedPkg
|
||||
DiagFunc func(string, ...interface{})
|
||||
DiagFlush func()
|
||||
DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node
|
||||
|
|
@ -699,6 +700,8 @@ type Link struct {
|
|||
defs []*LSym // list of defined symbols in the current package
|
||||
nonpkgdefs []*LSym // list of defined non-package symbols
|
||||
nonpkgrefs []*LSym // list of referenced non-package symbols
|
||||
|
||||
Fingerprint goobj2.FingerprintType // fingerprint of symbol indices, to catch index mismatch
|
||||
}
|
||||
|
||||
func (ctxt *Link) Diag(format string, args ...interface{}) {
|
||||
|
|
|
|||
|
|
@ -98,8 +98,9 @@ func WriteObjFile(ctxt *Link, bout *bio.Writer, pkgpath string) {
|
|||
w.wr.WriteByte(1)
|
||||
|
||||
// Autolib
|
||||
for _, pkg := range ctxt.Imports {
|
||||
w.writeString(pkg)
|
||||
for _, p := range ctxt.Imports {
|
||||
w.writeString(p.Pkg)
|
||||
// This object format ignores p.Fingerprint.
|
||||
}
|
||||
w.writeString("")
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,11 @@ func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
|
|||
if ctxt.Flag_shared {
|
||||
flags |= goobj2.ObjFlagShared
|
||||
}
|
||||
h := goobj2.Header{Magic: goobj2.Magic, Flags: flags}
|
||||
h := goobj2.Header{
|
||||
Magic: goobj2.Magic,
|
||||
Fingerprint: ctxt.Fingerprint,
|
||||
Flags: flags,
|
||||
}
|
||||
h.Write(w.Writer)
|
||||
|
||||
// String table
|
||||
|
|
@ -46,8 +50,8 @@ func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
|
|||
|
||||
// Autolib
|
||||
h.Offsets[goobj2.BlkAutolib] = w.Offset()
|
||||
for _, pkg := range ctxt.Imports {
|
||||
w.StringRef(pkg)
|
||||
for i := range ctxt.Imports {
|
||||
ctxt.Imports[i].Write(w.Writer)
|
||||
}
|
||||
|
||||
// Package references
|
||||
|
|
@ -180,8 +184,8 @@ func (w *writer) init() {
|
|||
|
||||
func (w *writer) StringTable() {
|
||||
w.AddString("")
|
||||
for _, pkg := range w.ctxt.Imports {
|
||||
w.AddString(pkg)
|
||||
for _, p := range w.ctxt.Imports {
|
||||
w.AddString(p.Pkg)
|
||||
}
|
||||
for _, pkg := range w.pkglist {
|
||||
w.AddString(pkg)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ package obj
|
|||
import (
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/objabi"
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
|
|
@ -241,6 +242,15 @@ func (ctxt *Link) NumberSyms(asm bool) {
|
|||
ctxt.pkgIdx[pkg] = ipkg
|
||||
ipkg++
|
||||
})
|
||||
|
||||
// Compute a fingerprint of the indices, for exporting.
|
||||
if !asm {
|
||||
h := md5.New()
|
||||
for _, s := range ctxt.defs {
|
||||
h.Write([]byte(s.Name))
|
||||
}
|
||||
copy(ctxt.Fingerprint[:], h.Sum(nil)[:])
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether s is a non-package symbol, which needs to be referenced
|
||||
|
|
|
|||
|
|
@ -78,48 +78,55 @@ func makeWritable(s *sym.Symbol) {
|
|||
}
|
||||
}
|
||||
|
||||
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
|
||||
targ := r.Sym()
|
||||
var targType sym.SymKind
|
||||
if targ != 0 {
|
||||
targType = ldr.SymType(targ)
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
switch r.Type() {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
|
||||
if r.Type() >= objabi.ElfRelocOffset {
|
||||
ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
|
||||
ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == sym.SXREF {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
if targType == 0 || targType == sym.SXREF {
|
||||
ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 8
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+8)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -127,34 +134,36 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX):
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||
makeWritable(s)
|
||||
sData := ldr.Data(s)
|
||||
if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
|
||||
su.MakeWritable()
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
s.P[r.Off-2] = 0x8d
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
writeableData := su.Data()
|
||||
writeableData[r.Off()-2] = 0x8d
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to using GOT and hope for the best (CMOV*)
|
||||
// TODO: just needs relocation, no need to put in .dynsym
|
||||
addgotsym(target, syms, targ)
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += 4
|
||||
r.Add += int64(targ.Got())
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
if target.IsPIE() && target.IsInternal() {
|
||||
// For internal linking PIE, this R_ADDR relocation cannot
|
||||
// be resolved statically. We need to generate a dynamic
|
||||
|
|
@ -168,19 +177,21 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
|
||||
// TODO: What is the difference between all these?
|
||||
r.Type = objabi.R_ADDR
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(targ.Plt())
|
||||
r.Type = objabi.R_PCREL
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
|
||||
return true
|
||||
}
|
||||
fallthrough
|
||||
|
|
@ -190,44 +201,53 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
|
||||
r.Type = objabi.R_PCREL
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||
ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
|
||||
sdata := ldr.Data(s)
|
||||
if r.Off() < 2 || sdata[r.Off()-2] != 0x8b {
|
||||
ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
|
||||
return false
|
||||
}
|
||||
|
||||
makeWritable(s)
|
||||
s.P[r.Off-2] = 0x8d
|
||||
r.Type = objabi.R_PCREL
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.MakeWritable()
|
||||
sdata = su.Data()
|
||||
sdata[r.Off()-2] = 0x8d
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
return true
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
if targType != sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
addgotsym(target, syms, targ)
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
// Reread the reloc to incorporate any changes in type above.
|
||||
relocs := ldr.Relocs(s)
|
||||
*r = relocs.At2(rIdx)
|
||||
|
||||
switch r.Type() {
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// nothing to do, the relocation will be laid out in reloc
|
||||
return true
|
||||
}
|
||||
|
|
@ -237,26 +257,28 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
}
|
||||
// Internal linking, for both ELF and Mach-O.
|
||||
// Build a PLT entry and change the relocation target to that entry.
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(targ.Plt())
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
|
||||
return true
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type == sym.STEXT && target.IsElf() {
|
||||
if ldr.SymType(s) == sym.STEXT && target.IsElf() {
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
if target.IsSolaris() {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
|
||||
return true
|
||||
}
|
||||
// The code is asking for the address of an external
|
||||
// function. We provide it with the address of the
|
||||
// correspondent GOT symbol.
|
||||
addgotsym(target, syms, targ)
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -293,7 +315,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
// symbol offset as determined by reloc(), not the
|
||||
// final dynamically linked address as a dynamic
|
||||
// relocation would provide.
|
||||
switch s.Name {
|
||||
switch ldr.SymName(s) {
|
||||
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
|
||||
return false
|
||||
}
|
||||
|
|
@ -304,7 +326,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
// linking, in which case the relocation will be
|
||||
// prepared in the 'reloc' phase and passed to the
|
||||
// external linker in the 'asmb' phase.
|
||||
if s.Type != sym.SDATA && s.Type != sym.SRODATA {
|
||||
if ldr.SymType(s) != sym.SDATA && ldr.SymType(s) != sym.SRODATA {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -327,14 +349,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
// AddAddrPlus is used for r_offset and r_addend to
|
||||
// generate new R_ADDR relocations that will update
|
||||
// these fields in the 'reloc' phase.
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, s, int64(r.Off))
|
||||
if r.Siz == 8 {
|
||||
rela := ldr.MakeSymbolUpdater(syms.Rela2)
|
||||
rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
|
||||
if r.Siz() == 8 {
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
|
||||
} else {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
rela.AddAddrPlus(target.Arch, targ, int64(r.Add))
|
||||
rela.AddAddrPlus(target.Arch, targ, int64(r.Add()))
|
||||
// Not mark r done here. So we still apply it statically,
|
||||
// so in the file content we'll also have the right offset
|
||||
// to the relocation target. So it can be examined statically
|
||||
|
|
@ -342,7 +364,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
return true
|
||||
}
|
||||
|
||||
if target.IsDarwin() && s.Size == int64(target.Arch.PtrSize) && r.Off == 0 {
|
||||
if target.IsDarwin() && ldr.SymSize(s) == int64(target.Arch.PtrSize) && r.Off() == 0 {
|
||||
// Mach-O relocations are a royal pain to lay out.
|
||||
// They use a compact stateful bytecode representation
|
||||
// that is too much bother to deal with.
|
||||
|
|
@ -353,18 +375,17 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
// just in case the C code assigns to the variable,
|
||||
// and of course it only works for single pointers,
|
||||
// but we only need to support cgo and that's all it needs.
|
||||
ld.Adddynsym(target, syms, targ)
|
||||
ld.Adddynsym2(ldr, target, syms, targ)
|
||||
|
||||
got := syms.GOT
|
||||
s.Type = got.Type
|
||||
s.Attr |= sym.AttrSubSymbol
|
||||
s.Outer = got
|
||||
s.Sub = got.Sub
|
||||
got.Sub = s
|
||||
s.Value = got.Size
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetType(got.Type())
|
||||
got.PrependSub(s)
|
||||
su.SetValue(got.Size())
|
||||
got.AddUint64(target.Arch, 0)
|
||||
syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid))
|
||||
r.Type = objabi.ElfRelocOffset // ignore during relocsym
|
||||
leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
|
||||
leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ)))
|
||||
su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -375,7 +396,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write64(uint64(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
|
@ -569,18 +590,18 @@ func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.S
|
|||
}
|
||||
}
|
||||
|
||||
func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymPlt(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
|
||||
if target.IsElf() {
|
||||
plt := syms.PLT
|
||||
got := syms.GOTPLT
|
||||
rela := syms.RelaPLT
|
||||
if plt.Size == 0 {
|
||||
plt := ldr.MakeSymbolUpdater(syms.PLT2)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
|
||||
rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
|
||||
if plt.Size() == 0 {
|
||||
panic("plt is not set up")
|
||||
}
|
||||
|
||||
|
|
@ -588,28 +609,29 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
|||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddPCRelPlus(target.Arch, got, got.Size)
|
||||
plt.AddPCRelPlus(target.Arch, got.Sym(), got.Size())
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
got.AddAddrPlus(target.Arch, plt, plt.Size)
|
||||
got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
|
||||
|
||||
// pushq $x
|
||||
plt.AddUint8(0x68)
|
||||
|
||||
plt.AddUint32(target.Arch, uint32((got.Size-24-8)/8))
|
||||
plt.AddUint32(target.Arch, uint32((got.Size()-24-8)/8))
|
||||
|
||||
// jmpq .plt
|
||||
plt.AddUint8(0xe9)
|
||||
|
||||
plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
|
||||
plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
|
||||
|
||||
// rela
|
||||
rela.AddAddrPlus(target.Arch, got, got.Size-8)
|
||||
rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
|
||||
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT)))
|
||||
sDynid := ldr.SymDynid(s)
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
|
||||
s.SetPlt(int32(plt.Size - 16))
|
||||
ldr.SetPlt(s, int32(plt.Size()-16))
|
||||
} else if target.IsDarwin() {
|
||||
// To do lazy symbol lookup right, we're supposed
|
||||
// to tell the dynamic loader which library each
|
||||
|
|
@ -621,45 +643,48 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
|||
// https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
|
||||
// has details about what we're avoiding.
|
||||
|
||||
addgotsym(target, syms, s)
|
||||
plt := syms.PLT
|
||||
addgotsym2(target, ldr, syms, s)
|
||||
plt := ldr.MakeSymbolUpdater(syms.PLT2)
|
||||
|
||||
syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid))
|
||||
sDynid := ldr.SymDynid(s)
|
||||
lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT2)
|
||||
lep.AddUint32(target.Arch, uint32(sDynid))
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
s.SetPlt(int32(plt.Size))
|
||||
ldr.SetPlt(s, int32(plt.Size()))
|
||||
|
||||
plt.AddUint8(0xff)
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddPCRelPlus(target.Arch, syms.GOT, int64(s.Got()))
|
||||
plt.AddPCRelPlus(target.Arch, syms.GOT2, int64(ldr.SymGot(s)))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymGot(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
got := syms.GOT
|
||||
s.SetGot(int32(got.Size))
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
ldr.SetGot(s, int32(got.Size()))
|
||||
got.AddUint64(target.Arch, 0)
|
||||
|
||||
if target.IsElf() {
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT)))
|
||||
rela := ldr.MakeSymbolUpdater(syms.Rela2)
|
||||
rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_X86_64_GLOB_DAT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
} else if target.IsDarwin() {
|
||||
syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid))
|
||||
leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
|
||||
leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
func asmb(ctxt *ld.Link, _ *loader.Loader) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
|
@ -816,7 +841,7 @@ func asmb2(ctxt *ld.Link) {
|
|||
}
|
||||
}
|
||||
|
||||
func tlsIEtoLE(s *sym.Symbol, off, size int) {
|
||||
func tlsIEtoLE(P []byte, off, size int) {
|
||||
// Transform the PC-relative instruction into a constant load.
|
||||
// That is,
|
||||
//
|
||||
|
|
@ -827,7 +852,7 @@ func tlsIEtoLE(s *sym.Symbol, off, size int) {
|
|||
if off < 3 {
|
||||
log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction")
|
||||
}
|
||||
op := s.P[off-3 : off]
|
||||
op := P[off-3 : off]
|
||||
reg := op[2] >> 3
|
||||
|
||||
if op[1] == 0x8b || reg == 4 {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
|||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Adddynrel2: adddynrel2,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
|
|
|
|||
|
|
@ -103,24 +103,30 @@ func braddoff(a int32, b int32) int32 {
|
|||
return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
|
||||
}
|
||||
|
||||
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
|
||||
|
||||
switch r.Type {
|
||||
targ := r.Sym()
|
||||
var targType sym.SymKind
|
||||
if targ != 0 {
|
||||
targType = ldr.SymType(targ)
|
||||
}
|
||||
|
||||
switch r.Type() {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
|
||||
if r.Type() >= objabi.ElfRelocOffset {
|
||||
ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PLT32):
|
||||
r.Type = objabi.R_CALLARM
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_CALLARM)
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4)))
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -130,113 +136,112 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT32): // R_ARM_GOT_BREL
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
addgotsyminternal(target, syms, targ)
|
||||
if targType != sym.SDYNIMPORT {
|
||||
addgotsyminternal2(target, ldr, syms, targ)
|
||||
} else {
|
||||
addgotsym(target, syms, targ)
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
}
|
||||
|
||||
r.Type = objabi.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
r.Add += int64(targ.Got())
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
|
||||
su.SetRelocSym(rIdx, 0)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT_PREL): // GOT(nil) + A - nil
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
addgotsyminternal(target, syms, targ)
|
||||
if targType != sym.SDYNIMPORT {
|
||||
addgotsyminternal2(target, ldr, syms, targ)
|
||||
} else {
|
||||
addgotsym(target, syms, targ)
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
}
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got()) + 4
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTOFF): // R_ARM_GOTOFF32
|
||||
r.Type = objabi.R_GOTOFF
|
||||
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_GOTOFF)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTPC): // R_ARM_BASE_PREL
|
||||
r.Type = objabi.R_PCREL
|
||||
|
||||
r.Sym = syms.GOT
|
||||
r.Add += 4
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_CALL):
|
||||
r.Type = objabi.R_CALLARM
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_CALLARM)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4)))
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_REL32): // R_ARM_REL32
|
||||
r.Type = objabi.R_PCREL
|
||||
|
||||
r.Add += 4
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_ABS32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
return true
|
||||
|
||||
// we can just ignore this, because we are targeting ARM V5+ anyway
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_V4BX):
|
||||
if r.Sym != nil {
|
||||
// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
|
||||
r.Sym.Type = 0
|
||||
}
|
||||
|
||||
r.Sym = nil
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PC24),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_JUMP24):
|
||||
r.Type = objabi.R_CALLARM
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_CALLARM)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, int64(braddoff(int32(r.Add()), ldr.SymPlt(targ)/4)))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
return true
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
// Reread the reloc to incorporate any changes in type above.
|
||||
relocs := ldr.Relocs(s)
|
||||
*r = relocs.At2(rIdx)
|
||||
|
||||
switch r.Type() {
|
||||
case objabi.R_CALLARM:
|
||||
if target.IsExternal() {
|
||||
// External linker will do this relocation.
|
||||
return true
|
||||
}
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(targ.Plt())
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
|
||||
return true
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type != sym.SDATA {
|
||||
if ldr.SymType(s) != sym.SDATA {
|
||||
break
|
||||
}
|
||||
if target.IsElf() {
|
||||
ld.Adddynsym(target, syms, targ)
|
||||
rel := syms.Rel
|
||||
rel.AddAddrPlus(target.Arch, s, int64(r.Off))
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
|
||||
r.Type = objabi.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
ld.Adddynsym2(ldr, target, syms, targ)
|
||||
rel := ldr.MakeSymbolUpdater(syms.Rel2)
|
||||
rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
|
||||
su.SetRelocSym(rIdx, 0)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -247,7 +252,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write32(uint32(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
|
@ -592,94 +597,92 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
|
|||
return t
|
||||
}
|
||||
|
||||
func addpltreloc(plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, typ objabi.RelocType) {
|
||||
r := plt.AddRel()
|
||||
r.Sym = got
|
||||
r.Off = int32(plt.Size)
|
||||
r.Siz = 4
|
||||
r.Type = typ
|
||||
r.Add = int64(s.Got()) - 8
|
||||
func addpltreloc2(ldr *loader.Loader, plt *loader.SymbolBuilder, got *loader.SymbolBuilder, s loader.Sym, typ objabi.RelocType) {
|
||||
r, _ := plt.AddRel(typ)
|
||||
r.SetSym(got.Sym())
|
||||
r.SetOff(int32(plt.Size()))
|
||||
r.SetSiz(4)
|
||||
r.SetAdd(int64(ldr.SymGot(s)) - 8)
|
||||
|
||||
plt.Attr |= sym.AttrReachable
|
||||
plt.Size += 4
|
||||
plt.Grow(plt.Size)
|
||||
plt.SetReachable(true)
|
||||
plt.SetSize(plt.Size() + 4)
|
||||
plt.Grow(plt.Size())
|
||||
}
|
||||
|
||||
func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymPlt(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
|
||||
if target.IsElf() {
|
||||
plt := syms.PLT
|
||||
got := syms.GOTPLT
|
||||
rel := syms.RelPLT
|
||||
if plt.Size == 0 {
|
||||
plt := ldr.MakeSymbolUpdater(syms.PLT2)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
|
||||
rel := ldr.MakeSymbolUpdater(syms.RelPLT2)
|
||||
if plt.Size() == 0 {
|
||||
panic("plt is not set up")
|
||||
}
|
||||
|
||||
// .got entry
|
||||
s.SetGot(int32(got.Size))
|
||||
ldr.SetGot(s, int32(got.Size()))
|
||||
|
||||
// In theory, all GOT should point to the first PLT entry,
|
||||
// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
|
||||
// dynamic linker won't, so we'd better do it ourselves.
|
||||
got.AddAddrPlus(target.Arch, plt, 0)
|
||||
got.AddAddrPlus(target.Arch, plt.Sym(), 0)
|
||||
|
||||
// .plt entry, this depends on the .got entry
|
||||
s.SetPlt(int32(plt.Size))
|
||||
ldr.SetPlt(s, int32(plt.Size()))
|
||||
|
||||
addpltreloc(plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000
|
||||
addpltreloc(plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000
|
||||
addpltreloc(plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]!
|
||||
addpltreloc2(ldr, plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000
|
||||
addpltreloc2(ldr, plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000
|
||||
addpltreloc2(ldr, plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]!
|
||||
|
||||
// rel
|
||||
rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
|
||||
rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
|
||||
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_JUMP_SLOT)))
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_JUMP_SLOT)))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsyminternal(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
func addgotsyminternal2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymGot(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
got := syms.GOT
|
||||
s.SetGot(int32(got.Size))
|
||||
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
ldr.SetGot(s, int32(got.Size()))
|
||||
got.AddAddrPlus(target.Arch, s, 0)
|
||||
|
||||
if target.IsElf() {
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsyminternal: unsupported binary format")
|
||||
ldr.Errorf(s, "addgotsyminternal: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymGot(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
got := syms.GOT
|
||||
s.SetGot(int32(got.Size))
|
||||
got.AddUint32(target.Arch, 0)
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
ldr.SetGot(s, int32(got.Size()))
|
||||
got.AddUint64(target.Arch, 0)
|
||||
|
||||
if target.IsElf() {
|
||||
rel := syms.Rel
|
||||
rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_GLOB_DAT)))
|
||||
rel := ldr.MakeSymbolUpdater(syms.Rel2)
|
||||
rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_GLOB_DAT)))
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
func asmb(ctxt *ld.Link, _ *loader.Loader) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
|||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Adddynrel2: adddynrel2,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
|
|
|
|||
|
|
@ -78,86 +78,97 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
|
|||
initfunc.AddReloc(rel2)
|
||||
}
|
||||
|
||||
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
|
||||
|
||||
switch r.Type {
|
||||
targ := r.Sym()
|
||||
var targType sym.SymKind
|
||||
if targ != 0 {
|
||||
targType = ldr.SymType(targ)
|
||||
}
|
||||
|
||||
switch r.Type() {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
|
||||
if r.Type() >= objabi.ElfRelocOffset {
|
||||
ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
|
||||
ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == sym.SXREF {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
if targType == 0 || targType == sym.SXREF {
|
||||
ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 8
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+8)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
|
||||
}
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in callarm64", targ.Name)
|
||||
if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
|
||||
ldr.Errorf(s, "unknown symbol %s in callarm64", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_CALLARM64
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_CALLARM64)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC):
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
// TODO: turn LDR of GOT entry into ADR of symbol itself
|
||||
}
|
||||
|
||||
// fall back to using GOT
|
||||
// TODO: just needs relocation, no need to put in .dynsym
|
||||
addgotsym(target, syms, targ)
|
||||
|
||||
r.Type = objabi.R_ARM64_GOT
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == sym.SXREF {
|
||||
ld.Errorf(s, "unknown symbol %s", targ.Name)
|
||||
if targType == 0 || targType == sym.SXREF {
|
||||
ldr.Errorf(s, "unknown symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ARM64_PCREL
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
if target.IsPIE() && target.IsInternal() {
|
||||
// For internal linking PIE, this R_ADDR relocation cannot
|
||||
// be resolved statically. We need to generate a dynamic
|
||||
|
|
@ -167,39 +178,48 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ARM64_LDST8
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ARM64_LDST8)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ARM64_LDST32
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ARM64_LDST32)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ARM64_LDST64
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ARM64_LDST64)
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ARM64_LDST128
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ARM64_LDST128)
|
||||
return true
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
// Reread the reloc to incorporate any changes in type above.
|
||||
relocs := ldr.Relocs(s)
|
||||
*r = relocs.At2(rIdx)
|
||||
|
||||
switch r.Type() {
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL,
|
||||
objabi.R_CALLARM64:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// nothing to do, the relocation will be laid out in reloc
|
||||
return true
|
||||
}
|
||||
|
|
@ -209,14 +229,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
}
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type == sym.STEXT && target.IsElf() {
|
||||
if ldr.SymType(s) == sym.STEXT && target.IsElf() {
|
||||
// The code is asking for the address of an external
|
||||
// function. We provide it with the address of the
|
||||
// correspondent GOT symbol.
|
||||
addgotsym(target, syms, targ)
|
||||
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -253,7 +273,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
// symbol offset as determined by reloc(), not the
|
||||
// final dynamically linked address as a dynamic
|
||||
// relocation would provide.
|
||||
switch s.Name {
|
||||
switch ldr.SymName(s) {
|
||||
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
|
||||
return false
|
||||
}
|
||||
|
|
@ -264,7 +284,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
// linking, in which case the relocation will be
|
||||
// prepared in the 'reloc' phase and passed to the
|
||||
// external linker in the 'asmb' phase.
|
||||
if s.Type != sym.SDATA && s.Type != sym.SRODATA {
|
||||
if ldr.SymType(s) != sym.SDATA && ldr.SymType(s) != sym.SRODATA {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -287,14 +307,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
// AddAddrPlus is used for r_offset and r_addend to
|
||||
// generate new R_ADDR relocations that will update
|
||||
// these fields in the 'reloc' phase.
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, s, int64(r.Off))
|
||||
if r.Siz == 8 {
|
||||
rela := ldr.MakeSymbolUpdater(syms.Rela2)
|
||||
rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
|
||||
if r.Siz() == 8 {
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
|
||||
} else {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
rela.AddAddrPlus(target.Arch, targ, int64(r.Add))
|
||||
rela.AddAddrPlus(target.Arch, targ, int64(r.Add()))
|
||||
// Not mark r done here. So we still apply it statically,
|
||||
// so in the file content we'll also have the right offset
|
||||
// to the relocation target. So it can be examined statically
|
||||
|
|
@ -308,7 +328,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write64(uint64(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
|
@ -737,75 +757,80 @@ func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loade
|
|||
}
|
||||
}
|
||||
|
||||
func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymPlt(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
|
||||
if target.IsElf() {
|
||||
plt := syms.PLT
|
||||
gotplt := syms.GOTPLT
|
||||
rela := syms.RelaPLT
|
||||
if plt.Size == 0 {
|
||||
plt := ldr.MakeSymbolUpdater(syms.PLT2)
|
||||
gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT2)
|
||||
rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
|
||||
if plt.Size() == 0 {
|
||||
panic("plt is not set up")
|
||||
}
|
||||
|
||||
// adrp x16, &got.plt[0]
|
||||
plt.AddAddrPlus4(gotplt, gotplt.Size)
|
||||
plt.SetUint32(target.Arch, plt.Size-4, 0x90000010)
|
||||
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
|
||||
plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
|
||||
plt.SetUint32(target.Arch, plt.Size()-4, 0x90000010)
|
||||
relocs := plt.Relocs()
|
||||
plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
|
||||
|
||||
// <offset> is the offset value of &got.plt[n] to &got.plt[0]
|
||||
// ldr x17, [x16, <offset>]
|
||||
plt.AddAddrPlus4(gotplt, gotplt.Size)
|
||||
plt.SetUint32(target.Arch, plt.Size-4, 0xf9400211)
|
||||
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
|
||||
plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
|
||||
plt.SetUint32(target.Arch, plt.Size()-4, 0xf9400211)
|
||||
relocs = plt.Relocs()
|
||||
plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
|
||||
|
||||
// add x16, x16, <offset>
|
||||
plt.AddAddrPlus4(gotplt, gotplt.Size)
|
||||
plt.SetUint32(target.Arch, plt.Size-4, 0x91000210)
|
||||
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL
|
||||
plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
|
||||
plt.SetUint32(target.Arch, plt.Size()-4, 0x91000210)
|
||||
relocs = plt.Relocs()
|
||||
plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_PCREL)
|
||||
|
||||
// br x17
|
||||
plt.AddUint32(target.Arch, 0xd61f0220)
|
||||
|
||||
// add to got.plt: pointer to plt[0]
|
||||
gotplt.AddAddrPlus(target.Arch, plt, 0)
|
||||
gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
|
||||
|
||||
// rela
|
||||
rela.AddAddrPlus(target.Arch, gotplt, gotplt.Size-8)
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
|
||||
rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
|
||||
sDynid := ldr.SymDynid(s)
|
||||
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
|
||||
s.SetPlt(int32(plt.Size - 16))
|
||||
ldr.SetPlt(s, int32(plt.Size()-16))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymGot(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
got := syms.GOT
|
||||
s.SetGot(int32(got.Size))
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
ldr.SetGot(s, int32(got.Size()))
|
||||
got.AddUint64(target.Arch, 0)
|
||||
|
||||
if target.IsElf() {
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_GLOB_DAT)))
|
||||
rela := ldr.MakeSymbolUpdater(syms.Rela2)
|
||||
rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_AARCH64_GLOB_DAT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
func asmb(ctxt *ld.Link, _ *loader.Loader) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
|||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Adddynrel2: adddynrel2,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
518
src/cmd/link/internal/ld/data2.go
Normal file
518
src/cmd/link/internal/ld/data2.go
Normal 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()
|
||||
}
|
||||
|
|
@ -5,12 +5,9 @@
|
|||
package ld
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/sym"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Decoding the type.* symbols. This has to be in sync with
|
||||
|
|
@ -29,23 +26,6 @@ const (
|
|||
tflagExtraStar = 1 << 1
|
||||
)
|
||||
|
||||
func decodeReloc(s *sym.Symbol, off int32) *sym.Reloc {
|
||||
for i := range s.R {
|
||||
if s.R[i].Off == off {
|
||||
return &s.R[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeRelocSym(s *sym.Symbol, off int32) *sym.Symbol {
|
||||
r := decodeReloc(s, off)
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return r.Sym
|
||||
}
|
||||
|
||||
func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 {
|
||||
switch sz {
|
||||
case 2:
|
||||
|
|
@ -103,26 +83,6 @@ func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Type.commonType.gc
|
||||
func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte {
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
addr := decodetypeGcprogShlib(ctxt, s.P)
|
||||
sect := findShlibSection(ctxt, s.File, addr)
|
||||
if sect != nil {
|
||||
// A gcprog is a 4-byte uint32 indicating length, followed by
|
||||
// the actual program.
|
||||
progsize := make([]byte, 4)
|
||||
sect.ReadAt(progsize, int64(addr-sect.Addr))
|
||||
progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
|
||||
sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
|
||||
return append(progsize, progbytes...)
|
||||
}
|
||||
Exitf("cannot find gcprog for %s", s.Name)
|
||||
return nil
|
||||
}
|
||||
return decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)).P
|
||||
}
|
||||
|
||||
func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
|
||||
if ctxt.Arch.Family == sys.ARM64 {
|
||||
return 0
|
||||
|
|
@ -130,51 +90,6 @@ func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
|
|||
return decodeInuxi(ctxt.Arch, data[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
|
||||
}
|
||||
|
||||
func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
addr := decodetypeGcprogShlib(ctxt, s.P)
|
||||
ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
|
||||
sect := findShlibSection(ctxt, s.File, addr)
|
||||
if sect != nil {
|
||||
r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
|
||||
sect.ReadAt(r, int64(addr-sect.Addr))
|
||||
return r
|
||||
}
|
||||
Exitf("cannot find gcmask for %s", s.Name)
|
||||
return nil
|
||||
}
|
||||
mask := decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
|
||||
return mask.P
|
||||
}
|
||||
|
||||
// Type.ArrayType.elem and Type.SliceType.Elem
|
||||
func decodetypeArrayElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
func decodetypeArrayLen(arch *sys.Arch, s *sym.Symbol) int64 {
|
||||
return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
|
||||
}
|
||||
|
||||
// Type.PtrType.elem
|
||||
func decodetypePtrElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
// Type.MapType.key, elem
|
||||
func decodetypeMapKey(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
func decodetypeMapValue(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38
|
||||
}
|
||||
|
||||
// Type.ChanType.elem
|
||||
func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
// Type.FuncType.dotdotdot
|
||||
func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
|
||||
return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
|
||||
|
|
@ -189,75 +104,6 @@ func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
|
|||
return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
|
||||
}
|
||||
|
||||
func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
|
||||
uadd := commonsize(arch) + 4
|
||||
if arch.PtrSize == 8 {
|
||||
uadd += 4
|
||||
}
|
||||
if decodetypeHasUncommon(arch, s.P) {
|
||||
uadd += uncommonSize()
|
||||
}
|
||||
return decodeRelocSym(s, int32(uadd+i*arch.PtrSize))
|
||||
}
|
||||
|
||||
func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
|
||||
return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s.P))
|
||||
}
|
||||
|
||||
// Type.StructType.fields.Slice::length
|
||||
func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int {
|
||||
return int(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
|
||||
}
|
||||
|
||||
func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int {
|
||||
off := commonsize(arch) + 4*arch.PtrSize
|
||||
if decodetypeHasUncommon(arch, s.P) {
|
||||
off += uncommonSize()
|
||||
}
|
||||
off += i * structfieldSize(arch)
|
||||
return off
|
||||
}
|
||||
|
||||
// decodetypeStr returns the contents of an rtype's str field (a nameOff).
|
||||
func decodetypeStr(arch *sys.Arch, s *sym.Symbol) string {
|
||||
str := decodetypeName(s, 4*arch.PtrSize+8)
|
||||
if s.P[2*arch.PtrSize+4]&tflagExtraStar != 0 {
|
||||
return str[1:]
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// decodetypeName decodes the name from a reflect.name.
|
||||
func decodetypeName(s *sym.Symbol, off int) string {
|
||||
r := decodeReloc(s, int32(off))
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
data := r.Sym.P
|
||||
namelen := int(uint16(data[1])<<8 | uint16(data[2]))
|
||||
return string(data[3 : 3+namelen])
|
||||
}
|
||||
|
||||
func decodetypeStructFieldName(arch *sys.Arch, s *sym.Symbol, i int) string {
|
||||
off := decodetypeStructFieldArrayOff(arch, s, i)
|
||||
return decodetypeName(s, off)
|
||||
}
|
||||
|
||||
func decodetypeStructFieldType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
|
||||
off := decodetypeStructFieldArrayOff(arch, s, i)
|
||||
return decodeRelocSym(s, int32(off+arch.PtrSize))
|
||||
}
|
||||
|
||||
func decodetypeStructFieldOffs(arch *sys.Arch, s *sym.Symbol, i int) int64 {
|
||||
return decodetypeStructFieldOffsAnon(arch, s, i) >> 1
|
||||
}
|
||||
|
||||
func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 {
|
||||
off := decodetypeStructFieldArrayOff(arch, s, i)
|
||||
return int64(decodeInuxi(arch, s.P[off+2*arch.PtrSize:], arch.PtrSize))
|
||||
}
|
||||
|
||||
// InterfaceType.methods.length
|
||||
func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
|
||||
return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
|
||||
|
|
@ -279,91 +125,3 @@ const (
|
|||
kindStruct = 25
|
||||
kindMask = (1 << 5) - 1
|
||||
)
|
||||
|
||||
// decodeMethodSig decodes an array of method signature information.
|
||||
// Each element of the array is size bytes. The first 4 bytes is a
|
||||
// nameOff for the method name, and the next 4 bytes is a typeOff for
|
||||
// the function type.
|
||||
//
|
||||
// Conveniently this is the layout of both runtime.method and runtime.imethod.
|
||||
func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []methodsig {
|
||||
var buf bytes.Buffer
|
||||
var methods []methodsig
|
||||
for i := 0; i < count; i++ {
|
||||
buf.WriteString(decodetypeName(s, off))
|
||||
mtypSym := decodeRelocSym(s, int32(off+4))
|
||||
|
||||
buf.WriteRune('(')
|
||||
inCount := decodetypeFuncInCount(arch, mtypSym.P)
|
||||
for i := 0; i < inCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(decodetypeFuncInType(arch, mtypSym, i).Name)
|
||||
}
|
||||
buf.WriteString(") (")
|
||||
outCount := decodetypeFuncOutCount(arch, mtypSym.P)
|
||||
for i := 0; i < outCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(decodetypeFuncOutType(arch, mtypSym, i).Name)
|
||||
}
|
||||
buf.WriteRune(')')
|
||||
|
||||
off += size
|
||||
methods = append(methods, methodsig(buf.String()))
|
||||
buf.Reset()
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
|
||||
if decodetypeKind(arch, s.P)&kindMask != kindInterface {
|
||||
panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
|
||||
}
|
||||
r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize))
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if r.Sym != s {
|
||||
panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
|
||||
}
|
||||
off := int(r.Add) // array of reflect.imethod values
|
||||
numMethods := int(decodetypeIfaceMethodCount(arch, s.P))
|
||||
sizeofIMethod := 4 + 4
|
||||
return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
|
||||
}
|
||||
|
||||
func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
|
||||
if !decodetypeHasUncommon(arch, s.P) {
|
||||
panic(fmt.Sprintf("no methods on %q", s.Name))
|
||||
}
|
||||
off := commonsize(arch) // reflect.rtype
|
||||
switch decodetypeKind(arch, s.P) & kindMask {
|
||||
case kindStruct: // reflect.structType
|
||||
off += 4 * arch.PtrSize
|
||||
case kindPtr: // reflect.ptrType
|
||||
off += arch.PtrSize
|
||||
case kindFunc: // reflect.funcType
|
||||
off += arch.PtrSize // 4 bytes, pointer aligned
|
||||
case kindSlice: // reflect.sliceType
|
||||
off += arch.PtrSize
|
||||
case kindArray: // reflect.arrayType
|
||||
off += 3 * arch.PtrSize
|
||||
case kindChan: // reflect.chanType
|
||||
off += 2 * arch.PtrSize
|
||||
case kindMap: // reflect.mapType
|
||||
off += 4*arch.PtrSize + 8
|
||||
case kindInterface: // reflect.interfaceType
|
||||
off += 3 * arch.PtrSize
|
||||
default:
|
||||
// just Sizeof(rtype)
|
||||
}
|
||||
|
||||
mcount := int(decodeInuxi(arch, s.P[off+4:], 2))
|
||||
moff := int(decodeInuxi(arch, s.P[off+4+2+2:], 4))
|
||||
off += moff // offset to array of reflect.method values
|
||||
const sizeofMethod = 4 * 4 // sizeof reflect.method in program
|
||||
return decodeMethodSig(arch, s, off, sizeofMethod, mcount)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,20 +101,20 @@ func dwarfcompress(ctxt *Link) {
|
|||
type compressedSect struct {
|
||||
index int
|
||||
compressed []byte
|
||||
syms []*sym.Symbol
|
||||
syms []loader.Sym
|
||||
}
|
||||
|
||||
supported := ctxt.IsELF || ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Hdarwin
|
||||
if !ctxt.compressDWARF || !supported || ctxt.LinkMode != LinkInternal {
|
||||
supported := ctxt.IsELF || ctxt.IsWindows() || ctxt.IsDarwin()
|
||||
if !ctxt.compressDWARF || !supported || ctxt.IsExternal() {
|
||||
return
|
||||
}
|
||||
|
||||
var compressedCount int
|
||||
resChannel := make(chan compressedSect)
|
||||
for i := range dwarfp {
|
||||
go func(resIndex int, syms []*sym.Symbol) {
|
||||
for i := range dwarfp2 {
|
||||
go func(resIndex int, syms []loader.Sym) {
|
||||
resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms}
|
||||
}(compressedCount, dwarfp[i].syms)
|
||||
}(compressedCount, dwarfp2[i].syms)
|
||||
compressedCount++
|
||||
}
|
||||
res := make([]compressedSect, compressedCount)
|
||||
|
|
@ -123,46 +123,55 @@ func dwarfcompress(ctxt *Link) {
|
|||
res[r.index] = r
|
||||
}
|
||||
|
||||
var newDwarfp []dwarfSecInfo2
|
||||
ldr := ctxt.loader
|
||||
var newDwarfp []dwarfSecInfo
|
||||
Segdwarf.Sections = Segdwarf.Sections[:0]
|
||||
for _, z := range res {
|
||||
s := z.syms[0]
|
||||
if z.compressed == nil {
|
||||
// Compression didn't help.
|
||||
ds := dwarfSecInfo2{syms: z.syms}
|
||||
ds := dwarfSecInfo{syms: z.syms}
|
||||
newDwarfp = append(newDwarfp, ds)
|
||||
Segdwarf.Sections = append(Segdwarf.Sections, s.Sect)
|
||||
Segdwarf.Sections = append(Segdwarf.Sections, ldr.SymSect(s))
|
||||
} else {
|
||||
compressedSegName := ".zdebug_" + s.Sect.Name[len(".debug_"):]
|
||||
compressedSegName := ".zdebug_" + ldr.SymSect(s).Name[len(".debug_"):]
|
||||
sect := addsection(ctxt.loader, ctxt.Arch, &Segdwarf, compressedSegName, 04)
|
||||
sect.Align = 1
|
||||
sect.Length = uint64(len(z.compressed))
|
||||
newSym := ctxt.Syms.Lookup(compressedSegName, 0)
|
||||
newSym.P = z.compressed
|
||||
newSym.Size = int64(len(z.compressed))
|
||||
newSym.Sect = sect
|
||||
ds := dwarfSecInfo2{syms: []*sym.Symbol{newSym}}
|
||||
newSym := ldr.CreateSymForUpdate(compressedSegName, 0)
|
||||
newSym.SetReachable(true)
|
||||
newSym.SetData(z.compressed)
|
||||
newSym.SetSize(int64(len(z.compressed)))
|
||||
ldr.SetSymSect(newSym.Sym(), sect)
|
||||
ds := dwarfSecInfo{syms: []loader.Sym{newSym.Sym()}}
|
||||
newDwarfp = append(newDwarfp, ds)
|
||||
|
||||
// compressed symbols are no longer needed.
|
||||
for _, s := range z.syms {
|
||||
ldr.SetAttrReachable(s, false)
|
||||
}
|
||||
}
|
||||
dwarfp = newDwarfp
|
||||
}
|
||||
dwarfp2 = newDwarfp
|
||||
|
||||
// Re-compute the locations of the compressed DWARF symbols
|
||||
// and sections, since the layout of these within the file is
|
||||
// based on Section.Vaddr and Symbol.Value.
|
||||
pos := Segdwarf.Vaddr
|
||||
var prevSect *sym.Section
|
||||
for _, si := range dwarfp {
|
||||
for _, si := range dwarfp2 {
|
||||
for _, s := range si.syms {
|
||||
s.Value = int64(pos)
|
||||
if s.Sect != prevSect {
|
||||
s.Sect.Vaddr = uint64(s.Value)
|
||||
prevSect = s.Sect
|
||||
ldr.SetSymValue(s, int64(pos))
|
||||
sect := ldr.SymSect(s)
|
||||
if sect != prevSect {
|
||||
sect.Vaddr = uint64(pos)
|
||||
prevSect = sect
|
||||
}
|
||||
if s.Sub != nil {
|
||||
log.Fatalf("%s: unexpected sub-symbols", s)
|
||||
if ldr.SubSym(s) != 0 {
|
||||
log.Fatalf("%s: unexpected sub-symbols", ldr.SymName(s))
|
||||
}
|
||||
pos += uint64(s.Size)
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
pos += uint64(ldr.SymSize(s))
|
||||
if ctxt.IsWindows() {
|
||||
pos = uint64(Rnd(int64(pos), PEFILEALIGN))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -628,9 +628,9 @@ func elfwriteshdrs(out *OutBuf) uint32 {
|
|||
return uint32(ehdr.shnum) * ELF32SHDRSIZE
|
||||
}
|
||||
|
||||
func elfsetstring(s *sym.Symbol, str string, off int) {
|
||||
func elfsetstring2(ctxt *Link, s loader.Sym, str string, off int) {
|
||||
if nelfstr >= len(elfstr) {
|
||||
Errorf(s, "too many elf strings")
|
||||
ctxt.Errorf(s, "too many elf strings")
|
||||
errorexit()
|
||||
}
|
||||
|
||||
|
|
@ -753,8 +753,8 @@ func elfWriteDynEnt(arch *sys.Arch, s *sym.Symbol, tag int, val uint64) {
|
|||
}
|
||||
}
|
||||
|
||||
func elfWriteDynEntSym(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol) {
|
||||
Elfwritedynentsymplus(arch, s, tag, t, 0)
|
||||
func elfWriteDynEntSym2(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
|
||||
Elfwritedynentsymplus2(ctxt, s, tag, t, 0)
|
||||
}
|
||||
|
||||
func Elfwritedynentsymplus(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol, add int64) {
|
||||
|
|
@ -1057,15 +1057,16 @@ havelib:
|
|||
return aux
|
||||
}
|
||||
|
||||
func elfdynhash(ctxt *Link) {
|
||||
func elfdynhash2(ctxt *Link) {
|
||||
if !ctxt.IsELF {
|
||||
return
|
||||
}
|
||||
|
||||
nsym := Nelfsym
|
||||
s := ctxt.Syms.Lookup(".hash", 0)
|
||||
s.Type = sym.SELFROSECT
|
||||
s.Attr |= sym.AttrReachable
|
||||
ldr := ctxt.loader
|
||||
s := ldr.CreateSymForUpdate(".hash", 0)
|
||||
s.SetType(sym.SELFROSECT)
|
||||
s.SetReachable(true)
|
||||
|
||||
i := nsym
|
||||
nbucket := 1
|
||||
|
|
@ -1079,21 +1080,19 @@ func elfdynhash(ctxt *Link) {
|
|||
chain := make([]uint32, nsym)
|
||||
buckets := make([]uint32, nbucket)
|
||||
|
||||
for _, sy := range ctxt.Syms.Allsym {
|
||||
if sy.Dynid <= 0 {
|
||||
continue
|
||||
for _, sy := range ldr.DynidSyms() {
|
||||
|
||||
dynid := ldr.SymDynid(sy)
|
||||
if ldr.SymDynimpvers(sy) != "" {
|
||||
need[dynid] = addelflib(&needlib, ldr.SymDynimplib(sy), ldr.SymDynimpvers(sy))
|
||||
}
|
||||
|
||||
if sy.Dynimpvers() != "" {
|
||||
need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib(), sy.Dynimpvers())
|
||||
}
|
||||
|
||||
name := sy.Extname()
|
||||
name := ldr.SymExtname(sy)
|
||||
hc := elfhash(name)
|
||||
|
||||
b := hc % uint32(nbucket)
|
||||
chain[sy.Dynid] = buckets[b]
|
||||
buckets[b] = uint32(sy.Dynid)
|
||||
chain[dynid] = buckets[b]
|
||||
buckets[b] = uint32(dynid)
|
||||
}
|
||||
|
||||
// s390x (ELF64) hash table entries are 8 bytes
|
||||
|
|
@ -1117,10 +1116,11 @@ func elfdynhash(ctxt *Link) {
|
|||
}
|
||||
}
|
||||
|
||||
// version symbols
|
||||
dynstr := ctxt.Syms.Lookup(".dynstr", 0)
|
||||
dynstr := ldr.CreateSymForUpdate(".dynstr", 0)
|
||||
|
||||
s = ctxt.Syms.Lookup(".gnu.version_r", 0)
|
||||
// version symbols
|
||||
gnuVersionR := ldr.CreateSymForUpdate(".gnu.version_r", 0)
|
||||
s = gnuVersionR
|
||||
i = 2
|
||||
nfile := 0
|
||||
for l := needlib; l != nil; l = l.next {
|
||||
|
|
@ -1133,7 +1133,7 @@ func elfdynhash(ctxt *Link) {
|
|||
j++
|
||||
}
|
||||
s.AddUint16(ctxt.Arch, uint16(j)) // aux count
|
||||
s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, l.file))) // file string offset
|
||||
s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(l.file))) // file string offset
|
||||
s.AddUint32(ctxt.Arch, 16) // offset from header to first aux
|
||||
if l.next != nil {
|
||||
s.AddUint32(ctxt.Arch, 16+uint32(j)*16) // offset from this header to next
|
||||
|
|
@ -1149,7 +1149,7 @@ func elfdynhash(ctxt *Link) {
|
|||
s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash
|
||||
s.AddUint16(ctxt.Arch, 0) // flags
|
||||
s.AddUint16(ctxt.Arch, uint16(x.num)) // other - index we refer to this by
|
||||
s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, x.vers))) // version string offset
|
||||
s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(x.vers))) // version string offset
|
||||
if x.next != nil {
|
||||
s.AddUint32(ctxt.Arch, 16) // offset from this aux to next
|
||||
} else {
|
||||
|
|
@ -1159,7 +1159,8 @@ func elfdynhash(ctxt *Link) {
|
|||
}
|
||||
|
||||
// version references
|
||||
s = ctxt.Syms.Lookup(".gnu.version", 0)
|
||||
gnuVersion := ldr.CreateSymForUpdate(".gnu.version", 0)
|
||||
s = gnuVersion
|
||||
|
||||
for i := 0; i < nsym; i++ {
|
||||
if i == 0 {
|
||||
|
|
@ -1171,26 +1172,26 @@ func elfdynhash(ctxt *Link) {
|
|||
}
|
||||
}
|
||||
|
||||
s = ctxt.Syms.Lookup(".dynamic", 0)
|
||||
s = ldr.CreateSymForUpdate(".dynamic", 0)
|
||||
elfverneed = nfile
|
||||
if elfverneed != 0 {
|
||||
elfWriteDynEntSym(ctxt.Arch, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
|
||||
elfWriteDynEntSym(ctxt.Arch, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
|
||||
elfWriteDynEntSym2(ctxt, s, DT_VERNEED, gnuVersionR.Sym())
|
||||
Elfwritedynent2(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
|
||||
elfWriteDynEntSym2(ctxt, s, DT_VERSYM, gnuVersion.Sym())
|
||||
}
|
||||
|
||||
sy := ctxt.Syms.Lookup(elfRelType+".plt", 0)
|
||||
if sy.Size > 0 {
|
||||
sy := ldr.CreateSymForUpdate(elfRelType+".plt", 0)
|
||||
if sy.Size() > 0 {
|
||||
if elfRelType == ".rela" {
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_RELA)
|
||||
Elfwritedynent2(ctxt.Arch, s, DT_PLTREL, DT_RELA)
|
||||
} else {
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_REL)
|
||||
Elfwritedynent2(ctxt.Arch, s, DT_PLTREL, DT_REL)
|
||||
}
|
||||
elfWriteDynEntSymSize(ctxt.Arch, s, DT_PLTRELSZ, sy)
|
||||
elfWriteDynEntSym(ctxt.Arch, s, DT_JMPREL, sy)
|
||||
elfwritedynentsymsize2(ctxt, s, DT_PLTRELSZ, sy.Sym())
|
||||
elfWriteDynEntSym2(ctxt, s, DT_JMPREL, sy.Sym())
|
||||
}
|
||||
|
||||
elfWriteDynEnt(ctxt.Arch, s, DT_NULL, 0)
|
||||
Elfwritedynent2(ctxt.Arch, s, DT_NULL, 0)
|
||||
}
|
||||
|
||||
func elfphload(seg *sym.Segment) *ElfPhdr {
|
||||
|
|
@ -1410,7 +1411,8 @@ func elfrelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
|
|||
Errorf(s, "missing xsym in relocation %#v %#v", r.Sym.Name, s)
|
||||
continue
|
||||
}
|
||||
if r.Xsym.ElfsymForReloc() == 0 {
|
||||
esr := ElfSymForReloc(ctxt, r.Xsym)
|
||||
if esr == 0 {
|
||||
Errorf(s, "reloc %d (%s) to non-elf symbol %s (outer=%s) %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Name, r.Xsym.Name, r.Sym.Type, r.Sym.Type)
|
||||
}
|
||||
if !r.Xsym.Attr.Reachable() {
|
||||
|
|
@ -2342,93 +2344,6 @@ elfobj:
|
|||
}
|
||||
}
|
||||
|
||||
func elfadddynsym(target *Target, syms *ArchSyms, s *sym.Symbol) {
|
||||
if elf64 {
|
||||
s.Dynid = int32(Nelfsym)
|
||||
Nelfsym++
|
||||
|
||||
d := syms.DynSym
|
||||
|
||||
name := s.Extname()
|
||||
d.AddUint32(target.Arch, uint32(Addstring(syms.DynStr, name)))
|
||||
|
||||
/* type */
|
||||
t := STB_GLOBAL << 4
|
||||
|
||||
if s.Attr.CgoExport() && s.Type == sym.STEXT {
|
||||
t |= STT_FUNC
|
||||
} else {
|
||||
t |= STT_OBJECT
|
||||
}
|
||||
d.AddUint8(uint8(t))
|
||||
|
||||
/* reserved */
|
||||
d.AddUint8(0)
|
||||
|
||||
/* section where symbol is defined */
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
d.AddUint16(target.Arch, SHN_UNDEF)
|
||||
} else {
|
||||
d.AddUint16(target.Arch, 1)
|
||||
}
|
||||
|
||||
/* value */
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
d.AddUint64(target.Arch, 0)
|
||||
} else {
|
||||
d.AddAddr(target.Arch, s)
|
||||
}
|
||||
|
||||
/* size of object */
|
||||
d.AddUint64(target.Arch, uint64(s.Size))
|
||||
|
||||
if target.Arch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib() != "" && !seenlib[s.Dynimplib()] {
|
||||
elfWriteDynEnt(target.Arch, syms.Dynamic, DT_NEEDED, uint64(Addstring(syms.DynStr, s.Dynimplib())))
|
||||
}
|
||||
} else {
|
||||
s.Dynid = int32(Nelfsym)
|
||||
Nelfsym++
|
||||
|
||||
d := syms.DynSym
|
||||
|
||||
/* name */
|
||||
name := s.Extname()
|
||||
|
||||
d.AddUint32(target.Arch, uint32(Addstring(syms.DynStr, name)))
|
||||
|
||||
/* value */
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
d.AddUint32(target.Arch, 0)
|
||||
} else {
|
||||
d.AddAddr(target.Arch, s)
|
||||
}
|
||||
|
||||
/* size of object */
|
||||
d.AddUint32(target.Arch, uint32(s.Size))
|
||||
|
||||
/* type */
|
||||
t := STB_GLOBAL << 4
|
||||
|
||||
// TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
|
||||
if target.Arch.Family == sys.I386 && s.Attr.CgoExport() && s.Type == sym.STEXT {
|
||||
t |= STT_FUNC
|
||||
} else if target.Arch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type == sym.STEXT {
|
||||
t |= STT_FUNC
|
||||
} else {
|
||||
t |= STT_OBJECT
|
||||
}
|
||||
d.AddUint8(uint8(t))
|
||||
d.AddUint8(0)
|
||||
|
||||
/* shndx */
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
d.AddUint16(target.Arch, SHN_UNDEF)
|
||||
} else {
|
||||
d.AddUint16(target.Arch, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func elfadddynsym2(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
|
||||
ldr.SetSymDynid(s, int32(Nelfsym))
|
||||
Nelfsym++
|
||||
|
|
|
|||
25
src/cmd/link/internal/ld/elf2.go
Normal file
25
src/cmd/link/internal/ld/elf2.go
Normal 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++
|
||||
}
|
||||
|
|
@ -7,12 +7,15 @@ import (
|
|||
"cmd/internal/obj"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type unresolvedSymKey struct {
|
||||
from loader.Sym // Symbol that referenced unresolved "to"
|
||||
to loader.Sym // Unresolved symbol referenced by "from"
|
||||
}
|
||||
|
||||
type unresolvedSymKey2 struct {
|
||||
from *sym.Symbol // Symbol that referenced unresolved "to"
|
||||
to *sym.Symbol // Unresolved symbol referenced by "from"
|
||||
}
|
||||
|
|
@ -22,22 +25,62 @@ type symNameFn func(s loader.Sym) string
|
|||
|
||||
// ErrorReporter is used to make error reporting thread safe.
|
||||
type ErrorReporter struct {
|
||||
loader.ErrorReporter
|
||||
unresOnce sync.Once
|
||||
unresSyms map[unresolvedSymKey]bool
|
||||
unresSyms2 map[unresolvedSymKey2]bool
|
||||
unresMutex sync.Mutex
|
||||
lookup lookupFn
|
||||
SymName symNameFn
|
||||
}
|
||||
|
||||
// errorUnresolved prints unresolved symbol error for r.Sym that is referenced from s.
|
||||
func (reporter *ErrorReporter) errorUnresolved(s *sym.Symbol, r *sym.Reloc) {
|
||||
// errorUnresolved prints unresolved symbol error for rs that is referenced from s.
|
||||
func (reporter *ErrorReporter) errorUnresolved(ldr *loader.Loader, s, rs loader.Sym) {
|
||||
reporter.unresOnce.Do(func() { reporter.unresSyms = make(map[unresolvedSymKey]bool) })
|
||||
|
||||
k := unresolvedSymKey{from: s, to: r.Sym}
|
||||
k := unresolvedSymKey{from: s, to: rs}
|
||||
reporter.unresMutex.Lock()
|
||||
defer reporter.unresMutex.Unlock()
|
||||
if !reporter.unresSyms[k] {
|
||||
reporter.unresSyms[k] = true
|
||||
name := ldr.SymName(rs)
|
||||
|
||||
// Try to find symbol under another ABI.
|
||||
var reqABI, haveABI obj.ABI
|
||||
haveABI = ^obj.ABI(0)
|
||||
reqABI, ok := sym.VersionToABI(ldr.SymVersion(rs))
|
||||
if ok {
|
||||
for abi := obj.ABI(0); abi < obj.ABICount; abi++ {
|
||||
v := sym.ABIToVersion(abi)
|
||||
if v == -1 {
|
||||
continue
|
||||
}
|
||||
if rs1 := ldr.Lookup(name, v); rs1 != 0 && ldr.SymType(rs1) != sym.Sxxx && ldr.SymType(rs1) != sym.SXREF {
|
||||
haveABI = abi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Give a special error message for main symbol (see #24809).
|
||||
if name == "main.main" {
|
||||
reporter.Errorf(s, "function main is undeclared in the main package")
|
||||
} else if haveABI != ^obj.ABI(0) {
|
||||
reporter.Errorf(s, "relocation target %s not defined for %s (but is defined for %s)", name, reqABI, haveABI)
|
||||
} else {
|
||||
reporter.Errorf(s, "relocation target %s not defined", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// errorUnresolved2 prints unresolved symbol error for r.Sym that is referenced from s.
|
||||
func (reporter *ErrorReporter) errorUnresolved2(s *sym.Symbol, r *sym.Reloc) {
|
||||
reporter.unresOnce.Do(func() { reporter.unresSyms2 = make(map[unresolvedSymKey2]bool) })
|
||||
|
||||
k := unresolvedSymKey2{from: s, to: r.Sym}
|
||||
reporter.unresMutex.Lock()
|
||||
defer reporter.unresMutex.Unlock()
|
||||
if !reporter.unresSyms2[k] {
|
||||
reporter.unresSyms2[k] = true
|
||||
|
||||
// Try to find symbol under another ABI.
|
||||
var reqABI, haveABI obj.ABI
|
||||
|
|
@ -65,23 +108,3 @@ func (reporter *ErrorReporter) errorUnresolved(s *sym.Symbol, r *sym.Reloc) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf method logs an error message.
|
||||
//
|
||||
// If more than 20 errors have been printed, exit with an error.
|
||||
//
|
||||
// Logging an error means that on exit cmd/link will delete any
|
||||
// output file and return a non-zero error code.
|
||||
// TODO: consolidate the various different versions of Errorf (
|
||||
// function, Link method, and ErrorReporter method).
|
||||
func (reporter *ErrorReporter) Errorf(s loader.Sym, format string, args ...interface{}) {
|
||||
if s != 0 && reporter.SymName != nil {
|
||||
sn := reporter.SymName(s)
|
||||
format = sn + ": " + format
|
||||
} else {
|
||||
format = fmt.Sprintf("sym %d: %s", s, format)
|
||||
}
|
||||
format += "\n"
|
||||
fmt.Fprintf(os.Stderr, format, args...)
|
||||
afterErrorAction()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ func adddynlib(ctxt *Link, lib string) {
|
|||
}
|
||||
}
|
||||
|
||||
func Adddynsym2(ldr *loader.Loader, reporter *ErrorReporter, target *Target, syms *ArchSyms, s loader.Sym) {
|
||||
func Adddynsym2(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
|
||||
if ldr.SymDynid(s) >= 0 || target.LinkMode == LinkExternal {
|
||||
return
|
||||
}
|
||||
|
|
@ -339,27 +339,11 @@ func Adddynsym2(ldr *loader.Loader, reporter *ErrorReporter, target *Target, sym
|
|||
if target.IsELF {
|
||||
elfadddynsym2(ldr, target, syms, s)
|
||||
} else if target.HeadType == objabi.Hdarwin {
|
||||
reporter.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s))
|
||||
ldr.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s))
|
||||
} else if target.HeadType == objabi.Hwindows {
|
||||
// already taken care of
|
||||
} else {
|
||||
reporter.Errorf(s, "adddynsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func Adddynsym(target *Target, syms *ArchSyms, s *sym.Symbol) {
|
||||
if s.Dynid >= 0 || target.LinkMode == LinkExternal {
|
||||
return
|
||||
}
|
||||
|
||||
if target.IsELF {
|
||||
elfadddynsym(target, syms, s)
|
||||
} else if target.HeadType == objabi.Hdarwin {
|
||||
Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname())
|
||||
} else if target.HeadType == objabi.Hwindows {
|
||||
// already taken care of
|
||||
} else {
|
||||
Errorf(s, "adddynsym: unsupported binary format")
|
||||
ldr.Errorf(s, "adddynsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -425,7 +409,7 @@ func (ctxt *Link) addexport() {
|
|||
}
|
||||
|
||||
for _, exp := range ctxt.dynexp2 {
|
||||
Adddynsym2(ctxt.loader, &ctxt.ErrorReporter, &ctxt.Target, &ctxt.ArchSyms, exp)
|
||||
Adddynsym2(ctxt.loader, &ctxt.Target, &ctxt.ArchSyms, exp)
|
||||
}
|
||||
for _, lib := range dynlib {
|
||||
adddynlib(ctxt, lib)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"io/ioutil"
|
||||
|
|
@ -155,11 +156,12 @@ func findlib(ctxt *Link, lib string) (string, bool) {
|
|||
return pname, isshlib
|
||||
}
|
||||
|
||||
func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
|
||||
func addlib(ctxt *Link, src, obj, lib string, fingerprint goobj2.FingerprintType) *sym.Library {
|
||||
pkg := pkgname(ctxt, lib)
|
||||
|
||||
// already loaded?
|
||||
if l := ctxt.LibraryByPkg[pkg]; l != nil {
|
||||
checkFingerprint(l, l.Fingerprint, src, fingerprint)
|
||||
return l
|
||||
}
|
||||
|
||||
|
|
@ -170,9 +172,9 @@ func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
|
|||
}
|
||||
|
||||
if isshlib {
|
||||
return addlibpath(ctxt, src, obj, "", pkg, pname)
|
||||
return addlibpath(ctxt, src, obj, "", pkg, pname, fingerprint)
|
||||
}
|
||||
return addlibpath(ctxt, src, obj, pname, pkg, "")
|
||||
return addlibpath(ctxt, src, obj, pname, pkg, "", fingerprint)
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -182,14 +184,16 @@ func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
|
|||
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
|
||||
* pkg: package import path, e.g. container/vector
|
||||
* shlib: path to shared library, or .shlibname file holding path
|
||||
* fingerprint: if not 0, expected fingerprint for import from srcref
|
||||
* fingerprint is 0 if the library is not imported (e.g. main)
|
||||
*/
|
||||
func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlib string) *sym.Library {
|
||||
func addlibpath(ctxt *Link, srcref, objref, file, pkg, shlib string, fingerprint goobj2.FingerprintType) *sym.Library {
|
||||
if l := ctxt.LibraryByPkg[pkg]; l != nil {
|
||||
return l
|
||||
}
|
||||
|
||||
if ctxt.Debugvlog > 1 {
|
||||
ctxt.Logf("addlibpath: srcref: %s objref: %s file: %s pkg: %s shlib: %s\n", srcref, objref, file, pkg, shlib)
|
||||
ctxt.Logf("addlibpath: srcref: %s objref: %s file: %s pkg: %s shlib: %s fingerprint: %x\n", srcref, objref, file, pkg, shlib, fingerprint)
|
||||
}
|
||||
|
||||
l := &sym.Library{}
|
||||
|
|
@ -199,6 +203,7 @@ func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg strin
|
|||
l.Srcref = srcref
|
||||
l.File = file
|
||||
l.Pkg = pkg
|
||||
l.Fingerprint = fingerprint
|
||||
if shlib != "" {
|
||||
if strings.HasSuffix(shlib, ".shlibname") {
|
||||
data, err := ioutil.ReadFile(shlib)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ package ld
|
|||
import (
|
||||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
|
|
@ -232,6 +233,7 @@ type Arch struct {
|
|||
Dragonflydynld string
|
||||
Solarisdynld string
|
||||
Adddynrel func(*Target, *loader.Loader, *ArchSyms, *sym.Symbol, *sym.Reloc) bool
|
||||
Adddynrel2 func(*Target, *loader.Loader, *ArchSyms, loader.Sym, *loader.Reloc2, int) bool
|
||||
Archinit func(*Link)
|
||||
// Archreloc is an arch-specific hook that assists in
|
||||
// relocation processing (invoked by 'relocsym'); it handles
|
||||
|
|
@ -263,7 +265,7 @@ type Arch struct {
|
|||
// file. Typically, Asmb writes most of the content (sections and
|
||||
// segments), for which we have computed the size and offset. Asmb2
|
||||
// writes the rest.
|
||||
Asmb func(*Link)
|
||||
Asmb func(*Link, *loader.Loader)
|
||||
Asmb2 func(*Link)
|
||||
|
||||
Elfreloc1 func(*Link, *sym.Reloc, int64) bool
|
||||
|
|
@ -280,7 +282,7 @@ type Arch struct {
|
|||
// This is possible when a TLS IE relocation refers to a local
|
||||
// symbol in an executable, which is typical when internally
|
||||
// linking PIE binaries.
|
||||
TLSIEtoLE func(s *sym.Symbol, off, size int)
|
||||
TLSIEtoLE func(P []byte, off, size int)
|
||||
|
||||
// optional override for assignAddress
|
||||
AssignAddress func(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64)
|
||||
|
|
@ -424,14 +426,15 @@ func errorexit() {
|
|||
}
|
||||
|
||||
func loadinternal(ctxt *Link, name string) *sym.Library {
|
||||
zerofp := goobj2.FingerprintType{}
|
||||
if ctxt.linkShared && ctxt.PackageShlib != nil {
|
||||
if shlib := ctxt.PackageShlib[name]; shlib != "" {
|
||||
return addlibpath(ctxt, "internal", "internal", "", name, shlib)
|
||||
return addlibpath(ctxt, "internal", "internal", "", name, shlib, zerofp)
|
||||
}
|
||||
}
|
||||
if ctxt.PackageFile != nil {
|
||||
if pname := ctxt.PackageFile[name]; pname != "" {
|
||||
return addlibpath(ctxt, "internal", "internal", pname, name, "")
|
||||
return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
|
||||
}
|
||||
ctxt.Logf("loadinternal: cannot find %s\n", name)
|
||||
return nil
|
||||
|
|
@ -444,7 +447,7 @@ func loadinternal(ctxt *Link, name string) *sym.Library {
|
|||
ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
|
||||
}
|
||||
if _, err := os.Stat(shlibname); err == nil {
|
||||
return addlibpath(ctxt, "internal", "internal", "", name, shlibname)
|
||||
return addlibpath(ctxt, "internal", "internal", "", name, shlibname, zerofp)
|
||||
}
|
||||
}
|
||||
pname := filepath.Join(libdir, name+".a")
|
||||
|
|
@ -452,7 +455,7 @@ func loadinternal(ctxt *Link, name string) *sym.Library {
|
|||
ctxt.Logf("searching for %s.a in %s\n", name, pname)
|
||||
}
|
||||
if _, err := os.Stat(pname); err == nil {
|
||||
return addlibpath(ctxt, "internal", "internal", pname, name, "")
|
||||
return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -503,7 +506,7 @@ func (ctxt *Link) loadlib() {
|
|||
default:
|
||||
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
|
||||
}
|
||||
ctxt.loader = loader.NewLoader(flags, elfsetstring)
|
||||
ctxt.loader = loader.NewLoader(flags, elfsetstring, &ctxt.ErrorReporter.ErrorReporter)
|
||||
ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
|
||||
return ctxt.loader.SymName(s)
|
||||
}
|
||||
|
|
@ -1984,11 +1987,29 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
|
|||
ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
|
||||
f.MustSeek(import1, 0)
|
||||
|
||||
ctxt.loader.Preload(ctxt.Syms, f, lib, unit, eof-f.Offset(), 0)
|
||||
fingerprint := ctxt.loader.Preload(ctxt.Syms, f, lib, unit, eof-f.Offset())
|
||||
if !fingerprint.IsZero() { // Assembly objects don't have fingerprints. Ignore them.
|
||||
// Check fingerprint, to ensure the importing and imported packages
|
||||
// have consistent view of symbol indices.
|
||||
// Normally the go command should ensure this. But in case something
|
||||
// goes wrong, it could lead to obscure bugs like run-time crash.
|
||||
// Check it here to be sure.
|
||||
if lib.Fingerprint.IsZero() { // Not yet imported. Update its fingerprint.
|
||||
lib.Fingerprint = fingerprint
|
||||
}
|
||||
checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
|
||||
}
|
||||
|
||||
addImports(ctxt, lib, pn)
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkFingerprint(lib *sym.Library, libfp goobj2.FingerprintType, src string, srcfp goobj2.FingerprintType) {
|
||||
if libfp != srcfp {
|
||||
Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
|
||||
}
|
||||
}
|
||||
|
||||
func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
|
||||
data := make([]byte, sym.Size)
|
||||
sect := f.Sections[sym.Section]
|
||||
|
|
@ -2472,7 +2493,7 @@ const (
|
|||
DeletedAutoSym = 'x'
|
||||
)
|
||||
|
||||
func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int64, *sym.Symbol)) {
|
||||
func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int64)) {
|
||||
// These symbols won't show up in the first loop below because we
|
||||
// skip sym.STEXT symbols. Normal sym.STEXT symbols are emitted by walking textp.
|
||||
s := ctxt.Syms.Lookup("runtime.text", 0)
|
||||
|
|
@ -2482,7 +2503,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
|
|||
// on AIX with external linker.
|
||||
// See data.go:/textaddress
|
||||
if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
|
||||
put(ctxt, s, s.Name, TextSym, s.Value, nil)
|
||||
put(ctxt, s, s.Name, TextSym, s.Value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2503,7 +2524,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
|
|||
break
|
||||
}
|
||||
if s.Type == sym.STEXT {
|
||||
put(ctxt, s, s.Name, TextSym, s.Value, nil)
|
||||
put(ctxt, s, s.Name, TextSym, s.Value)
|
||||
}
|
||||
n++
|
||||
}
|
||||
|
|
@ -2515,7 +2536,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
|
|||
// on AIX with external linker.
|
||||
// See data.go:/textaddress
|
||||
if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
|
||||
put(ctxt, s, s.Name, TextSym, s.Value, nil)
|
||||
put(ctxt, s, s.Name, TextSym, s.Value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2534,7 +2555,10 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
|
|||
return true
|
||||
}
|
||||
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
for _, s := range ctxt.loader.Syms {
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
if !shouldBeInSymbolTable(s) {
|
||||
continue
|
||||
}
|
||||
|
|
@ -2565,7 +2589,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
|
|||
if !s.Attr.Reachable() {
|
||||
continue
|
||||
}
|
||||
put(ctxt, s, s.Name, DataSym, Symaddr(s), s.Gotype)
|
||||
put(ctxt, s, s.Name, DataSym, Symaddr(s))
|
||||
|
||||
case sym.SBSS, sym.SNOPTRBSS, sym.SLIBFUZZER_EXTRA_COUNTER:
|
||||
if !s.Attr.Reachable() {
|
||||
|
|
@ -2574,11 +2598,11 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
|
|||
if len(s.P) > 0 {
|
||||
Errorf(s, "should not be bss (size=%d type=%v special=%v)", len(s.P), s.Type, s.Attr.Special())
|
||||
}
|
||||
put(ctxt, s, s.Name, BSSSym, Symaddr(s), s.Gotype)
|
||||
put(ctxt, s, s.Name, BSSSym, Symaddr(s))
|
||||
|
||||
case sym.SUNDEFEXT:
|
||||
if ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Haix || ctxt.IsELF {
|
||||
put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
|
||||
put(ctxt, s, s.Name, UndefinedSym, s.Value)
|
||||
}
|
||||
|
||||
case sym.SHOSTOBJ:
|
||||
|
|
@ -2586,24 +2610,24 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
|
|||
continue
|
||||
}
|
||||
if ctxt.HeadType == objabi.Hwindows || ctxt.IsELF {
|
||||
put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
|
||||
put(ctxt, s, s.Name, UndefinedSym, s.Value)
|
||||
}
|
||||
|
||||
case sym.SDYNIMPORT:
|
||||
if !s.Attr.Reachable() {
|
||||
continue
|
||||
}
|
||||
put(ctxt, s, s.Extname(), UndefinedSym, 0, nil)
|
||||
put(ctxt, s, s.Extname(), UndefinedSym, 0)
|
||||
|
||||
case sym.STLSBSS:
|
||||
if ctxt.LinkMode == LinkExternal {
|
||||
put(ctxt, s, s.Name, TLSSym, Symaddr(s), s.Gotype)
|
||||
put(ctxt, s, s.Name, TLSSym, Symaddr(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range ctxt.Textp {
|
||||
put(ctxt, s, s.Name, TextSym, s.Value, s.Gotype)
|
||||
put(ctxt, s, s.Name, TextSym, s.Value)
|
||||
}
|
||||
|
||||
if ctxt.Debugvlog != 0 || *flagN {
|
||||
|
|
@ -2800,10 +2824,9 @@ func addToTextp(ctxt *Link) {
|
|||
ctxt.Textp = textp
|
||||
}
|
||||
|
||||
func (ctxt *Link) loadlibfull() {
|
||||
|
||||
func (ctxt *Link) loadlibfull(symGroupType []sym.SymKind, needReloc bool) {
|
||||
// Load full symbol contents, resolve indexed references.
|
||||
ctxt.loader.LoadFull(ctxt.Arch, ctxt.Syms)
|
||||
ctxt.loader.LoadFull(ctxt.Arch, ctxt.Syms, needReloc)
|
||||
|
||||
// Convert ctxt.Moduledata2 to ctxt.Moduledata, etc
|
||||
if ctxt.Moduledata2 != 0 {
|
||||
|
|
@ -2841,12 +2864,41 @@ func (ctxt *Link) loadlibfull() {
|
|||
dwarfp = append(dwarfp, dwarfSecInfo2{syms: syms})
|
||||
}
|
||||
|
||||
// Populate datap from datap2
|
||||
ctxt.datap = make([]*sym.Symbol, len(ctxt.datap2))
|
||||
for i, symIdx := range ctxt.datap2 {
|
||||
s := ctxt.loader.Syms[symIdx]
|
||||
if s == nil {
|
||||
panic(fmt.Sprintf("nil sym for datap2 element %d", symIdx))
|
||||
}
|
||||
ctxt.datap[i] = s
|
||||
}
|
||||
|
||||
// Populate the sym.Section 'Sym' fields based on their 'Sym2'
|
||||
// fields.
|
||||
allSegments := []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf}
|
||||
for _, seg := range allSegments {
|
||||
for _, sect := range seg.Sections {
|
||||
if sect.Sym2 != 0 {
|
||||
s := ctxt.loader.Syms[sect.Sym2]
|
||||
if s == nil {
|
||||
panic(fmt.Sprintf("nil sym for sect %s sym %d", sect.Name, sect.Sym2))
|
||||
}
|
||||
sect.Sym = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For now, overwrite symbol type with its "group" type, as dodata
|
||||
// expected. Once we converted dodata, this will probably not be
|
||||
// needed.
|
||||
for i, t := range symGroupType {
|
||||
if t != sym.Sxxx {
|
||||
ctxt.loader.Syms[i].Type = t
|
||||
s := ctxt.loader.Syms[i]
|
||||
if s == nil {
|
||||
continue // in dwarfcompress we drop compressed DWARF symbols
|
||||
}
|
||||
s.Type = t
|
||||
}
|
||||
}
|
||||
symGroupType = nil
|
||||
|
|
@ -2858,8 +2910,29 @@ func (ctxt *Link) loadlibfull() {
|
|||
}
|
||||
}
|
||||
|
||||
func symPkg(ctxt *Link, s *sym.Symbol) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return ctxt.loader.SymPkg(loader.Sym(s.SymIdx))
|
||||
}
|
||||
|
||||
func ElfSymForReloc(ctxt *Link, s *sym.Symbol) int32 {
|
||||
// If putelfsym created a local version of this symbol, use that in all
|
||||
// relocations.
|
||||
les := ctxt.loader.SymLocalElfSym(loader.Sym(s.SymIdx))
|
||||
if les != 0 {
|
||||
return les
|
||||
} else {
|
||||
return ctxt.loader.SymElfSym(loader.Sym(s.SymIdx))
|
||||
}
|
||||
}
|
||||
|
||||
func (ctxt *Link) dumpsyms() {
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
for _, s := range ctxt.loader.Syms {
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
fmt.Printf("%s %s reachable=%v onlist=%v outer=%v sub=%v\n", s, s.Type, s.Attr.Reachable(), s.Attr.OnList(), s.Outer, s.Sub)
|
||||
for i := range s.R {
|
||||
fmt.Println("\t", s.R[i].Type, s.R[i].Sym)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ type Link struct {
|
|||
|
||||
compressDWARF bool
|
||||
|
||||
Tlsg2 loader.Sym
|
||||
Libdir []string
|
||||
Library []*sym.Library
|
||||
LibraryByPkg map[string]*sym.Library
|
||||
|
|
@ -92,6 +91,7 @@ type Link struct {
|
|||
cgo_export_dynamic map[string]bool
|
||||
|
||||
datap []*sym.Symbol
|
||||
datap2 []loader.Sym
|
||||
dynexp2 []loader.Sym
|
||||
|
||||
// Elf symtab variables.
|
||||
|
|
@ -129,11 +129,11 @@ func (ctxt *Link) Logf(format string, args ...interface{}) {
|
|||
|
||||
func addImports(ctxt *Link, l *sym.Library, pn string) {
|
||||
pkg := objabi.PathToPrefix(l.Pkg)
|
||||
for _, importStr := range l.ImportStrings {
|
||||
lib := addlib(ctxt, pkg, pn, importStr)
|
||||
for _, imp := range l.Autolib {
|
||||
lib := addlib(ctxt, pkg, pn, imp.Pkg, imp.Fingerprint)
|
||||
if lib != nil {
|
||||
l.Imports = append(l.Imports, lib)
|
||||
}
|
||||
}
|
||||
l.ImportStrings = nil
|
||||
l.Autolib = nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"bytes"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"debug/macho"
|
||||
"encoding/binary"
|
||||
|
|
@ -216,7 +217,7 @@ const (
|
|||
|
||||
var nkind [NumSymKind]int
|
||||
|
||||
var sortsym []*sym.Symbol
|
||||
var sortsym []loader.Sym
|
||||
|
||||
var nsortsym int
|
||||
|
||||
|
|
@ -743,106 +744,125 @@ func Asmbmacho(ctxt *Link) {
|
|||
}
|
||||
}
|
||||
|
||||
func symkind(s *sym.Symbol) int {
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
func symkind(ldr *loader.Loader, s loader.Sym) int {
|
||||
if ldr.SymType(s) == sym.SDYNIMPORT {
|
||||
return SymKindUndef
|
||||
}
|
||||
if s.Attr.CgoExport() {
|
||||
if ldr.AttrCgoExport(s) {
|
||||
return SymKindExtdef
|
||||
}
|
||||
return SymKindLocal
|
||||
}
|
||||
|
||||
func addsym(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) {
|
||||
if s == nil {
|
||||
return
|
||||
func collectmachosyms(ctxt *Link) {
|
||||
ldr := ctxt.loader
|
||||
|
||||
addsym := func(s loader.Sym) {
|
||||
sortsym = append(sortsym, s)
|
||||
nkind[symkind(ldr, s)]++
|
||||
}
|
||||
|
||||
switch type_ {
|
||||
default:
|
||||
return
|
||||
|
||||
case DataSym, BSSSym, TextSym:
|
||||
break
|
||||
// Add special runtime.text and runtime.etext symbols.
|
||||
// We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
|
||||
// See data.go:/textaddress
|
||||
if !ctxt.DynlinkingGo() {
|
||||
s := ldr.Lookup("runtime.text", 0)
|
||||
if ldr.SymType(s) == sym.STEXT {
|
||||
addsym(s)
|
||||
}
|
||||
s = ldr.Lookup("runtime.etext", 0)
|
||||
if ldr.SymType(s) == sym.STEXT {
|
||||
addsym(s)
|
||||
}
|
||||
}
|
||||
|
||||
if sortsym != nil {
|
||||
sortsym[nsortsym] = s
|
||||
nkind[symkind(s)]++
|
||||
// Add text symbols.
|
||||
for _, s := range ctxt.Textp2 {
|
||||
addsym(s)
|
||||
}
|
||||
|
||||
nsortsym++
|
||||
}
|
||||
|
||||
type machoscmp []*sym.Symbol
|
||||
|
||||
func (x machoscmp) Len() int {
|
||||
return len(x)
|
||||
}
|
||||
|
||||
func (x machoscmp) Swap(i, j int) {
|
||||
x[i], x[j] = x[j], x[i]
|
||||
}
|
||||
|
||||
func (x machoscmp) Less(i, j int) bool {
|
||||
s1 := x[i]
|
||||
s2 := x[j]
|
||||
|
||||
k1 := symkind(s1)
|
||||
k2 := symkind(s2)
|
||||
if k1 != k2 {
|
||||
return k1 < k2
|
||||
shouldBeInSymbolTable := func(s loader.Sym) bool {
|
||||
if ldr.AttrNotInSymbolTable(s) {
|
||||
return false
|
||||
}
|
||||
name := ldr.RawSymName(s) // TODO: try not to read the name
|
||||
if name == "" || name[0] == '.' {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return s1.Extname() < s2.Extname()
|
||||
}
|
||||
// Add data symbols and external references.
|
||||
for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
|
||||
if !ldr.AttrReachable(s) {
|
||||
continue
|
||||
}
|
||||
t := ldr.SymType(s)
|
||||
if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
|
||||
if t == sym.STLSBSS {
|
||||
// TLSBSS is not used on darwin. See data.go:allocateDataSections
|
||||
continue
|
||||
}
|
||||
if !shouldBeInSymbolTable(s) {
|
||||
continue
|
||||
}
|
||||
addsym(s)
|
||||
}
|
||||
|
||||
switch t {
|
||||
case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT, sym.SCONST:
|
||||
addsym(s)
|
||||
}
|
||||
|
||||
func machogenasmsym(ctxt *Link) {
|
||||
genasmsym(ctxt, addsym)
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
// Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
|
||||
if s.Type == sym.SDYNIMPORT && s.Dynimplib() == "/usr/lib/libSystem.B.dylib" {
|
||||
if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
|
||||
// But only on macOS.
|
||||
if machoPlatform == PLATFORM_MACOS {
|
||||
switch n := s.Extname(); n {
|
||||
switch n := ldr.SymExtname(s); n {
|
||||
case "fdopendir":
|
||||
switch objabi.GOARCH {
|
||||
case "amd64":
|
||||
s.SetExtname(n + "$INODE64")
|
||||
ldr.SetSymExtname(s, n+"$INODE64")
|
||||
case "386":
|
||||
s.SetExtname(n + "$INODE64$UNIX2003")
|
||||
ldr.SetSymExtname(s, n+"$INODE64$UNIX2003")
|
||||
}
|
||||
case "readdir_r", "getfsstat":
|
||||
switch objabi.GOARCH {
|
||||
case "amd64", "386":
|
||||
s.SetExtname(n + "$INODE64")
|
||||
ldr.SetSymExtname(s, n+"$INODE64")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ || s.Type == sym.SUNDEFEXT {
|
||||
if s.Attr.Reachable() {
|
||||
addsym(ctxt, s, "", DataSym, 0, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
nsortsym = len(sortsym)
|
||||
}
|
||||
|
||||
func machosymorder(ctxt *Link) {
|
||||
ldr := ctxt.loader
|
||||
|
||||
// On Mac OS X Mountain Lion, we must sort exported symbols
|
||||
// So we sort them here and pre-allocate dynid for them
|
||||
// See https://golang.org/issue/4029
|
||||
for i := range dynexp {
|
||||
dynexp[i].Attr |= sym.AttrReachable
|
||||
for _, s := range ctxt.dynexp2 {
|
||||
if !ldr.AttrReachable(s) {
|
||||
panic("dynexp symbol is not reachable")
|
||||
}
|
||||
machogenasmsym(ctxt)
|
||||
sortsym = make([]*sym.Symbol, nsortsym)
|
||||
nsortsym = 0
|
||||
machogenasmsym(ctxt)
|
||||
sort.Sort(machoscmp(sortsym[:nsortsym]))
|
||||
for i := 0; i < nsortsym; i++ {
|
||||
sortsym[i].Dynid = int32(i)
|
||||
}
|
||||
collectmachosyms(ctxt)
|
||||
sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
|
||||
s1 := sortsym[i]
|
||||
s2 := sortsym[j]
|
||||
k1 := symkind(ldr, s1)
|
||||
k2 := symkind(ldr, s2)
|
||||
if k1 != k2 {
|
||||
return k1 < k2
|
||||
}
|
||||
return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms
|
||||
})
|
||||
for i, s := range sortsym {
|
||||
ldr.SetSymDynid(s, int32(i))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -877,7 +897,7 @@ func machosymtab(ctxt *Link) {
|
|||
symstr := ctxt.Syms.Lookup(".machosymstr", 0)
|
||||
|
||||
for i := 0; i < nsortsym; i++ {
|
||||
s := sortsym[i]
|
||||
s := ctxt.loader.Syms[sortsym[i]]
|
||||
symtab.AddUint32(ctxt.Arch, uint32(symstr.Size))
|
||||
|
||||
export := machoShouldExport(ctxt, s)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ package ld
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/benchmark"
|
||||
|
|
@ -74,7 +75,7 @@ var (
|
|||
flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker")
|
||||
flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive")
|
||||
|
||||
flagA = flag.Bool("a", false, "disassemble output")
|
||||
flagA = flag.Bool("a", false, "no-op (deprecated)")
|
||||
FlagC = flag.Bool("c", false, "dump call graph")
|
||||
FlagD = flag.Bool("d", false, "disable dynamic executable")
|
||||
flagF = flag.Bool("f", false, "ignore version mismatch")
|
||||
|
|
@ -154,6 +155,9 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
usage()
|
||||
}
|
||||
}
|
||||
if ctxt.HeadType == objabi.Hunknown {
|
||||
ctxt.HeadType.Set(objabi.GOOS)
|
||||
}
|
||||
|
||||
checkStrictDups = *FlagStrictDups
|
||||
|
||||
|
|
@ -190,11 +194,6 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
|
||||
bench.Start("libinit")
|
||||
libinit(ctxt) // creates outfile
|
||||
|
||||
if ctxt.HeadType == objabi.Hunknown {
|
||||
ctxt.HeadType.Set(objabi.GOOS)
|
||||
}
|
||||
|
||||
bench.Start("computeTLSOffset")
|
||||
ctxt.computeTLSOffset()
|
||||
bench.Start("Archinit")
|
||||
|
|
@ -208,6 +207,7 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
ctxt.Logf("HEADER = -H%d -T0x%x -R0x%x\n", ctxt.HeadType, uint64(*FlagTextAddr), uint32(*FlagRound))
|
||||
}
|
||||
|
||||
zerofp := goobj2.FingerprintType{}
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeShared:
|
||||
for i := 0; i < flag.NArg(); i++ {
|
||||
|
|
@ -221,12 +221,12 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
}
|
||||
pkglistfornote = append(pkglistfornote, pkgpath...)
|
||||
pkglistfornote = append(pkglistfornote, '\n')
|
||||
addlibpath(ctxt, "command line", "command line", file, pkgpath, "")
|
||||
addlibpath(ctxt, "command line", "command line", file, pkgpath, "", zerofp)
|
||||
}
|
||||
case BuildModePlugin:
|
||||
addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "")
|
||||
addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "", zerofp)
|
||||
default:
|
||||
addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "")
|
||||
addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "", zerofp)
|
||||
}
|
||||
bench.Start("loadlib")
|
||||
ctxt.loadlib()
|
||||
|
|
@ -297,11 +297,9 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
bench.Start("dwarfGenerateDebugSyms")
|
||||
dwarfGenerateDebugSyms(ctxt)
|
||||
bench.Start("symtab")
|
||||
ctxt.symtab()
|
||||
bench.Start("loadlibfull")
|
||||
ctxt.loadlibfull() // XXX do it here for now
|
||||
symGroupType := ctxt.symtab()
|
||||
bench.Start("dodata")
|
||||
ctxt.dodata()
|
||||
ctxt.dodata2(symGroupType)
|
||||
bench.Start("address")
|
||||
order := ctxt.address()
|
||||
bench.Start("dwarfcompress")
|
||||
|
|
@ -321,19 +319,27 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
if err := ctxt.Out.Mmap(filesize); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
// Asmb will redirect symbols to the output file mmap, and relocations
|
||||
// will be applied directly there.
|
||||
bench.Start("Asmb")
|
||||
thearch.Asmb(ctxt)
|
||||
ctxt.loader.InitOutData()
|
||||
thearch.Asmb(ctxt, ctxt.loader)
|
||||
|
||||
newreloc := ctxt.IsInternal() && ctxt.IsAMD64()
|
||||
if newreloc {
|
||||
bench.Start("reloc")
|
||||
ctxt.reloc()
|
||||
bench.Start("loadlibfull")
|
||||
// We don't need relocations at this point.
|
||||
// An exception is Windows, see pe.go:addPEBaseRelocSym
|
||||
needReloc := ctxt.IsWindows()
|
||||
ctxt.loadlibfull(symGroupType, needReloc) // XXX do it here for now
|
||||
} else {
|
||||
// If we don't mmap, we need to apply relocations before
|
||||
// writing out.
|
||||
bench.Start("loadlibfull")
|
||||
ctxt.loadlibfull(symGroupType, true) // XXX do it here for now
|
||||
bench.Start("reloc")
|
||||
ctxt.reloc()
|
||||
bench.Start("Asmb")
|
||||
thearch.Asmb(ctxt)
|
||||
ctxt.reloc2()
|
||||
}
|
||||
bench.Start("Asmb2")
|
||||
thearch.Asmb2(ctxt)
|
||||
|
|
@ -346,7 +352,7 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
bench.Start("hostlink")
|
||||
ctxt.hostlink()
|
||||
if ctxt.Debugvlog != 0 {
|
||||
ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym))
|
||||
ctxt.Logf("%d symbols, %d reachable\n", len(ctxt.loader.Syms), ctxt.loader.NReachableSym())
|
||||
ctxt.Logf("%d liveness data\n", liveness)
|
||||
}
|
||||
bench.Start("Flush")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ package ld
|
|||
|
||||
import (
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/sym"
|
||||
"cmd/link/internal/loader"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"log"
|
||||
|
|
@ -285,11 +285,11 @@ func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) {
|
|||
// to point to the output buffer that we just wrote, so we can apply further
|
||||
// edit to the symbol content.
|
||||
// If the output file is not Mmap'd, just writes the content.
|
||||
func (out *OutBuf) WriteSym(s *sym.Symbol) {
|
||||
n := int64(len(s.P))
|
||||
func (out *OutBuf) WriteSym(ldr *loader.Loader, s loader.Sym) {
|
||||
P := ldr.Data(s)
|
||||
n := int64(len(P))
|
||||
pos, buf := out.writeLoc(n)
|
||||
copy(buf[pos:], s.P)
|
||||
copy(buf[pos:], P)
|
||||
out.off += n
|
||||
s.P = buf[pos : pos+n]
|
||||
s.Attr.Set(sym.AttrReadOnly, false)
|
||||
ldr.SetOutData(s, buf[pos:pos+n])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -646,7 +646,7 @@ func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int
|
|||
// writeSymbols writes all COFF symbol table records.
|
||||
func (f *peFile) writeSymbols(ctxt *Link) {
|
||||
|
||||
put := func(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) {
|
||||
put := func(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,12 +34,14 @@ package ld
|
|||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"log"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func linknew(arch *sys.Arch) *Link {
|
||||
ler := loader.ErrorReporter{AfterErrorAction: afterErrorAction}
|
||||
ctxt := &Link{
|
||||
Target: Target{Arch: arch},
|
||||
Syms: sym.NewSymbols(),
|
||||
|
|
@ -47,6 +49,7 @@ func linknew(arch *sys.Arch) *Link {
|
|||
Out: NewOutBuf(arch),
|
||||
LibraryByPkg: make(map[string]*sym.Library),
|
||||
numelfsym: 1,
|
||||
ErrorReporter: ErrorReporter{ErrorReporter: ler},
|
||||
}
|
||||
|
||||
if objabi.GOARCH != arch.Name {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ func putelfsyment(out *OutBuf, off int, addr int64, size int64, info int, shndx
|
|||
}
|
||||
}
|
||||
|
||||
func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go_ *sym.Symbol) {
|
||||
func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64) {
|
||||
var typ int
|
||||
|
||||
switch t {
|
||||
|
|
@ -185,7 +185,7 @@ func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go
|
|||
// ELF linker -Bsymbolic-functions option, but that is buggy on
|
||||
// several platforms.
|
||||
putelfsyment(ctxt.Out, putelfstr("local."+s), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other)
|
||||
x.LocalElfsym = int32(ctxt.numelfsym)
|
||||
ctxt.loader.SetSymLocalElfSym(loader.Sym(x.SymIdx), int32(ctxt.numelfsym))
|
||||
ctxt.numelfsym++
|
||||
return
|
||||
} else if bind != ctxt.elfbind {
|
||||
|
|
@ -193,13 +193,13 @@ func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go
|
|||
}
|
||||
|
||||
putelfsyment(ctxt.Out, putelfstr(s), addr, size, bind<<4|typ&0xf, elfshnum, other)
|
||||
x.Elfsym = int32(ctxt.numelfsym)
|
||||
ctxt.loader.SetSymElfSym(loader.Sym(x.SymIdx), int32(ctxt.numelfsym))
|
||||
ctxt.numelfsym++
|
||||
}
|
||||
|
||||
func putelfsectionsym(ctxt *Link, out *OutBuf, s *sym.Symbol, shndx int) {
|
||||
putelfsyment(out, 0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
|
||||
s.Elfsym = int32(ctxt.numelfsym)
|
||||
ctxt.loader.SetSymElfSym(loader.Sym(s.SymIdx), int32(ctxt.numelfsym))
|
||||
ctxt.numelfsym++
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +224,7 @@ func Asmelfsym(ctxt *Link) {
|
|||
genasmsym(ctxt, putelfsym)
|
||||
}
|
||||
|
||||
func putplan9sym(ctxt *Link, x *sym.Symbol, s string, typ SymbolType, addr int64, go_ *sym.Symbol) {
|
||||
func putplan9sym(ctxt *Link, x *sym.Symbol, s string, typ SymbolType, addr int64) {
|
||||
t := int(typ)
|
||||
switch typ {
|
||||
case TextSym, DataSym, BSSSym:
|
||||
|
|
@ -327,9 +327,7 @@ func textsectionmap(ctxt *Link) (loader.Sym, uint32) {
|
|||
return t.Sym(), uint32(n)
|
||||
}
|
||||
|
||||
var symGroupType []sym.SymKind // temporarily assign a symbol's "group" type
|
||||
|
||||
func (ctxt *Link) symtab() {
|
||||
func (ctxt *Link) symtab() []sym.SymKind {
|
||||
ldr := ctxt.loader
|
||||
|
||||
if !ctxt.IsAIX() {
|
||||
|
|
@ -441,7 +439,7 @@ func (ctxt *Link) symtab() {
|
|||
// just defined above will be first.
|
||||
// hide the specific symbols.
|
||||
nsym := loader.Sym(ldr.NSym())
|
||||
symGroupType = make([]sym.SymKind, nsym)
|
||||
symGroupType := make([]sym.SymKind, nsym)
|
||||
for s := loader.Sym(1); s < nsym; s++ {
|
||||
name := ldr.SymName(s)
|
||||
if !ctxt.IsExternal() && isStaticTemp(name) {
|
||||
|
|
@ -709,6 +707,7 @@ func (ctxt *Link) symtab() {
|
|||
lastmoduledatap.SetData(nil)
|
||||
lastmoduledatap.AddAddr(ctxt.Arch, moduledata.Sym())
|
||||
}
|
||||
return symGroupType
|
||||
}
|
||||
|
||||
func isStaticTemp(name string) bool {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ func (t *Target) CanUsePlugins() bool {
|
|||
}
|
||||
|
||||
func (t *Target) IsElf() bool {
|
||||
t.mustSetHeadType()
|
||||
return t.IsELF
|
||||
}
|
||||
|
||||
|
|
@ -91,14 +92,30 @@ func (t *Target) IsARM() bool {
|
|||
return t.Arch.Family == sys.ARM
|
||||
}
|
||||
|
||||
func (t *Target) IsARM64() bool {
|
||||
return t.Arch.Family == sys.ARM64
|
||||
}
|
||||
|
||||
func (t *Target) IsAMD64() bool {
|
||||
return t.Arch.Family == sys.AMD64
|
||||
}
|
||||
|
||||
func (t *Target) IsMIPS() bool {
|
||||
return t.Arch.Family == sys.MIPS
|
||||
}
|
||||
|
||||
func (t *Target) IsMIPS64() bool {
|
||||
return t.Arch.Family == sys.MIPS64
|
||||
}
|
||||
|
||||
func (t *Target) IsPPC64() bool {
|
||||
return t.Arch.Family == sys.PPC64
|
||||
}
|
||||
|
||||
func (t *Target) IsRISCV64() bool {
|
||||
return t.Arch.Family == sys.RISCV64
|
||||
}
|
||||
|
||||
func (t *Target) IsS390X() bool {
|
||||
return t.Arch.Family == sys.S390X
|
||||
}
|
||||
|
|
@ -112,37 +129,51 @@ func (t *Target) IsWasm() bool {
|
|||
//
|
||||
|
||||
func (t *Target) IsLinux() bool {
|
||||
t.mustSetHeadType()
|
||||
return t.HeadType == objabi.Hlinux
|
||||
}
|
||||
|
||||
func (t *Target) IsDarwin() bool {
|
||||
t.mustSetHeadType()
|
||||
return t.HeadType == objabi.Hdarwin
|
||||
}
|
||||
|
||||
func (t *Target) IsWindows() bool {
|
||||
t.mustSetHeadType()
|
||||
return t.HeadType == objabi.Hwindows
|
||||
}
|
||||
|
||||
func (t *Target) IsPlan9() bool {
|
||||
t.mustSetHeadType()
|
||||
return t.HeadType == objabi.Hplan9
|
||||
}
|
||||
|
||||
func (t *Target) IsAIX() bool {
|
||||
t.mustSetHeadType()
|
||||
return t.HeadType == objabi.Haix
|
||||
}
|
||||
|
||||
func (t *Target) IsSolaris() bool {
|
||||
t.mustSetHeadType()
|
||||
return t.HeadType == objabi.Hsolaris
|
||||
}
|
||||
|
||||
func (t *Target) IsNetbsd() bool {
|
||||
t.mustSetHeadType()
|
||||
return t.HeadType == objabi.Hnetbsd
|
||||
}
|
||||
|
||||
func (t *Target) IsOpenbsd() bool {
|
||||
t.mustSetHeadType()
|
||||
return t.HeadType == objabi.Hopenbsd
|
||||
}
|
||||
|
||||
func (t *Target) mustSetHeadType() {
|
||||
if t.HeadType == objabi.Hunknown {
|
||||
panic("HeadType is not set")
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// MISC
|
||||
//
|
||||
|
|
|
|||
|
|
@ -73,12 +73,12 @@ func Errorf(s *sym.Symbol, format string, args ...interface{}) {
|
|||
// Logging an error means that on exit cmd/link will delete any
|
||||
// output file and return a non-zero error code.
|
||||
func (ctxt *Link) Errorf(s loader.Sym, format string, args ...interface{}) {
|
||||
if s != 0 && ctxt.loader != nil {
|
||||
sn := ctxt.loader.SymName(s)
|
||||
format = sn + ": " + format
|
||||
} else {
|
||||
format = fmt.Sprintf("sym %d: %s", s, format)
|
||||
if ctxt.loader != nil {
|
||||
ctxt.loader.Errorf(s, format, args...)
|
||||
return
|
||||
}
|
||||
// Note: this is not expected to happen very often.
|
||||
format = fmt.Sprintf("sym %d: %s", s, format)
|
||||
format += "\n"
|
||||
fmt.Fprintf(os.Stderr, format, args...)
|
||||
afterErrorAction()
|
||||
|
|
|
|||
|
|
@ -360,7 +360,8 @@ type XcoffLdRel64 struct {
|
|||
// xcoffLoaderReloc holds information about a relocation made by the loader.
|
||||
type xcoffLoaderReloc struct {
|
||||
sym *sym.Symbol
|
||||
rel *sym.Reloc
|
||||
sym2 loader.Sym
|
||||
roff int32
|
||||
rtype uint16
|
||||
symndx int32
|
||||
}
|
||||
|
|
@ -567,11 +568,12 @@ var (
|
|||
|
||||
// xcoffUpdateOuterSize stores the size of outer symbols in order to have it
|
||||
// in the symbol table.
|
||||
func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
|
||||
func xcoffUpdateOuterSize2(ctxt *Link, size int64, stype sym.SymKind) {
|
||||
if size == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ldr := ctxt.loader
|
||||
switch stype {
|
||||
default:
|
||||
Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String())
|
||||
|
|
@ -580,14 +582,16 @@ func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
|
|||
case sym.STYPERELRO:
|
||||
if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
|
||||
// runtime.types size must be removed, as it's a real symbol.
|
||||
outerSymSize["typerel.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
|
||||
tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
|
||||
outerSymSize["typerel.*"] = size - tsize
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case sym.STYPE:
|
||||
if !ctxt.DynlinkingGo() {
|
||||
// runtime.types size must be removed, as it's a real symbol.
|
||||
outerSymSize["type.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
|
||||
tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
|
||||
outerSymSize["type.*"] = size - tsize
|
||||
}
|
||||
case sym.SGOSTRING:
|
||||
outerSymSize["go.string.*"] = size
|
||||
|
|
@ -603,7 +607,6 @@ func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
|
|||
outerSymSize["runtime.itablink"] = size
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// addSymbol writes a symbol or an auxiliary symbol entry on ctxt.out.
|
||||
|
|
@ -780,19 +783,19 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
|
|||
// Trampoline don't have a FILE so there are considered
|
||||
// in the current file.
|
||||
// Same goes for runtime.text.X symbols.
|
||||
} else if x.File == "" { // Undefined global symbol
|
||||
} else if symPkg(ctxt, x) == "" { // Undefined global symbol
|
||||
// If this happens, the algorithm must be redone.
|
||||
if currSymSrcFile.name != "" {
|
||||
Exitf("undefined global symbol found inside another file")
|
||||
}
|
||||
} else {
|
||||
// Current file has changed. New C_FILE, C_DWARF, etc must be generated.
|
||||
if currSymSrcFile.name != x.File {
|
||||
if currSymSrcFile.name != symPkg(ctxt, x) {
|
||||
if ctxt.LinkMode == LinkInternal {
|
||||
// update previous file values
|
||||
xfile.updatePreviousFile(ctxt, false)
|
||||
currSymSrcFile.name = x.File
|
||||
f.writeSymbolNewFile(ctxt, x.File, uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
|
||||
currSymSrcFile.name = symPkg(ctxt, x)
|
||||
f.writeSymbolNewFile(ctxt, symPkg(ctxt, x), uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
|
||||
} else {
|
||||
// With external linking, ld will crash if there is several
|
||||
// .FILE and DWARF debugging enable, somewhere during
|
||||
|
|
@ -802,7 +805,7 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
|
|||
// TODO(aix); remove once ld has been fixed or the triggering
|
||||
// relocation has been found and fixed.
|
||||
if currSymSrcFile.name == "" {
|
||||
currSymSrcFile.name = x.File
|
||||
currSymSrcFile.name = symPkg(ctxt, x)
|
||||
f.writeSymbolNewFile(ctxt, "go_functions", uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
|
||||
}
|
||||
}
|
||||
|
|
@ -852,7 +855,7 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
|
|||
}
|
||||
|
||||
// put function used by genasmsym to write symbol table
|
||||
func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, go_ *sym.Symbol) {
|
||||
func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64) {
|
||||
|
||||
// All XCOFF symbols generated by this GO symbols
|
||||
// Can be a symbol entry or a auxiliary entry
|
||||
|
|
@ -863,7 +866,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64,
|
|||
return
|
||||
|
||||
case TextSym:
|
||||
if x.File != "" || strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
|
||||
if symPkg(ctxt, x) != "" || strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
|
||||
// Function within a file
|
||||
syms = xfile.writeSymbolFunc(ctxt, x)
|
||||
} else {
|
||||
|
|
@ -1106,51 +1109,55 @@ func (f *xcoffFile) adddynimpsym(ctxt *Link, s loader.Sym) {
|
|||
|
||||
// Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
|
||||
// This relocation will be made by the loader.
|
||||
func Xcoffadddynrel(target *Target, ldr *loader.Loader, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
func Xcoffadddynrel2(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
|
||||
if target.IsExternal() {
|
||||
return true
|
||||
}
|
||||
if s.Type <= sym.SPCLNTAB {
|
||||
Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name)
|
||||
if ldr.SymType(s) <= sym.SPCLNTAB {
|
||||
ldr.Errorf(s, "cannot have a relocation to %s in a text section symbol", ldr.SymName(r.Sym()))
|
||||
return false
|
||||
}
|
||||
|
||||
xldr := &xcoffLoaderReloc{
|
||||
sym: s,
|
||||
rel: r,
|
||||
sym2: s,
|
||||
roff: r.Off(),
|
||||
}
|
||||
targ := r.Sym()
|
||||
var targType sym.SymKind
|
||||
if targ != 0 {
|
||||
targType = ldr.SymType(targ)
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
switch r.Type() {
|
||||
default:
|
||||
Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", r.Sym.Name, r.Type.String())
|
||||
ldr.Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", ldr.SymName(targ), r.Type().String())
|
||||
return false
|
||||
case objabi.R_ADDR:
|
||||
if s.Type == sym.SXCOFFTOC && r.Sym.Type == sym.SDYNIMPORT {
|
||||
if ldr.SymType(s) == sym.SXCOFFTOC && targType == sym.SDYNIMPORT {
|
||||
// Imported symbol relocation
|
||||
for i, dynsym := range xfile.loaderSymbols {
|
||||
if ldr.Syms[dynsym.sym].Name == r.Sym.Name {
|
||||
if ldr.SymName(dynsym.sym) == ldr.SymName(targ) {
|
||||
xldr.symndx = int32(i + 3) // +3 because of 3 section symbols
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if s.Type == sym.SDATA {
|
||||
switch r.Sym.Sect.Seg {
|
||||
} else if t := ldr.SymType(s); t == sym.SDATA || t == sym.SNOPTRDATA || t == sym.SBUILDINFO || t == sym.SXCOFFTOC {
|
||||
switch ldr.SymSect(targ).Seg {
|
||||
default:
|
||||
Errorf(s, "unknown segment for .loader relocation with symbol %s", r.Sym.Name)
|
||||
ldr.Errorf(s, "unknown segment for .loader relocation with symbol %s", ldr.SymName(targ))
|
||||
case &Segtext:
|
||||
case &Segrodata:
|
||||
xldr.symndx = 0 // .text
|
||||
case &Segdata:
|
||||
if r.Sym.Type == sym.SBSS || r.Sym.Type == sym.SNOPTRBSS {
|
||||
if targType == sym.SBSS || targType == sym.SNOPTRBSS {
|
||||
xldr.symndx = 2 // .bss
|
||||
} else {
|
||||
xldr.symndx = 1 // .data
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", r.Sym.Name, s.Type, r.Sym.Type)
|
||||
ldr.Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", ldr.SymName(targ), ldr.SymType(s), ldr.SymType(targ))
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -1301,14 +1308,18 @@ func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
|
|||
|
||||
off += uint64(16 * len(f.loaderReloc))
|
||||
for _, r := range f.loaderReloc {
|
||||
symp := r.sym
|
||||
if symp == nil {
|
||||
symp = ctxt.loader.Syms[r.sym2]
|
||||
}
|
||||
xldr = &XcoffLdRel64{
|
||||
Lvaddr: uint64(r.sym.Value + int64(r.rel.Off)),
|
||||
Lvaddr: uint64(symp.Value + int64(r.roff)),
|
||||
Lrtype: r.rtype,
|
||||
Lsymndx: r.symndx,
|
||||
}
|
||||
|
||||
if r.sym.Sect != nil {
|
||||
xldr.Lrsecnm = f.getXCOFFscnum(r.sym.Sect)
|
||||
if symp.Sect != nil {
|
||||
xldr.Lrsecnm = f.getXCOFFscnum(symp.Sect)
|
||||
}
|
||||
|
||||
reloctab = append(reloctab, xldr)
|
||||
|
|
@ -1389,45 +1400,6 @@ func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
|
|||
}
|
||||
|
||||
f.loaderSize = off + uint64(stlen)
|
||||
|
||||
/* again for printing */
|
||||
if !*flagA {
|
||||
return
|
||||
}
|
||||
|
||||
ctxt.Logf("\n.loader section")
|
||||
// write in buf
|
||||
var buf bytes.Buffer
|
||||
|
||||
binary.Write(&buf, ctxt.Arch.ByteOrder, hdr)
|
||||
for _, s := range symtab {
|
||||
binary.Write(&buf, ctxt.Arch.ByteOrder, s)
|
||||
|
||||
}
|
||||
for _, f := range importtab {
|
||||
buf.WriteString(f.Limpidpath)
|
||||
buf.WriteByte(0)
|
||||
buf.WriteString(f.Limpidbase)
|
||||
buf.WriteByte(0)
|
||||
buf.WriteString(f.Limpidmem)
|
||||
buf.WriteByte(0)
|
||||
}
|
||||
for _, s := range strtab {
|
||||
binary.Write(&buf, ctxt.Arch.ByteOrder, s.size)
|
||||
buf.WriteString(s.name)
|
||||
buf.WriteByte(0) // null terminator
|
||||
}
|
||||
|
||||
// Log buffer
|
||||
ctxt.Logf("\n\t%.8x|", globalOff)
|
||||
for i, b := range buf.Bytes() {
|
||||
if i > 0 && i%16 == 0 {
|
||||
ctxt.Logf("\n\t%.8x|", uint64(globalOff)+uint64(i))
|
||||
}
|
||||
ctxt.Logf(" %.2x", b)
|
||||
}
|
||||
ctxt.Logf("\n")
|
||||
|
||||
}
|
||||
|
||||
// XCOFF assembling and writing file
|
||||
|
|
@ -1683,7 +1655,10 @@ func xcoffCreateExportFile(ctxt *Link) (fname string) {
|
|||
fname = filepath.Join(*flagTmpdir, "export_file.exp")
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
for _, s := range ctxt.loader.Syms {
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
if !s.Attr.CgoExport() {
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
113
src/cmd/link/internal/ld/xcoff2.go
Normal file
113
src/cmd/link/internal/ld/xcoff2.go
Normal 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
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ type Reloc2 struct {
|
|||
|
||||
// External reloc types may not fit into a uint8 which the Go object file uses.
|
||||
// Store it here, instead of in the byte of goobj2.Reloc2.
|
||||
// For Go symbols this will always be 0.
|
||||
// For Go symbols this will always be zero.
|
||||
// goobj2.Reloc2.Type() + typ is always the right type, for both Go and external
|
||||
// symbols.
|
||||
typ objabi.RelocType
|
||||
|
|
@ -73,6 +73,10 @@ func (rel Reloc2) SetType(t objabi.RelocType) {
|
|||
panic("SetType: type doesn't fit into Reloc2")
|
||||
}
|
||||
rel.Reloc.SetType(uint8(t))
|
||||
if rel.typ != 0 {
|
||||
// should use SymbolBuilder.SetRelocType
|
||||
panic("wrong method to set reloc type")
|
||||
}
|
||||
}
|
||||
|
||||
// Aux2 holds a "handle" to access an aux symbol record from an
|
||||
|
|
@ -143,6 +147,16 @@ func (bm Bitmap) Has(i Sym) bool {
|
|||
func (bm Bitmap) Len() int {
|
||||
return len(bm) * 32
|
||||
}
|
||||
|
||||
// return the number of bits set.
|
||||
func (bm Bitmap) Count() int {
|
||||
s := 0
|
||||
for _, x := range bm {
|
||||
s += bits.OnesCount32(x)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func MakeBitmap(n int) Bitmap {
|
||||
return make(Bitmap, (n+31)/32)
|
||||
}
|
||||
|
|
@ -202,6 +216,8 @@ type Loader struct {
|
|||
sects []*sym.Section // sections
|
||||
symSects []uint16 // symbol's section, index to sects array
|
||||
|
||||
outdata [][]byte // symbol's data in the output buffer
|
||||
|
||||
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
|
||||
|
||||
objByPkg map[string]*oReader // map package path to its Go object reader
|
||||
|
|
@ -246,6 +262,8 @@ type Loader struct {
|
|||
localentry map[Sym]uint8 // stores Localentry symbol attribute
|
||||
extname map[Sym]string // stores Extname symbol attribute
|
||||
elfType map[Sym]elf.SymType // stores elf type symbol property
|
||||
elfSym map[Sym]int32 // stores elf sym symbol property
|
||||
localElfSym map[Sym]int32 // stores "local" elf sym symbol property
|
||||
symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms
|
||||
plt map[Sym]int32 // stores dynimport for pe objects
|
||||
got map[Sym]int32 // stores got for pe objects
|
||||
|
|
@ -266,6 +284,8 @@ type Loader struct {
|
|||
|
||||
elfsetstring elfsetstringFunc
|
||||
|
||||
errorReporter *ErrorReporter
|
||||
|
||||
SymLookup func(name string, ver int) *sym.Symbol
|
||||
}
|
||||
|
||||
|
|
@ -297,9 +317,9 @@ const (
|
|||
FlagStrictDups = 1 << iota
|
||||
)
|
||||
|
||||
func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
|
||||
func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
|
||||
nbuiltin := goobj2.NBuiltin()
|
||||
return &Loader{
|
||||
ldr := &Loader{
|
||||
start: make(map[*oReader]Sym),
|
||||
objs: []objIdx{{}}, // reserve index 0 for nil symbol
|
||||
objSyms: []objSym{{}}, // reserve index 0 for nil symbol
|
||||
|
|
@ -315,6 +335,8 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
|
|||
extname: make(map[Sym]string),
|
||||
attrReadOnly: make(map[Sym]bool),
|
||||
elfType: make(map[Sym]elf.SymType),
|
||||
elfSym: make(map[Sym]int32),
|
||||
localElfSym: make(map[Sym]int32),
|
||||
symPkg: make(map[Sym]string),
|
||||
plt: make(map[Sym]int32),
|
||||
got: make(map[Sym]int32),
|
||||
|
|
@ -328,8 +350,11 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
|
|||
builtinSyms: make([]Sym, nbuiltin),
|
||||
flags: flags,
|
||||
elfsetstring: elfsetstring,
|
||||
errorReporter: reporter,
|
||||
sects: []*sym.Section{nil}, // reserve index 0 for nil section
|
||||
}
|
||||
reporter.ldr = ldr
|
||||
return ldr
|
||||
}
|
||||
|
||||
// Add object file r, return the start index.
|
||||
|
|
@ -616,6 +641,11 @@ func (l *Loader) NDef() int {
|
|||
return int(l.extStart)
|
||||
}
|
||||
|
||||
// Number of reachable symbols.
|
||||
func (l *Loader) NReachableSym() int {
|
||||
return l.attrReachable.Count()
|
||||
}
|
||||
|
||||
// Returns the raw (unpatched) name of the i-th symbol.
|
||||
func (l *Loader) RawSymName(i Sym) string {
|
||||
if l.IsExternal(i) {
|
||||
|
|
@ -732,6 +762,14 @@ func (l *Loader) SetAttrLocal(i Sym, v bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// SymAddr checks that a symbol is reachable, and returns its value.
|
||||
func (l *Loader) SymAddr(i Sym) int64 {
|
||||
if !l.AttrReachable(i) {
|
||||
panic("unreachable symbol in symaddr")
|
||||
}
|
||||
return l.values[i]
|
||||
}
|
||||
|
||||
// AttrNotInSymbolTable returns true for symbols that should not be
|
||||
// added to the symbol table of the final generated load module.
|
||||
func (l *Loader) AttrNotInSymbolTable(i Sym) bool {
|
||||
|
|
@ -1026,6 +1064,11 @@ func (l *Loader) SetSymValue(i Sym, val int64) {
|
|||
l.values[i] = val
|
||||
}
|
||||
|
||||
// AddToSymValue adds to the value of the i-th symbol. i is the global index.
|
||||
func (l *Loader) AddToSymValue(i Sym, val int64) {
|
||||
l.values[i] += val
|
||||
}
|
||||
|
||||
// Returns the symbol content of the i-th symbol. i is global index.
|
||||
func (l *Loader) Data(i Sym) []byte {
|
||||
if l.IsExternal(i) {
|
||||
|
|
@ -1039,6 +1082,32 @@ func (l *Loader) Data(i Sym) []byte {
|
|||
return r.Data(li)
|
||||
}
|
||||
|
||||
// Returns the data of the i-th symbol in the output buffer.
|
||||
func (l *Loader) OutData(i Sym) []byte {
|
||||
if int(i) < len(l.outdata) && l.outdata[i] != nil {
|
||||
return l.outdata[i]
|
||||
}
|
||||
return l.Data(i)
|
||||
}
|
||||
|
||||
// SetOutData sets the position of the data of the i-th symbol in the output buffer.
|
||||
// i is global index.
|
||||
func (l *Loader) SetOutData(i Sym, data []byte) {
|
||||
if l.IsExternal(i) {
|
||||
pp := l.getPayload(i)
|
||||
if pp != nil {
|
||||
pp.data = data
|
||||
return
|
||||
}
|
||||
}
|
||||
l.outdata[i] = data
|
||||
}
|
||||
|
||||
// InitOutData initializes the slice used to store symbol output data.
|
||||
func (l *Loader) InitOutData() {
|
||||
l.outdata = make([][]byte, l.extStart)
|
||||
}
|
||||
|
||||
// SymAlign returns the alignment for a symbol.
|
||||
func (l *Loader) SymAlign(i Sym) int32 {
|
||||
// If an alignment has been recorded, return that.
|
||||
|
|
@ -1075,6 +1144,12 @@ func (l *Loader) SetSymAlign(i Sym, align int32) {
|
|||
|
||||
// SymValue returns the section of the i-th symbol. i is global index.
|
||||
func (l *Loader) SymSect(i Sym) *sym.Section {
|
||||
if int(i) >= len(l.symSects) {
|
||||
// symSects is extended lazily -- it the sym in question is
|
||||
// outside the range of the existing slice, then we assume its
|
||||
// section has not yet been set.
|
||||
return nil
|
||||
}
|
||||
return l.sects[l.symSects[i]]
|
||||
}
|
||||
|
||||
|
|
@ -1192,6 +1267,42 @@ func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
|
|||
}
|
||||
}
|
||||
|
||||
// SymElfSym returns the ELF symbol index for a given loader
|
||||
// symbol, assigned during ELF symtab generation.
|
||||
func (l *Loader) SymElfSym(i Sym) int32 {
|
||||
return l.elfSym[i]
|
||||
}
|
||||
|
||||
// SetSymElfSym sets the elf symbol index for a symbol.
|
||||
func (l *Loader) SetSymElfSym(i Sym, es int32) {
|
||||
if i == 0 {
|
||||
panic("bad sym index")
|
||||
}
|
||||
if es == 0 {
|
||||
delete(l.elfSym, i)
|
||||
} else {
|
||||
l.elfSym[i] = es
|
||||
}
|
||||
}
|
||||
|
||||
// SymLocalElfSym returns the "local" ELF symbol index for a given loader
|
||||
// symbol, assigned during ELF symtab generation.
|
||||
func (l *Loader) SymLocalElfSym(i Sym) int32 {
|
||||
return l.localElfSym[i]
|
||||
}
|
||||
|
||||
// SetSymLocalElfSym sets the "local" elf symbol index for a symbol.
|
||||
func (l *Loader) SetSymLocalElfSym(i Sym, es int32) {
|
||||
if i == 0 {
|
||||
panic("bad sym index")
|
||||
}
|
||||
if es == 0 {
|
||||
delete(l.localElfSym, i)
|
||||
} else {
|
||||
l.localElfSym[i] = es
|
||||
}
|
||||
}
|
||||
|
||||
// SymPlt returns the plt value for pe symbols.
|
||||
func (l *Loader) SymPlt(s Sym) int32 {
|
||||
if v, ok := l.plt[s]; ok {
|
||||
|
|
@ -1253,6 +1364,18 @@ func (l *Loader) SetSymDynid(i Sym, val int32) {
|
|||
}
|
||||
}
|
||||
|
||||
// DynIdSyms returns the set of symbols for which dynID is set to an
|
||||
// interesting (non-default) value. This is expected to be a fairly
|
||||
// small set.
|
||||
func (l *Loader) DynidSyms() []Sym {
|
||||
sl := make([]Sym, 0, len(l.dynid))
|
||||
for s := range l.dynid {
|
||||
sl = append(sl, s)
|
||||
}
|
||||
sort.Slice(sl, func(i, j int) bool { return sl[i] < sl[j] })
|
||||
return sl
|
||||
}
|
||||
|
||||
// SymGoType returns the 'Gotype' property for a given symbol (set by
|
||||
// the Go compiler for variable symbols). This version relies on
|
||||
// reading aux symbols for the target sym -- it could be that a faster
|
||||
|
|
@ -1734,7 +1857,8 @@ func (l *Loader) FuncInfo(i Sym) FuncInfo {
|
|||
// Preload a package: add autolibs, add defined package symbols to the symbol table.
|
||||
// Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
|
||||
// Does not read symbol data.
|
||||
func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, flags int) {
|
||||
// Returns the fingerprint of the object.
|
||||
func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj2.FingerprintType {
|
||||
roObject, readonly, err := f.Slice(uint64(length))
|
||||
if err != nil {
|
||||
log.Fatal("cannot read object file:", err)
|
||||
|
|
@ -1753,7 +1877,7 @@ func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, uni
|
|||
or := &oReader{r, unit, localSymVersion, r.Flags(), pkgprefix, make([]Sym, ndef+nnonpkgdef+r.NNonpkgref()), ndef, uint32(len(l.objs))}
|
||||
|
||||
// Autolib
|
||||
lib.ImportStrings = append(lib.ImportStrings, r.Autolib()...)
|
||||
lib.Autolib = append(lib.Autolib, r.Autolib()...)
|
||||
|
||||
// DWARF file table
|
||||
nfile := r.NDwarfFile()
|
||||
|
|
@ -1767,6 +1891,8 @@ func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, uni
|
|||
|
||||
// The caller expects us consuming all the data
|
||||
f.MustSeek(length, os.SEEK_CUR)
|
||||
|
||||
return r.Fingerprint()
|
||||
}
|
||||
|
||||
// Preload symbols of given kind from an object.
|
||||
|
|
@ -1890,7 +2016,7 @@ func (l *Loader) preprocess(arch *sys.Arch, s Sym, name string) {
|
|||
}
|
||||
|
||||
// Load full contents.
|
||||
func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
||||
func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
|
||||
// create all Symbols first.
|
||||
l.growSyms(l.NSym())
|
||||
l.growSects(l.NSym())
|
||||
|
|
@ -1923,7 +2049,9 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
|||
}
|
||||
|
||||
// allocate a single large slab of relocations for all live symbols
|
||||
if needReloc {
|
||||
l.relocBatch = make([]sym.Reloc, nr)
|
||||
}
|
||||
|
||||
// convert payload-based external symbols into sym.Symbol-based
|
||||
for _, i := range toConvert {
|
||||
|
|
@ -1934,21 +2062,15 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
|||
s.Version = int16(pp.ver)
|
||||
s.Type = pp.kind
|
||||
s.Size = pp.size
|
||||
if pp.gotype != 0 {
|
||||
s.Gotype = l.Syms[pp.gotype]
|
||||
}
|
||||
if f, ok := l.symPkg[i]; ok {
|
||||
s.File = f
|
||||
} else if pp.objidx != 0 {
|
||||
s.File = l.objs[pp.objidx].r.unit.Lib.Pkg
|
||||
}
|
||||
|
||||
// Copy relocations
|
||||
if needReloc {
|
||||
batch := l.relocBatch
|
||||
s.R = batch[:len(pp.relocs):len(pp.relocs)]
|
||||
l.relocBatch = batch[len(pp.relocs):]
|
||||
relocs := l.Relocs(i)
|
||||
l.convertRelocations(i, &relocs, s, false)
|
||||
}
|
||||
|
||||
// Copy data
|
||||
s.P = pp.data
|
||||
|
|
@ -1959,7 +2081,7 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
|||
|
||||
// load contents of defined symbols
|
||||
for _, o := range l.objs[1:] {
|
||||
loadObjFull(l, o.r)
|
||||
loadObjFull(l, o.r, needReloc)
|
||||
}
|
||||
|
||||
// Note: resolution of ABI aliases is now also handled in
|
||||
|
|
@ -2103,22 +2225,7 @@ func (l *Loader) PropagateLoaderChangesToSymbols(toconvert []Sym, anonVerReplace
|
|||
relfix = true
|
||||
}
|
||||
|
||||
// For 'new' symbols, copy other content (such as Gotype,
|
||||
// sym file, relocations, etc).
|
||||
if isnew {
|
||||
if gt := l.SymGoType(cand); gt != 0 {
|
||||
s.Gotype = l.Syms[gt]
|
||||
}
|
||||
if f, ok := l.symPkg[cand]; ok {
|
||||
s.File = f
|
||||
} else {
|
||||
r, _ := l.toLocal(cand)
|
||||
if r != nil && r != l.extReader {
|
||||
s.File = l.SymPkg(cand)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For 'new' symbols, copy other content.
|
||||
if relfix {
|
||||
relocfixup = append(relocfixup, cand)
|
||||
}
|
||||
|
|
@ -2165,7 +2272,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
|
|||
if s == nil {
|
||||
continue
|
||||
}
|
||||
syms.Allsym = append(syms.Allsym, s) // XXX still add to Allsym for now, as there are code looping through Allsym
|
||||
if s.Version < 0 {
|
||||
s.Version = int16(anonVerReplacement)
|
||||
}
|
||||
|
|
@ -2179,7 +2285,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
|
|||
}
|
||||
s := l.allocSym(name, ver)
|
||||
l.installSym(i, s)
|
||||
syms.Allsym = append(syms.Allsym, s) // XXX see above
|
||||
return s
|
||||
}
|
||||
syms.Lookup = l.SymLookup
|
||||
|
|
@ -2191,7 +2296,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
|
|||
i := l.newExtSym(name, ver)
|
||||
s := l.allocSym(name, ver)
|
||||
l.installSym(i, s)
|
||||
syms.Allsym = append(syms.Allsym, s) // XXX see above
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
|
@ -2221,6 +2325,7 @@ func (l *Loader) installSym(i Sym, s *sym.Symbol) {
|
|||
panic("sym already present in installSym")
|
||||
}
|
||||
l.Syms[i] = s
|
||||
s.SymIdx = sym.LoaderSym(i)
|
||||
}
|
||||
|
||||
// addNewSym adds a new sym.Symbol to the i-th index in the list of symbols.
|
||||
|
|
@ -2234,12 +2339,35 @@ func (l *Loader) addNewSym(i Sym, name string, ver int, unit *sym.CompilationUni
|
|||
t = s.Type
|
||||
}
|
||||
s.Type = t
|
||||
s.Unit = unit
|
||||
l.growSyms(int(i))
|
||||
l.installSym(i, s)
|
||||
return s
|
||||
}
|
||||
|
||||
// TopLevelSym tests a symbol (by name and kind) to determine whether
|
||||
// the symbol first class sym (participating in the link) or is an
|
||||
// anonymous aux or sub-symbol containing some sub-part or payload of
|
||||
// another symbol.
|
||||
func (l *Loader) TopLevelSym(s Sym) bool {
|
||||
return topLevelSym(l.RawSymName(s), l.SymType(s))
|
||||
}
|
||||
|
||||
// topLevelSym tests a symbol name and kind to determine whether
|
||||
// the symbol first class sym (participating in the link) or is an
|
||||
// anonymous aux or sub-symbol containing some sub-part or payload of
|
||||
// another symbol.
|
||||
func topLevelSym(sname string, skind sym.SymKind) bool {
|
||||
if sname != "" {
|
||||
return true
|
||||
}
|
||||
switch skind {
|
||||
case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES, sym.SGOFUNC:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// loadObjSyms creates sym.Symbol objects for the live Syms in the
|
||||
// object corresponding to object reader "r". Return value is the
|
||||
// number of sym.Reloc entries required for all the new symbols.
|
||||
|
|
@ -2253,17 +2381,12 @@ func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
|
|||
osym := r.Sym(i)
|
||||
name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
|
||||
t := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
|
||||
// NB: for the test below, we can skip most anonymous symbols
|
||||
// since they will never be turned into sym.Symbols (eg:
|
||||
// funcdata). DWARF symbols are an exception however -- we
|
||||
// want to include all reachable but nameless DWARF symbols.
|
||||
if name == "" {
|
||||
switch t {
|
||||
case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES:
|
||||
default:
|
||||
|
||||
// Skip non-dwarf anonymous symbols (e.g. funcdata),
|
||||
// since they will never be turned into sym.Symbols.
|
||||
if !topLevelSym(name, t) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
ver := abiToVer(osym.ABI(), r.version)
|
||||
if t == sym.SXREF {
|
||||
log.Fatalf("bad sxref")
|
||||
|
|
@ -2479,12 +2602,7 @@ func (l *Loader) CreateStaticSym(name string) Sym {
|
|||
return l.newExtSym(name, l.anonVersion)
|
||||
}
|
||||
|
||||
func loadObjFull(l *Loader, r *oReader) {
|
||||
resolveSymRef := func(s goobj2.SymRef) *sym.Symbol {
|
||||
i := l.resolve(r, s)
|
||||
return l.Syms[i]
|
||||
}
|
||||
|
||||
func loadObjFull(l *Loader, r *oReader, needReloc bool) {
|
||||
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
|
||||
// A symbol may be a dup or overwritten. In this case, its
|
||||
// content will actually be provided by a different object
|
||||
|
|
@ -2506,27 +2624,23 @@ func loadObjFull(l *Loader, r *oReader) {
|
|||
size := osym.Siz()
|
||||
|
||||
// Symbol data
|
||||
s.P = r.Data(i)
|
||||
s.Attr.Set(sym.AttrReadOnly, r.ReadOnly())
|
||||
s.P = l.OutData(gi)
|
||||
|
||||
// Relocs
|
||||
if needReloc {
|
||||
relocs := l.relocs(r, i)
|
||||
batch := l.relocBatch
|
||||
s.R = batch[:relocs.Count():relocs.Count()]
|
||||
l.relocBatch = batch[relocs.Count():]
|
||||
l.convertRelocations(gi, &relocs, s, false)
|
||||
}
|
||||
|
||||
// Aux symbol info
|
||||
auxs := r.Auxs(i)
|
||||
for j := range auxs {
|
||||
a := &auxs[j]
|
||||
switch a.Type() {
|
||||
case goobj2.AuxGotype:
|
||||
typ := resolveSymRef(a.Sym())
|
||||
if typ != nil {
|
||||
s.Gotype = typ
|
||||
}
|
||||
case goobj2.AuxFuncInfo, goobj2.AuxFuncdata:
|
||||
case goobj2.AuxFuncInfo, goobj2.AuxFuncdata, goobj2.AuxGotype:
|
||||
// already handled
|
||||
case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines:
|
||||
// ignored for now
|
||||
|
|
@ -2535,7 +2649,6 @@ func loadObjFull(l *Loader, r *oReader) {
|
|||
}
|
||||
}
|
||||
|
||||
s.File = r.pkgprefix[:len(r.pkgprefix)-1]
|
||||
if s.Size < int64(size) {
|
||||
s.Size = int64(size)
|
||||
}
|
||||
|
|
@ -2744,6 +2857,42 @@ func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, exts
|
|||
return textp2
|
||||
}
|
||||
|
||||
// ErrorReporter is a helper class for reporting errors.
|
||||
type ErrorReporter struct {
|
||||
ldr *Loader
|
||||
AfterErrorAction func()
|
||||
}
|
||||
|
||||
// Errorf method logs an error message.
|
||||
//
|
||||
// After each error, the error actions function will be invoked; this
|
||||
// will either terminate the link immediately (if -h option given)
|
||||
// or it will keep a count and exit if more than 20 errors have been printed.
|
||||
//
|
||||
// Logging an error means that on exit cmd/link will delete any
|
||||
// output file and return a non-zero error code.
|
||||
//
|
||||
func (reporter *ErrorReporter) Errorf(s Sym, format string, args ...interface{}) {
|
||||
if s != 0 && reporter.ldr.SymName(s) != "" {
|
||||
format = reporter.ldr.SymName(s) + ": " + format
|
||||
} else {
|
||||
format = fmt.Sprintf("sym %d: %s", s, format)
|
||||
}
|
||||
format += "\n"
|
||||
fmt.Fprintf(os.Stderr, format, args...)
|
||||
reporter.AfterErrorAction()
|
||||
}
|
||||
|
||||
// GetErrorReporter returns the loader's associated error reporter.
|
||||
func (l *Loader) GetErrorReporter() *ErrorReporter {
|
||||
return l.errorReporter
|
||||
}
|
||||
|
||||
// Errorf method logs an error message. See ErrorReporter.Errorf for details.
|
||||
func (l *Loader) Errorf(s Sym, format string, args ...interface{}) {
|
||||
l.errorReporter.Errorf(s, format, args...)
|
||||
}
|
||||
|
||||
// For debugging.
|
||||
func (l *Loader) Dump() {
|
||||
fmt.Println("objs")
|
||||
|
|
|
|||
|
|
@ -27,9 +27,16 @@ func addDummyObjSym(t *testing.T, ldr *Loader, or *oReader, name string) Sym {
|
|||
return s
|
||||
}
|
||||
|
||||
func TestAddMaterializedSymbol(t *testing.T) {
|
||||
func mkLoader() *Loader {
|
||||
edummy := func(s *sym.Symbol, str string, off int) {}
|
||||
ldr := NewLoader(0, edummy)
|
||||
er := ErrorReporter{}
|
||||
ldr := NewLoader(0, edummy, &er)
|
||||
er.ldr = ldr
|
||||
return ldr
|
||||
}
|
||||
|
||||
func TestAddMaterializedSymbol(t *testing.T) {
|
||||
ldr := mkLoader()
|
||||
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
||||
or := &dummyOreader
|
||||
|
||||
|
|
@ -229,8 +236,7 @@ func sameRelocSlice(s1 *Relocs, s2 []Reloc) bool {
|
|||
type addFunc func(l *Loader, s Sym, s2 Sym) Sym
|
||||
|
||||
func TestAddDataMethods(t *testing.T) {
|
||||
edummy := func(s *sym.Symbol, str string, off int) {}
|
||||
ldr := NewLoader(0, edummy)
|
||||
ldr := mkLoader()
|
||||
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
||||
or := &dummyOreader
|
||||
|
||||
|
|
@ -352,8 +358,7 @@ func TestAddDataMethods(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestOuterSub(t *testing.T) {
|
||||
edummy := func(s *sym.Symbol, str string, off int) {}
|
||||
ldr := NewLoader(0, edummy)
|
||||
ldr := mkLoader()
|
||||
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
||||
or := &dummyOreader
|
||||
|
||||
|
|
|
|||
|
|
@ -143,6 +143,22 @@ func (sb *SymbolBuilder) SetRelocs(rslice []Reloc) {
|
|||
}
|
||||
}
|
||||
|
||||
// SetRelocType sets the type of the 'i'-th relocation on this sym to 't'
|
||||
func (sb *SymbolBuilder) SetRelocType(i int, t objabi.RelocType) {
|
||||
sb.relocs[i].SetType(0)
|
||||
sb.reltypes[i] = t
|
||||
}
|
||||
|
||||
// SetRelocSym sets the target sym of the 'i'-th relocation on this sym to 's'
|
||||
func (sb *SymbolBuilder) SetRelocSym(i int, tgt Sym) {
|
||||
sb.relocs[i].SetSym(goobj2.SymRef{PkgIdx: 0, SymIdx: uint32(tgt)})
|
||||
}
|
||||
|
||||
// SetRelocAdd sets the addend of the 'i'-th relocation on this sym to 'a'
|
||||
func (sb *SymbolBuilder) SetRelocAdd(i int, a int64) {
|
||||
sb.relocs[i].SetAdd(a)
|
||||
}
|
||||
|
||||
// Add n relocations, return a handle to the relocations.
|
||||
func (sb *SymbolBuilder) AddRelocs(n int) Relocs {
|
||||
sb.relocs = append(sb.relocs, make([]goobj2.Reloc, n)...)
|
||||
|
|
@ -431,3 +447,10 @@ func GenAddAddrPlusFunc(internalExec bool) func(s *SymbolBuilder, arch *sys.Arch
|
|||
return (*SymbolBuilder).AddAddrPlus
|
||||
}
|
||||
}
|
||||
|
||||
func (sb *SymbolBuilder) MakeWritable() {
|
||||
if sb.ReadOnly() {
|
||||
sb.data = append([]byte(nil), sb.data...)
|
||||
sb.l.SetAttrReadOnly(sb.symIdx, false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write32(uint32(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
|
@ -164,7 +164,7 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
|
|||
return -1
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
func asmb(ctxt *ld.Link, _ *loader.Loader) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
|||
|
||||
ctxt.Out.Write64(uint64(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
|
||||
ctxt.Out.Write32(uint32(elfsym))
|
||||
ctxt.Out.Write8(0)
|
||||
ctxt.Out.Write8(0)
|
||||
|
|
@ -170,7 +170,7 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
|
|||
return -1
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
func asmb(ctxt *ld.Link, _ *loader.Loader) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -267,120 +267,134 @@ func gencallstub2(ctxt *ld.Link, ldr *loader.Loader, abicase int, stub *loader.S
|
|||
stub.AddUint32(ctxt.Arch, 0x4e800420) // bctr
|
||||
}
|
||||
|
||||
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
|
||||
if target.IsElf() {
|
||||
return addelfdynrel(target, syms, s, r)
|
||||
return addelfdynrel2(target, ldr, syms, s, r, rIdx)
|
||||
} else if target.IsAIX() {
|
||||
return ld.Xcoffadddynrel(target, ldr, s, r)
|
||||
return ld.Xcoffadddynrel2(target, ldr, syms, s, r, rIdx)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func addelfdynrel(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
r.InitExt()
|
||||
func addelfdynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
|
||||
targ := r.Sym()
|
||||
var targType sym.SymKind
|
||||
if targ != 0 {
|
||||
targType = ldr.SymType(targ)
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
switch r.Type() {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
|
||||
if r.Type() >= objabi.ElfRelocOffset {
|
||||
ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL24):
|
||||
r.Type = objabi.R_CALLPOWER
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_CALLPOWER)
|
||||
|
||||
// This is a local call, so the caller isn't setting
|
||||
// up r12 and r2 is the same for the caller and
|
||||
// callee. Hence, we need to go to the local entry
|
||||
// point. (If we don't do this, the callee will try
|
||||
// to use r12 to compute r2.)
|
||||
r.Add += int64(r.Sym.Localentry()) * 4
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymLocalentry(targ))*4)
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
if targType == sym.SDYNIMPORT {
|
||||
// Should have been handled in elfsetupplt
|
||||
ld.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
|
||||
ldr.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC_REL32):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_ADDR64):
|
||||
r.Type = objabi.R_ADDR
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
// These happen in .toc sections
|
||||
ld.Adddynsym(target, syms, targ)
|
||||
ld.Adddynsym2(ldr, target, syms, targ)
|
||||
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, s, int64(r.Off))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_PPC64_ADDR64)))
|
||||
rela.AddUint64(target.Arch, uint64(r.Add))
|
||||
r.Type = objabi.ElfRelocOffset // ignore during relocsym
|
||||
rela := ldr.MakeSymbolUpdater(syms.Rela2)
|
||||
rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_PPC64_ADDR64)))
|
||||
rela.AddUint64(target.Arch, uint64(r.Add()))
|
||||
su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16):
|
||||
r.Type = objabi.R_POWER_TOC
|
||||
r.Variant = sym.RV_POWER_LO | sym.RV_CHECK_OVERFLOW
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_POWER_TOC)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_LO|sym.RV_CHECK_OVERFLOW)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO):
|
||||
r.Type = objabi.R_POWER_TOC
|
||||
r.Variant = sym.RV_POWER_LO
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_POWER_TOC)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_LO)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HA):
|
||||
r.Type = objabi.R_POWER_TOC
|
||||
r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_POWER_TOC)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HA|sym.RV_CHECK_OVERFLOW)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HI):
|
||||
r.Type = objabi.R_POWER_TOC
|
||||
r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_POWER_TOC)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HI|sym.RV_CHECK_OVERFLOW)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_DS):
|
||||
r.Type = objabi.R_POWER_TOC
|
||||
r.Variant = sym.RV_POWER_DS | sym.RV_CHECK_OVERFLOW
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_POWER_TOC)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_DS|sym.RV_CHECK_OVERFLOW)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO_DS):
|
||||
r.Type = objabi.R_POWER_TOC
|
||||
r.Variant = sym.RV_POWER_DS
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_POWER_TOC)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_DS)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_LO):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_POWER_LO
|
||||
r.Add += 2 // Compensate for relocation size of 2
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_LO)
|
||||
su.SetRelocAdd(rIdx, r.Add()+2) // Compensate for relocation size of 2
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HI):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
|
||||
r.Add += 2
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HI|sym.RV_CHECK_OVERFLOW)
|
||||
su.SetRelocAdd(rIdx, r.Add()+2)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HA):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
|
||||
r.Add += 2
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HA|sym.RV_CHECK_OVERFLOW)
|
||||
su.SetRelocAdd(rIdx, r.Add()+2)
|
||||
return true
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -439,7 +453,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
|||
}
|
||||
ctxt.Out.Write64(uint64(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
|
@ -972,7 +986,7 @@ func addpltsym2(ctxt *ld.Link, ldr *loader.Loader, s loader.Sym) {
|
|||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym2(ldr, &ctxt.ErrorReporter, &ctxt.Target, &ctxt.ArchSyms, s)
|
||||
ld.Adddynsym2(ldr, &ctxt.Target, &ctxt.ArchSyms, s)
|
||||
|
||||
if ctxt.IsELF {
|
||||
plt := ldr.MakeSymbolUpdater(ctxt.PLT2)
|
||||
|
|
@ -1068,7 +1082,7 @@ func ensureglinkresolver2(ctxt *ld.Link, ldr *loader.Loader) *loader.SymbolBuild
|
|||
return glink
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
func asmb(ctxt *ld.Link, _ *loader.Loader) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
|||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Adddynrel2: adddynrel2,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
|
|||
return -1
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
func asmb(ctxt *ld.Link, _ *loader.Loader) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,135 +75,146 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
|
|||
initfunc.AddUint32(ctxt.Arch, 0)
|
||||
}
|
||||
|
||||
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
r.InitExt()
|
||||
func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
|
||||
targ := r.Sym()
|
||||
var targType sym.SymKind
|
||||
if targ != 0 {
|
||||
targType = ldr.SymType(targ)
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
switch r.Type() {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d", r.Type)
|
||||
if r.Type() >= objabi.ElfRelocOffset {
|
||||
ldr.Errorf(s, "unexpected relocation type %d", r.Type())
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_12),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT12):
|
||||
ld.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type-objabi.ElfRelocOffset)
|
||||
ldr.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type()-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_8),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_16),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
|
||||
ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += int64(r.Siz)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT16),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT64):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT16DBL),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32DBL):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_390_DBL
|
||||
r.Add += int64(r.Siz)
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
r.SetSym(syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT64):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += int64(r.Siz)
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
r.SetSym(syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_COPY):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GLOB_DAT):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_JMP_SLOT):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_RELATIVE):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTOFF):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_GOTOFF
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_GOTOFF)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPC):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(r.Siz)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
r.SetSym(syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16DBL),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32DBL):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_390_DBL
|
||||
r.Add += int64(r.Siz)
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPCDBL):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_390_DBL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(r.Siz)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
|
||||
r.SetSym(syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTENT):
|
||||
addgotsym(target, syms, targ)
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_390_DBL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
r.Add += int64(r.Siz)
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
|
||||
r.SetSym(syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ))+int64(r.Siz()))
|
||||
return true
|
||||
}
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +224,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write64(uint64(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
|
@ -388,28 +399,30 @@ func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym
|
|||
}
|
||||
}
|
||||
|
||||
func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymPlt(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
|
||||
if target.IsElf() {
|
||||
plt := syms.PLT
|
||||
got := syms.GOT
|
||||
rela := syms.RelaPLT
|
||||
if plt.Size == 0 {
|
||||
plt := ldr.MakeSymbolUpdater(syms.PLT2)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
rela := ldr.MakeSymbolUpdater(syms.RelaPLT2)
|
||||
if plt.Size() == 0 {
|
||||
panic("plt is not set up")
|
||||
}
|
||||
// larl %r1,_GLOBAL_OFFSET_TABLE_+index
|
||||
|
||||
plt.AddUint8(0xc0)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddPCRelPlus(target.Arch, got, got.Size+6) // need variant?
|
||||
plt.AddPCRelPlus(target.Arch, got.Sym(), got.Size()+6)
|
||||
pltrelocs := plt.Relocs()
|
||||
ldr.SetRelocVariant(plt.Sym(), pltrelocs.Count()-1, sym.RV_390_DBL)
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
got.AddAddrPlus(target.Arch, plt, plt.Size+8) // weird but correct
|
||||
got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size()+8) // weird but correct
|
||||
// lg %r1,0(%r1)
|
||||
plt.AddUint8(0xe3)
|
||||
plt.AddUint8(0x10)
|
||||
|
|
@ -434,44 +447,45 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
|||
plt.AddUint8(0xc0)
|
||||
plt.AddUint8(0xf4)
|
||||
|
||||
plt.AddUint32(target.Arch, uint32(-((plt.Size - 2) >> 1))) // roll-your-own relocation
|
||||
plt.AddUint32(target.Arch, uint32(-((plt.Size() - 2) >> 1))) // roll-your-own relocation
|
||||
//.plt index
|
||||
plt.AddUint32(target.Arch, uint32(rela.Size)) // rela size before current entry
|
||||
plt.AddUint32(target.Arch, uint32(rela.Size())) // rela size before current entry
|
||||
|
||||
// rela
|
||||
rela.AddAddrPlus(target.Arch, got, got.Size-8)
|
||||
rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
|
||||
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_JMP_SLOT)))
|
||||
sDynid := ldr.SymDynid(s)
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_390_JMP_SLOT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
|
||||
s.SetPlt(int32(plt.Size - 32))
|
||||
ldr.SetPlt(s, int32(plt.Size()-32))
|
||||
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymGot(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
got := syms.GOT
|
||||
s.SetGot(int32(got.Size))
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
ldr.SetGot(s, int32(got.Size()))
|
||||
got.AddUint64(target.Arch, 0)
|
||||
|
||||
if target.IsElf() {
|
||||
rela := syms.Rela
|
||||
rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_GLOB_DAT)))
|
||||
rela := ldr.MakeSymbolUpdater(syms.Rela2)
|
||||
rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
|
||||
rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_390_GLOB_DAT)))
|
||||
rela.AddUint64(target.Arch, 0)
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
func asmb(ctxt *ld.Link, _ *loader.Loader) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
|||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Adddynrel2: adddynrel2,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package sym
|
||||
|
||||
import "cmd/internal/goobj2"
|
||||
|
||||
type Library struct {
|
||||
Objref string
|
||||
Srcref string
|
||||
|
|
@ -11,7 +13,8 @@ type Library struct {
|
|||
Pkg string
|
||||
Shlib string
|
||||
Hash string
|
||||
ImportStrings []string
|
||||
Fingerprint goobj2.FingerprintType
|
||||
Autolib []goobj2.ImportedPkg
|
||||
Imports []*Library
|
||||
Main bool
|
||||
Safe bool
|
||||
|
|
|
|||
|
|
@ -56,5 +56,6 @@ type Section struct {
|
|||
Reloff uint64
|
||||
Rellen uint64
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
|
|||
_32bit uintptr // size on 32bit platforms
|
||||
_64bit uintptr // size on 64bit platforms
|
||||
}{
|
||||
{Symbol{}, 104, 168},
|
||||
{Symbol{}, 84, 136},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
|||
|
|
@ -21,17 +21,13 @@ type Symbol struct {
|
|||
Attr Attribute
|
||||
Dynid int32
|
||||
Align int32
|
||||
Elfsym int32
|
||||
LocalElfsym int32
|
||||
Value int64
|
||||
Size int64
|
||||
Sub *Symbol
|
||||
Outer *Symbol
|
||||
Gotype *Symbol
|
||||
File string // actually package!
|
||||
SymIdx LoaderSym
|
||||
auxinfo *AuxSymbol
|
||||
Sect *Section
|
||||
Unit *CompilationUnit
|
||||
// P contains the raw symbol data.
|
||||
P []byte
|
||||
R []Reloc
|
||||
|
|
@ -88,16 +84,6 @@ func (s *Symbol) IsFileLocal() bool {
|
|||
return s.Version >= SymVerStatic
|
||||
}
|
||||
|
||||
func (s *Symbol) ElfsymForReloc() int32 {
|
||||
// If putelfsym created a local version of this symbol, use that in all
|
||||
// relocations.
|
||||
if s.LocalElfsym != 0 {
|
||||
return s.LocalElfsym
|
||||
} else {
|
||||
return s.Elfsym
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Symbol) Len() int64 {
|
||||
return s.Size
|
||||
}
|
||||
|
|
@ -444,80 +430,6 @@ func (s *Symbol) SetElfType(val elf.SymType) {
|
|||
s.auxinfo.elftype = val
|
||||
}
|
||||
|
||||
// SortSub sorts a linked-list (by Sub) of *Symbol by Value.
|
||||
// Used for sub-symbols when loading host objects (see e.g. ldelf.go).
|
||||
func SortSub(l *Symbol) *Symbol {
|
||||
if l == nil || l.Sub == nil {
|
||||
return l
|
||||
}
|
||||
|
||||
l1 := l
|
||||
l2 := l
|
||||
for {
|
||||
l2 = l2.Sub
|
||||
if l2 == nil {
|
||||
break
|
||||
}
|
||||
l2 = l2.Sub
|
||||
if l2 == nil {
|
||||
break
|
||||
}
|
||||
l1 = l1.Sub
|
||||
}
|
||||
|
||||
l2 = l1.Sub
|
||||
l1.Sub = nil
|
||||
l1 = SortSub(l)
|
||||
l2 = SortSub(l2)
|
||||
|
||||
/* set up lead element */
|
||||
if l1.Value < l2.Value {
|
||||
l = l1
|
||||
l1 = l1.Sub
|
||||
} else {
|
||||
l = l2
|
||||
l2 = l2.Sub
|
||||
}
|
||||
|
||||
le := l
|
||||
|
||||
for {
|
||||
if l1 == nil {
|
||||
for l2 != nil {
|
||||
le.Sub = l2
|
||||
le = l2
|
||||
l2 = l2.Sub
|
||||
}
|
||||
|
||||
le.Sub = nil
|
||||
break
|
||||
}
|
||||
|
||||
if l2 == nil {
|
||||
for l1 != nil {
|
||||
le.Sub = l1
|
||||
le = l1
|
||||
l1 = l1.Sub
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if l1.Value < l2.Value {
|
||||
le.Sub = l1
|
||||
le = l1
|
||||
l1 = l1.Sub
|
||||
} else {
|
||||
le.Sub = l2
|
||||
le = l2
|
||||
l2 = l2.Sub
|
||||
}
|
||||
}
|
||||
|
||||
le.Sub = nil
|
||||
return l
|
||||
}
|
||||
|
||||
type Pcdata struct {
|
||||
P []byte
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@ type Symbols struct {
|
|||
// Symbol lookup based on name and indexed by version.
|
||||
versions int
|
||||
|
||||
Allsym []*Symbol
|
||||
|
||||
// Provided by the loader
|
||||
|
||||
// Look up the symbol with the given name and version, creating the
|
||||
|
|
@ -55,7 +53,6 @@ type Symbols struct {
|
|||
func NewSymbols() *Symbols {
|
||||
return &Symbols{
|
||||
versions: SymVerStatic,
|
||||
Allsym: make([]*Symbol, 0, 100000),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,30 @@ func assignAddress(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, v
|
|||
return sect, n, va
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {} // dummy
|
||||
type wasmDataSect struct {
|
||||
sect *sym.Section
|
||||
data []byte
|
||||
}
|
||||
|
||||
var dataSects []wasmDataSect
|
||||
|
||||
func asmb(ctxt *ld.Link, ldr *loader.Loader) {
|
||||
sections := []*sym.Section{
|
||||
ldr.SymSect(ldr.Lookup("runtime.rodata", 0)),
|
||||
ldr.SymSect(ldr.Lookup("runtime.typelink", 0)),
|
||||
ldr.SymSect(ldr.Lookup("runtime.itablink", 0)),
|
||||
ldr.SymSect(ldr.Lookup("runtime.symtab", 0)),
|
||||
ldr.SymSect(ldr.Lookup("runtime.pclntab", 0)),
|
||||
ldr.SymSect(ldr.Lookup("runtime.noptrdata", 0)),
|
||||
ldr.SymSect(ldr.Lookup("runtime.data", 0)),
|
||||
}
|
||||
|
||||
dataSects = make([]wasmDataSect, len(sections))
|
||||
for i, sect := range sections {
|
||||
data := ld.DatblkBytes(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
dataSects[i] = wasmDataSect{sect, data}
|
||||
}
|
||||
}
|
||||
|
||||
// asmb writes the final WebAssembly module binary.
|
||||
// Spec: https://webassembly.github.io/spec/core/binary/modules.html
|
||||
|
|
@ -396,16 +419,6 @@ func writeCodeSec(ctxt *ld.Link, fns []*wasmFunc) {
|
|||
func writeDataSec(ctxt *ld.Link) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionData)
|
||||
|
||||
sections := []*sym.Section{
|
||||
ctxt.Syms.Lookup("runtime.rodata", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.typelink", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.itablink", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.symtab", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.pclntab", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.data", 0).Sect,
|
||||
}
|
||||
|
||||
type dataSegment struct {
|
||||
offset int32
|
||||
data []byte
|
||||
|
|
@ -420,9 +433,9 @@ func writeDataSec(ctxt *ld.Link) {
|
|||
const maxNumSegments = 100000
|
||||
|
||||
var segments []*dataSegment
|
||||
for secIndex, sec := range sections {
|
||||
data := ld.DatblkBytes(ctxt, int64(sec.Vaddr), int64(sec.Length))
|
||||
offset := int32(sec.Vaddr)
|
||||
for secIndex, ds := range dataSects {
|
||||
data := ds.data
|
||||
offset := int32(ds.sect.Vaddr)
|
||||
|
||||
// skip leading zeroes
|
||||
for len(data) > 0 && data[0] == 0 {
|
||||
|
|
@ -433,7 +446,7 @@ func writeDataSec(ctxt *ld.Link) {
|
|||
for len(data) > 0 {
|
||||
dataLen := int32(len(data))
|
||||
var segmentEnd, zeroEnd int32
|
||||
if len(segments)+(len(sections)-secIndex) == maxNumSegments {
|
||||
if len(segments)+(len(dataSects)-secIndex) == maxNumSegments {
|
||||
segmentEnd = dataLen
|
||||
zeroEnd = dataLen
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -129,161 +129,189 @@ func gentext2(ctxt *ld.Link, ldr *loader.Loader) {
|
|||
o(0xc3)
|
||||
}
|
||||
|
||||
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r *loader.Reloc2, rIdx int) bool {
|
||||
targ := r.Sym()
|
||||
var targType sym.SymKind
|
||||
if targ != 0 {
|
||||
targType = ldr.SymType(targ)
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
switch r.Type() {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
|
||||
if r.Type() >= objabi.ElfRelocOffset {
|
||||
ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
|
||||
ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add += int64(targ.Plt())
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
|
||||
s.P[r.Off-2] = 0x8d
|
||||
sData := ldr.Data(s)
|
||||
|
||||
r.Type = objabi.R_GOTOFF
|
||||
if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
|
||||
su.MakeWritable()
|
||||
|
||||
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
|
||||
writeableData := su.Data()
|
||||
writeableData[r.Off()-2] = 0x8d
|
||||
su.SetRelocType(rIdx, objabi.R_GOTOFF)
|
||||
return true
|
||||
}
|
||||
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
|
||||
if r.Off() >= 2 && sData[r.Off()-2] == 0xff && sData[r.Off()-1] == 0xb3 {
|
||||
su.MakeWritable()
|
||||
// turn PUSHL of GOT entry into PUSHL of symbol itself.
|
||||
// use unnecessary SS prefix to keep instruction same length.
|
||||
s.P[r.Off-2] = 0x36
|
||||
|
||||
s.P[r.Off-1] = 0x68
|
||||
r.Type = objabi.R_ADDR
|
||||
writeableData := su.Data()
|
||||
writeableData[r.Off()-2] = 0x36
|
||||
writeableData[r.Off()-1] = 0x68
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
return true
|
||||
}
|
||||
|
||||
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
|
||||
return false
|
||||
}
|
||||
|
||||
addgotsym(target, syms, targ)
|
||||
r.Type = objabi.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
r.Add += int64(targ.Got())
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
|
||||
su.SetRelocSym(rIdx, 0)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF):
|
||||
r.Type = objabi.R_GOTOFF
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_GOTOFF)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = syms.GOT
|
||||
r.Add += 4
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+4)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
|
||||
r.Type = objabi.R_ADDR
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_ADDR)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(targ.Plt())
|
||||
r.Type = objabi.R_PCREL
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
return true
|
||||
}
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
if targType != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
// turn MOVL of GOT entry into LEAL of symbol itself
|
||||
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
sData := ldr.Data(s)
|
||||
if r.Off() < 2 || sData[r.Off()-2] != 0x8b {
|
||||
ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
|
||||
return false
|
||||
}
|
||||
|
||||
s.P[r.Off-2] = 0x8d
|
||||
r.Type = objabi.R_PCREL
|
||||
su.MakeWritable()
|
||||
writeableData := su.Data()
|
||||
writeableData[r.Off()-2] = 0x8d
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
return true
|
||||
}
|
||||
|
||||
addgotsym(target, syms, targ)
|
||||
r.Sym = syms.GOT
|
||||
r.Add += int64(targ.Got())
|
||||
r.Type = objabi.R_PCREL
|
||||
addgotsym2(target, ldr, syms, targ)
|
||||
su.SetRelocSym(rIdx, syms.GOT2)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
su.SetRelocType(rIdx, objabi.R_PCREL)
|
||||
return true
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
if targType != sym.SDYNIMPORT {
|
||||
return true
|
||||
}
|
||||
switch r.Type {
|
||||
|
||||
// Reread the reloc to incorporate any changes in type above.
|
||||
relocs := ldr.Relocs(s)
|
||||
*r = relocs.At2(rIdx)
|
||||
|
||||
switch r.Type() {
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
if target.IsExternal() {
|
||||
// External linker will do this relocation.
|
||||
return true
|
||||
}
|
||||
addpltsym(target, syms, targ)
|
||||
r.Sym = syms.PLT
|
||||
r.Add = int64(targ.Plt())
|
||||
addpltsym2(target, ldr, syms, targ)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocSym(rIdx, syms.PLT2)
|
||||
su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
|
||||
return true
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type != sym.SDATA {
|
||||
if ldr.SymType(s) != sym.SDATA {
|
||||
break
|
||||
}
|
||||
if target.IsElf() {
|
||||
ld.Adddynsym(target, syms, targ)
|
||||
rel := syms.Rel
|
||||
rel.AddAddrPlus(target.Arch, s, int64(r.Off))
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32)))
|
||||
r.Type = objabi.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
ld.Adddynsym2(ldr, target, syms, targ)
|
||||
rel := ldr.MakeSymbolUpdater(syms.Rel2)
|
||||
rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
|
||||
su.SetRelocSym(rIdx, 0)
|
||||
return true
|
||||
}
|
||||
|
||||
if target.IsDarwin() && s.Size == int64(target.Arch.PtrSize) && r.Off == 0 {
|
||||
if target.IsDarwin() && ldr.SymSize(s) == int64(target.Arch.PtrSize) && r.Off() == 0 {
|
||||
// Mach-O relocations are a royal pain to lay out.
|
||||
// They use a compact stateful bytecode representation
|
||||
// that is too much bother to deal with.
|
||||
|
|
@ -294,18 +322,17 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
// just in case the C code assigns to the variable,
|
||||
// and of course it only works for single pointers,
|
||||
// but we only need to support cgo and that's all it needs.
|
||||
ld.Adddynsym(target, syms, targ)
|
||||
ld.Adddynsym2(ldr, target, syms, targ)
|
||||
|
||||
got := syms.GOT
|
||||
s.Type = got.Type
|
||||
s.Attr |= sym.AttrSubSymbol
|
||||
s.Outer = got
|
||||
s.Sub = got.Sub
|
||||
got.Sub = s
|
||||
s.Value = got.Size
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
su.SetType(got.Type())
|
||||
got.PrependSub(s)
|
||||
su.SetValue(got.Size())
|
||||
got.AddUint32(target.Arch, 0)
|
||||
syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid))
|
||||
r.Type = objabi.ElfRelocOffset // ignore during relocsym
|
||||
leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
|
||||
leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ)))
|
||||
su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -316,7 +343,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.
|
|||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write32(uint32(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
|
@ -452,18 +479,18 @@ func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.S
|
|||
}
|
||||
}
|
||||
|
||||
func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
func addpltsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymPlt(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
|
||||
if target.IsElf() {
|
||||
plt := syms.PLT
|
||||
got := syms.GOTPLT
|
||||
rel := syms.RelPLT
|
||||
if plt.Size == 0 {
|
||||
plt := ldr.MakeSymbolUpdater(syms.PLT2)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOTPLT2)
|
||||
rel := ldr.MakeSymbolUpdater(syms.RelPLT2)
|
||||
if plt.Size() == 0 {
|
||||
panic("plt is not set up")
|
||||
}
|
||||
|
||||
|
|
@ -471,69 +498,73 @@ func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
|||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddAddrPlus(target.Arch, got, got.Size)
|
||||
plt.AddAddrPlus(target.Arch, got.Sym(), got.Size())
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
got.AddAddrPlus(target.Arch, plt, plt.Size)
|
||||
got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
|
||||
|
||||
// pushl $x
|
||||
plt.AddUint8(0x68)
|
||||
|
||||
plt.AddUint32(target.Arch, uint32(rel.Size))
|
||||
plt.AddUint32(target.Arch, uint32(rel.Size()))
|
||||
|
||||
// jmp .plt
|
||||
plt.AddUint8(0xe9)
|
||||
|
||||
plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
|
||||
plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
|
||||
|
||||
// rel
|
||||
rel.AddAddrPlus(target.Arch, got, got.Size-4)
|
||||
rel.AddAddrPlus(target.Arch, got.Sym(), got.Size()-4)
|
||||
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT)))
|
||||
sDynid := ldr.SymDynid(s)
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(sDynid), uint32(elf.R_386_JMP_SLOT)))
|
||||
|
||||
s.SetPlt(int32(plt.Size - 16))
|
||||
ldr.SetPlt(s, int32(plt.Size()-16))
|
||||
} else if target.IsDarwin() {
|
||||
// Same laziness as in 6l.
|
||||
|
||||
plt := syms.PLT
|
||||
plt := ldr.MakeSymbolUpdater(syms.PLT2)
|
||||
|
||||
addgotsym(target, syms, s)
|
||||
addgotsym2(target, ldr, syms, s)
|
||||
|
||||
syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid))
|
||||
sDynid := ldr.SymDynid(s)
|
||||
lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT2)
|
||||
lep.AddUint32(target.Arch, uint32(sDynid))
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
s.SetPlt(int32(plt.Size))
|
||||
ldr.SetPlt(s, int32(plt.Size()))
|
||||
|
||||
plt.AddUint8(0xff)
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddAddrPlus(target.Arch, syms.GOT, int64(s.Got()))
|
||||
plt.AddAddrPlus(target.Arch, syms.GOT2, int64(ldr.SymGot(s)))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
func addgotsym2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
|
||||
if ldr.SymGot(s) >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(target, syms, s)
|
||||
got := syms.GOT
|
||||
s.SetGot(int32(got.Size))
|
||||
ld.Adddynsym2(ldr, target, syms, s)
|
||||
got := ldr.MakeSymbolUpdater(syms.GOT2)
|
||||
ldr.SetGot(s, int32(got.Size()))
|
||||
got.AddUint32(target.Arch, 0)
|
||||
|
||||
if target.IsElf() {
|
||||
rel := syms.Rel
|
||||
rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT)))
|
||||
rel := ldr.MakeSymbolUpdater(syms.Rel2)
|
||||
rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
|
||||
rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_386_GLOB_DAT)))
|
||||
} else if target.IsDarwin() {
|
||||
syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid))
|
||||
leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT2)
|
||||
leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
ldr.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
func asmb(ctxt *ld.Link, _ *loader.Loader) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func Init() (*sys.Arch, ld.Arch) {
|
|||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Adddynrel2: adddynrel2,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
|
|
|
|||
|
|
@ -675,3 +675,61 @@ func TestTrampoline(t *testing.T) {
|
|||
t.Errorf("unexpected output:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndexMismatch(t *testing.T) {
|
||||
// Test that index mismatch will cause a link-time error (not run-time error).
|
||||
// This shouldn't happen with "go build". We invoke the compiler and the linker
|
||||
// manually, and try to "trick" the linker with an inconsistent object file.
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "TestIndexMismatch")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
aSrc := filepath.Join("testdata", "testIndexMismatch", "a.go")
|
||||
bSrc := filepath.Join("testdata", "testIndexMismatch", "b.go")
|
||||
mSrc := filepath.Join("testdata", "testIndexMismatch", "main.go")
|
||||
aObj := filepath.Join(tmpdir, "a.o")
|
||||
mObj := filepath.Join(tmpdir, "main.o")
|
||||
exe := filepath.Join(tmpdir, "main.exe")
|
||||
|
||||
// Build a program with main package importing package a.
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, aSrc)
|
||||
t.Log(cmd)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("compiling a.go failed: %v\n%s", err, out)
|
||||
}
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-I", tmpdir, "-o", mObj, mSrc)
|
||||
t.Log(cmd)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("compiling main.go failed: %v\n%s", err, out)
|
||||
}
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
|
||||
t.Log(cmd)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("linking failed: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
// Now, overwrite a.o with the object of b.go. This should
|
||||
// result in an index mismatch.
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, bSrc)
|
||||
t.Log(cmd)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("compiling a.go failed: %v\n%s", err, out)
|
||||
}
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
|
||||
t.Log(cmd)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Fatalf("linking didn't fail")
|
||||
}
|
||||
if !bytes.Contains(out, []byte("fingerprint mismatch")) {
|
||||
t.Errorf("did not see expected error message. out:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
8
src/cmd/link/testdata/testIndexMismatch/a.go
vendored
Normal file
8
src/cmd/link/testdata/testIndexMismatch/a.go
vendored
Normal 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") }
|
||||
8
src/cmd/link/testdata/testIndexMismatch/b.go
vendored
Normal file
8
src/cmd/link/testdata/testIndexMismatch/b.go
vendored
Normal 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") }
|
||||
9
src/cmd/link/testdata/testIndexMismatch/main.go
vendored
Normal file
9
src/cmd/link/testdata/testIndexMismatch/main.go
vendored
Normal 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() }
|
||||
Loading…
Add table
Add a link
Reference in a new issue