mirror of https://github.com/golang/go.git
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: I57c510b651a39354d78478a9a4499f770eef2eb1
This commit is contained in:
commit
a02349bc9d
|
|
@ -17,6 +17,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -150,6 +151,14 @@ func buildGoobj() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Check that a symbol has a given name, accepting both
|
||||
// new and old objects.
|
||||
// TODO(go115newobj): remove.
|
||||
func matchSymName(symname, want string) bool {
|
||||
return symname == want ||
|
||||
strings.HasPrefix(symname, want+"#") // new style, with index
|
||||
}
|
||||
|
||||
func TestParseGoobj(t *testing.T) {
|
||||
path := go1obj
|
||||
|
||||
|
|
@ -168,7 +177,7 @@ func TestParseGoobj(t *testing.T) {
|
|||
}
|
||||
var found bool
|
||||
for _, s := range p.Syms {
|
||||
if s.Name == "mypkg.go1" {
|
||||
if matchSymName(s.Name, "mypkg.go1") {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
|
@ -197,10 +206,10 @@ func TestParseArchive(t *testing.T) {
|
|||
var found1 bool
|
||||
var found2 bool
|
||||
for _, s := range p.Syms {
|
||||
if s.Name == "mypkg.go1" {
|
||||
if matchSymName(s.Name, "mypkg.go1") {
|
||||
found1 = true
|
||||
}
|
||||
if s.Name == "mypkg.go2" {
|
||||
if matchSymName(s.Name, "mypkg.go2") {
|
||||
found2 = true
|
||||
}
|
||||
}
|
||||
|
|
@ -233,10 +242,10 @@ func TestParseCGOArchive(t *testing.T) {
|
|||
var found1 bool
|
||||
var found2 bool
|
||||
for _, s := range p.Syms {
|
||||
if s.Name == "mycgo.go1" {
|
||||
if matchSymName(s.Name, "mycgo.go1") {
|
||||
found1 = true
|
||||
}
|
||||
if s.Name == "mycgo.go2" {
|
||||
if matchSymName(s.Name, "mycgo.go2") {
|
||||
found2 = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,10 @@ func (r *objReader) readNew() {
|
|||
case goobj2.PkgIdxSelf:
|
||||
i = int(s.SymIdx)
|
||||
default:
|
||||
// Symbol from other package, referenced by index.
|
||||
// We don't know the name. Use index.
|
||||
pkg := pkglist[p]
|
||||
return SymID{fmt.Sprintf("%s.<#%d>", pkg, s.SymIdx), 0}
|
||||
return SymID{fmt.Sprintf("%s.#%d", pkg, s.SymIdx), 0}
|
||||
}
|
||||
sym := rr.Sym(i)
|
||||
return SymID{sym.Name(rr), abiToVer(sym.ABI())}
|
||||
|
|
@ -66,6 +68,7 @@ func (r *objReader) readNew() {
|
|||
// Symbols
|
||||
pcdataBase := start + rr.PcdataBase()
|
||||
n := rr.NSym() + rr.NNonpkgdef() + rr.NNonpkgref()
|
||||
npkgdef := rr.NSym()
|
||||
ndef := rr.NSym() + rr.NNonpkgdef()
|
||||
for i := 0; i < n; i++ {
|
||||
osym := rr.Sym(i)
|
||||
|
|
@ -76,6 +79,10 @@ func (r *objReader) readNew() {
|
|||
// prefix for the package in which the object file has been found.
|
||||
// Expand it.
|
||||
name := strings.ReplaceAll(osym.Name(rr), `"".`, r.pkgprefix)
|
||||
if i < npkgdef {
|
||||
// Indexed symbol. Attach index to the name.
|
||||
name += fmt.Sprintf("#%d", i)
|
||||
}
|
||||
symID := SymID{Name: name, Version: abiToVer(osym.ABI())}
|
||||
r.p.SymRefs = append(r.p.SymRefs, symID)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ var builtins = [...]struct {
|
|||
{"runtime.panicdivide", 1},
|
||||
{"runtime.panicshift", 1},
|
||||
{"runtime.panicmakeslicelen", 1},
|
||||
{"runtime.panicmakeslicecap", 1},
|
||||
{"runtime.throwinit", 1},
|
||||
{"runtime.panicwrap", 1},
|
||||
{"runtime.gopanic", 1},
|
||||
|
|
@ -180,14 +181,26 @@ var builtins = [...]struct {
|
|||
{"runtime.msanwrite", 1},
|
||||
{"runtime.checkptrAlignment", 1},
|
||||
{"runtime.checkptrArithmetic", 1},
|
||||
{"runtime.libfuzzerTraceCmp1", 1},
|
||||
{"runtime.libfuzzerTraceCmp2", 1},
|
||||
{"runtime.libfuzzerTraceCmp4", 1},
|
||||
{"runtime.libfuzzerTraceCmp8", 1},
|
||||
{"runtime.libfuzzerTraceConstCmp1", 1},
|
||||
{"runtime.libfuzzerTraceConstCmp2", 1},
|
||||
{"runtime.libfuzzerTraceConstCmp4", 1},
|
||||
{"runtime.libfuzzerTraceConstCmp8", 1},
|
||||
{"runtime.x86HasPOPCNT", 0},
|
||||
{"runtime.x86HasSSE41", 0},
|
||||
{"runtime.x86HasFMA", 0},
|
||||
{"runtime.armHasVFPv4", 0},
|
||||
{"runtime.arm64HasATOMICS", 0},
|
||||
{"runtime.gcWriteBarrier", 0},
|
||||
{"runtime.deferproc", 1},
|
||||
{"runtime.deferprocStack", 1},
|
||||
{"runtime.deferreturn", 1},
|
||||
{"runtime.newproc", 1},
|
||||
{"runtime.panicoverflow", 1},
|
||||
{"runtime.sigpanic", 1},
|
||||
{"runtime.gcWriteBarrier", 0},
|
||||
{"runtime.morestack", 0},
|
||||
{"runtime.morestackc", 0},
|
||||
{"runtime.morestack_noctxt", 0},
|
||||
|
|
|
|||
|
|
@ -113,11 +113,18 @@ var extra = [...]struct {
|
|||
name string
|
||||
abi int
|
||||
}{
|
||||
{"gcWriteBarrier", 0}, // asm function, ABI0
|
||||
// compiler frontend inserted calls (sysfunc)
|
||||
{"deferproc", 1},
|
||||
{"deferprocStack", 1},
|
||||
{"deferreturn", 1},
|
||||
{"newproc", 1},
|
||||
{"panicoverflow", 1},
|
||||
{"sigpanic", 1},
|
||||
|
||||
// compiler backend inserted calls
|
||||
{"gcWriteBarrier", 0}, // asm function, ABI0
|
||||
|
||||
// assembler backend inserted calls
|
||||
{"morestack", 0}, // asm function, ABI0
|
||||
{"morestackc", 0}, // asm function, ABI0
|
||||
{"morestack_noctxt", 0}, // asm function, ABI0
|
||||
|
|
|
|||
|
|
@ -756,7 +756,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
if ctxt.IsELF {
|
||||
ctxt.Out.SeekSet(symo)
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
|
|
@ -766,13 +765,11 @@ func asmb2(ctxt *ld.Link) {
|
|||
|
||||
case objabi.Hplan9:
|
||||
ld.Asmplan9sym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
|
||||
sym := ctxt.Syms.Lookup("pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
ctxt.Out.Write(sym.P)
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
||||
case objabi.Hwindows:
|
||||
|
|
@ -817,8 +814,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
case objabi.Hwindows:
|
||||
ld.Asmbpe(ctxt)
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
||||
func tlsIEtoLE(s *sym.Symbol, off, size int) {
|
||||
|
|
|
|||
|
|
@ -314,87 +314,7 @@ func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.S
|
|||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
var v uint32
|
||||
|
||||
rs := r.Xsym
|
||||
|
||||
if r.Type == objabi.R_PCREL {
|
||||
if rs.Type == sym.SHOSTOBJ {
|
||||
ld.Errorf(s, "pc-relative relocation of external symbol is not supported")
|
||||
return false
|
||||
}
|
||||
if r.Siz != 4 {
|
||||
return false
|
||||
}
|
||||
|
||||
// emit a pair of "scattered" relocations that
|
||||
// resolve to the difference of section addresses of
|
||||
// the symbol and the instruction
|
||||
// this value is added to the field being relocated
|
||||
o1 := uint32(sectoff)
|
||||
o1 |= 1 << 31 // scattered bit
|
||||
o1 |= ld.MACHO_ARM_RELOC_SECTDIFF << 24
|
||||
o1 |= 2 << 28 // size = 4
|
||||
|
||||
o2 := uint32(0)
|
||||
o2 |= 1 << 31 // scattered bit
|
||||
o2 |= ld.MACHO_ARM_RELOC_PAIR << 24
|
||||
o2 |= 2 << 28 // size = 4
|
||||
|
||||
out.Write32(o1)
|
||||
out.Write32(uint32(ld.Symaddr(rs)))
|
||||
out.Write32(o2)
|
||||
out.Write32(uint32(s.Value + int64(r.Off)))
|
||||
return true
|
||||
}
|
||||
|
||||
if rs.Type == sym.SHOSTOBJ || r.Type == objabi.R_CALLARM {
|
||||
if rs.Dynid < 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
|
||||
v = uint32(rs.Dynid)
|
||||
v |= 1 << 27 // external relocation
|
||||
} else {
|
||||
v = uint32(rs.Sect.Extnum)
|
||||
if v == 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Sect.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
||||
case objabi.R_ADDR:
|
||||
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||
|
||||
case objabi.R_CALLARM:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_ARM_RELOC_BR24 << 28
|
||||
}
|
||||
|
||||
switch r.Siz {
|
||||
default:
|
||||
return false
|
||||
case 1:
|
||||
v |= 0 << 25
|
||||
|
||||
case 2:
|
||||
v |= 1 << 25
|
||||
|
||||
case 4:
|
||||
v |= 2 << 25
|
||||
|
||||
case 8:
|
||||
v |= 3 << 25
|
||||
}
|
||||
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32(v)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
|
|
@ -816,7 +736,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
default:
|
||||
if ctxt.IsELF {
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
|
|
@ -826,13 +745,11 @@ func asmb2(ctxt *ld.Link) {
|
|||
|
||||
case objabi.Hplan9:
|
||||
ld.Asmplan9sym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
|
||||
sym := ctxt.Syms.Lookup("pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
ctxt.Out.Write(sym.P)
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
||||
case objabi.Hwindows:
|
||||
|
|
@ -863,7 +780,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
ld.Asmbpe(ctxt)
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
if *ld.FlagC {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||
|
|
|
|||
|
|
@ -866,7 +866,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
default:
|
||||
if ctxt.IsELF {
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
|
|
@ -876,13 +875,11 @@ func asmb2(ctxt *ld.Link) {
|
|||
|
||||
case objabi.Hplan9:
|
||||
ld.Asmplan9sym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
|
||||
sym := ctxt.Syms.Lookup("pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
ctxt.Out.Write(sym.P)
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
||||
case objabi.Hdarwin:
|
||||
|
|
@ -915,7 +912,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
ld.Asmbmacho(ctxt)
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
if *ld.FlagC {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,13 +1,218 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Copyright 2019 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 (
|
||||
"bytes"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
type workQueue []loader.Sym
|
||||
|
||||
// Implement container/heap.Interface.
|
||||
func (q *workQueue) Len() int { return len(*q) }
|
||||
func (q *workQueue) Less(i, j int) bool { return (*q)[i] < (*q)[j] }
|
||||
func (q *workQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
|
||||
func (q *workQueue) Push(i interface{}) { *q = append(*q, i.(loader.Sym)) }
|
||||
func (q *workQueue) Pop() interface{} { i := (*q)[len(*q)-1]; *q = (*q)[:len(*q)-1]; return i }
|
||||
|
||||
// Functions for deadcode pass to use.
|
||||
// Deadcode pass should call push/pop, not Push/Pop.
|
||||
func (q *workQueue) push(i loader.Sym) { heap.Push(q, i) }
|
||||
func (q *workQueue) pop() loader.Sym { return heap.Pop(q).(loader.Sym) }
|
||||
func (q *workQueue) empty() bool { return len(*q) == 0 }
|
||||
|
||||
type deadcodePass struct {
|
||||
ctxt *Link
|
||||
ldr *loader.Loader
|
||||
wq workQueue
|
||||
|
||||
ifaceMethod map[methodsig]bool // methods declared in reached interfaces
|
||||
markableMethods []methodref2 // methods of reached types
|
||||
reflectSeen bool // whether we have seen a reflect method call
|
||||
}
|
||||
|
||||
func (d *deadcodePass) init() {
|
||||
d.ldr.InitReachable()
|
||||
d.ifaceMethod = make(map[methodsig]bool)
|
||||
if objabi.Fieldtrack_enabled != 0 {
|
||||
d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym())
|
||||
}
|
||||
heap.Init(&d.wq)
|
||||
|
||||
if d.ctxt.BuildMode == BuildModeShared {
|
||||
// Mark all symbols defined in this library as reachable when
|
||||
// building a shared library.
|
||||
n := d.ldr.NDef()
|
||||
for i := 1; i < n; i++ {
|
||||
s := loader.Sym(i)
|
||||
d.mark(s, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var names []string
|
||||
|
||||
// In a normal binary, start at main.main and the init
|
||||
// functions and mark what is reachable from there.
|
||||
if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
|
||||
names = append(names, "main.main", "main..inittask")
|
||||
} else {
|
||||
// The external linker refers main symbol directly.
|
||||
if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
|
||||
if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 {
|
||||
*flagEntrySymbol = "_main"
|
||||
} else {
|
||||
*flagEntrySymbol = "main"
|
||||
}
|
||||
}
|
||||
names = append(names, *flagEntrySymbol)
|
||||
if d.ctxt.BuildMode == BuildModePlugin {
|
||||
names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
|
||||
|
||||
// We don't keep the go.plugin.exports symbol,
|
||||
// but we do keep the symbols it refers to.
|
||||
exportsIdx := d.ldr.Lookup("go.plugin.exports", 0)
|
||||
if exportsIdx != 0 {
|
||||
relocs := d.ldr.Relocs(exportsIdx)
|
||||
for i := 0; i < relocs.Count(); i++ {
|
||||
d.mark(relocs.At2(i).Sym(), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynexpMap := d.ctxt.cgo_export_dynamic
|
||||
if d.ctxt.LinkMode == LinkExternal {
|
||||
dynexpMap = d.ctxt.cgo_export_static
|
||||
}
|
||||
for exp := range dynexpMap {
|
||||
names = append(names, exp)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
// Mark symbol as a data/ABI0 symbol.
|
||||
d.mark(d.ldr.Lookup(name, 0), 0)
|
||||
// Also mark any Go functions (internal ABI).
|
||||
d.mark(d.ldr.Lookup(name, sym.SymVerABIInternal), 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deadcodePass) flood() {
|
||||
for !d.wq.empty() {
|
||||
symIdx := d.wq.pop()
|
||||
|
||||
d.reflectSeen = d.reflectSeen || d.ldr.IsReflectMethod(symIdx)
|
||||
|
||||
isgotype := d.ldr.IsGoType(symIdx)
|
||||
relocs := d.ldr.Relocs(symIdx)
|
||||
|
||||
if isgotype {
|
||||
p := d.ldr.Data(symIdx)
|
||||
if len(p) != 0 && decodetypeKind(d.ctxt.Arch, p)&kindMask == kindInterface {
|
||||
for _, sig := range d.decodeIfaceMethods2(d.ldr, d.ctxt.Arch, symIdx, &relocs) {
|
||||
if d.ctxt.Debugvlog > 1 {
|
||||
d.ctxt.Logf("reached iface method: %s\n", sig)
|
||||
}
|
||||
d.ifaceMethod[sig] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var methods []methodref2
|
||||
for i := 0; i < relocs.Count(); i++ {
|
||||
r := relocs.At2(i)
|
||||
t := r.Type()
|
||||
if t == objabi.R_WEAKADDROFF {
|
||||
continue
|
||||
}
|
||||
if t == objabi.R_METHODOFF {
|
||||
if i+2 >= relocs.Count() {
|
||||
panic("expect three consecutive R_METHODOFF relocs")
|
||||
}
|
||||
methods = append(methods, methodref2{src: symIdx, r: i})
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
if t == objabi.R_USETYPE {
|
||||
// type symbol used for DWARF. we need to load the symbol but it may not
|
||||
// be otherwise reachable in the program.
|
||||
// do nothing for now as we still load all type symbols.
|
||||
continue
|
||||
}
|
||||
d.mark(r.Sym(), symIdx)
|
||||
}
|
||||
naux := d.ldr.NAux(symIdx)
|
||||
for i := 0; i < naux; i++ {
|
||||
d.mark(d.ldr.Aux2(symIdx, i).Sym(), symIdx)
|
||||
}
|
||||
// Some host object symbols have an outer object, which acts like a
|
||||
// "carrier" symbol, or it holds all the symbols for a particular
|
||||
// section. We need to mark all "referenced" symbols from that carrier,
|
||||
// so we make sure we're pulling in all outer symbols, and their sub
|
||||
// symbols. This is not ideal, and these carrier/section symbols could
|
||||
// be removed.
|
||||
if d.ldr.IsExternal(symIdx) {
|
||||
d.mark(d.ldr.OuterSym(symIdx), symIdx)
|
||||
d.mark(d.ldr.SubSym(symIdx), symIdx)
|
||||
}
|
||||
|
||||
if len(methods) != 0 {
|
||||
if !isgotype {
|
||||
panic("method found on non-type symbol")
|
||||
}
|
||||
// Decode runtime type information for type methods
|
||||
// to help work out which methods can be called
|
||||
// dynamically via interfaces.
|
||||
methodsigs := d.decodetypeMethods2(d.ldr, d.ctxt.Arch, symIdx, &relocs)
|
||||
if len(methods) != len(methodsigs) {
|
||||
panic(fmt.Sprintf("%q has %d method relocations for %d methods", d.ldr.SymName(symIdx), len(methods), len(methodsigs)))
|
||||
}
|
||||
for i, m := range methodsigs {
|
||||
methods[i].m = m
|
||||
}
|
||||
d.markableMethods = append(d.markableMethods, methods...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deadcodePass) mark(symIdx, parent loader.Sym) {
|
||||
if symIdx != 0 && !d.ldr.AttrReachable(symIdx) {
|
||||
d.wq.push(symIdx)
|
||||
d.ldr.SetAttrReachable(symIdx, true)
|
||||
if objabi.Fieldtrack_enabled != 0 {
|
||||
d.ldr.Reachparent[symIdx] = parent
|
||||
}
|
||||
if *flagDumpDep {
|
||||
to := d.ldr.SymName(symIdx)
|
||||
if to != "" {
|
||||
from := "_"
|
||||
if parent != 0 {
|
||||
from = d.ldr.SymName(parent)
|
||||
}
|
||||
fmt.Printf("%s -> %s\n", from, to)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deadcodePass) markMethod(m methodref2) {
|
||||
relocs := d.ldr.Relocs(m.src)
|
||||
d.mark(relocs.At2(m.r).Sym(), m.src)
|
||||
d.mark(relocs.At2(m.r+1).Sym(), m.src)
|
||||
d.mark(relocs.At2(m.r+2).Sym(), m.src)
|
||||
}
|
||||
|
||||
// deadcode marks all reachable symbols.
|
||||
//
|
||||
// The basis of the dead code elimination is a flood fill of symbols,
|
||||
|
|
@ -42,24 +247,173 @@ import (
|
|||
//
|
||||
// Any unreached text symbols are removed from ctxt.Textp.
|
||||
func deadcode(ctxt *Link) {
|
||||
deadcode2(ctxt)
|
||||
ldr := ctxt.loader
|
||||
d := deadcodePass{ctxt: ctxt, ldr: ldr}
|
||||
d.init()
|
||||
d.flood()
|
||||
|
||||
methSym := ldr.Lookup("reflect.Value.Method", sym.SymVerABIInternal)
|
||||
methByNameSym := ldr.Lookup("reflect.Value.MethodByName", sym.SymVerABIInternal)
|
||||
|
||||
if ctxt.DynlinkingGo() {
|
||||
// Exported methods may satisfy interfaces we don't know
|
||||
// about yet when dynamically linking.
|
||||
d.reflectSeen = true
|
||||
}
|
||||
|
||||
for {
|
||||
// Methods might be called via reflection. Give up on
|
||||
// static analysis, mark all exported methods of
|
||||
// all reachable types as reachable.
|
||||
d.reflectSeen = d.reflectSeen || (methSym != 0 && ldr.AttrReachable(methSym)) || (methByNameSym != 0 && ldr.AttrReachable(methByNameSym))
|
||||
|
||||
// Mark all methods that could satisfy a discovered
|
||||
// interface as reachable. We recheck old marked interfaces
|
||||
// as new types (with new methods) may have been discovered
|
||||
// in the last pass.
|
||||
rem := d.markableMethods[:0]
|
||||
for _, m := range d.markableMethods {
|
||||
if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
|
||||
d.markMethod(m)
|
||||
} else {
|
||||
rem = append(rem, m)
|
||||
}
|
||||
}
|
||||
d.markableMethods = rem
|
||||
|
||||
if d.wq.empty() {
|
||||
// No new work was discovered. Done.
|
||||
break
|
||||
}
|
||||
d.flood()
|
||||
}
|
||||
|
||||
n := ldr.NSym()
|
||||
|
||||
if ctxt.BuildMode != BuildModeShared {
|
||||
// Keep a itablink if the symbol it points at is being kept.
|
||||
// (When BuildModeShared, always keep itablinks.)
|
||||
for i := 1; i < n; i++ {
|
||||
s := loader.Sym(i)
|
||||
if ldr.IsItabLink(s) {
|
||||
relocs := ldr.Relocs(s)
|
||||
if relocs.Count() > 0 && ldr.AttrReachable(relocs.At2(0).Sym()) {
|
||||
ldr.SetAttrReachable(s, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// addToTextp populates the context Textp slice (needed in various places
|
||||
// in the linker).
|
||||
func addToTextp(ctxt *Link) {
|
||||
// Set up ctxt.Textp, based on ctxt.Textp2.
|
||||
textp := make([]*sym.Symbol, 0, len(ctxt.Textp2))
|
||||
haveshlibs := len(ctxt.Shlibs) > 0
|
||||
for _, tsym := range ctxt.Textp2 {
|
||||
sp := ctxt.loader.Syms[tsym]
|
||||
if sp == nil || !ctxt.loader.AttrReachable(tsym) {
|
||||
panic("should never happen")
|
||||
}
|
||||
if haveshlibs && sp.Type == sym.SDYNIMPORT {
|
||||
continue
|
||||
}
|
||||
textp = append(textp, sp)
|
||||
}
|
||||
ctxt.Textp = textp
|
||||
// methodref2 holds the relocations from a receiver type symbol to its
|
||||
// method. There are three relocations, one for each of the fields in
|
||||
// the reflect.method struct: mtyp, ifn, and tfn.
|
||||
type methodref2 struct {
|
||||
m methodsig
|
||||
src loader.Sym // receiver type symbol
|
||||
r int // the index of R_METHODOFF relocations
|
||||
}
|
||||
|
||||
func (m methodref2) isExported() bool {
|
||||
for _, r := range m.m {
|
||||
return unicode.IsUpper(r)
|
||||
}
|
||||
panic("methodref has no signature")
|
||||
}
|
||||
|
||||
// decodeMethodSig2 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 (d *deadcodePass) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, off, size, count int) []methodsig {
|
||||
var buf bytes.Buffer
|
||||
var methods []methodsig
|
||||
for i := 0; i < count; i++ {
|
||||
buf.WriteString(decodetypeName2(ldr, symIdx, relocs, off))
|
||||
mtypSym := decodeRelocSym2(ldr, symIdx, relocs, int32(off+4))
|
||||
// FIXME: add some sort of caching here, since we may see some of the
|
||||
// same symbols over time for param types.
|
||||
mrelocs := ldr.Relocs(mtypSym)
|
||||
mp := ldr.Data(mtypSym)
|
||||
|
||||
buf.WriteRune('(')
|
||||
inCount := decodetypeFuncInCount(arch, mp)
|
||||
for i := 0; i < inCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
a := decodetypeFuncInType2(ldr, arch, mtypSym, &mrelocs, i)
|
||||
buf.WriteString(ldr.SymName(a))
|
||||
}
|
||||
buf.WriteString(") (")
|
||||
outCount := decodetypeFuncOutCount(arch, mp)
|
||||
for i := 0; i < outCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
a := decodetypeFuncOutType2(ldr, arch, mtypSym, &mrelocs, i)
|
||||
buf.WriteString(ldr.SymName(a))
|
||||
}
|
||||
buf.WriteRune(')')
|
||||
|
||||
off += size
|
||||
methods = append(methods, methodsig(buf.String()))
|
||||
buf.Reset()
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
func (d *deadcodePass) decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
|
||||
p := ldr.Data(symIdx)
|
||||
if decodetypeKind(arch, p)&kindMask != kindInterface {
|
||||
panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx)))
|
||||
}
|
||||
rel := decodeReloc2(ldr, symIdx, relocs, int32(commonsize(arch)+arch.PtrSize))
|
||||
s := rel.Sym()
|
||||
if s == 0 {
|
||||
return nil
|
||||
}
|
||||
if s != symIdx {
|
||||
panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", ldr.SymName(symIdx)))
|
||||
}
|
||||
off := int(rel.Add()) // array of reflect.imethod values
|
||||
numMethods := int(decodetypeIfaceMethodCount(arch, p))
|
||||
sizeofIMethod := 4 + 4
|
||||
return d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofIMethod, numMethods)
|
||||
}
|
||||
|
||||
func (d *deadcodePass) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
|
||||
p := ldr.Data(symIdx)
|
||||
if !decodetypeHasUncommon(arch, p) {
|
||||
panic(fmt.Sprintf("no methods on %q", ldr.SymName(symIdx)))
|
||||
}
|
||||
off := commonsize(arch) // reflect.rtype
|
||||
switch decodetypeKind(arch, 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, p[off+4:], 2))
|
||||
moff := int(decodeInuxi(arch, 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 d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofMethod, mcount)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,385 +0,0 @@
|
|||
// Copyright 2019 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 (
|
||||
"bytes"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
type workQueue []loader.Sym
|
||||
|
||||
// Implement container/heap.Interface.
|
||||
func (q *workQueue) Len() int { return len(*q) }
|
||||
func (q *workQueue) Less(i, j int) bool { return (*q)[i] < (*q)[j] }
|
||||
func (q *workQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
|
||||
func (q *workQueue) Push(i interface{}) { *q = append(*q, i.(loader.Sym)) }
|
||||
func (q *workQueue) Pop() interface{} { i := (*q)[len(*q)-1]; *q = (*q)[:len(*q)-1]; return i }
|
||||
|
||||
// Functions for deadcode pass to use.
|
||||
// Deadcode pass should call push/pop, not Push/Pop.
|
||||
func (q *workQueue) push(i loader.Sym) { heap.Push(q, i) }
|
||||
func (q *workQueue) pop() loader.Sym { return heap.Pop(q).(loader.Sym) }
|
||||
func (q *workQueue) empty() bool { return len(*q) == 0 }
|
||||
|
||||
type deadcodePass2 struct {
|
||||
ctxt *Link
|
||||
ldr *loader.Loader
|
||||
wq workQueue
|
||||
|
||||
ifaceMethod map[methodsig]bool // methods declared in reached interfaces
|
||||
markableMethods []methodref2 // methods of reached types
|
||||
reflectSeen bool // whether we have seen a reflect method call
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) init() {
|
||||
d.ldr.InitReachable()
|
||||
d.ifaceMethod = make(map[methodsig]bool)
|
||||
if d.ctxt.Reachparent != nil {
|
||||
d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym())
|
||||
}
|
||||
heap.Init(&d.wq)
|
||||
|
||||
if d.ctxt.BuildMode == BuildModeShared {
|
||||
// Mark all symbols defined in this library as reachable when
|
||||
// building a shared library.
|
||||
n := d.ldr.NDef()
|
||||
for i := 1; i < n; i++ {
|
||||
s := loader.Sym(i)
|
||||
d.mark(s, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var names []string
|
||||
|
||||
// In a normal binary, start at main.main and the init
|
||||
// functions and mark what is reachable from there.
|
||||
if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
|
||||
names = append(names, "main.main", "main..inittask")
|
||||
} else {
|
||||
// The external linker refers main symbol directly.
|
||||
if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
|
||||
if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 {
|
||||
*flagEntrySymbol = "_main"
|
||||
} else {
|
||||
*flagEntrySymbol = "main"
|
||||
}
|
||||
}
|
||||
names = append(names, *flagEntrySymbol)
|
||||
if d.ctxt.BuildMode == BuildModePlugin {
|
||||
names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
|
||||
|
||||
// We don't keep the go.plugin.exports symbol,
|
||||
// but we do keep the symbols it refers to.
|
||||
exportsIdx := d.ldr.Lookup("go.plugin.exports", 0)
|
||||
if exportsIdx != 0 {
|
||||
relocs := d.ldr.Relocs(exportsIdx)
|
||||
for i := 0; i < relocs.Count(); i++ {
|
||||
d.mark(relocs.At2(i).Sym(), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynexpMap := d.ctxt.cgo_export_dynamic
|
||||
if d.ctxt.LinkMode == LinkExternal {
|
||||
dynexpMap = d.ctxt.cgo_export_static
|
||||
}
|
||||
for exp := range dynexpMap {
|
||||
names = append(names, exp)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
// Mark symbol as a data/ABI0 symbol.
|
||||
d.mark(d.ldr.Lookup(name, 0), 0)
|
||||
// Also mark any Go functions (internal ABI).
|
||||
d.mark(d.ldr.Lookup(name, sym.SymVerABIInternal), 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) flood() {
|
||||
for !d.wq.empty() {
|
||||
symIdx := d.wq.pop()
|
||||
|
||||
d.reflectSeen = d.reflectSeen || d.ldr.IsReflectMethod(symIdx)
|
||||
|
||||
isgotype := d.ldr.IsGoType(symIdx)
|
||||
relocs := d.ldr.Relocs(symIdx)
|
||||
|
||||
if isgotype {
|
||||
p := d.ldr.Data(symIdx)
|
||||
if len(p) != 0 && decodetypeKind(d.ctxt.Arch, p)&kindMask == kindInterface {
|
||||
for _, sig := range d.decodeIfaceMethods2(d.ldr, d.ctxt.Arch, symIdx, &relocs) {
|
||||
if d.ctxt.Debugvlog > 1 {
|
||||
d.ctxt.Logf("reached iface method: %s\n", sig)
|
||||
}
|
||||
d.ifaceMethod[sig] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var methods []methodref2
|
||||
for i := 0; i < relocs.Count(); i++ {
|
||||
r := relocs.At2(i)
|
||||
t := r.Type()
|
||||
if t == objabi.R_WEAKADDROFF {
|
||||
continue
|
||||
}
|
||||
if t == objabi.R_METHODOFF {
|
||||
if i+2 >= relocs.Count() {
|
||||
panic("expect three consecutive R_METHODOFF relocs")
|
||||
}
|
||||
methods = append(methods, methodref2{src: symIdx, r: i})
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
if t == objabi.R_USETYPE {
|
||||
// type symbol used for DWARF. we need to load the symbol but it may not
|
||||
// be otherwise reachable in the program.
|
||||
// do nothing for now as we still load all type symbols.
|
||||
continue
|
||||
}
|
||||
d.mark(r.Sym(), symIdx)
|
||||
}
|
||||
naux := d.ldr.NAux(symIdx)
|
||||
for i := 0; i < naux; i++ {
|
||||
d.mark(d.ldr.Aux2(symIdx, i).Sym(), symIdx)
|
||||
}
|
||||
// Some host object symbols have an outer object, which acts like a
|
||||
// "carrier" symbol, or it holds all the symbols for a particular
|
||||
// section. We need to mark all "referenced" symbols from that carrier,
|
||||
// so we make sure we're pulling in all outer symbols, and their sub
|
||||
// symbols. This is not ideal, and these carrier/section symbols could
|
||||
// be removed.
|
||||
if d.ldr.IsExternal(symIdx) {
|
||||
d.mark(d.ldr.OuterSym(symIdx), symIdx)
|
||||
d.mark(d.ldr.SubSym(symIdx), symIdx)
|
||||
}
|
||||
|
||||
if len(methods) != 0 {
|
||||
if !isgotype {
|
||||
panic("method found on non-type symbol")
|
||||
}
|
||||
// Decode runtime type information for type methods
|
||||
// to help work out which methods can be called
|
||||
// dynamically via interfaces.
|
||||
methodsigs := d.decodetypeMethods2(d.ldr, d.ctxt.Arch, symIdx, &relocs)
|
||||
if len(methods) != len(methodsigs) {
|
||||
panic(fmt.Sprintf("%q has %d method relocations for %d methods", d.ldr.SymName(symIdx), len(methods), len(methodsigs)))
|
||||
}
|
||||
for i, m := range methodsigs {
|
||||
methods[i].m = m
|
||||
}
|
||||
d.markableMethods = append(d.markableMethods, methods...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) mark(symIdx, parent loader.Sym) {
|
||||
if symIdx != 0 && !d.ldr.AttrReachable(symIdx) {
|
||||
d.wq.push(symIdx)
|
||||
d.ldr.SetAttrReachable(symIdx, true)
|
||||
if d.ctxt.Reachparent != nil {
|
||||
d.ldr.Reachparent[symIdx] = parent
|
||||
}
|
||||
if *flagDumpDep {
|
||||
to := d.ldr.SymName(symIdx)
|
||||
if to != "" {
|
||||
from := "_"
|
||||
if parent != 0 {
|
||||
from = d.ldr.SymName(parent)
|
||||
}
|
||||
fmt.Printf("%s -> %s\n", from, to)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) markMethod(m methodref2) {
|
||||
relocs := d.ldr.Relocs(m.src)
|
||||
d.mark(relocs.At2(m.r).Sym(), m.src)
|
||||
d.mark(relocs.At2(m.r+1).Sym(), m.src)
|
||||
d.mark(relocs.At2(m.r+2).Sym(), m.src)
|
||||
}
|
||||
|
||||
func deadcode2(ctxt *Link) {
|
||||
ldr := ctxt.loader
|
||||
d := deadcodePass2{ctxt: ctxt, ldr: ldr}
|
||||
d.init()
|
||||
d.flood()
|
||||
|
||||
methSym := ldr.Lookup("reflect.Value.Method", sym.SymVerABIInternal)
|
||||
methByNameSym := ldr.Lookup("reflect.Value.MethodByName", sym.SymVerABIInternal)
|
||||
if ctxt.DynlinkingGo() {
|
||||
// Exported methods may satisfy interfaces we don't know
|
||||
// about yet when dynamically linking.
|
||||
d.reflectSeen = true
|
||||
}
|
||||
|
||||
for {
|
||||
// Methods might be called via reflection. Give up on
|
||||
// static analysis, mark all exported methods of
|
||||
// all reachable types as reachable.
|
||||
d.reflectSeen = d.reflectSeen || (methSym != 0 && ldr.AttrReachable(methSym)) || (methByNameSym != 0 && ldr.AttrReachable(methByNameSym))
|
||||
|
||||
// Mark all methods that could satisfy a discovered
|
||||
// interface as reachable. We recheck old marked interfaces
|
||||
// as new types (with new methods) may have been discovered
|
||||
// in the last pass.
|
||||
rem := d.markableMethods[:0]
|
||||
for _, m := range d.markableMethods {
|
||||
if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
|
||||
d.markMethod(m)
|
||||
} else {
|
||||
rem = append(rem, m)
|
||||
}
|
||||
}
|
||||
d.markableMethods = rem
|
||||
|
||||
if d.wq.empty() {
|
||||
// No new work was discovered. Done.
|
||||
break
|
||||
}
|
||||
d.flood()
|
||||
}
|
||||
|
||||
n := ldr.NSym()
|
||||
|
||||
if ctxt.BuildMode != BuildModeShared {
|
||||
// Keep a itablink if the symbol it points at is being kept.
|
||||
// (When BuildModeShared, always keep itablinks.)
|
||||
for i := 1; i < n; i++ {
|
||||
s := loader.Sym(i)
|
||||
if ldr.IsItabLink(s) {
|
||||
relocs := ldr.Relocs(s)
|
||||
if relocs.Count() > 0 && ldr.AttrReachable(relocs.At2(0).Sym()) {
|
||||
ldr.SetAttrReachable(s, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// methodref2 holds the relocations from a receiver type symbol to its
|
||||
// method. There are three relocations, one for each of the fields in
|
||||
// the reflect.method struct: mtyp, ifn, and tfn.
|
||||
type methodref2 struct {
|
||||
m methodsig
|
||||
src loader.Sym // receiver type symbol
|
||||
r int // the index of R_METHODOFF relocations
|
||||
}
|
||||
|
||||
func (m methodref2) isExported() bool {
|
||||
for _, r := range m.m {
|
||||
return unicode.IsUpper(r)
|
||||
}
|
||||
panic("methodref has no signature")
|
||||
}
|
||||
|
||||
// decodeMethodSig2 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 (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, off, size, count int) []methodsig {
|
||||
var buf bytes.Buffer
|
||||
var methods []methodsig
|
||||
for i := 0; i < count; i++ {
|
||||
buf.WriteString(decodetypeName2(ldr, symIdx, relocs, off))
|
||||
mtypSym := decodeRelocSym2(ldr, symIdx, relocs, int32(off+4))
|
||||
// FIXME: add some sort of caching here, since we may see some of the
|
||||
// same symbols over time for param types.
|
||||
mrelocs := ldr.Relocs(mtypSym)
|
||||
mp := ldr.Data(mtypSym)
|
||||
|
||||
buf.WriteRune('(')
|
||||
inCount := decodetypeFuncInCount(arch, mp)
|
||||
for i := 0; i < inCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
a := decodetypeFuncInType2(ldr, arch, mtypSym, &mrelocs, i)
|
||||
buf.WriteString(ldr.SymName(a))
|
||||
}
|
||||
buf.WriteString(") (")
|
||||
outCount := decodetypeFuncOutCount(arch, mp)
|
||||
for i := 0; i < outCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
a := decodetypeFuncOutType2(ldr, arch, mtypSym, &mrelocs, i)
|
||||
buf.WriteString(ldr.SymName(a))
|
||||
}
|
||||
buf.WriteRune(')')
|
||||
|
||||
off += size
|
||||
methods = append(methods, methodsig(buf.String()))
|
||||
buf.Reset()
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
|
||||
p := ldr.Data(symIdx)
|
||||
if decodetypeKind(arch, p)&kindMask != kindInterface {
|
||||
panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx)))
|
||||
}
|
||||
rel := decodeReloc2(ldr, symIdx, relocs, int32(commonsize(arch)+arch.PtrSize))
|
||||
s := rel.Sym()
|
||||
if s == 0 {
|
||||
return nil
|
||||
}
|
||||
if s != symIdx {
|
||||
panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", ldr.SymName(symIdx)))
|
||||
}
|
||||
off := int(rel.Add()) // array of reflect.imethod values
|
||||
numMethods := int(decodetypeIfaceMethodCount(arch, p))
|
||||
sizeofIMethod := 4 + 4
|
||||
return d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofIMethod, numMethods)
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
|
||||
p := ldr.Data(symIdx)
|
||||
if !decodetypeHasUncommon(arch, p) {
|
||||
panic(fmt.Sprintf("no methods on %q", ldr.SymName(symIdx)))
|
||||
}
|
||||
off := commonsize(arch) // reflect.rtype
|
||||
switch decodetypeKind(arch, 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, p[off+4:], 2))
|
||||
moff := int(decodeInuxi(arch, 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 d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofMethod, mcount)
|
||||
}
|
||||
|
|
@ -106,7 +106,7 @@ func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
|
|||
// Type.commonType.gc
|
||||
func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte {
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
addr := decodetypeGcprogShlib(ctxt, s)
|
||||
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
|
||||
|
|
@ -123,16 +123,16 @@ func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte {
|
|||
return decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)).P
|
||||
}
|
||||
|
||||
func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 {
|
||||
func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
|
||||
if ctxt.Arch.Family == sys.ARM64 {
|
||||
return 0
|
||||
}
|
||||
return decodeInuxi(ctxt.Arch, s.P[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
|
||||
return decodeInuxi(ctxt.Arch, data[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
|
||||
}
|
||||
|
||||
func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
addr := decodetypeGcprogShlib(ctxt, s)
|
||||
addr := decodetypeGcprogShlib(ctxt, s.P)
|
||||
ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
|
||||
sect := findShlibSection(ctxt, s.File, addr)
|
||||
if sect != nil {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package ld
|
|||
import (
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
)
|
||||
|
||||
// This file contains utilities to decode type.* symbols, for
|
||||
|
|
@ -129,3 +130,45 @@ func decodetypeStr2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) strin
|
|||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func decodetypeGcmask2(ctxt *Link, s loader.Sym) []byte {
|
||||
if ctxt.loader.SymType(s) == sym.SDYNIMPORT {
|
||||
symData := ctxt.loader.Data(s)
|
||||
addr := decodetypeGcprogShlib(ctxt, symData)
|
||||
ptrdata := decodetypePtrdata(ctxt.Arch, symData)
|
||||
sect := findShlibSection(ctxt, ctxt.loader.SymPkg(s), 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", ctxt.loader.SymName(s))
|
||||
return nil
|
||||
}
|
||||
relocs := ctxt.loader.Relocs(s)
|
||||
mask := decodeRelocSym2(ctxt.loader, s, &relocs, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
|
||||
return ctxt.loader.Data(mask)
|
||||
}
|
||||
|
||||
// Type.commonType.gc
|
||||
func decodetypeGcprog2(ctxt *Link, s loader.Sym) []byte {
|
||||
if ctxt.loader.SymType(s) == sym.SDYNIMPORT {
|
||||
symData := ctxt.loader.Data(s)
|
||||
addr := decodetypeGcprogShlib(ctxt, symData)
|
||||
sect := findShlibSection(ctxt, ctxt.loader.SymPkg(s), 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 gcmask for %s", ctxt.loader.SymName(s))
|
||||
return nil
|
||||
}
|
||||
relocs := ctxt.loader.Relocs(s)
|
||||
rs := decodeRelocSym2(ctxt.loader, s, &relocs, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
|
||||
return ctxt.loader.Data(rs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,14 +177,46 @@ func (c dwctxt2) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets [
|
|||
|
||||
var gdbscript string
|
||||
|
||||
var dwarfp2 []loader.Sym
|
||||
// dwarfSecInfo holds information about a DWARF output section,
|
||||
// specifically a section symbol and a list of symbols contained in
|
||||
// that section. On the syms list, the first symbol will always be the
|
||||
// section symbol, then any remaining symbols (if any) will be
|
||||
// sub-symbols in that section. Note that for some sections (eg:
|
||||
// .debug_abbrev), the section symbol is all there is (all content is
|
||||
// contained in it). For other sections (eg: .debug_info), the section
|
||||
// symbol is empty and all the content is in the sub-symbols. Finally
|
||||
// there are some sections (eg: .debug_ranges) where it is a mix (both
|
||||
// the section symbol and the sub-symbols have content)
|
||||
type dwarfSecInfo struct {
|
||||
syms []loader.Sym
|
||||
}
|
||||
|
||||
func (d *dwctxt2) writeabbrev() loader.Sym {
|
||||
// secSym returns the section symbol for the section.
|
||||
func (dsi *dwarfSecInfo) secSym() loader.Sym {
|
||||
if len(dsi.syms) == 0 {
|
||||
return 0
|
||||
}
|
||||
return dsi.syms[0]
|
||||
}
|
||||
|
||||
// subSyms returns a list of sub-symbols for the section.
|
||||
func (dsi *dwarfSecInfo) subSyms() []loader.Sym {
|
||||
if len(dsi.syms) == 0 {
|
||||
return []loader.Sym{}
|
||||
}
|
||||
return dsi.syms[1:]
|
||||
}
|
||||
|
||||
// dwarfp2 stores the collected DWARF symbols created during
|
||||
// dwarf generation.
|
||||
var dwarfp2 []dwarfSecInfo
|
||||
|
||||
func (d *dwctxt2) writeabbrev() dwarfSecInfo {
|
||||
abrvs := d.ldr.LookupOrCreateSym(".debug_abbrev", 0)
|
||||
u := d.ldr.MakeSymbolUpdater(abrvs)
|
||||
u.SetType(sym.SDWARFSECT)
|
||||
u.AddBytes(dwarf.GetAbbrev())
|
||||
return abrvs
|
||||
return dwarfSecInfo{syms: []loader.Sym{abrvs}}
|
||||
}
|
||||
|
||||
var dwtypes dwarf.DWDie
|
||||
|
|
@ -1140,6 +1172,9 @@ func (d *dwctxt2) writelines(unit *sym.CompilationUnit, ls loader.Sym) {
|
|||
lsu := d.ldr.MakeSymbolUpdater(ls)
|
||||
newattr(unit.DWInfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, lsu.Size(), dwSym(ls))
|
||||
|
||||
internalExec := d.linkctxt.BuildMode == BuildModeExe && d.linkctxt.IsInternal()
|
||||
addAddrPlus := loader.GenAddAddrPlusFunc(internalExec)
|
||||
|
||||
// Write .debug_line Line Number Program Header (sec 6.2.4)
|
||||
// Fields marked with (*) must be changed for 64-bit dwarf
|
||||
unitLengthOffset := lsu.Size()
|
||||
|
|
@ -1209,7 +1244,7 @@ func (d *dwctxt2) writelines(unit *sym.CompilationUnit, ls loader.Sym) {
|
|||
lsu.AddUint8(0)
|
||||
dwarf.Uleb128put(d, lsDwsym, 1+int64(d.arch.PtrSize))
|
||||
lsu.AddUint8(dwarf.DW_LNE_set_address)
|
||||
addr := lsu.AddAddrPlus(d.arch, fnSym, 0)
|
||||
addr := addAddrPlus(lsu, d.arch, fnSym, 0)
|
||||
// Make sure the units are sorted.
|
||||
if addr < lastAddr {
|
||||
d.linkctxt.Errorf(fnSym, "address wasn't increasing %x < %x",
|
||||
|
|
@ -1291,12 +1326,11 @@ func appendPCDeltaCFA(arch *sys.Arch, b []byte, deltapc, cfa int64) []byte {
|
|||
return b
|
||||
}
|
||||
|
||||
func (d *dwctxt2) writeframes(syms []loader.Sym) []loader.Sym {
|
||||
func (d *dwctxt2) writeframes() dwarfSecInfo {
|
||||
fs := d.ldr.LookupOrCreateSym(".debug_frame", 0)
|
||||
fsd := dwSym(fs)
|
||||
fsu := d.ldr.MakeSymbolUpdater(fs)
|
||||
fsu.SetType(sym.SDWARFSECT)
|
||||
syms = append(syms, fs)
|
||||
isdw64 := isDwarf64(d.linkctxt)
|
||||
haslr := haslinkregister(d.linkctxt)
|
||||
|
||||
|
|
@ -1347,6 +1381,9 @@ func (d *dwctxt2) writeframes(syms []loader.Sym) []loader.Sym {
|
|||
Exitf("dwarf: cieReserve too small by %d bytes.", -pad)
|
||||
}
|
||||
|
||||
internalExec := d.linkctxt.BuildMode == BuildModeExe && d.linkctxt.IsInternal()
|
||||
addAddrPlus := loader.GenAddAddrPlusFunc(internalExec)
|
||||
|
||||
fsu.AddBytes(zeros[:pad])
|
||||
|
||||
var deltaBuf []byte
|
||||
|
|
@ -1428,7 +1465,7 @@ func (d *dwctxt2) writeframes(syms []loader.Sym) []loader.Sym {
|
|||
} else {
|
||||
d.addDwarfAddrField(fsu, 0) // CIE offset
|
||||
}
|
||||
fsu.AddAddrPlus(d.arch, s, 0)
|
||||
addAddrPlus(fsu, d.arch, s, 0)
|
||||
fsu.AddUintXX(d.arch, uint64(len(d.ldr.Data(fn))), d.arch.PtrSize) // address range
|
||||
fsu.AddBytes(deltaBuf)
|
||||
|
||||
|
|
@ -1437,7 +1474,7 @@ func (d *dwctxt2) writeframes(syms []loader.Sym) []loader.Sym {
|
|||
}
|
||||
}
|
||||
|
||||
return syms
|
||||
return dwarfSecInfo{syms: []loader.Sym{fs}}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1458,13 +1495,13 @@ func appendSyms(syms []loader.Sym, src []sym.LoaderSym) []loader.Sym {
|
|||
return syms
|
||||
}
|
||||
|
||||
func (d *dwctxt2) writeinfo(syms []loader.Sym, units []*sym.CompilationUnit, abbrevsym loader.Sym, pubNames, pubTypes *pubWriter2) []loader.Sym {
|
||||
func (d *dwctxt2) writeinfo(units []*sym.CompilationUnit, abbrevsym loader.Sym, pubNames, pubTypes *pubWriter2) dwarfSecInfo {
|
||||
|
||||
infosec := d.ldr.LookupOrCreateSym(".debug_info", 0)
|
||||
disu := d.ldr.MakeSymbolUpdater(infosec)
|
||||
disu.SetType(sym.SDWARFINFO)
|
||||
d.ldr.SetAttrReachable(infosec, true)
|
||||
syms = append(syms, infosec)
|
||||
syms := []loader.Sym{infosec}
|
||||
|
||||
for _, u := range units {
|
||||
compunit := u.DWInfo
|
||||
|
|
@ -1542,7 +1579,8 @@ func (d *dwctxt2) writeinfo(syms []loader.Sym, units []*sym.CompilationUnit, abb
|
|||
pubTypes.endCompUnit(compunit, uint32(cusize)+4)
|
||||
syms = append(syms, cu...)
|
||||
}
|
||||
return syms
|
||||
|
||||
return dwarfSecInfo{syms: syms}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1618,10 +1656,10 @@ func ispubtype(die *dwarf.DWDie) bool {
|
|||
return die.Abbrev >= dwarf.DW_ABRV_NULLTYPE
|
||||
}
|
||||
|
||||
func (d *dwctxt2) writegdbscript(syms []loader.Sym) []loader.Sym {
|
||||
func (d *dwctxt2) writegdbscript() dwarfSecInfo {
|
||||
// TODO (aix): make it available
|
||||
if d.linkctxt.HeadType == objabi.Haix {
|
||||
return syms
|
||||
return dwarfSecInfo{}
|
||||
}
|
||||
if d.linkctxt.LinkMode == LinkExternal && d.linkctxt.HeadType == objabi.Hwindows && d.linkctxt.BuildMode == BuildModeCArchive {
|
||||
// gcc on Windows places .debug_gdb_scripts in the wrong location, which
|
||||
|
|
@ -1630,21 +1668,19 @@ func (d *dwctxt2) writegdbscript(syms []loader.Sym) []loader.Sym {
|
|||
// (see fix near writeGDBLinkerScript).
|
||||
// c-archive users would need to specify the linker script manually.
|
||||
// For UX it's better not to deal with this.
|
||||
return syms
|
||||
return dwarfSecInfo{}
|
||||
}
|
||||
if gdbscript == "" {
|
||||
return dwarfSecInfo{}
|
||||
}
|
||||
|
||||
if gdbscript != "" {
|
||||
gs := d.ldr.LookupOrCreateSym(".debug_gdb_scripts", 0)
|
||||
u := d.ldr.MakeSymbolUpdater(gs)
|
||||
u.SetType(sym.SDWARFSECT)
|
||||
|
||||
syms = append(syms, gs)
|
||||
u.AddUint8(1) // magic 1 byte?
|
||||
u.Addstring(gdbscript)
|
||||
}
|
||||
|
||||
return syms
|
||||
gs := d.ldr.LookupOrCreateSym(".debug_gdb_scripts", 0)
|
||||
u := d.ldr.MakeSymbolUpdater(gs)
|
||||
u.SetType(sym.SDWARFSECT)
|
||||
|
||||
u.AddUint8(1) // magic 1 byte?
|
||||
u.Addstring(gdbscript)
|
||||
return dwarfSecInfo{syms: []loader.Sym{gs}}
|
||||
}
|
||||
|
||||
// FIXME: might be worth looking replacing this map with a function
|
||||
|
|
@ -1970,19 +2006,8 @@ func dwarfGenerateDebugSyms(ctxt *Link) {
|
|||
}
|
||||
|
||||
func (d *dwctxt2) dwarfGenerateDebugSyms() {
|
||||
|
||||
// Hack: because the "wavefront" hasn't been pushed all the way
|
||||
// up to dodata(), there will have been changes made to the sym.Symbol's
|
||||
// that are not yet reflected in the loader. Call a temporary
|
||||
// loader routine that copies any changes back.
|
||||
// WARNING: changing a symbol's content will usually require
|
||||
// calling the loader cloneToExternal method, meaning that there
|
||||
// can be an increase in memory, so this is likely to mess up any
|
||||
// benchmarking runs.
|
||||
d.ldr.PropagateSymbolChangesBackToLoader()
|
||||
|
||||
abbrev := d.writeabbrev()
|
||||
syms := []loader.Sym{abbrev}
|
||||
abbrevSec := d.writeabbrev()
|
||||
dwarfp2 = append(dwarfp2, abbrevSec)
|
||||
|
||||
d.calcCompUnitRanges()
|
||||
sort.Sort(compilationUnitByStartPC(d.linkctxt.compUnits))
|
||||
|
|
@ -1992,7 +2017,7 @@ func (d *dwctxt2) dwarfGenerateDebugSyms() {
|
|||
dlu := d.ldr.MakeSymbolUpdater(debugLine)
|
||||
dlu.SetType(sym.SDWARFSECT)
|
||||
d.ldr.SetAttrReachable(debugLine, true)
|
||||
syms = append(syms, debugLine)
|
||||
dwarfp2 = append(dwarfp2, dwarfSecInfo{syms: []loader.Sym{debugLine}})
|
||||
|
||||
debugRanges := d.ldr.LookupOrCreateSym(".debug_ranges", 0)
|
||||
dru := d.ldr.MakeSymbolUpdater(debugRanges)
|
||||
|
|
@ -2019,29 +2044,34 @@ func (d *dwctxt2) dwarfGenerateDebugSyms() {
|
|||
pubNames := newPubWriter2(d, ".debug_pubnames")
|
||||
pubTypes := newPubWriter2(d, ".debug_pubtypes")
|
||||
|
||||
// Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT
|
||||
infosyms := d.writeinfo(nil, d.linkctxt.compUnits, abbrev, pubNames, pubTypes)
|
||||
infoSec := d.writeinfo(d.linkctxt.compUnits, abbrevSec.secSym(), pubNames, pubTypes)
|
||||
|
||||
syms = d.writeframes(syms)
|
||||
syms = append(syms, pubNames.s, pubTypes.s)
|
||||
syms = d.writegdbscript(syms)
|
||||
// We are now done writing SDWARFSECT symbols, so we can write
|
||||
// other SDWARF* symbols.
|
||||
syms = append(syms, infosyms...)
|
||||
syms = d.collectlocs(syms, d.linkctxt.compUnits)
|
||||
syms = append(syms, debugRanges)
|
||||
framesSec := d.writeframes()
|
||||
dwarfp2 = append(dwarfp2, framesSec)
|
||||
dwarfp2 = append(dwarfp2, dwarfSecInfo{syms: []loader.Sym{pubNames.s}})
|
||||
dwarfp2 = append(dwarfp2, dwarfSecInfo{syms: []loader.Sym{pubTypes.s}})
|
||||
gdbScriptSec := d.writegdbscript()
|
||||
if gdbScriptSec.secSym() != 0 {
|
||||
dwarfp2 = append(dwarfp2, gdbScriptSec)
|
||||
}
|
||||
dwarfp2 = append(dwarfp2, infoSec)
|
||||
locSec := d.collectlocs(d.linkctxt.compUnits)
|
||||
if locSec.secSym() != 0 {
|
||||
dwarfp2 = append(dwarfp2, locSec)
|
||||
}
|
||||
|
||||
rsyms := []loader.Sym{debugRanges}
|
||||
for _, unit := range d.linkctxt.compUnits {
|
||||
for _, s := range unit.RangeSyms2 {
|
||||
syms = append(syms, loader.Sym(s))
|
||||
rsyms = append(rsyms, loader.Sym(s))
|
||||
}
|
||||
}
|
||||
dwarfp2 = syms
|
||||
anonVerReplacement := d.linkctxt.Syms.IncVersion()
|
||||
dwarfp = d.ldr.PropagateLoaderChangesToSymbols(dwarfp2, anonVerReplacement)
|
||||
dwarfp2 = append(dwarfp2, dwarfSecInfo{syms: rsyms})
|
||||
}
|
||||
|
||||
func (d *dwctxt2) collectlocs(syms []loader.Sym, units []*sym.CompilationUnit) []loader.Sym {
|
||||
func (d *dwctxt2) collectlocs(units []*sym.CompilationUnit) dwarfSecInfo {
|
||||
empty := true
|
||||
syms := []loader.Sym{}
|
||||
for _, u := range units {
|
||||
for _, fn := range u.FuncDIEs2 {
|
||||
relocs := d.ldr.Relocs(loader.Sym(fn))
|
||||
|
|
@ -2064,14 +2094,15 @@ func (d *dwctxt2) collectlocs(syms []loader.Sym, units []*sym.CompilationUnit) [
|
|||
}
|
||||
|
||||
// Don't emit .debug_loc if it's empty -- it makes the ARM linker mad.
|
||||
if !empty {
|
||||
locsym := d.ldr.LookupOrCreateSym(".debug_loc", 0)
|
||||
u := d.ldr.MakeSymbolUpdater(locsym)
|
||||
u.SetType(sym.SDWARFLOC)
|
||||
d.ldr.SetAttrReachable(locsym, true)
|
||||
syms = append(syms, locsym)
|
||||
if empty {
|
||||
return dwarfSecInfo{}
|
||||
}
|
||||
return syms
|
||||
|
||||
locsym := d.ldr.LookupOrCreateSym(".debug_loc", 0)
|
||||
u := d.ldr.MakeSymbolUpdater(locsym)
|
||||
u.SetType(sym.SDWARFLOC)
|
||||
d.ldr.SetAttrReachable(locsym, true)
|
||||
return dwarfSecInfo{syms: append([]loader.Sym{locsym}, syms...)}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -24,7 +24,27 @@ func isDwarf64(ctxt *Link) bool {
|
|||
return ctxt.HeadType == objabi.Haix
|
||||
}
|
||||
|
||||
var dwarfp []*sym.Symbol
|
||||
// dwarfSecInfo2 is a replica of the dwarfSecInfo struct but with
|
||||
// *sym.Symbol content instead of loader.Sym content.
|
||||
type dwarfSecInfo2 struct {
|
||||
syms []*sym.Symbol
|
||||
}
|
||||
|
||||
func (dsi *dwarfSecInfo2) secSym() *sym.Symbol {
|
||||
if len(dsi.syms) == 0 {
|
||||
return nil
|
||||
}
|
||||
return dsi.syms[0]
|
||||
}
|
||||
|
||||
func (dsi *dwarfSecInfo2) subSyms() []*sym.Symbol {
|
||||
if len(dsi.syms) == 0 {
|
||||
return []*sym.Symbol{}
|
||||
}
|
||||
return dsi.syms[1:]
|
||||
}
|
||||
|
||||
var dwarfp []dwarfSecInfo2
|
||||
|
||||
/*
|
||||
* Elf.
|
||||
|
|
@ -89,19 +109,13 @@ func dwarfcompress(ctxt *Link) {
|
|||
return
|
||||
}
|
||||
|
||||
var start, compressedCount int
|
||||
var compressedCount int
|
||||
resChannel := make(chan compressedSect)
|
||||
for i, s := range dwarfp {
|
||||
// Find the boundaries between sections and compress
|
||||
// the whole section once we've found the last of its
|
||||
// symbols.
|
||||
if i+1 >= len(dwarfp) || s.Sect != dwarfp[i+1].Sect {
|
||||
go func(resIndex int, syms []*sym.Symbol) {
|
||||
resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms}
|
||||
}(compressedCount, dwarfp[start:i+1])
|
||||
compressedCount++
|
||||
start = i + 1
|
||||
}
|
||||
for i := range dwarfp {
|
||||
go func(resIndex int, syms []*sym.Symbol) {
|
||||
resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms}
|
||||
}(compressedCount, dwarfp[i].syms)
|
||||
compressedCount++
|
||||
}
|
||||
res := make([]compressedSect, compressedCount)
|
||||
for ; compressedCount > 0; compressedCount-- {
|
||||
|
|
@ -109,23 +123,25 @@ func dwarfcompress(ctxt *Link) {
|
|||
res[r.index] = r
|
||||
}
|
||||
|
||||
var newDwarfp []*sym.Symbol
|
||||
var newDwarfp []dwarfSecInfo2
|
||||
Segdwarf.Sections = Segdwarf.Sections[:0]
|
||||
for _, z := range res {
|
||||
s := z.syms[0]
|
||||
if z.compressed == nil {
|
||||
// Compression didn't help.
|
||||
newDwarfp = append(newDwarfp, z.syms...)
|
||||
ds := dwarfSecInfo2{syms: z.syms}
|
||||
newDwarfp = append(newDwarfp, ds)
|
||||
Segdwarf.Sections = append(Segdwarf.Sections, s.Sect)
|
||||
} else {
|
||||
compressedSegName := ".zdebug_" + s.Sect.Name[len(".debug_"):]
|
||||
sect := addsection(ctxt.Arch, &Segdwarf, compressedSegName, 04)
|
||||
sect := addsection(ctxt.loader, ctxt.Arch, &Segdwarf, compressedSegName, 04)
|
||||
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
|
||||
newDwarfp = append(newDwarfp, newSym)
|
||||
ds := dwarfSecInfo2{syms: []*sym.Symbol{newSym}}
|
||||
newDwarfp = append(newDwarfp, ds)
|
||||
}
|
||||
}
|
||||
dwarfp = newDwarfp
|
||||
|
|
@ -135,20 +151,21 @@ func dwarfcompress(ctxt *Link) {
|
|||
// based on Section.Vaddr and Symbol.Value.
|
||||
pos := Segdwarf.Vaddr
|
||||
var prevSect *sym.Section
|
||||
for _, s := range dwarfp {
|
||||
s.Value = int64(pos)
|
||||
if s.Sect != prevSect {
|
||||
s.Sect.Vaddr = uint64(s.Value)
|
||||
prevSect = s.Sect
|
||||
for _, si := range dwarfp {
|
||||
for _, s := range si.syms {
|
||||
s.Value = int64(pos)
|
||||
if s.Sect != prevSect {
|
||||
s.Sect.Vaddr = uint64(s.Value)
|
||||
prevSect = s.Sect
|
||||
}
|
||||
if s.Sub != nil {
|
||||
log.Fatalf("%s: unexpected sub-symbols", s)
|
||||
}
|
||||
pos += uint64(s.Size)
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
pos = uint64(Rnd(int64(pos), PEFILEALIGN))
|
||||
}
|
||||
}
|
||||
if s.Sub != nil {
|
||||
log.Fatalf("%s: unexpected sub-symbols", s)
|
||||
}
|
||||
pos += uint64(s.Size)
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
pos = uint64(Rnd(int64(pos), PEFILEALIGN))
|
||||
}
|
||||
|
||||
}
|
||||
Segdwarf.Length = pos - Segdwarf.Vaddr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1447,8 +1447,14 @@ func Elfemitreloc(ctxt *Link) {
|
|||
for _, sect := range Segdata.Sections {
|
||||
elfrelocsect(ctxt, sect, ctxt.datap)
|
||||
}
|
||||
for _, sect := range Segdwarf.Sections {
|
||||
elfrelocsect(ctxt, sect, dwarfp)
|
||||
for i := 0; i < len(Segdwarf.Sections); i++ {
|
||||
sect := Segdwarf.Sections[i]
|
||||
si := dwarfp[i]
|
||||
if si.secSym() != sect.Sym ||
|
||||
si.secSym().Sect != sect {
|
||||
panic("inconsistency between dwarfp and Segdwarf")
|
||||
}
|
||||
elfrelocsect(ctxt, sect, si.syms)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2230,10 +2236,9 @@ elfobj:
|
|||
for _, sect := range Segdata.Sections {
|
||||
elfshreloc(ctxt.Arch, sect)
|
||||
}
|
||||
for _, s := range dwarfp {
|
||||
if len(s.R) > 0 || s.Type == sym.SDWARFINFO || s.Type == sym.SDWARFLOC {
|
||||
elfshreloc(ctxt.Arch, s.Sect)
|
||||
}
|
||||
for _, si := range dwarfp {
|
||||
s := si.secSym()
|
||||
elfshreloc(ctxt.Arch, s.Sect)
|
||||
}
|
||||
// add a .note.GNU-stack section to mark the stack as non-executable
|
||||
sh := elfshname(".note.GNU-stack")
|
||||
|
|
|
|||
|
|
@ -383,6 +383,7 @@ func fieldtrack(arch *sys.Arch, l *loader.Loader) {
|
|||
}
|
||||
}
|
||||
}
|
||||
l.Reachparent = nil // we are done with it
|
||||
if *flagFieldTrack == "" {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -561,7 +561,7 @@ func (ctxt *Link) loadlib() {
|
|||
}
|
||||
|
||||
// Add non-package symbols and references of externally defined symbols.
|
||||
ctxt.loader.LoadNonpkgSyms(ctxt.Syms)
|
||||
ctxt.loader.LoadNonpkgSyms(ctxt.Arch)
|
||||
|
||||
// Load symbols from shared libraries, after all Go object symbols are loaded.
|
||||
for _, lib := range ctxt.Library {
|
||||
|
|
@ -2218,8 +2218,8 @@ func ldshlibsyms(ctxt *Link, shlib string) {
|
|||
ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f})
|
||||
}
|
||||
|
||||
func addsection(arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
|
||||
sect := new(sym.Section)
|
||||
func addsection(ldr *loader.Loader, arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
|
||||
sect := ldr.NewSection()
|
||||
sect.Rwx = uint8(rwx)
|
||||
sect.Name = name
|
||||
sect.Seg = seg
|
||||
|
|
@ -2627,6 +2627,16 @@ func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) {
|
|||
s.Attr |= sym.AttrLocal
|
||||
}
|
||||
|
||||
func (ctxt *Link) xdefine2(p string, t sym.SymKind, v int64) {
|
||||
ldr := ctxt.loader
|
||||
s := ldr.CreateSymForUpdate(p, 0)
|
||||
s.SetType(t)
|
||||
s.SetValue(v)
|
||||
s.SetReachable(true)
|
||||
s.SetSpecial(true)
|
||||
s.SetLocal(true)
|
||||
}
|
||||
|
||||
func datoff(s *sym.Symbol, addr int64) int64 {
|
||||
if uint64(addr) >= Segdata.Vaddr {
|
||||
return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
|
||||
|
|
@ -2772,6 +2782,24 @@ func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library
|
|||
*order = append(*order, lib)
|
||||
}
|
||||
|
||||
// addToTextp populates the context Textp slice.
|
||||
func addToTextp(ctxt *Link) {
|
||||
// Set up ctxt.Textp, based on ctxt.Textp2.
|
||||
textp := make([]*sym.Symbol, 0, len(ctxt.Textp2))
|
||||
haveshlibs := len(ctxt.Shlibs) > 0
|
||||
for _, tsym := range ctxt.Textp2 {
|
||||
sp := ctxt.loader.Syms[tsym]
|
||||
if sp == nil || !ctxt.loader.AttrReachable(tsym) {
|
||||
panic("should never happen")
|
||||
}
|
||||
if haveshlibs && sp.Type == sym.SDYNIMPORT {
|
||||
continue
|
||||
}
|
||||
textp = append(textp, sp)
|
||||
}
|
||||
ctxt.Textp = textp
|
||||
}
|
||||
|
||||
func (ctxt *Link) loadlibfull() {
|
||||
|
||||
// Load full symbol contents, resolve indexed references.
|
||||
|
|
@ -2784,7 +2812,7 @@ func (ctxt *Link) loadlibfull() {
|
|||
}
|
||||
|
||||
// Pull the symbols out.
|
||||
ctxt.loader.ExtractSymbols(ctxt.Syms, ctxt.Reachparent)
|
||||
ctxt.loader.ExtractSymbols(ctxt.Syms)
|
||||
ctxt.lookup = ctxt.Syms.ROLookup
|
||||
|
||||
// Recreate dynexp using *sym.Symbol instead of loader.Sym
|
||||
|
|
@ -2798,14 +2826,41 @@ func (ctxt *Link) loadlibfull() {
|
|||
// Set special global symbols.
|
||||
ctxt.setArchSyms(AfterLoadlibFull)
|
||||
|
||||
// Convert special symbols created by pcln.
|
||||
pclntabFirstFunc = ctxt.loader.Syms[pclntabFirstFunc2]
|
||||
pclntabLastFunc = ctxt.loader.Syms[pclntabLastFunc2]
|
||||
// Populate dwarfp from dwarfp2. If we see a symbol index
|
||||
// whose loader.Syms entry is nil, something went wrong.
|
||||
for _, si := range dwarfp2 {
|
||||
syms := make([]*sym.Symbol, 0, len(si.syms))
|
||||
for _, symIdx := range si.syms {
|
||||
s := ctxt.loader.Syms[symIdx]
|
||||
if s == nil {
|
||||
panic(fmt.Sprintf("nil sym for dwarfp2 element %d", symIdx))
|
||||
}
|
||||
s.Attr |= sym.AttrLocal
|
||||
syms = append(syms, s)
|
||||
}
|
||||
dwarfp = append(dwarfp, dwarfSecInfo2{syms: syms})
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
symGroupType = nil
|
||||
|
||||
if ctxt.Debugvlog > 1 {
|
||||
// loadlibfull is likely a good place to dump.
|
||||
// Only dump under -v=2 and above.
|
||||
ctxt.dumpsyms()
|
||||
}
|
||||
}
|
||||
|
||||
func (ctxt *Link) dumpsyms() {
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
fmt.Printf("%s %s %p %v %v\n", s, s.Type, s, s.Attr.Reachable(), s.Attr.OnList())
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,9 +82,6 @@ type Link struct {
|
|||
|
||||
tramps []loader.Sym // trampolines
|
||||
|
||||
// Used to implement field tracking.
|
||||
Reachparent map[*sym.Symbol]*sym.Symbol
|
||||
|
||||
compUnits []*sym.CompilationUnit // DWARF compilation units
|
||||
runtimeCU *sym.CompilationUnit // One of the runtime CUs, the last one seen.
|
||||
|
||||
|
|
|
|||
|
|
@ -1065,8 +1065,14 @@ func Machoemitreloc(ctxt *Link) {
|
|||
for _, sect := range Segdata.Sections {
|
||||
machorelocsect(ctxt, sect, ctxt.datap)
|
||||
}
|
||||
for _, sect := range Segdwarf.Sections {
|
||||
machorelocsect(ctxt, sect, dwarfp)
|
||||
for i := 0; i < len(Segdwarf.Sections); i++ {
|
||||
sect := Segdwarf.Sections[i]
|
||||
si := dwarfp[i]
|
||||
if si.secSym() != sect.Sym ||
|
||||
si.secSym().Sect != sect {
|
||||
panic("inconsistency between dwarfp and Segdwarf")
|
||||
}
|
||||
machorelocsect(ctxt, sect, si.syms)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ import (
|
|||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/benchmark"
|
||||
"cmd/link/internal/sym"
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
|
|
@ -156,9 +155,6 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
}
|
||||
}
|
||||
|
||||
if objabi.Fieldtrack_enabled != 0 {
|
||||
ctxt.Reachparent = make(map[*sym.Symbol]*sym.Symbol)
|
||||
}
|
||||
checkStrictDups = *FlagStrictDups
|
||||
|
||||
startProfile()
|
||||
|
|
@ -298,10 +294,12 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
container := ctxt.pclntab()
|
||||
bench.Start("findfunctab")
|
||||
ctxt.findfunctab(container)
|
||||
bench.Start("loadlibfull")
|
||||
ctxt.loadlibfull() // XXX do it here for now
|
||||
bench.Start("dwarfGenerateDebugSyms")
|
||||
dwarfGenerateDebugSyms(ctxt)
|
||||
bench.Start("symtab")
|
||||
ctxt.symtab()
|
||||
bench.Start("loadlibfull")
|
||||
ctxt.loadlibfull() // XXX do it here for now
|
||||
bench.Start("dodata")
|
||||
ctxt.dodata()
|
||||
bench.Start("address")
|
||||
|
|
@ -317,22 +315,18 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
// for which we have computed the size and offset, in a
|
||||
// mmap'd region. The second part writes more content, for
|
||||
// which we don't know the size.
|
||||
var outputMmapped bool
|
||||
if ctxt.Arch.Family != sys.Wasm {
|
||||
// Don't mmap if we're building for Wasm. Wasm file
|
||||
// layout is very different so filesize is meaningless.
|
||||
err := ctxt.Out.Mmap(filesize)
|
||||
outputMmapped = err == nil
|
||||
}
|
||||
if outputMmapped {
|
||||
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)
|
||||
bench.Start("reloc")
|
||||
ctxt.reloc()
|
||||
bench.Start("Munmap")
|
||||
ctxt.Out.Munmap()
|
||||
} else {
|
||||
// If we don't mmap, we need to apply relocations before
|
||||
// writing out.
|
||||
|
|
@ -344,6 +338,9 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
bench.Start("Asmb2")
|
||||
thearch.Asmb2(ctxt)
|
||||
|
||||
bench.Start("Munmap")
|
||||
ctxt.Out.Close() // Close handles Munmapping if necessary.
|
||||
|
||||
bench.Start("undef")
|
||||
ctxt.undef()
|
||||
bench.Start("hostlink")
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
package ld
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/sym"
|
||||
"encoding/binary"
|
||||
|
|
@ -14,6 +13,13 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
// If fallocate is not supported on this platform, return this error.
|
||||
// Note this is the same error returned by filesystems that don't support
|
||||
// fallocate, and that is intentional. The error is ignored where needed, and
|
||||
// OutBuf writes to heap memory.
|
||||
const fallocateNotSupportedErr = "operation not supported"
|
||||
const outbufMode = 0775
|
||||
|
||||
// OutBuf is a buffered file writer.
|
||||
//
|
||||
// It is simlar to the Writer in cmd/internal/bio with a few small differences.
|
||||
|
|
@ -28,8 +34,9 @@ import (
|
|||
// - Mmap the output file
|
||||
// - Write the content
|
||||
// - possibly apply any edits in the output buffer
|
||||
// - possibly write more content to the file. These writes take place in a heap
|
||||
// backed buffer that will get synced to disk.
|
||||
// - Munmap the output file
|
||||
// - possibly write more content to the file, which will not be edited later.
|
||||
//
|
||||
// And finally, it provides a mechanism by which you can multithread the
|
||||
// writing of output files. This mechanism is accomplished by copying a OutBuf,
|
||||
|
|
@ -54,28 +61,28 @@ import (
|
|||
// wg.Wait()
|
||||
// }
|
||||
type OutBuf struct {
|
||||
arch *sys.Arch
|
||||
off int64
|
||||
w *bufio.Writer
|
||||
buf []byte // backing store of mmap'd output file
|
||||
name string
|
||||
f *os.File
|
||||
encbuf [8]byte // temp buffer used by WriteN methods
|
||||
isView bool // true if created from View()
|
||||
start, length uint64 // start and length mmaped data.
|
||||
arch *sys.Arch
|
||||
off int64
|
||||
|
||||
buf []byte // backing store of mmap'd output file
|
||||
heap []byte // backing store for non-mmapped data
|
||||
|
||||
name string
|
||||
f *os.File
|
||||
encbuf [8]byte // temp buffer used by WriteN methods
|
||||
isView bool // true if created from View()
|
||||
}
|
||||
|
||||
func (out *OutBuf) Open(name string) error {
|
||||
if out.f != nil {
|
||||
return errors.New("cannont open more than one file")
|
||||
return errors.New("cannot open more than one file")
|
||||
}
|
||||
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
|
||||
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, outbufMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.off = 0
|
||||
out.name = name
|
||||
out.w = bufio.NewWriter(f)
|
||||
out.f = f
|
||||
return nil
|
||||
}
|
||||
|
|
@ -89,16 +96,12 @@ func NewOutBuf(arch *sys.Arch) *OutBuf {
|
|||
var viewError = errors.New("output not mmapped")
|
||||
|
||||
func (out *OutBuf) View(start uint64) (*OutBuf, error) {
|
||||
if out.buf == nil {
|
||||
return nil, viewError
|
||||
}
|
||||
return &OutBuf{
|
||||
arch: out.arch,
|
||||
name: out.name,
|
||||
buf: out.buf,
|
||||
heap: out.heap,
|
||||
off: int64(start),
|
||||
start: start,
|
||||
length: out.length,
|
||||
isView: true,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -109,10 +112,19 @@ func (out *OutBuf) Close() error {
|
|||
if out.isView {
|
||||
return viewCloseError
|
||||
}
|
||||
out.Flush()
|
||||
if out.isMmapped() {
|
||||
out.copyHeap()
|
||||
out.munmap()
|
||||
return nil
|
||||
}
|
||||
if out.f == nil {
|
||||
return nil
|
||||
}
|
||||
if len(out.heap) != 0 {
|
||||
if _, err := out.f.Write(out.heap); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := out.f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -120,16 +132,70 @@ func (out *OutBuf) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (out *OutBuf) SeekSet(p int64) {
|
||||
if p == out.off {
|
||||
return
|
||||
// isMmapped returns true if the OutBuf is mmaped.
|
||||
func (out *OutBuf) isMmapped() bool {
|
||||
return len(out.buf) != 0
|
||||
}
|
||||
|
||||
// copyHeap copies the heap to the mmapped section of memory, returning true if
|
||||
// a copy takes place.
|
||||
func (out *OutBuf) copyHeap() bool {
|
||||
if !out.isMmapped() { // only valuable for mmapped OutBufs.
|
||||
return false
|
||||
}
|
||||
if out.buf == nil {
|
||||
out.Flush()
|
||||
if _, err := out.f.Seek(p, 0); err != nil {
|
||||
Exitf("seeking to %d in %s: %v", p, out.name, err)
|
||||
if out.isView {
|
||||
panic("can't copyHeap a view")
|
||||
}
|
||||
|
||||
bufLen := len(out.buf)
|
||||
heapLen := len(out.heap)
|
||||
total := uint64(bufLen + heapLen)
|
||||
out.munmap()
|
||||
if heapLen != 0 {
|
||||
if err := out.Mmap(total); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
copy(out.buf[bufLen:], out.heap[:heapLen])
|
||||
out.heap = out.heap[:0]
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// maxOutBufHeapLen limits the growth of the heap area.
|
||||
const maxOutBufHeapLen = 10 << 20
|
||||
|
||||
// writeLoc determines the write location if a buffer is mmaped.
|
||||
// We maintain two write buffers, an mmapped section, and a heap section for
|
||||
// writing. When the mmapped section is full, we switch over the heap memory
|
||||
// for writing.
|
||||
func (out *OutBuf) writeLoc(lenToWrite int64) (int64, []byte) {
|
||||
// See if we have enough space in the mmaped area.
|
||||
bufLen := int64(len(out.buf))
|
||||
if out.off+lenToWrite <= bufLen {
|
||||
return out.off, out.buf
|
||||
}
|
||||
|
||||
// Not enough space in the mmaped area, write to heap area instead.
|
||||
heapPos := out.off - bufLen
|
||||
heapLen := int64(len(out.heap))
|
||||
lenNeeded := heapPos + lenToWrite
|
||||
if lenNeeded > heapLen { // do we need to grow the heap storage?
|
||||
// The heap variables aren't protected by a mutex. For now, just bomb if you
|
||||
// try to use OutBuf in parallel. (Note this probably could be fixed.)
|
||||
if out.isView {
|
||||
panic("cannot write to heap in parallel")
|
||||
}
|
||||
// See if our heap would grow to be too large, and if so, copy it to the end
|
||||
// of the mmapped area.
|
||||
if heapLen > maxOutBufHeapLen && out.copyHeap() {
|
||||
heapPos, heapLen, lenNeeded = 0, 0, lenToWrite
|
||||
}
|
||||
out.heap = append(out.heap, make([]byte, lenNeeded-heapLen)...)
|
||||
}
|
||||
return heapPos, out.heap
|
||||
}
|
||||
|
||||
func (out *OutBuf) SeekSet(p int64) {
|
||||
out.off = p
|
||||
}
|
||||
|
||||
|
|
@ -138,30 +204,18 @@ func (out *OutBuf) Offset() int64 {
|
|||
}
|
||||
|
||||
// Write writes the contents of v to the buffer.
|
||||
//
|
||||
// As Write is backed by a bufio.Writer, callers do not have
|
||||
// to explicitly handle the returned error as long as Flush is
|
||||
// eventually called.
|
||||
func (out *OutBuf) Write(v []byte) (int, error) {
|
||||
if out.buf != nil {
|
||||
n := copy(out.buf[out.off:], v)
|
||||
out.off += int64(n)
|
||||
return n, nil
|
||||
}
|
||||
n, err := out.w.Write(v)
|
||||
n := len(v)
|
||||
pos, buf := out.writeLoc(int64(n))
|
||||
copy(buf[pos:], v)
|
||||
out.off += int64(n)
|
||||
return n, err
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (out *OutBuf) Write8(v uint8) {
|
||||
if out.buf != nil {
|
||||
out.buf[out.off] = v
|
||||
out.off++
|
||||
return
|
||||
}
|
||||
if err := out.w.WriteByte(v); err == nil {
|
||||
out.off++
|
||||
}
|
||||
pos, buf := out.writeLoc(1)
|
||||
buf[pos] = v
|
||||
out.off++
|
||||
}
|
||||
|
||||
// WriteByte is an alias for Write8 to fulfill the io.ByteWriter interface.
|
||||
|
|
@ -196,15 +250,11 @@ func (out *OutBuf) Write64b(v uint64) {
|
|||
}
|
||||
|
||||
func (out *OutBuf) WriteString(s string) {
|
||||
if out.buf != nil {
|
||||
n := copy(out.buf[out.off:], s)
|
||||
if n != len(s) {
|
||||
log.Fatalf("WriteString truncated. buffer size: %d, offset: %d, len(s)=%d", len(out.buf), out.off, len(s))
|
||||
}
|
||||
out.off += int64(n)
|
||||
return
|
||||
pos, buf := out.writeLoc(int64(len(s)))
|
||||
n := copy(buf[pos:], s)
|
||||
if n != len(s) {
|
||||
log.Fatalf("WriteString truncated. buffer size: %d, offset: %d, len(s)=%d", len(out.buf), out.off, len(s))
|
||||
}
|
||||
n, _ := out.w.WriteString(s)
|
||||
out.off += int64(n)
|
||||
}
|
||||
|
||||
|
|
@ -236,28 +286,10 @@ func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) {
|
|||
// edit to the symbol content.
|
||||
// If the output file is not Mmap'd, just writes the content.
|
||||
func (out *OutBuf) WriteSym(s *sym.Symbol) {
|
||||
// NB: We inline the Write call for speediness.
|
||||
if out.buf != nil {
|
||||
start := out.off
|
||||
n := copy(out.buf[out.off:], s.P)
|
||||
out.off += int64(n)
|
||||
s.P = out.buf[start:out.off]
|
||||
s.Attr.Set(sym.AttrReadOnly, false)
|
||||
} else {
|
||||
n, _ := out.w.Write(s.P)
|
||||
out.off += int64(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (out *OutBuf) Flush() {
|
||||
var err error
|
||||
if out.buf != nil {
|
||||
err = out.Msync()
|
||||
}
|
||||
if out.w != nil {
|
||||
err = out.w.Flush()
|
||||
}
|
||||
if err != nil {
|
||||
Exitf("flushing %s: %v", out.name, err)
|
||||
}
|
||||
n := int64(len(s.P))
|
||||
pos, buf := out.writeLoc(n)
|
||||
copy(buf[pos:], s.P)
|
||||
out.off += n
|
||||
s.P = buf[pos : pos+n]
|
||||
s.Attr.Set(sym.AttrReadOnly, false)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
// 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 (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (out *OutBuf) fallocate(size uint64) error {
|
||||
store := &syscall.Fstore_t{
|
||||
Flags: syscall.F_ALLOCATEALL,
|
||||
Posmode: syscall.F_PEOFPOSMODE,
|
||||
Offset: 0,
|
||||
Length: int64(size),
|
||||
}
|
||||
|
||||
_, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
|
||||
if err != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// 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 "syscall"
|
||||
|
||||
func (out *OutBuf) fallocate(size uint64) error {
|
||||
return syscall.Fallocate(int(out.f.Fd()), outbufMode, 0, int64(size))
|
||||
}
|
||||
|
|
@ -8,44 +8,34 @@ package ld
|
|||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (out *OutBuf) Mmap(filesize uint64) error {
|
||||
err := out.f.Truncate(int64(filesize))
|
||||
err := out.fallocate(filesize)
|
||||
if err != nil {
|
||||
// Some file systems do not support fallocate. We ignore that error as linking
|
||||
// can still take place, but you might SIGBUS when you write to the mmapped
|
||||
// area.
|
||||
if err.Error() != fallocateNotSupportedErr {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = out.f.Truncate(int64(filesize))
|
||||
if err != nil {
|
||||
Exitf("resize output file failed: %v", err)
|
||||
}
|
||||
out.length = filesize
|
||||
out.buf, err = syscall.Mmap(int(out.f.Fd()), 0, int(filesize), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED|syscall.MAP_FILE)
|
||||
return err
|
||||
}
|
||||
|
||||
func (out *OutBuf) Munmap() {
|
||||
func (out *OutBuf) munmap() {
|
||||
if out.buf == nil {
|
||||
return
|
||||
}
|
||||
err := out.Msync()
|
||||
if err != nil {
|
||||
Exitf("msync output file failed: %v", err)
|
||||
}
|
||||
syscall.Munmap(out.buf)
|
||||
out.buf = nil
|
||||
_, err = out.f.Seek(out.off, 0)
|
||||
_, err := out.f.Seek(out.off, 0)
|
||||
if err != nil {
|
||||
Exitf("seek output file failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (out *OutBuf) Msync() error {
|
||||
if out.buf == nil || out.length <= 0 {
|
||||
return nil
|
||||
}
|
||||
// TODO: netbsd supports mmap and msync, but the syscall package doesn't define MSYNC.
|
||||
// It is excluded from the build tag for now.
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&out.buf[0])), uintptr(out.length), syscall.MS_SYNC)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
// 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.
|
||||
|
||||
// +build !darwin,!linux
|
||||
|
||||
package ld
|
||||
|
||||
import "errors"
|
||||
|
||||
func (out *OutBuf) fallocate(size uint64) error {
|
||||
return errors.New(fallocateNotSupportedErr)
|
||||
}
|
||||
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
package ld
|
||||
|
||||
import "errors"
|
||||
func (out *OutBuf) Mmap(filesize uint64) error {
|
||||
// We need space to put all the symbols before we apply relocations.
|
||||
out.heap = make([]byte, filesize)
|
||||
return nil
|
||||
}
|
||||
|
||||
var errNotSupported = errors.New("mmap not supported")
|
||||
|
||||
func (out *OutBuf) Mmap(filesize uint64) error { return errNotSupported }
|
||||
func (out *OutBuf) Munmap() { panic("unreachable") }
|
||||
func (out *OutBuf) Msync() error { panic("unreachable") }
|
||||
func (out *OutBuf) munmap() { panic("unreachable") }
|
||||
|
|
|
|||
|
|
@ -33,4 +33,67 @@ func TestMMap(t *testing.T) {
|
|||
if err := ob.Mmap(1 << 20); err != nil {
|
||||
t.Errorf("error mmapping file %v", err)
|
||||
}
|
||||
if !ob.isMmapped() {
|
||||
t.Errorf("should be mmapped")
|
||||
}
|
||||
}
|
||||
|
||||
// TestWriteLoc ensures that the math surrounding writeLoc is correct.
|
||||
func TestWriteLoc(t *testing.T) {
|
||||
tests := []struct {
|
||||
bufLen int
|
||||
off int64
|
||||
heapLen int
|
||||
lenToWrite int64
|
||||
expectedHeapLen int
|
||||
writePos int64
|
||||
addressInHeap bool
|
||||
}{
|
||||
{100, 0, 0, 100, 0, 0, false},
|
||||
{100, 100, 0, 100, 100, 0, true},
|
||||
{10, 10, 0, 100, 100, 0, true},
|
||||
{10, 20, 10, 100, 110, 10, true},
|
||||
{0, 0, 0, 100, 100, 0, true},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
ob := &OutBuf{
|
||||
buf: make([]byte, test.bufLen),
|
||||
off: test.off,
|
||||
heap: make([]byte, test.heapLen),
|
||||
}
|
||||
pos, buf := ob.writeLoc(test.lenToWrite)
|
||||
if pos != test.writePos {
|
||||
t.Errorf("[%d] position = %d, expected %d", i, pos, test.writePos)
|
||||
}
|
||||
message := "mmapped area"
|
||||
expected := ob.buf
|
||||
if test.addressInHeap {
|
||||
message = "heap"
|
||||
expected = ob.heap
|
||||
}
|
||||
if &buf[0] != &expected[0] {
|
||||
t.Errorf("[%d] expected position to be %q", i, message)
|
||||
}
|
||||
if len(ob.heap) != test.expectedHeapLen {
|
||||
t.Errorf("[%d] expected len(ob.heap) == %d, got %d", i, test.expectedHeapLen, len(ob.heap))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsMmapped(t *testing.T) {
|
||||
tests := []struct {
|
||||
length int
|
||||
expected bool
|
||||
}{
|
||||
{0, false},
|
||||
{1, true},
|
||||
}
|
||||
for i, test := range tests {
|
||||
ob := &OutBuf{buf: make([]byte, test.length)}
|
||||
if v := ob.isMmapped(); v != test.expected {
|
||||
|
||||
t.Errorf("[%d] isMmapped == %t, expected %t", i, v, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func (out *OutBuf) Mmap(filesize uint64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (out *OutBuf) Munmap() {
|
||||
func (out *OutBuf) munmap() {
|
||||
if out.buf == nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -41,10 +41,3 @@ func (out *OutBuf) Munmap() {
|
|||
Exitf("UnmapViewOfFile failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (out *OutBuf) Msync() error {
|
||||
if out.buf == nil {
|
||||
return nil
|
||||
}
|
||||
return syscall.FlushViewOfFile(uintptr(unsafe.Pointer(&out.buf[0])), 0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,10 +234,8 @@ func (state *pclnState) genInlTreeSym(fi loader.FuncInfo, arch *sys.Arch) loader
|
|||
var pclntabNfunc int32
|
||||
var pclntabFiletabOffset int32
|
||||
var pclntabPclntabOffset int32
|
||||
var pclntabFirstFunc *sym.Symbol
|
||||
var pclntabLastFunc *sym.Symbol
|
||||
var pclntabFirstFunc2 loader.Sym
|
||||
var pclntabLastFunc2 loader.Sym
|
||||
var pclntabFirstFunc loader.Sym
|
||||
var pclntabLastFunc loader.Sym
|
||||
|
||||
// pclntab generates the pcln table for the link output. Return value
|
||||
// is a bitmap indexed by global symbol that marks 'container' text
|
||||
|
|
@ -276,8 +274,8 @@ func (ctxt *Link) pclntab() loader.Bitmap {
|
|||
continue
|
||||
}
|
||||
nfunc++
|
||||
if pclntabFirstFunc2 == 0 {
|
||||
pclntabFirstFunc2 = s
|
||||
if pclntabFirstFunc == 0 {
|
||||
pclntabFirstFunc = s
|
||||
}
|
||||
ss := ldr.SymSect(s)
|
||||
if ss != prevSect {
|
||||
|
|
@ -325,6 +323,25 @@ func (ctxt *Link) pclntab() loader.Bitmap {
|
|||
return newoff
|
||||
}
|
||||
|
||||
setAddr := (*loader.SymbolBuilder).SetAddrPlus
|
||||
if ctxt.IsExe() && ctxt.IsInternal() && !ctxt.DynlinkingGo() {
|
||||
// Internal linking static executable. At this point the function
|
||||
// addresses are known, so we can just use them instead of emitting
|
||||
// relocations.
|
||||
// For other cases we are generating a relocatable binary so we
|
||||
// still need to emit relocations.
|
||||
//
|
||||
// Also not do this optimization when using plugins (DynlinkingGo),
|
||||
// as on darwin it does weird things with runtime.etext symbol.
|
||||
// TODO: remove the weird thing and remove this condition.
|
||||
setAddr = func(s *loader.SymbolBuilder, arch *sys.Arch, off int64, tgt loader.Sym, add int64) int64 {
|
||||
if v := ldr.SymValue(tgt); v != 0 {
|
||||
return s.SetUint(arch, off, uint64(v+add))
|
||||
}
|
||||
return s.SetAddrPlus(arch, off, tgt, add)
|
||||
}
|
||||
}
|
||||
|
||||
pcsp := sym.Pcdata{}
|
||||
pcfile := sym.Pcdata{}
|
||||
pcline := sym.Pcdata{}
|
||||
|
|
@ -347,7 +364,7 @@ func (ctxt *Link) pclntab() loader.Bitmap {
|
|||
// invalid funcoff value to mark the hole. See also
|
||||
// runtime/symtab.go:findfunc
|
||||
prevFuncSize := int64(ldr.SymSize(prevFunc))
|
||||
ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), prevFunc, prevFuncSize)
|
||||
setAddr(ftab, ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), prevFunc, prevFuncSize)
|
||||
ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), ^uint64(0))
|
||||
nfunc++
|
||||
}
|
||||
|
|
@ -397,10 +414,7 @@ func (ctxt *Link) pclntab() loader.Bitmap {
|
|||
funcstart := int32(dSize)
|
||||
funcstart += int32(-dSize) & (int32(ctxt.Arch.PtrSize) - 1) // align to ptrsize
|
||||
|
||||
// NB: for the static binary internal-link case, we could just
|
||||
// emit the symbol value instead of creating a relocation here
|
||||
// (might speed things up for that case).
|
||||
ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), s, 0)
|
||||
setAddr(ftab, ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), s, 0)
|
||||
ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint64(funcstart))
|
||||
|
||||
// Write runtime._func. Keep in sync with ../../../../runtime/runtime2.go:/_func
|
||||
|
|
@ -416,7 +430,7 @@ func (ctxt *Link) pclntab() loader.Bitmap {
|
|||
ftab.Grow(int64(end))
|
||||
|
||||
// entry uintptr
|
||||
off = int32(ftab.SetAddrPlus(ctxt.Arch, int64(off), s, 0))
|
||||
off = int32(setAddr(ftab, ctxt.Arch, int64(off), s, 0))
|
||||
|
||||
// name int32
|
||||
sn := ldr.SymName(s)
|
||||
|
|
@ -497,7 +511,7 @@ func (ctxt *Link) pclntab() loader.Bitmap {
|
|||
}
|
||||
// TODO: Dedup.
|
||||
funcdataBytes += int64(len(ldr.Data(funcdata[i])))
|
||||
ftab.SetAddrPlus(ctxt.Arch, dataoff, funcdata[i], funcdataoff[i])
|
||||
setAddr(ftab, ctxt.Arch, dataoff, funcdata[i], funcdataoff[i])
|
||||
}
|
||||
off += int32(len(funcdata)) * int32(ctxt.Arch.PtrSize)
|
||||
}
|
||||
|
|
@ -511,9 +525,9 @@ func (ctxt *Link) pclntab() loader.Bitmap {
|
|||
}
|
||||
|
||||
last := ctxt.Textp2[len(ctxt.Textp2)-1]
|
||||
pclntabLastFunc2 = last
|
||||
pclntabLastFunc = last
|
||||
// Final entry of table is just end pc.
|
||||
ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), last, ldr.SymSize(last))
|
||||
setAddr(ftab, ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), last, ldr.SymSize(last))
|
||||
|
||||
// Start file table.
|
||||
dSize := len(ftab.Data())
|
||||
|
|
|
|||
|
|
@ -557,11 +557,17 @@ func (f *peFile) emitRelocations(ctxt *Link) {
|
|||
}
|
||||
|
||||
dwarfLoop:
|
||||
for _, sect := range Segdwarf.Sections {
|
||||
for i := 0; i < len(Segdwarf.Sections); i++ {
|
||||
sect := Segdwarf.Sections[i]
|
||||
si := dwarfp[i]
|
||||
if si.secSym() != sect.Sym ||
|
||||
si.secSym().Sect != sect {
|
||||
panic("inconsistency between dwarfp and Segdwarf")
|
||||
}
|
||||
for _, pesect := range f.sections {
|
||||
if sect.Name == pesect.name {
|
||||
pesect.emitRelocations(ctxt.Out, func() int {
|
||||
return relocsect(sect, dwarfp, sect.Vaddr)
|
||||
return relocsect(sect, si.syms, sect.Vaddr)
|
||||
})
|
||||
continue dwarfLoop
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ package ld
|
|||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
|
@ -271,12 +272,12 @@ func (libs byPkg) Swap(a, b int) {
|
|||
}
|
||||
|
||||
// Create a table with information on the text sections.
|
||||
|
||||
func textsectionmap(ctxt *Link) uint32 {
|
||||
|
||||
t := ctxt.Syms.Lookup("runtime.textsectionmap", 0)
|
||||
t.Type = sym.SRODATA
|
||||
t.Attr |= sym.AttrReachable
|
||||
// Return the symbol of the table, and number of sections.
|
||||
func textsectionmap(ctxt *Link) (loader.Sym, uint32) {
|
||||
ldr := ctxt.loader
|
||||
t := ldr.CreateSymForUpdate("runtime.textsectionmap", 0)
|
||||
t.SetType(sym.SRODATA)
|
||||
t.SetReachable(true)
|
||||
nsections := int64(0)
|
||||
|
||||
for _, sect := range Segtext.Sections {
|
||||
|
|
@ -308,107 +309,106 @@ func textsectionmap(ctxt *Link) uint32 {
|
|||
off = t.SetUint(ctxt.Arch, off, sect.Vaddr-textbase)
|
||||
off = t.SetUint(ctxt.Arch, off, sect.Length)
|
||||
if n == 0 {
|
||||
s := ctxt.Syms.ROLookup("runtime.text", 0)
|
||||
if s == nil {
|
||||
Errorf(nil, "Unable to find symbol runtime.text\n")
|
||||
s := ldr.Lookup("runtime.text", 0)
|
||||
if s == 0 {
|
||||
ctxt.Errorf(s, "Unable to find symbol runtime.text\n")
|
||||
}
|
||||
off = t.SetAddr(ctxt.Arch, off, s)
|
||||
|
||||
} else {
|
||||
s := ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
|
||||
if s == nil {
|
||||
Errorf(nil, "Unable to find symbol runtime.text.%d\n", n)
|
||||
s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
|
||||
if s == 0 {
|
||||
ctxt.Errorf(s, "Unable to find symbol runtime.text.%d\n", n)
|
||||
}
|
||||
off = t.SetAddr(ctxt.Arch, off, s)
|
||||
}
|
||||
n++
|
||||
}
|
||||
return uint32(n)
|
||||
return t.Sym(), uint32(n)
|
||||
}
|
||||
|
||||
var symGroupType []sym.SymKind // temporarily assign a symbol's "group" type
|
||||
|
||||
func (ctxt *Link) symtab() {
|
||||
if ctxt.HeadType != objabi.Haix {
|
||||
ldr := ctxt.loader
|
||||
|
||||
if !ctxt.IsAIX() {
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCArchive, BuildModeCShared:
|
||||
s := ctxt.Syms.ROLookup(*flagEntrySymbol, sym.SymVerABI0)
|
||||
if s != nil {
|
||||
addinitarrdata(ctxt, s)
|
||||
s := ldr.Lookup(*flagEntrySymbol, sym.SymVerABI0)
|
||||
if s != 0 {
|
||||
addinitarrdata(ctxt, ldr, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define these so that they'll get put into the symbol table.
|
||||
// data.c:/^address will provide the actual values.
|
||||
ctxt.xdefine("runtime.text", sym.STEXT, 0)
|
||||
|
||||
ctxt.xdefine("runtime.etext", sym.STEXT, 0)
|
||||
ctxt.xdefine("runtime.itablink", sym.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.eitablink", sym.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.rodata", sym.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.erodata", sym.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.types", sym.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.etypes", sym.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.noptrdata", sym.SNOPTRDATA, 0)
|
||||
ctxt.xdefine("runtime.enoptrdata", sym.SNOPTRDATA, 0)
|
||||
ctxt.xdefine("runtime.data", sym.SDATA, 0)
|
||||
ctxt.xdefine("runtime.edata", sym.SDATA, 0)
|
||||
ctxt.xdefine("runtime.bss", sym.SBSS, 0)
|
||||
ctxt.xdefine("runtime.ebss", sym.SBSS, 0)
|
||||
ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, 0)
|
||||
ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, 0)
|
||||
ctxt.xdefine("runtime.end", sym.SBSS, 0)
|
||||
ctxt.xdefine("runtime.epclntab", sym.SRODATA, 0)
|
||||
ctxt.xdefine("runtime.esymtab", sym.SRODATA, 0)
|
||||
ctxt.xdefine2("runtime.text", sym.STEXT, 0)
|
||||
ctxt.xdefine2("runtime.etext", sym.STEXT, 0)
|
||||
ctxt.xdefine2("runtime.itablink", sym.SRODATA, 0)
|
||||
ctxt.xdefine2("runtime.eitablink", sym.SRODATA, 0)
|
||||
ctxt.xdefine2("runtime.rodata", sym.SRODATA, 0)
|
||||
ctxt.xdefine2("runtime.erodata", sym.SRODATA, 0)
|
||||
ctxt.xdefine2("runtime.types", sym.SRODATA, 0)
|
||||
ctxt.xdefine2("runtime.etypes", sym.SRODATA, 0)
|
||||
ctxt.xdefine2("runtime.noptrdata", sym.SNOPTRDATA, 0)
|
||||
ctxt.xdefine2("runtime.enoptrdata", sym.SNOPTRDATA, 0)
|
||||
ctxt.xdefine2("runtime.data", sym.SDATA, 0)
|
||||
ctxt.xdefine2("runtime.edata", sym.SDATA, 0)
|
||||
ctxt.xdefine2("runtime.bss", sym.SBSS, 0)
|
||||
ctxt.xdefine2("runtime.ebss", sym.SBSS, 0)
|
||||
ctxt.xdefine2("runtime.noptrbss", sym.SNOPTRBSS, 0)
|
||||
ctxt.xdefine2("runtime.enoptrbss", sym.SNOPTRBSS, 0)
|
||||
ctxt.xdefine2("runtime.end", sym.SBSS, 0)
|
||||
ctxt.xdefine2("runtime.epclntab", sym.SRODATA, 0)
|
||||
ctxt.xdefine2("runtime.esymtab", sym.SRODATA, 0)
|
||||
|
||||
// garbage collection symbols
|
||||
s := ctxt.Syms.Lookup("runtime.gcdata", 0)
|
||||
s := ldr.CreateSymForUpdate("runtime.gcdata", 0)
|
||||
s.SetType(sym.SRODATA)
|
||||
s.SetSize(0)
|
||||
s.SetReachable(true)
|
||||
ctxt.xdefine2("runtime.egcdata", sym.SRODATA, 0)
|
||||
|
||||
s.Type = sym.SRODATA
|
||||
s.Size = 0
|
||||
s.Attr |= sym.AttrReachable
|
||||
ctxt.xdefine("runtime.egcdata", sym.SRODATA, 0)
|
||||
|
||||
s = ctxt.Syms.Lookup("runtime.gcbss", 0)
|
||||
s.Type = sym.SRODATA
|
||||
s.Size = 0
|
||||
s.Attr |= sym.AttrReachable
|
||||
ctxt.xdefine("runtime.egcbss", sym.SRODATA, 0)
|
||||
s = ldr.CreateSymForUpdate("runtime.gcbss", 0)
|
||||
s.SetType(sym.SRODATA)
|
||||
s.SetSize(0)
|
||||
s.SetReachable(true)
|
||||
ctxt.xdefine2("runtime.egcbss", sym.SRODATA, 0)
|
||||
|
||||
// pseudo-symbols to mark locations of type, string, and go string data.
|
||||
var symtype *sym.Symbol
|
||||
var symtyperel *sym.Symbol
|
||||
var symtype, symtyperel loader.Sym
|
||||
if !ctxt.DynlinkingGo() {
|
||||
if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
|
||||
s = ctxt.Syms.Lookup("type.*", 0)
|
||||
s = ldr.CreateSymForUpdate("type.*", 0)
|
||||
s.SetType(sym.STYPE)
|
||||
s.SetSize(0)
|
||||
s.SetReachable(true)
|
||||
symtype = s.Sym()
|
||||
|
||||
s.Type = sym.STYPE
|
||||
s.Size = 0
|
||||
s.Attr |= sym.AttrReachable
|
||||
symtype = s
|
||||
|
||||
s = ctxt.Syms.Lookup("typerel.*", 0)
|
||||
|
||||
s.Type = sym.STYPERELRO
|
||||
s.Size = 0
|
||||
s.Attr |= sym.AttrReachable
|
||||
symtyperel = s
|
||||
s = ldr.CreateSymForUpdate("typerel.*", 0)
|
||||
s.SetType(sym.STYPERELRO)
|
||||
s.SetSize(0)
|
||||
s.SetReachable(true)
|
||||
symtyperel = s.Sym()
|
||||
} else {
|
||||
s = ctxt.Syms.Lookup("type.*", 0)
|
||||
|
||||
s.Type = sym.STYPE
|
||||
s.Size = 0
|
||||
s.Attr |= sym.AttrReachable
|
||||
symtype = s
|
||||
symtyperel = s
|
||||
s = ldr.CreateSymForUpdate("type.*", 0)
|
||||
s.SetType(sym.STYPE)
|
||||
s.SetSize(0)
|
||||
s.SetReachable(true)
|
||||
symtype = s.Sym()
|
||||
symtyperel = s.Sym()
|
||||
}
|
||||
}
|
||||
|
||||
groupSym := func(name string, t sym.SymKind) *sym.Symbol {
|
||||
s := ctxt.Syms.Lookup(name, 0)
|
||||
s.Type = t
|
||||
s.Size = 0
|
||||
s.Attr |= sym.AttrLocal | sym.AttrReachable
|
||||
return s
|
||||
groupSym := func(name string, t sym.SymKind) loader.Sym {
|
||||
s := ldr.CreateSymForUpdate(name, 0)
|
||||
s.SetType(t)
|
||||
s.SetSize(0)
|
||||
s.SetLocal(true)
|
||||
s.SetReachable(true)
|
||||
return s.Sym()
|
||||
}
|
||||
var (
|
||||
symgostring = groupSym("go.string.*", sym.SGOSTRING)
|
||||
|
|
@ -416,7 +416,7 @@ func (ctxt *Link) symtab() {
|
|||
symgcbits = groupSym("runtime.gcbits.*", sym.SGCBITS)
|
||||
)
|
||||
|
||||
var symgofuncrel *sym.Symbol
|
||||
var symgofuncrel loader.Sym
|
||||
if !ctxt.DynlinkingGo() {
|
||||
if ctxt.UseRelro() {
|
||||
symgofuncrel = groupSym("go.funcrel.*", sym.SGOFUNCRELRO)
|
||||
|
|
@ -425,14 +425,14 @@ func (ctxt *Link) symtab() {
|
|||
}
|
||||
}
|
||||
|
||||
symitablink := ctxt.Syms.Lookup("runtime.itablink", 0)
|
||||
symitablink.Type = sym.SITABLINK
|
||||
symitablink := ldr.CreateSymForUpdate("runtime.itablink", 0)
|
||||
symitablink.SetType(sym.SITABLINK)
|
||||
|
||||
symt := ctxt.Syms.Lookup("runtime.symtab", 0)
|
||||
symt.Attr |= sym.AttrLocal
|
||||
symt.Type = sym.SSYMTAB
|
||||
symt.Size = 0
|
||||
symt.Attr |= sym.AttrReachable
|
||||
symt := ldr.CreateSymForUpdate("runtime.symtab", 0)
|
||||
symt.SetType(sym.SSYMTAB)
|
||||
symt.SetSize(0)
|
||||
symt.SetReachable(true)
|
||||
symt.SetLocal(true)
|
||||
|
||||
nitablinks := 0
|
||||
|
||||
|
|
@ -440,147 +440,150 @@ func (ctxt *Link) symtab() {
|
|||
// within a type they sort by size, so the .* symbols
|
||||
// just defined above will be first.
|
||||
// hide the specific symbols.
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
if ctxt.LinkMode != LinkExternal && isStaticTemp(s.Name) {
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
nsym := loader.Sym(ldr.NSym())
|
||||
symGroupType = make([]sym.SymKind, nsym)
|
||||
for s := loader.Sym(1); s < nsym; s++ {
|
||||
name := ldr.SymName(s)
|
||||
if !ctxt.IsExternal() && isStaticTemp(name) {
|
||||
ldr.SetAttrNotInSymbolTable(s, true)
|
||||
}
|
||||
|
||||
if !s.Attr.Reachable() || s.Attr.Special() ||
|
||||
(s.Type != sym.SRODATA && s.Type != sym.SGOFUNC) {
|
||||
if !ldr.AttrReachable(s) || ldr.AttrSpecial(s) || (ldr.SymType(s) != sym.SRODATA && ldr.SymType(s) != sym.SGOFUNC) {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(s.Name, "type."):
|
||||
case strings.HasPrefix(name, "type."):
|
||||
if !ctxt.DynlinkingGo() {
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
ldr.SetAttrNotInSymbolTable(s, true)
|
||||
}
|
||||
if ctxt.UseRelro() {
|
||||
s.Type = sym.STYPERELRO
|
||||
s.Outer = symtyperel
|
||||
symGroupType[s] = sym.STYPERELRO
|
||||
ldr.SetOuterSym(s, symtyperel)
|
||||
} else {
|
||||
s.Type = sym.STYPE
|
||||
s.Outer = symtype
|
||||
symGroupType[s] = sym.STYPE
|
||||
ldr.SetOuterSym(s, symtype)
|
||||
}
|
||||
|
||||
case strings.HasPrefix(s.Name, "go.importpath.") && ctxt.UseRelro():
|
||||
case strings.HasPrefix(name, "go.importpath.") && ctxt.UseRelro():
|
||||
// Keep go.importpath symbols in the same section as types and
|
||||
// names, as they can be referred to by a section offset.
|
||||
s.Type = sym.STYPERELRO
|
||||
symGroupType[s] = sym.STYPERELRO
|
||||
|
||||
case strings.HasPrefix(s.Name, "go.itablink."):
|
||||
case strings.HasPrefix(name, "go.itablink."):
|
||||
nitablinks++
|
||||
s.Type = sym.SITABLINK
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
s.Outer = symitablink
|
||||
symGroupType[s] = sym.SITABLINK
|
||||
ldr.SetAttrNotInSymbolTable(s, true)
|
||||
ldr.SetOuterSym(s, symitablink.Sym())
|
||||
|
||||
case strings.HasPrefix(s.Name, "go.string."):
|
||||
s.Type = sym.SGOSTRING
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
s.Outer = symgostring
|
||||
case strings.HasPrefix(name, "go.string."):
|
||||
symGroupType[s] = sym.SGOSTRING
|
||||
ldr.SetAttrNotInSymbolTable(s, true)
|
||||
ldr.SetOuterSym(s, symgostring)
|
||||
|
||||
case strings.HasPrefix(s.Name, "runtime.gcbits."):
|
||||
s.Type = sym.SGCBITS
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
s.Outer = symgcbits
|
||||
case strings.HasPrefix(name, "runtime.gcbits."):
|
||||
symGroupType[s] = sym.SGCBITS
|
||||
ldr.SetAttrNotInSymbolTable(s, true)
|
||||
ldr.SetOuterSym(s, symgcbits)
|
||||
|
||||
case strings.HasSuffix(s.Name, "·f"):
|
||||
case strings.HasSuffix(name, "·f"):
|
||||
if !ctxt.DynlinkingGo() {
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
ldr.SetAttrNotInSymbolTable(s, true)
|
||||
}
|
||||
if ctxt.UseRelro() {
|
||||
s.Type = sym.SGOFUNCRELRO
|
||||
s.Outer = symgofuncrel
|
||||
symGroupType[s] = sym.SGOFUNCRELRO
|
||||
ldr.SetOuterSym(s, symgofuncrel)
|
||||
} else {
|
||||
s.Type = sym.SGOFUNC
|
||||
s.Outer = symgofunc
|
||||
symGroupType[s] = sym.SGOFUNC
|
||||
ldr.SetOuterSym(s, symgofunc)
|
||||
}
|
||||
|
||||
case strings.HasPrefix(s.Name, "gcargs."),
|
||||
strings.HasPrefix(s.Name, "gclocals."),
|
||||
strings.HasPrefix(s.Name, "gclocals·"),
|
||||
s.Type == sym.SGOFUNC && s != symgofunc,
|
||||
strings.HasSuffix(s.Name, ".opendefer"):
|
||||
s.Type = sym.SGOFUNC
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
s.Outer = symgofunc
|
||||
s.Align = 4
|
||||
liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
|
||||
case strings.HasPrefix(name, "gcargs."),
|
||||
strings.HasPrefix(name, "gclocals."),
|
||||
strings.HasPrefix(name, "gclocals·"),
|
||||
ldr.SymType(s) == sym.SGOFUNC && s != symgofunc,
|
||||
strings.HasSuffix(name, ".opendefer"):
|
||||
symGroupType[s] = sym.SGOFUNC
|
||||
ldr.SetAttrNotInSymbolTable(s, true)
|
||||
ldr.SetOuterSym(s, symgofunc)
|
||||
const align = 4
|
||||
ldr.SetSymAlign(s, align)
|
||||
liveness += (ldr.SymSize(s) + int64(align) - 1) &^ (int64(align) - 1)
|
||||
}
|
||||
}
|
||||
|
||||
if ctxt.BuildMode == BuildModeShared {
|
||||
abihashgostr := ctxt.Syms.Lookup("go.link.abihash."+filepath.Base(*flagOutfile), 0)
|
||||
abihashgostr.Attr |= sym.AttrReachable
|
||||
abihashgostr.Type = sym.SRODATA
|
||||
hashsym := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
|
||||
abihashgostr := ldr.CreateSymForUpdate("go.link.abihash."+filepath.Base(*flagOutfile), 0)
|
||||
abihashgostr.SetReachable(true)
|
||||
abihashgostr.SetType(sym.SRODATA)
|
||||
hashsym := ldr.LookupOrCreateSym("go.link.abihashbytes", 0)
|
||||
abihashgostr.AddAddr(ctxt.Arch, hashsym)
|
||||
abihashgostr.AddUint(ctxt.Arch, uint64(hashsym.Size))
|
||||
abihashgostr.AddUint(ctxt.Arch, uint64(ldr.SymSize(hashsym)))
|
||||
}
|
||||
if ctxt.BuildMode == BuildModePlugin || ctxt.CanUsePlugins() {
|
||||
for _, l := range ctxt.Library {
|
||||
s := ctxt.Syms.Lookup("go.link.pkghashbytes."+l.Pkg, 0)
|
||||
s.Attr |= sym.AttrReachable
|
||||
s.Type = sym.SRODATA
|
||||
s.Size = int64(len(l.Hash))
|
||||
s.P = []byte(l.Hash)
|
||||
str := ctxt.Syms.Lookup("go.link.pkghash."+l.Pkg, 0)
|
||||
str.Attr |= sym.AttrReachable
|
||||
str.Type = sym.SRODATA
|
||||
str.AddAddr(ctxt.Arch, s)
|
||||
s := ldr.CreateSymForUpdate("go.link.pkghashbytes."+l.Pkg, 0)
|
||||
s.SetReachable(true)
|
||||
s.SetType(sym.SRODATA)
|
||||
s.SetSize(int64(len(l.Hash)))
|
||||
s.SetData([]byte(l.Hash))
|
||||
str := ldr.CreateSymForUpdate("go.link.pkghash."+l.Pkg, 0)
|
||||
str.SetReachable(true)
|
||||
str.SetType(sym.SRODATA)
|
||||
str.AddAddr(ctxt.Arch, s.Sym())
|
||||
str.AddUint(ctxt.Arch, uint64(len(l.Hash)))
|
||||
}
|
||||
}
|
||||
|
||||
nsections := textsectionmap(ctxt)
|
||||
textsectionmapSym, nsections := textsectionmap(ctxt)
|
||||
|
||||
// Information about the layout of the executable image for the
|
||||
// runtime to use. Any changes here must be matched by changes to
|
||||
// the definition of moduledata in runtime/symtab.go.
|
||||
// This code uses several global variables that are set by pcln.go:pclntab.
|
||||
moduledata := ctxt.Moduledata
|
||||
moduledata := ldr.MakeSymbolUpdater(ctxt.Moduledata2)
|
||||
pclntab := ldr.Lookup("runtime.pclntab", 0)
|
||||
// The pclntab slice
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size))
|
||||
moduledata.AddAddr(ctxt.Arch, pclntab)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pclntab)))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pclntab)))
|
||||
// The ftab slice
|
||||
moduledata.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabPclntabOffset))
|
||||
moduledata.AddAddrPlus(ctxt.Arch, pclntab, int64(pclntabPclntabOffset))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(pclntabNfunc+1))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(pclntabNfunc+1))
|
||||
// The filetab slice
|
||||
moduledata.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabFiletabOffset))
|
||||
moduledata.AddAddrPlus(ctxt.Arch, pclntab, int64(pclntabFiletabOffset))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ctxt.NumFilesyms)+1)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(ctxt.NumFilesyms)+1)
|
||||
// findfunctab
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.findfunctab", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.findfunctab", 0))
|
||||
// minpc, maxpc
|
||||
moduledata.AddAddr(ctxt.Arch, pclntabFirstFunc)
|
||||
moduledata.AddAddrPlus(ctxt.Arch, pclntabLastFunc, pclntabLastFunc.Size)
|
||||
moduledata.AddAddrPlus(ctxt.Arch, pclntabLastFunc, ldr.SymSize(pclntabLastFunc))
|
||||
// pointers to specific parts of the module
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.text", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.etext", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.noptrdata", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.enoptrdata", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.data", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.edata", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.bss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.ebss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.noptrbss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.enoptrbss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.end", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.gcdata", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.gcbss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.types", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.etypes", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.text", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etext", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.noptrdata", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.enoptrdata", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.data", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.edata", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.bss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.ebss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.noptrbss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.enoptrbss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.end", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcdata", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcbss", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.types", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etypes", 0))
|
||||
|
||||
if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
|
||||
// Add R_REF relocation to prevent ld's garbage collection of
|
||||
if ctxt.IsAIX() && ctxt.IsExternal() {
|
||||
// Add R_XCOFFREF relocation to prevent ld's garbage collection of
|
||||
// runtime.rodata, runtime.erodata and runtime.epclntab.
|
||||
addRef := func(name string) {
|
||||
r := moduledata.AddRel()
|
||||
r.Sym = ctxt.Syms.Lookup(name, 0)
|
||||
r.Type = objabi.R_XCOFFREF
|
||||
r.Siz = uint8(ctxt.Arch.PtrSize)
|
||||
r, _ := moduledata.AddRel(objabi.R_XCOFFREF)
|
||||
r.SetSym(ldr.Lookup(name, 0))
|
||||
r.SetSiz(uint8(ctxt.Arch.PtrSize))
|
||||
}
|
||||
addRef("runtime.rodata")
|
||||
addRef("runtime.erodata")
|
||||
|
|
@ -588,26 +591,27 @@ func (ctxt *Link) symtab() {
|
|||
}
|
||||
|
||||
// text section information
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.textsectionmap", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, textsectionmapSym)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(nsections))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(nsections))
|
||||
|
||||
// The typelinks slice
|
||||
typelinkSym := ctxt.Syms.Lookup("runtime.typelink", 0)
|
||||
ntypelinks := uint64(typelinkSym.Size) / 4
|
||||
typelinkSym := ldr.Lookup("runtime.typelink", 0)
|
||||
ntypelinks := uint64(ldr.SymSize(typelinkSym)) / 4
|
||||
moduledata.AddAddr(ctxt.Arch, typelinkSym)
|
||||
moduledata.AddUint(ctxt.Arch, ntypelinks)
|
||||
moduledata.AddUint(ctxt.Arch, ntypelinks)
|
||||
// The itablinks slice
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.itablink", 0))
|
||||
moduledata.AddAddr(ctxt.Arch, symitablink.Sym())
|
||||
moduledata.AddUint(ctxt.Arch, uint64(nitablinks))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(nitablinks))
|
||||
// The ptab slice
|
||||
if ptab := ctxt.Syms.ROLookup("go.plugin.tabs", 0); ptab != nil && ptab.Attr.Reachable() {
|
||||
ptab.Attr |= sym.AttrLocal
|
||||
ptab.Type = sym.SRODATA
|
||||
|
||||
nentries := uint64(len(ptab.P) / 8) // sizeof(nameOff) + sizeof(typeOff)
|
||||
if ptab := ldr.Lookup("go.plugin.tabs", 0); ptab != 0 && ldr.AttrReachable(ptab) {
|
||||
ldr.SetAttrLocal(ptab, true)
|
||||
if ldr.SymType(ptab) != sym.SRODATA {
|
||||
panic(fmt.Sprintf("go.plugin.tabs is %v, not SRODATA", ldr.SymType(ptab)))
|
||||
}
|
||||
nentries := uint64(len(ldr.Data(ptab)) / 8) // sizeof(nameOff) + sizeof(typeOff)
|
||||
moduledata.AddAddr(ctxt.Arch, ptab)
|
||||
moduledata.AddUint(ctxt.Arch, nentries)
|
||||
moduledata.AddUint(ctxt.Arch, nentries)
|
||||
|
|
@ -617,23 +621,23 @@ func (ctxt *Link) symtab() {
|
|||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
}
|
||||
if ctxt.BuildMode == BuildModePlugin {
|
||||
addgostring(ctxt, moduledata, "go.link.thispluginpath", objabi.PathToPrefix(*flagPluginPath))
|
||||
addgostring(ctxt, ldr, moduledata, "go.link.thispluginpath", objabi.PathToPrefix(*flagPluginPath))
|
||||
|
||||
pkghashes := ctxt.Syms.Lookup("go.link.pkghashes", 0)
|
||||
pkghashes.Attr |= sym.AttrReachable
|
||||
pkghashes.Attr |= sym.AttrLocal
|
||||
pkghashes.Type = sym.SRODATA
|
||||
pkghashes := ldr.CreateSymForUpdate("go.link.pkghashes", 0)
|
||||
pkghashes.SetReachable(true)
|
||||
pkghashes.SetLocal(true)
|
||||
pkghashes.SetType(sym.SRODATA)
|
||||
|
||||
for i, l := range ctxt.Library {
|
||||
// pkghashes[i].name
|
||||
addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkgname.%d", i), l.Pkg)
|
||||
addgostring(ctxt, ldr, pkghashes, fmt.Sprintf("go.link.pkgname.%d", i), l.Pkg)
|
||||
// pkghashes[i].linktimehash
|
||||
addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkglinkhash.%d", i), l.Hash)
|
||||
addgostring(ctxt, ldr, pkghashes, fmt.Sprintf("go.link.pkglinkhash.%d", i), l.Hash)
|
||||
// pkghashes[i].runtimehash
|
||||
hash := ctxt.Syms.ROLookup("go.link.pkghash."+l.Pkg, 0)
|
||||
hash := ldr.Lookup("go.link.pkghash."+l.Pkg, 0)
|
||||
pkghashes.AddAddr(ctxt.Arch, hash)
|
||||
}
|
||||
moduledata.AddAddr(ctxt.Arch, pkghashes)
|
||||
moduledata.AddAddr(ctxt.Arch, pkghashes.Sym())
|
||||
moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Library)))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Library)))
|
||||
} else {
|
||||
|
|
@ -651,28 +655,28 @@ func (ctxt *Link) symtab() {
|
|||
// it something slightly more comprehensible.
|
||||
thismodulename = "the executable"
|
||||
}
|
||||
addgostring(ctxt, moduledata, "go.link.thismodulename", thismodulename)
|
||||
addgostring(ctxt, ldr, moduledata, "go.link.thismodulename", thismodulename)
|
||||
|
||||
modulehashes := ctxt.Syms.Lookup("go.link.abihashes", 0)
|
||||
modulehashes.Attr |= sym.AttrReachable
|
||||
modulehashes.Attr |= sym.AttrLocal
|
||||
modulehashes.Type = sym.SRODATA
|
||||
modulehashes := ldr.CreateSymForUpdate("go.link.abihashes", 0)
|
||||
modulehashes.SetReachable(true)
|
||||
modulehashes.SetLocal(true)
|
||||
modulehashes.SetType(sym.SRODATA)
|
||||
|
||||
for i, shlib := range ctxt.Shlibs {
|
||||
// modulehashes[i].modulename
|
||||
modulename := filepath.Base(shlib.Path)
|
||||
addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename)
|
||||
addgostring(ctxt, ldr, modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename)
|
||||
|
||||
// modulehashes[i].linktimehash
|
||||
addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash))
|
||||
addgostring(ctxt, ldr, modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash))
|
||||
|
||||
// modulehashes[i].runtimehash
|
||||
abihash := ctxt.Syms.Lookup("go.link.abihash."+modulename, 0)
|
||||
abihash.Attr |= sym.AttrReachable
|
||||
abihash := ldr.LookupOrCreateSym("go.link.abihash."+modulename, 0)
|
||||
ldr.SetAttrReachable(abihash, true)
|
||||
modulehashes.AddAddr(ctxt.Arch, abihash)
|
||||
}
|
||||
|
||||
moduledata.AddAddr(ctxt.Arch, modulehashes)
|
||||
moduledata.AddAddr(ctxt.Arch, modulehashes.Sym())
|
||||
moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Shlibs)))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Shlibs)))
|
||||
} else {
|
||||
|
|
@ -694,15 +698,16 @@ func (ctxt *Link) symtab() {
|
|||
// When linking an object that does not contain the runtime we are
|
||||
// creating the moduledata from scratch and it does not have a
|
||||
// compiler-provided size, so read it from the type data.
|
||||
moduledatatype := ctxt.Syms.ROLookup("type.runtime.moduledata", 0)
|
||||
moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype.P)
|
||||
moduledata.Grow(moduledata.Size)
|
||||
moduledatatype := ldr.Lookup("type.runtime.moduledata", 0)
|
||||
moduledata.SetSize(decodetypeSize(ctxt.Arch, ldr.Data(moduledatatype)))
|
||||
moduledata.Grow(moduledata.Size())
|
||||
|
||||
lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0)
|
||||
if lastmoduledatap.Type != sym.SDYNIMPORT {
|
||||
lastmoduledatap.Type = sym.SNOPTRDATA
|
||||
lastmoduledatap.Size = 0 // overwrite existing value
|
||||
lastmoduledatap.AddAddr(ctxt.Arch, moduledata)
|
||||
lastmoduledatap := ldr.CreateSymForUpdate("runtime.lastmoduledatap", 0)
|
||||
if lastmoduledatap.Type() != sym.SDYNIMPORT {
|
||||
lastmoduledatap.SetType(sym.SNOPTRDATA)
|
||||
lastmoduledatap.SetSize(0) // overwrite existing value
|
||||
lastmoduledatap.SetData(nil)
|
||||
lastmoduledatap.AddAddr(ctxt.Arch, moduledata.Sym())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ type Target struct {
|
|||
// Target type functions
|
||||
//
|
||||
|
||||
func (t *Target) IsExe() bool {
|
||||
return t.BuildMode == BuildModeExe
|
||||
}
|
||||
|
||||
func (t *Target) IsShared() bool {
|
||||
return t.BuildMode == BuildModeShared
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1389,7 +1389,6 @@ func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
|
|||
}
|
||||
|
||||
f.loaderSize = off + uint64(stlen)
|
||||
ctxt.Out.Flush()
|
||||
|
||||
/* again for printing */
|
||||
if !*flagA {
|
||||
|
|
@ -1559,8 +1558,6 @@ func Asmbxcoff(ctxt *Link, fileoff int64) {
|
|||
// write string table
|
||||
xfile.stringTable.write(ctxt.Out)
|
||||
|
||||
ctxt.Out.Flush()
|
||||
|
||||
// write headers
|
||||
xcoffwrite(ctxt)
|
||||
}
|
||||
|
|
@ -1660,12 +1657,18 @@ func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) {
|
|||
}
|
||||
|
||||
dwarfLoop:
|
||||
for _, sect := range Segdwarf.Sections {
|
||||
for i := 0; i < len(Segdwarf.Sections); i++ {
|
||||
sect := Segdwarf.Sections[i]
|
||||
si := dwarfp[i]
|
||||
if si.secSym() != sect.Sym ||
|
||||
si.secSym().Sect != sect {
|
||||
panic("inconsistency between dwarfp and Segdwarf")
|
||||
}
|
||||
for _, xcoffSect := range f.sections {
|
||||
_, subtyp := xcoffGetDwarfSubtype(sect.Name)
|
||||
if xcoffSect.Sflags&0xF0000 == subtyp {
|
||||
xcoffSect.Srelptr = uint64(ctxt.Out.Offset())
|
||||
xcoffSect.Snreloc = relocsect(sect, dwarfp, sect.Vaddr)
|
||||
xcoffSect.Snreloc = relocsect(sect, si.syms, sect.Vaddr)
|
||||
continue dwarfLoop
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,7 +198,9 @@ type Loader struct {
|
|||
payloadBatch []extSymPayload
|
||||
payloads []*extSymPayload // contents of linker-materialized external syms
|
||||
values []int64 // symbol values, indexed by global sym index
|
||||
sects []*sym.Section // symbol's section, indexed by global index
|
||||
|
||||
sects []*sym.Section // sections
|
||||
symSects []uint16 // symbol's section, index to sects array
|
||||
|
||||
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
|
||||
|
||||
|
|
@ -326,6 +328,7 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
|
|||
builtinSyms: make([]Sym, nbuiltin),
|
||||
flags: flags,
|
||||
elfsetstring: elfsetstring,
|
||||
sects: []*sym.Section{nil}, // reserve index 0 for nil section
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -947,10 +950,30 @@ func (l *Loader) SetAttrReadOnly(i Sym, v bool) {
|
|||
// become regular linker symbols and symbols go on the Sub list of
|
||||
// their section) and for constructing the global offset table when
|
||||
// internally linking a dynamic executable.
|
||||
//
|
||||
// Note that in later stages of the linker, we set Outer(S) to some
|
||||
// container symbol C, but don't set Sub(C). Thus we have two
|
||||
// distinct scenarios:
|
||||
//
|
||||
// - Outer symbol covers the address ranges of its sub-symbols.
|
||||
// Outer.Sub is set in this case.
|
||||
// - Outer symbol doesn't conver the address ranges. It is zero-sized
|
||||
// and doesn't have sub-symbols. In the case, the inner symbol is
|
||||
// not actually a "SubSymbol". (Tricky!)
|
||||
//
|
||||
// This method returns TRUE only for sub-symbols in the first scenario.
|
||||
//
|
||||
// FIXME: would be better to do away with this and have a better way
|
||||
// to represent container symbols.
|
||||
|
||||
func (l *Loader) AttrSubSymbol(i Sym) bool {
|
||||
// we don't explicitly store this attribute any more -- return
|
||||
// a value based on the sub-symbol setting.
|
||||
return l.OuterSym(i) != 0
|
||||
o := l.OuterSym(i)
|
||||
if o == 0 {
|
||||
return false
|
||||
}
|
||||
return l.SubSym(o) != 0
|
||||
}
|
||||
|
||||
// Note that we don't have a 'SetAttrSubSymbol' method in the loader;
|
||||
|
|
@ -990,7 +1013,6 @@ func (l *Loader) growValues(reqLen int) {
|
|||
curLen := len(l.values)
|
||||
if reqLen > curLen {
|
||||
l.values = append(l.values, make([]int64, reqLen+1-curLen)...)
|
||||
l.sects = append(l.sects, make([]*sym.Section, reqLen+1-curLen)...)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1053,12 +1075,35 @@ 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 {
|
||||
return l.sects[i]
|
||||
return l.sects[l.symSects[i]]
|
||||
}
|
||||
|
||||
// SetSymValue sets the section of the i-th symbol. i is global index.
|
||||
func (l *Loader) SetSymSect(i Sym, sect *sym.Section) {
|
||||
l.sects[i] = sect
|
||||
if int(i) >= len(l.symSects) {
|
||||
l.symSects = append(l.symSects, make([]uint16, l.NSym()-len(l.symSects))...)
|
||||
}
|
||||
l.symSects[i] = sect.Index
|
||||
}
|
||||
|
||||
// growSects grows the slice used to store symbol sections.
|
||||
func (l *Loader) growSects(reqLen int) {
|
||||
curLen := len(l.symSects)
|
||||
if reqLen > curLen {
|
||||
l.symSects = append(l.symSects, make([]uint16, reqLen+1-curLen)...)
|
||||
}
|
||||
}
|
||||
|
||||
// NewSection creates a new (output) section.
|
||||
func (l *Loader) NewSection() *sym.Section {
|
||||
sect := new(sym.Section)
|
||||
idx := len(l.sects)
|
||||
if idx != int(uint16(idx)) {
|
||||
panic("too many sections created")
|
||||
}
|
||||
sect.Index = uint16(idx)
|
||||
l.sects = append(l.sects, sect)
|
||||
return sect
|
||||
}
|
||||
|
||||
// SymDynImplib returns the "dynimplib" attribute for the specified
|
||||
|
|
@ -1398,6 +1443,16 @@ func (l *Loader) SubSym(i Sym) Sym {
|
|||
return l.sub[i]
|
||||
}
|
||||
|
||||
// SetOuterSym sets the outer symbol of i to o (without setting
|
||||
// sub symbols).
|
||||
func (l *Loader) SetOuterSym(i Sym, o Sym) {
|
||||
if o != 0 {
|
||||
l.outer[i] = o
|
||||
} else {
|
||||
delete(l.outer, i)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize Reachable bitmap and its siblings for running deadcode pass.
|
||||
func (l *Loader) InitReachable() {
|
||||
l.growAttrBitmaps(l.NSym() + 1)
|
||||
|
|
@ -1769,26 +1824,27 @@ func (l *Loader) preloadSyms(r *oReader, kind int) {
|
|||
|
||||
// Add non-package symbols and references to external symbols (which are always
|
||||
// named).
|
||||
func (l *Loader) LoadNonpkgSyms(syms *sym.Symbols) {
|
||||
func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
|
||||
for _, o := range l.objs[1:] {
|
||||
l.preloadSyms(o.r, nonPkgDef)
|
||||
}
|
||||
for _, o := range l.objs[1:] {
|
||||
loadObjRefs(l, o.r, syms)
|
||||
loadObjRefs(l, o.r, arch)
|
||||
}
|
||||
}
|
||||
|
||||
func loadObjRefs(l *Loader, r *oReader, syms *sym.Symbols) {
|
||||
func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
|
||||
ndef := r.NSym() + r.NNonpkgdef()
|
||||
for i, n := 0, r.NNonpkgref(); i < n; i++ {
|
||||
osym := r.Sym(ndef + i)
|
||||
name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
|
||||
v := abiToVer(osym.ABI(), r.version)
|
||||
r.syms[ndef+i] = l.LookupOrCreateSym(name, v)
|
||||
gi := r.syms[ndef+i]
|
||||
if osym.Local() {
|
||||
gi := r.syms[ndef+i]
|
||||
l.SetAttrLocal(gi, true)
|
||||
}
|
||||
l.preprocess(arch, gi, name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1806,24 +1862,29 @@ func abiToVer(abi uint16, localSymVersion int) int {
|
|||
return v
|
||||
}
|
||||
|
||||
func preprocess(arch *sys.Arch, s *sym.Symbol) {
|
||||
if s.Name != "" && s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
|
||||
x, err := strconv.ParseUint(s.Name[5:], 16, 64)
|
||||
// preprocess looks for integer/floating point constant symbols whose
|
||||
// content is encoded into the symbol name, and promotes them into
|
||||
// real symbols with RODATA type and a payload that matches the
|
||||
// encoded content.
|
||||
func (l *Loader) preprocess(arch *sys.Arch, s Sym, name string) {
|
||||
if name != "" && name[0] == '$' && len(name) > 5 && l.SymType(s) == 0 && len(l.Data(s)) == 0 {
|
||||
x, err := strconv.ParseUint(name[5:], 16, 64)
|
||||
if err != nil {
|
||||
log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
|
||||
log.Panicf("failed to parse $-symbol %s: %v", name, err)
|
||||
}
|
||||
s.Type = sym.SRODATA
|
||||
s.Attr |= sym.AttrLocal
|
||||
switch s.Name[:5] {
|
||||
su := l.MakeSymbolUpdater(s)
|
||||
su.SetType(sym.SRODATA)
|
||||
su.SetLocal(true)
|
||||
switch name[:5] {
|
||||
case "$f32.":
|
||||
if uint64(uint32(x)) != x {
|
||||
log.Panicf("$-symbol %s too large: %d", s.Name, x)
|
||||
log.Panicf("$-symbol %s too large: %d", name, x)
|
||||
}
|
||||
s.AddUint32(arch, uint32(x))
|
||||
su.AddUint32(arch, uint32(x))
|
||||
case "$f64.", "$i64.":
|
||||
s.AddUint64(arch, x)
|
||||
su.AddUint64(arch, x)
|
||||
default:
|
||||
log.Panicf("unrecognized $-symbol: %s", s.Name)
|
||||
log.Panicf("unrecognized $-symbol: %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1832,6 +1893,7 @@ func preprocess(arch *sys.Arch, s *sym.Symbol) {
|
|||
func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
||||
// create all Symbols first.
|
||||
l.growSyms(l.NSym())
|
||||
l.growSects(l.NSym())
|
||||
|
||||
nr := 0 // total number of sym.Reloc's we'll need
|
||||
for _, o := range l.objs[1:] {
|
||||
|
|
@ -1893,9 +1955,6 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
|||
|
||||
// Transfer over attributes.
|
||||
l.migrateAttributes(i, s)
|
||||
|
||||
// Preprocess symbol. May set 'AttrLocal'.
|
||||
preprocess(arch, s)
|
||||
}
|
||||
|
||||
// load contents of defined symbols
|
||||
|
|
@ -1909,8 +1968,6 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
|||
|
||||
// Resolve ABI aliases for external symbols. This is only
|
||||
// needed for internal cgo linking.
|
||||
// (The old code does this in deadcode, but deadcode2 doesn't
|
||||
// do this.)
|
||||
for _, i := range l.extReader.syms {
|
||||
if s := l.Syms[i]; s != nil && s.Attr.Reachable() {
|
||||
for ri := range s.R {
|
||||
|
|
@ -2094,7 +2151,7 @@ func (l *Loader) PropagateLoaderChangesToSymbols(toconvert []Sym, anonVerReplace
|
|||
|
||||
// ExtractSymbols grabs the symbols out of the loader for work that hasn't been
|
||||
// ported to the new symbol type.
|
||||
func (l *Loader) ExtractSymbols(syms *sym.Symbols, rp map[*sym.Symbol]*sym.Symbol) {
|
||||
func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
|
||||
// Add symbols to the ctxt.Syms lookup table. This explicitly skips things
|
||||
// created via loader.Create (marked with versions less than zero), since
|
||||
// if we tried to add these we'd wind up with collisions. We do, however,
|
||||
|
|
@ -2114,13 +2171,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols, rp map[*sym.Symbol]*sym.Symbo
|
|||
}
|
||||
}
|
||||
|
||||
for i, s := range l.Reachparent {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
rp[l.Syms[i]] = l.Syms[s]
|
||||
}
|
||||
|
||||
// Provide lookup functions for sym.Symbols.
|
||||
l.SymLookup = func(name string, ver int) *sym.Symbol {
|
||||
i := l.LookupOrCreateSym(name, ver)
|
||||
|
|
@ -2204,13 +2254,15 @@ func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
|
|||
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 (ex:
|
||||
// funcdata), however DWARF subprogram DIE symbols (which are
|
||||
// nameless) will eventually need to be turned into
|
||||
// sym.Symbols (with relocations), so the simplest thing to do
|
||||
// is include them as part of this loop.
|
||||
if name == "" && t != sym.SDWARFINFO {
|
||||
continue
|
||||
// since they will never be turned into sym.Symbols (eg:
|
||||
// funcdata). DWARF symbols are an exception however -- we
|
||||
// want to include all reachable but nameless DWARF symbols.
|
||||
if name == "" {
|
||||
switch t {
|
||||
case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES:
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
ver := abiToVer(osym.ABI(), r.version)
|
||||
if t == sym.SXREF {
|
||||
|
|
@ -2225,32 +2277,12 @@ func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
|
|||
continue
|
||||
}
|
||||
|
||||
s := l.addNewSym(gi, name, ver, r.unit, t)
|
||||
l.migrateAttributes(gi, s)
|
||||
l.addNewSym(gi, name, ver, r.unit, t)
|
||||
nr += r.NReloc(i)
|
||||
}
|
||||
return nr
|
||||
}
|
||||
|
||||
// funcInfoSym records the sym.Symbol for a function, along with a copy
|
||||
// of the corresponding goobj2.Sym and the index of its FuncInfo aux sym.
|
||||
// We use this to delay populating FuncInfo until we can batch-allocate
|
||||
// slices for their sub-objects.
|
||||
type funcInfoSym struct {
|
||||
s *sym.Symbol // sym.Symbol for a live function
|
||||
osym *goobj2.Sym // object file symbol data for that function
|
||||
isym int // global symbol index of FuncInfo aux sym for func
|
||||
}
|
||||
|
||||
// funcAllocInfo records totals/counts for all functions in an objfile;
|
||||
// used to help with bulk allocation of sym.Symbol sub-objects.
|
||||
type funcAllocInfo struct {
|
||||
symPtr uint32 // number of *sym.Symbol's needed in file slices
|
||||
inlCall uint32 // number of sym.InlinedCall's needed in inltree slices
|
||||
pcData uint32 // number of sym.Pcdata's needed in pdata slices
|
||||
fdOff uint32 // number of int64's needed in all Funcdataoff slices
|
||||
}
|
||||
|
||||
// cloneToExternal takes the existing object file symbol (symIdx)
|
||||
// and creates a new external symbol payload that is a clone with
|
||||
// respect to name, version, type, relocations, etc. The idea here
|
||||
|
|
@ -2397,10 +2429,9 @@ func (l *Loader) migrateAttributes(src Sym, dst *sym.Symbol) {
|
|||
dst.Sub = l.Syms[sub]
|
||||
}
|
||||
|
||||
// Set sub-symbol attribute. FIXME: would be better to do away
|
||||
// with this and just use l.OuterSymbol() != 0 elsewhere within
|
||||
// the linker.
|
||||
dst.Attr.Set(sym.AttrSubSymbol, dst.Outer != nil)
|
||||
// Set sub-symbol attribute. See the comment on the AttrSubSymbol
|
||||
// method for more on this, there is some tricky stuff here.
|
||||
dst.Attr.Set(sym.AttrSubSymbol, l.outer[src] != 0 && l.sub[l.outer[src]] != 0)
|
||||
|
||||
// Copy over dynimplib, dynimpvers, extname.
|
||||
if name, ok := l.extname[src]; ok {
|
||||
|
|
@ -2467,10 +2498,11 @@ func loadObjFull(l *Loader, r *oReader) {
|
|||
continue
|
||||
}
|
||||
|
||||
l.migrateAttributes(gi, s)
|
||||
// Be careful not to overwrite attributes set by the linker.
|
||||
// Don't use the attributes from the object file.
|
||||
|
||||
osym := r.Sym(i)
|
||||
dupok := osym.Dupok()
|
||||
local := osym.Local()
|
||||
makeTypelink := osym.Typelink()
|
||||
size := osym.Siz()
|
||||
|
||||
// Symbol data
|
||||
|
|
@ -2504,14 +2536,9 @@ func loadObjFull(l *Loader, r *oReader) {
|
|||
}
|
||||
|
||||
s.File = r.pkgprefix[:len(r.pkgprefix)-1]
|
||||
if dupok {
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
}
|
||||
if s.Size < int64(size) {
|
||||
s.Size = int64(size)
|
||||
}
|
||||
s.Attr.Set(sym.AttrLocal, local)
|
||||
s.Attr.Set(sym.AttrMakeTypelink, makeTypelink)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2681,19 +2708,17 @@ func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, exts
|
|||
}
|
||||
}
|
||||
|
||||
// Now redo the assignment of text symbols to libs/units.
|
||||
// Now assemble global textp, and assign text symbols to units.
|
||||
for _, doInternal := range [2]bool{true, false} {
|
||||
for idx, lib := range libs {
|
||||
if intlibs[idx] != doInternal {
|
||||
continue
|
||||
}
|
||||
libtextp2 := []sym.LoaderSym{}
|
||||
lists := [2][]sym.LoaderSym{lib.Textp2, lib.DupTextSyms2}
|
||||
for i, list := range lists {
|
||||
for _, s := range list {
|
||||
sym := Sym(s)
|
||||
if l.attrReachable.Has(sym) && !assignedToUnit.Has(sym) {
|
||||
libtextp2 = append(libtextp2, s)
|
||||
textp2 = append(textp2, sym)
|
||||
unit := l.SymUnit(sym)
|
||||
if unit != nil {
|
||||
|
|
@ -2711,7 +2736,8 @@ func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, exts
|
|||
}
|
||||
}
|
||||
}
|
||||
lib.Textp2 = libtextp2
|
||||
lib.Textp2 = nil
|
||||
lib.DupTextSyms2 = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ func (sb *SymbolBuilder) SetDynimpvers(value string) { sb.l.SetSymDynimpvers(sb.
|
|||
func (sb *SymbolBuilder) SetPlt(value int32) { sb.l.SetPlt(sb.symIdx, value) }
|
||||
func (sb *SymbolBuilder) SetGot(value int32) { sb.l.SetGot(sb.symIdx, value) }
|
||||
func (sb *SymbolBuilder) SetSpecial(value bool) { sb.l.SetAttrSpecial(sb.symIdx, value) }
|
||||
func (sb *SymbolBuilder) SetLocal(value bool) { sb.l.SetAttrLocal(sb.symIdx, value) }
|
||||
func (sb *SymbolBuilder) SetVisibilityHidden(value bool) {
|
||||
sb.l.SetAttrVisibilityHidden(sb.symIdx, value)
|
||||
}
|
||||
|
|
@ -334,6 +335,10 @@ func (sb *SymbolBuilder) SetAddrPlus(arch *sys.Arch, off int64, tgt Sym, add int
|
|||
return off + int64(r.Size)
|
||||
}
|
||||
|
||||
func (sb *SymbolBuilder) SetAddr(arch *sys.Arch, off int64, tgt Sym) int64 {
|
||||
return sb.SetAddrPlus(arch, off, tgt, 0)
|
||||
}
|
||||
|
||||
func (sb *SymbolBuilder) Addstring(str string) int64 {
|
||||
sb.setReachable()
|
||||
if sb.kind == 0 {
|
||||
|
|
@ -405,3 +410,24 @@ func (sb *SymbolBuilder) AddSize(arch *sys.Arch, tgt Sym) int64 {
|
|||
sb.setReachable()
|
||||
return sb.addSymRef(tgt, 0, objabi.R_SIZE, arch.PtrSize)
|
||||
}
|
||||
|
||||
// GenAddAddrPlusFunc returns a function to be called when capturing
|
||||
// a function symbol's address. In later stages of the link (when
|
||||
// address assignment is done) when doing internal linking and
|
||||
// targeting an executable, we can just emit the address of a function
|
||||
// directly instead of generating a relocation. Clients can call
|
||||
// this function (setting 'internalExec' based on build mode and target)
|
||||
// and then invoke the returned function in roughly the same way that
|
||||
// loader.*SymbolBuilder.AddAddrPlus would be used.
|
||||
func GenAddAddrPlusFunc(internalExec bool) func(s *SymbolBuilder, arch *sys.Arch, tgt Sym, add int64) int64 {
|
||||
if internalExec {
|
||||
return func(s *SymbolBuilder, arch *sys.Arch, tgt Sym, add int64) int64 {
|
||||
if v := s.l.SymValue(tgt); v != 0 {
|
||||
return s.AddUint(arch, uint64(v+add))
|
||||
}
|
||||
return s.AddAddrPlus(arch, tgt, add)
|
||||
}
|
||||
} else {
|
||||
return (*SymbolBuilder).AddAddrPlus
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
|
||||
ctxt.Out.SeekSet(int64(symo))
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
|
|
@ -220,7 +219,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
ld.Asmbelf(ctxt, int64(symo))
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
if *ld.FlagC {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||
|
|
|
|||
|
|
@ -223,7 +223,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
default:
|
||||
if ctxt.IsELF {
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
|
|
@ -233,13 +232,11 @@ func asmb2(ctxt *ld.Link) {
|
|||
|
||||
case objabi.Hplan9:
|
||||
ld.Asmplan9sym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
|
||||
sym := ctxt.Syms.Lookup("pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
ctxt.Out.Write(sym.P)
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -268,7 +265,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
ld.Asmbelf(ctxt, int64(symo))
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
if *ld.FlagC {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||
|
|
|
|||
|
|
@ -733,14 +733,13 @@ func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, ta
|
|||
toctramp := ldr.CreateSymForUpdate("TOC."+ldr.SymName(tramp.Sym()), 0)
|
||||
toctramp.SetType(sym.SXCOFFTOC)
|
||||
toctramp.SetReachable(true)
|
||||
toctramp.AddAddr(ctxt.Arch, target)
|
||||
toctramp.AddAddrPlus(ctxt.Arch, target, offset)
|
||||
|
||||
r := loader.Reloc{
|
||||
Off: 0,
|
||||
Type: objabi.R_ADDRPOWER_TOCREL_DS,
|
||||
Size: 8, // generates 2 relocations: HA + LO
|
||||
Sym: toctramp.Sym(),
|
||||
Add: offset,
|
||||
}
|
||||
tramp.AddReloc(r)
|
||||
} else {
|
||||
|
|
@ -1131,7 +1130,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
default:
|
||||
if ctxt.IsELF {
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
|
|
@ -1141,18 +1139,15 @@ func asmb2(ctxt *ld.Link) {
|
|||
|
||||
case objabi.Hplan9:
|
||||
ld.Asmplan9sym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
|
||||
sym := ctxt.Syms.Lookup("pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
ctxt.Out.Write(sym.P)
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
||||
case objabi.Haix:
|
||||
// symtab must be added once sections have been created in ld.Asmbxcoff
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1181,7 +1176,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
ld.Asmbxcoff(ctxt, int64(fileoff))
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
if *ld.FlagC {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||
|
|
|
|||
|
|
@ -142,7 +142,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
ctxt.Out.SeekSet(int64(symo))
|
||||
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
|
|
@ -157,7 +156,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
default:
|
||||
ld.Errorf(nil, "unsupported operating system")
|
||||
}
|
||||
ctxt.Out.Flush()
|
||||
|
||||
if *ld.FlagC {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
|
|
|
|||
|
|
@ -515,7 +515,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
|
||||
ctxt.Out.SeekSet(int64(symo))
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
|
|
@ -531,7 +530,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
ld.Asmbelf(ctxt, int64(symo))
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
if *ld.FlagC {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||
|
|
|
|||
|
|
@ -56,4 +56,5 @@ type Section struct {
|
|||
Reloff uint64
|
||||
Rellen uint64
|
||||
Sym *Symbol // symbol for the section, if any
|
||||
Index uint16 // each section has a unique index, used internally
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,8 +187,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
if !*ld.FlagS {
|
||||
writeNameSec(ctxt, len(hostImports), fns)
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
||||
func lookupType(sig *wasmFuncType, types *[]*wasmFuncType) uint32 {
|
||||
|
|
|
|||
|
|
@ -372,53 +372,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
|||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
var v uint32
|
||||
|
||||
rs := r.Xsym
|
||||
|
||||
if rs.Type == sym.SHOSTOBJ || r.Type == objabi.R_CALL {
|
||||
if rs.Dynid < 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
|
||||
v = uint32(rs.Dynid)
|
||||
v |= 1 << 27 // external relocation
|
||||
} else {
|
||||
v = uint32(rs.Sect.Extnum)
|
||||
if v == 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Sect.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
case objabi.R_ADDR:
|
||||
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||
}
|
||||
|
||||
switch r.Siz {
|
||||
default:
|
||||
return false
|
||||
case 1:
|
||||
v |= 0 << 25
|
||||
case 2:
|
||||
v |= 1 << 25
|
||||
case 4:
|
||||
v |= 2 << 25
|
||||
case 8:
|
||||
v |= 3 << 25
|
||||
}
|
||||
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32(v)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
|
|
@ -646,7 +600,6 @@ func asmb2(ctxt *ld.Link) {
|
|||
default:
|
||||
if ctxt.IsELF {
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
|
|
@ -656,13 +609,11 @@ func asmb2(ctxt *ld.Link) {
|
|||
|
||||
case objabi.Hplan9:
|
||||
ld.Asmplan9sym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
|
||||
sym := ctxt.Syms.Lookup("pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
ctxt.Out.Write(sym.P)
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
||||
case objabi.Hwindows:
|
||||
|
|
@ -702,6 +653,4 @@ func asmb2(ctxt *ld.Link) {
|
|||
case objabi.Hwindows:
|
||||
ld.Asmbpe(ctxt)
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ func TestBuildForTvOS(t *testing.T) {
|
|||
"-fembed-bitcode",
|
||||
"-framework", "CoreFoundation",
|
||||
}
|
||||
lib := filepath.Join("testdata", "lib.go")
|
||||
lib := filepath.Join("testdata", "testBuildFortvOS", "lib.go")
|
||||
tmpDir, err := ioutil.TempDir("", "go-link-TestBuildFortvOS")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -308,7 +308,7 @@ func TestBuildForTvOS(t *testing.T) {
|
|||
}
|
||||
|
||||
link := exec.Command(CC[0], CC[1:]...)
|
||||
link.Args = append(link.Args, ar, filepath.Join("testdata", "main.m"))
|
||||
link.Args = append(link.Args, ar, filepath.Join("testdata", "testBuildFortvOS", "main.m"))
|
||||
if out, err := link.CombinedOutput(); err != nil {
|
||||
t.Fatalf("%v: %v:\n%s", link.Args, err, out)
|
||||
}
|
||||
|
|
@ -628,3 +628,50 @@ func TestFuncAlign(t *testing.T) {
|
|||
t.Errorf("unexpected output: %s\n", out)
|
||||
}
|
||||
}
|
||||
|
||||
const helloSrc = `
|
||||
package main
|
||||
import "fmt"
|
||||
func main() { fmt.Println("hello") }
|
||||
`
|
||||
|
||||
func TestTrampoline(t *testing.T) {
|
||||
// Test that trampoline insertion works as expected.
|
||||
// For stress test, we set -debugtramp=2 flag, which sets a very low
|
||||
// threshold for trampoline generation, and essentially all cross-package
|
||||
// calls will use trampolines.
|
||||
switch runtime.GOARCH {
|
||||
case "arm", "ppc64", "ppc64le":
|
||||
default:
|
||||
t.Skipf("trampoline insertion is not implemented on %s", runtime.GOARCH)
|
||||
}
|
||||
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "TestTrampoline")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
src := filepath.Join(tmpdir, "hello.go")
|
||||
err = ioutil.WriteFile(src, []byte(helloSrc), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exe := filepath.Join(tmpdir, "hello.exe")
|
||||
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-debugtramp=2", "-o", exe, src)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("build failed: %v\n%s", err, out)
|
||||
}
|
||||
cmd = exec.Command(exe)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("executable failed to run: %v\n%s", err, out)
|
||||
}
|
||||
if string(out) != "hello\n" {
|
||||
t.Errorf("unexpected output:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ func testGoLib(t *testing.T, iscgo bool) {
|
|||
}
|
||||
for i := range syms {
|
||||
sym := &syms[i]
|
||||
if sym.Type == typ && sym.Name == name && sym.CSym == csym {
|
||||
if sym.Type == typ && matchSymName(name, sym.Name) && sym.CSym == csym {
|
||||
if sym.Found {
|
||||
t.Fatalf("duplicate symbol %s %s", sym.Type, sym.Name)
|
||||
}
|
||||
|
|
@ -334,6 +334,14 @@ func TestGoLib(t *testing.T) {
|
|||
testGoLib(t, false)
|
||||
}
|
||||
|
||||
// Check that a symbol has a given name, accepting both
|
||||
// new and old objects.
|
||||
// TODO(go115newobj): remove.
|
||||
func matchSymName(symname, want string) bool {
|
||||
return symname == want ||
|
||||
strings.HasPrefix(symname, want+"#") // new style, with index
|
||||
}
|
||||
|
||||
const testexec = `
|
||||
package main
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -284,9 +285,11 @@ func TestDisasmGoobj(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
// TODO(go115newobj): drop old object file support.
|
||||
need := []string{
|
||||
"main(SB)",
|
||||
"fmthello.go:6",
|
||||
`main(#\d+)?\(SB\)`, // either new or old object file
|
||||
`fmthello\.go:6`,
|
||||
}
|
||||
|
||||
args = []string{
|
||||
|
|
@ -302,8 +305,9 @@ func TestDisasmGoobj(t *testing.T) {
|
|||
text := string(out)
|
||||
ok := true
|
||||
for _, s := range need {
|
||||
if !strings.Contains(text, s) {
|
||||
t.Errorf("disassembly missing '%s'", s)
|
||||
re := regexp.MustCompile(s)
|
||||
if !re.MatchString(text) {
|
||||
t.Errorf("disassembly missing %q", s)
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -328,87 +328,7 @@ func elfsetupplt(ctxt *ld.Link) {
|
|||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
var v uint32
|
||||
|
||||
rs := r.Xsym
|
||||
|
||||
if r.Type == objabi.R_PCREL {
|
||||
if rs.Type == sym.SHOSTOBJ {
|
||||
ld.Errorf(s, "pc-relative relocation of external symbol is not supported")
|
||||
return false
|
||||
}
|
||||
if r.Siz != 4 {
|
||||
return false
|
||||
}
|
||||
|
||||
// emit a pair of "scattered" relocations that
|
||||
// resolve to the difference of section addresses of
|
||||
// the symbol and the instruction
|
||||
// this value is added to the field being relocated
|
||||
o1 := uint32(sectoff)
|
||||
o1 |= 1 << 31 // scattered bit
|
||||
o1 |= ld.MACHO_ARM_RELOC_SECTDIFF << 24
|
||||
o1 |= 2 << 28 // size = 4
|
||||
|
||||
o2 := uint32(0)
|
||||
o2 |= 1 << 31 // scattered bit
|
||||
o2 |= ld.MACHO_ARM_RELOC_PAIR << 24
|
||||
o2 |= 2 << 28 // size = 4
|
||||
|
||||
out.Write32(o1)
|
||||
out.Write32(uint32(ld.Symaddr(rs)))
|
||||
out.Write32(o2)
|
||||
out.Write32(uint32(s.Value + int64(r.Off)))
|
||||
return true
|
||||
}
|
||||
|
||||
if rs.Type == sym.SHOSTOBJ || r.Type == objabi.R_CALLARM {
|
||||
if rs.Dynid < 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
|
||||
v = uint32(rs.Dynid)
|
||||
v |= 1 << 27 // external relocation
|
||||
} else {
|
||||
v = uint32(rs.Sect.Extnum)
|
||||
if v == 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Sect.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
||||
case objabi.R_ADDR:
|
||||
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||
|
||||
case objabi.R_CALLARM:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_ARM_RELOC_BR24 << 28
|
||||
}
|
||||
|
||||
switch r.Siz {
|
||||
default:
|
||||
return false
|
||||
case 1:
|
||||
v |= 0 << 25
|
||||
|
||||
case 2:
|
||||
v |= 1 << 25
|
||||
|
||||
case 4:
|
||||
v |= 2 << 25
|
||||
|
||||
case 8:
|
||||
v |= 3 << 25
|
||||
}
|
||||
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32(v)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
|
|
|
|||
|
|
@ -455,14 +455,9 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
|
|||
} else if ctxt.HeadType == objabi.Hdarwin {
|
||||
if r.Type == objabi.R_CALL {
|
||||
if ctxt.LinkMode == LinkExternal && rs.Type == sym.SDYNIMPORT {
|
||||
switch ctxt.Arch.Family {
|
||||
case sys.AMD64:
|
||||
if ctxt.Arch.Family == sys.AMD64 {
|
||||
// AMD64 dynamic relocations are relative to the end of the relocation.
|
||||
o += int64(r.Siz)
|
||||
case sys.I386:
|
||||
// I386 dynamic relocations are relative to the start of the section.
|
||||
o -= int64(r.Off) // offset in symbol
|
||||
o -= int64(s.Value - int64(s.Sect.Vaddr)) // offset of symbol in section
|
||||
}
|
||||
} else {
|
||||
if rs.Type != sym.SHOSTOBJ {
|
||||
|
|
@ -470,9 +465,6 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
|
|||
}
|
||||
o -= int64(r.Off) // relative to section offset, not symbol
|
||||
}
|
||||
} else if ctxt.Arch.Family == sys.ARM {
|
||||
// see ../arm/asm.go:/machoreloc1
|
||||
o += Symaddr(rs) - s.Value - int64(r.Off)
|
||||
} else {
|
||||
o += int64(r.Siz)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ import (
|
|||
//
|
||||
// 1. direct call
|
||||
// 2. through a reachable interface type
|
||||
// 3. reflect.Value.Call, .Method, or reflect.Method.Func
|
||||
// 3. reflect.Value.Method (or MethodByName), or reflect.Type.Method
|
||||
// (or MethodByName)
|
||||
//
|
||||
// The first case is handled by the flood fill, a directly called method
|
||||
// is marked as reachable.
|
||||
|
|
@ -38,9 +39,9 @@ import (
|
|||
// as reachable. This is extremely conservative, but easy and correct.
|
||||
//
|
||||
// The third case is handled by looking to see if any of:
|
||||
// - reflect.Value.Call is reachable
|
||||
// - reflect.Value.Method is reachable
|
||||
// - reflect.Type.Method or MethodByName is called.
|
||||
// - reflect.Value.Method or MethodByName is reachable
|
||||
// - reflect.Type.Method or MethodByName is called (through the
|
||||
// REFLECTMETHOD attribute marked by the compiler).
|
||||
// If any of these happen, all bets are off and all exported methods
|
||||
// of reachable types are marked reachable.
|
||||
//
|
||||
|
|
@ -65,8 +66,8 @@ func deadcode(ctxt *Link) {
|
|||
d.init()
|
||||
d.flood()
|
||||
|
||||
callSym := ctxt.Syms.ROLookup("reflect.Value.Call", sym.SymVerABIInternal)
|
||||
methSym := ctxt.Syms.ROLookup("reflect.Value.Method", sym.SymVerABIInternal)
|
||||
methByNameSym := ctxt.Syms.ROLookup("reflect.Value.MethodByName", sym.SymVerABIInternal)
|
||||
reflectSeen := false
|
||||
|
||||
if ctxt.DynlinkingGo() {
|
||||
|
|
@ -77,7 +78,7 @@ func deadcode(ctxt *Link) {
|
|||
|
||||
for {
|
||||
if !reflectSeen {
|
||||
if d.reflectMethod || (callSym != nil && callSym.Attr.Reachable()) || (methSym != nil && methSym.Attr.Reachable()) {
|
||||
if d.reflectMethod || (methSym != nil && methSym.Attr.Reachable()) || (methByNameSym != nil && methByNameSym.Attr.Reachable()) {
|
||||
// Methods might be called via reflection. Give up on
|
||||
// static analysis, mark all exported methods of
|
||||
// all reachable types as reachable.
|
||||
|
|
|
|||
|
|
@ -410,53 +410,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
|||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
var v uint32
|
||||
|
||||
rs := r.Xsym
|
||||
|
||||
if rs.Type == sym.SHOSTOBJ || r.Type == objabi.R_CALL {
|
||||
if rs.Dynid < 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
|
||||
v = uint32(rs.Dynid)
|
||||
v |= 1 << 27 // external relocation
|
||||
} else {
|
||||
v = uint32(rs.Sect.Extnum)
|
||||
if v == 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Sect.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
case objabi.R_ADDR:
|
||||
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||
}
|
||||
|
||||
switch r.Siz {
|
||||
default:
|
||||
return false
|
||||
case 1:
|
||||
v |= 0 << 25
|
||||
case 2:
|
||||
v |= 1 << 25
|
||||
case 4:
|
||||
v |= 2 << 25
|
||||
case 8:
|
||||
v |= 3 << 25
|
||||
}
|
||||
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32(v)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
|
|
|
|||
Loading…
Reference in New Issue