mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.link] cmd: delete old object support
We are not going to merge to master until Go 1.16 cycle. The old object support can go now. Change-Id: I93e6f584974c7749d0a0c2e7a96def35134dc566 Reviewed-on: https://go-review.googlesource.com/c/go/+/231918 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
a38bc324ee
commit
c89251204e
102 changed files with 44 additions and 33389 deletions
|
|
@ -25,8 +25,6 @@ var (
|
|||
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
|
||||
Importpath = flag.String("p", "", "set expected package import to path")
|
||||
Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)")
|
||||
|
||||
Go115Newobj = flag.Bool("go115newobj", true, "use new object file format")
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ func main() {
|
|||
}
|
||||
ctxt.Flag_dynlink = *flags.Dynlink
|
||||
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
|
||||
ctxt.Flag_go115newobj = *flags.Go115Newobj
|
||||
ctxt.IsAsm = true
|
||||
switch *flags.Spectre {
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -997,7 +997,6 @@ func (w *exportWriter) linkname(s *types.Sym) {
|
|||
}
|
||||
|
||||
func (w *exportWriter) symIdx(s *types.Sym) {
|
||||
if Ctxt.Flag_go115newobj {
|
||||
lsym := s.Linksym()
|
||||
if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
|
||||
// Don't export index for non-package symbols, linkname'd symbols,
|
||||
|
|
@ -1010,7 +1009,6 @@ func (w *exportWriter) symIdx(s *types.Sym) {
|
|||
w.int64(int64(lsym.SymIdx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inline bodies.
|
||||
|
||||
|
|
|
|||
|
|
@ -696,7 +696,6 @@ func (r *importReader) linkname(s *types.Sym) {
|
|||
}
|
||||
|
||||
func (r *importReader) symIdx(s *types.Sym) {
|
||||
if Ctxt.Flag_go115newobj {
|
||||
lsym := s.Linksym()
|
||||
idx := int32(r.int64())
|
||||
if idx != -1 {
|
||||
|
|
@ -707,7 +706,6 @@ func (r *importReader) symIdx(s *types.Sym) {
|
|||
lsym.Set(obj.AttrIndexed, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *importReader) doInline(n *Node) {
|
||||
if len(n.Func.Inl.Body) != 0 {
|
||||
|
|
|
|||
|
|
@ -281,7 +281,6 @@ func Main(archInit func(*Arch)) {
|
|||
flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
|
||||
flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
|
||||
flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
|
||||
flag.BoolVar(&Ctxt.Flag_go115newobj, "go115newobj", true, "use new object file format")
|
||||
flag.StringVar(&jsonLogOpt, "json", "", "version,destination for JSON compiler/optimizer logging")
|
||||
|
||||
objabi.Flagparse(usage)
|
||||
|
|
@ -315,7 +314,7 @@ func Main(archInit func(*Arch)) {
|
|||
// Record flags that affect the build result. (And don't
|
||||
// record flags that don't, since that would cause spurious
|
||||
// changes in the binary.)
|
||||
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre", "go115newobj")
|
||||
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
|
||||
|
||||
if smallFrames {
|
||||
maxStackVarSize = 128 * 1024
|
||||
|
|
|
|||
|
|
@ -18,21 +18,9 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// TODO(go115newobj): clean up. Some constant prefixes here are no longer
|
||||
// needed in the new object files.
|
||||
|
||||
// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
|
||||
const InfoPrefix = "go.info."
|
||||
|
||||
// RangePrefix is the prefix for all the symbols containing DWARF location lists.
|
||||
const LocPrefix = "go.loc."
|
||||
|
||||
// RangePrefix is the prefix for all the symbols containing DWARF range lists.
|
||||
const RangePrefix = "go.range."
|
||||
|
||||
// DebugLinesPrefix is the prefix for all the symbols containing DWARF debug_line information from the compiler.
|
||||
const DebugLinesPrefix = "go.debuglines."
|
||||
|
||||
// ConstInfoPrefix is the prefix for all symbols containing DWARF info
|
||||
// entries that contain constants.
|
||||
const ConstInfoPrefix = "go.constinfo."
|
||||
|
|
|
|||
|
|
@ -151,12 +151,9 @@ func buildGoobj() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Check that a symbol has a given name, accepting both
|
||||
// new and old objects.
|
||||
// TODO(go115newobj): remove.
|
||||
// Check that a symbol has a given name.
|
||||
func matchSymName(symname, want string) bool {
|
||||
return symname == want ||
|
||||
strings.HasPrefix(symname, want+"#") // new style, with index
|
||||
return strings.HasPrefix(symname, want+"#") // new style, with index
|
||||
}
|
||||
|
||||
func TestParseGoobj(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -656,7 +656,6 @@ type Link struct {
|
|||
Flag_linkshared bool
|
||||
Flag_optimize bool
|
||||
Flag_locationlists bool
|
||||
Flag_go115newobj bool // use new object file format
|
||||
Retpoline bool // emit use of retpoline stubs for indirect jmp/call
|
||||
Bso *bufio.Writer
|
||||
Pathname string
|
||||
|
|
|
|||
|
|
@ -2,234 +2,18 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Writing of Go object files.
|
||||
|
||||
package obj
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// objWriter writes Go object files.
|
||||
type objWriter struct {
|
||||
wr *bufio.Writer
|
||||
ctxt *Link
|
||||
// Temporary buffer for zigzag int writing.
|
||||
varintbuf [10]uint8
|
||||
|
||||
// Number of objects written of each type.
|
||||
nRefs int
|
||||
nData int
|
||||
nReloc int
|
||||
nPcdata int
|
||||
nFuncdata int
|
||||
nFile int
|
||||
|
||||
pkgpath string // the package import path (escaped), "" if unknown
|
||||
}
|
||||
|
||||
func (w *objWriter) addLengths(s *LSym) {
|
||||
w.nData += len(s.P)
|
||||
w.nReloc += len(s.R)
|
||||
|
||||
if s.Type != objabi.STEXT {
|
||||
return
|
||||
}
|
||||
|
||||
pc := &s.Func.Pcln
|
||||
|
||||
data := 0
|
||||
data += len(pc.Pcsp.P)
|
||||
data += len(pc.Pcfile.P)
|
||||
data += len(pc.Pcline.P)
|
||||
data += len(pc.Pcinline.P)
|
||||
for _, pcd := range pc.Pcdata {
|
||||
data += len(pcd.P)
|
||||
}
|
||||
|
||||
w.nData += data
|
||||
w.nPcdata += len(pc.Pcdata)
|
||||
|
||||
w.nFuncdata += len(pc.Funcdataoff)
|
||||
w.nFile += len(pc.File)
|
||||
}
|
||||
|
||||
func (w *objWriter) writeLengths() {
|
||||
w.writeInt(int64(w.nData))
|
||||
w.writeInt(int64(w.nReloc))
|
||||
w.writeInt(int64(w.nPcdata))
|
||||
w.writeInt(int64(0)) // TODO: remove at next object file rev
|
||||
w.writeInt(int64(w.nFuncdata))
|
||||
w.writeInt(int64(w.nFile))
|
||||
}
|
||||
|
||||
func newObjWriter(ctxt *Link, b *bufio.Writer, pkgpath string) *objWriter {
|
||||
return &objWriter{
|
||||
ctxt: ctxt,
|
||||
wr: b,
|
||||
pkgpath: objabi.PathToPrefix(pkgpath),
|
||||
}
|
||||
}
|
||||
|
||||
func WriteObjFile(ctxt *Link, bout *bio.Writer, pkgpath string) {
|
||||
if ctxt.Flag_go115newobj {
|
||||
WriteObjFile2(ctxt, bout, pkgpath)
|
||||
return
|
||||
}
|
||||
|
||||
b := bout.Writer
|
||||
w := newObjWriter(ctxt, b, pkgpath)
|
||||
|
||||
// Magic header
|
||||
w.wr.WriteString("\x00go114ld")
|
||||
|
||||
// Version
|
||||
w.wr.WriteByte(1)
|
||||
|
||||
// Autolib
|
||||
for _, p := range ctxt.Imports {
|
||||
w.writeString(p.Pkg)
|
||||
// This object format ignores p.Fingerprint.
|
||||
}
|
||||
w.writeString("")
|
||||
|
||||
// DWARF File Table
|
||||
fileTable := ctxt.PosTable.DebugLinesFileTable()
|
||||
w.writeInt(int64(len(fileTable)))
|
||||
for _, str := range fileTable {
|
||||
w.writeString(filepath.ToSlash(str))
|
||||
}
|
||||
|
||||
// Symbol references
|
||||
for _, s := range ctxt.Text {
|
||||
w.writeRefs(s)
|
||||
w.addLengths(s)
|
||||
}
|
||||
|
||||
if ctxt.Headtype == objabi.Haix {
|
||||
// Data must be sorted to keep a constant order in TOC symbols.
|
||||
// As they are created during Progedit, two symbols can be switched between
|
||||
// two different compilations. Therefore, BuildID will be different.
|
||||
// TODO: find a better place and optimize to only sort TOC symbols
|
||||
sort.Slice(ctxt.Data, func(i, j int) bool {
|
||||
return ctxt.Data[i].Name < ctxt.Data[j].Name
|
||||
})
|
||||
}
|
||||
|
||||
for _, s := range ctxt.Data {
|
||||
w.writeRefs(s)
|
||||
w.addLengths(s)
|
||||
}
|
||||
for _, s := range ctxt.ABIAliases {
|
||||
w.writeRefs(s)
|
||||
w.addLengths(s)
|
||||
}
|
||||
// End symbol references
|
||||
w.wr.WriteByte(0xff)
|
||||
|
||||
// Lengths
|
||||
w.writeLengths()
|
||||
|
||||
// Data block
|
||||
for _, s := range ctxt.Text {
|
||||
w.wr.Write(s.P)
|
||||
pc := &s.Func.Pcln
|
||||
w.wr.Write(pc.Pcsp.P)
|
||||
w.wr.Write(pc.Pcfile.P)
|
||||
w.wr.Write(pc.Pcline.P)
|
||||
w.wr.Write(pc.Pcinline.P)
|
||||
for _, pcd := range pc.Pcdata {
|
||||
w.wr.Write(pcd.P)
|
||||
}
|
||||
}
|
||||
for _, s := range ctxt.Data {
|
||||
if len(s.P) > 0 {
|
||||
switch s.Type {
|
||||
case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
|
||||
ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name)
|
||||
}
|
||||
}
|
||||
w.wr.Write(s.P)
|
||||
}
|
||||
|
||||
// Symbols
|
||||
for _, s := range ctxt.Text {
|
||||
w.writeSym(s)
|
||||
}
|
||||
for _, s := range ctxt.Data {
|
||||
w.writeSym(s)
|
||||
}
|
||||
for _, s := range ctxt.ABIAliases {
|
||||
w.writeSym(s)
|
||||
}
|
||||
|
||||
// Magic footer
|
||||
w.wr.WriteString("\xffgo114ld")
|
||||
}
|
||||
|
||||
// Symbols are prefixed so their content doesn't get confused with the magic footer.
|
||||
const symPrefix = 0xfe
|
||||
|
||||
func (w *objWriter) writeRef(s *LSym, isPath bool) {
|
||||
if s == nil || s.RefIdx != 0 {
|
||||
return
|
||||
}
|
||||
w.wr.WriteByte(symPrefix)
|
||||
if isPath {
|
||||
w.writeString(filepath.ToSlash(s.Name))
|
||||
} else if w.pkgpath != "" {
|
||||
// w.pkgpath is already escaped.
|
||||
n := strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
|
||||
w.writeString(n)
|
||||
} else {
|
||||
w.writeString(s.Name)
|
||||
}
|
||||
// Write ABI/static information.
|
||||
abi := int64(s.ABI())
|
||||
if s.Static() {
|
||||
abi = -1
|
||||
}
|
||||
w.writeInt(abi)
|
||||
w.nRefs++
|
||||
s.RefIdx = w.nRefs
|
||||
}
|
||||
|
||||
func (w *objWriter) writeRefs(s *LSym) {
|
||||
w.writeRef(s, false)
|
||||
w.writeRef(s.Gotype, false)
|
||||
for _, r := range s.R {
|
||||
w.writeRef(r.Sym, false)
|
||||
}
|
||||
|
||||
if s.Type == objabi.STEXT {
|
||||
pc := &s.Func.Pcln
|
||||
for _, d := range pc.Funcdata {
|
||||
w.writeRef(d, false)
|
||||
}
|
||||
for _, f := range pc.File {
|
||||
fsym := w.ctxt.Lookup(f)
|
||||
w.writeRef(fsym, true)
|
||||
}
|
||||
for _, call := range pc.InlTree.nodes {
|
||||
w.writeRef(call.Func, false)
|
||||
f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
|
||||
fsym := w.ctxt.Lookup(f)
|
||||
w.writeRef(fsym, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ctxt *Link) writeSymDebug(s *LSym) {
|
||||
ctxt.writeSymDebugNamed(s, s.Name)
|
||||
}
|
||||
|
|
@ -311,138 +95,6 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *objWriter) writeSym(s *LSym) {
|
||||
ctxt := w.ctxt
|
||||
if ctxt.Debugasm > 0 {
|
||||
w.ctxt.writeSymDebug(s)
|
||||
}
|
||||
|
||||
w.wr.WriteByte(symPrefix)
|
||||
w.wr.WriteByte(byte(s.Type))
|
||||
w.writeRefIndex(s)
|
||||
flags := int64(0)
|
||||
if s.DuplicateOK() {
|
||||
flags |= 1
|
||||
}
|
||||
if s.Local() {
|
||||
flags |= 1 << 1
|
||||
}
|
||||
if s.MakeTypelink() {
|
||||
flags |= 1 << 2
|
||||
}
|
||||
w.writeInt(flags)
|
||||
w.writeInt(s.Size)
|
||||
w.writeRefIndex(s.Gotype)
|
||||
w.writeInt(int64(len(s.P)))
|
||||
|
||||
w.writeInt(int64(len(s.R)))
|
||||
var r *Reloc
|
||||
for i := range s.R {
|
||||
r = &s.R[i]
|
||||
w.writeInt(int64(r.Off))
|
||||
w.writeInt(int64(r.Siz))
|
||||
w.writeInt(int64(r.Type))
|
||||
w.writeInt(r.Add)
|
||||
w.writeRefIndex(r.Sym)
|
||||
}
|
||||
|
||||
if s.Type != objabi.STEXT {
|
||||
return
|
||||
}
|
||||
|
||||
w.writeInt(int64(s.Func.Args))
|
||||
w.writeInt(int64(s.Func.Locals))
|
||||
w.writeInt(int64(s.Func.Align))
|
||||
w.writeBool(s.NoSplit())
|
||||
flags = int64(0)
|
||||
if s.Leaf() {
|
||||
flags |= 1
|
||||
}
|
||||
if s.CFunc() {
|
||||
flags |= 1 << 1
|
||||
}
|
||||
if s.ReflectMethod() {
|
||||
flags |= 1 << 2
|
||||
}
|
||||
if ctxt.Flag_shared {
|
||||
flags |= 1 << 3
|
||||
}
|
||||
if s.TopFrame() {
|
||||
flags |= 1 << 4
|
||||
}
|
||||
w.writeInt(flags)
|
||||
w.writeInt(int64(0)) // TODO: remove at next object file rev
|
||||
|
||||
pc := &s.Func.Pcln
|
||||
w.writeInt(int64(len(pc.Pcsp.P)))
|
||||
w.writeInt(int64(len(pc.Pcfile.P)))
|
||||
w.writeInt(int64(len(pc.Pcline.P)))
|
||||
w.writeInt(int64(len(pc.Pcinline.P)))
|
||||
w.writeInt(int64(len(pc.Pcdata)))
|
||||
for _, pcd := range pc.Pcdata {
|
||||
w.writeInt(int64(len(pcd.P)))
|
||||
}
|
||||
w.writeInt(int64(len(pc.Funcdataoff)))
|
||||
for i := range pc.Funcdataoff {
|
||||
w.writeRefIndex(pc.Funcdata[i])
|
||||
}
|
||||
for i := range pc.Funcdataoff {
|
||||
w.writeInt(pc.Funcdataoff[i])
|
||||
}
|
||||
w.writeInt(int64(len(pc.File)))
|
||||
for _, f := range pc.File {
|
||||
fsym := ctxt.Lookup(f)
|
||||
w.writeRefIndex(fsym)
|
||||
}
|
||||
w.writeInt(int64(len(pc.InlTree.nodes)))
|
||||
for _, call := range pc.InlTree.nodes {
|
||||
w.writeInt(int64(call.Parent))
|
||||
f, l := linkgetlineFromPos(w.ctxt, call.Pos)
|
||||
fsym := ctxt.Lookup(f)
|
||||
w.writeRefIndex(fsym)
|
||||
w.writeInt(int64(l))
|
||||
w.writeRefIndex(call.Func)
|
||||
w.writeInt(int64(call.ParentPC))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *objWriter) writeBool(b bool) {
|
||||
if b {
|
||||
w.writeInt(1)
|
||||
} else {
|
||||
w.writeInt(0)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *objWriter) writeInt(sval int64) {
|
||||
var v uint64
|
||||
uv := (uint64(sval) << 1) ^ uint64(sval>>63)
|
||||
p := w.varintbuf[:]
|
||||
for v = uv; v >= 0x80; v >>= 7 {
|
||||
p[0] = uint8(v | 0x80)
|
||||
p = p[1:]
|
||||
}
|
||||
p[0] = uint8(v)
|
||||
p = p[1:]
|
||||
w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
|
||||
}
|
||||
|
||||
func (w *objWriter) writeString(s string) {
|
||||
w.writeInt(int64(len(s)))
|
||||
w.wr.WriteString(s)
|
||||
}
|
||||
|
||||
func (w *objWriter) writeRefIndex(s *LSym) {
|
||||
if s == nil {
|
||||
w.writeInt(0)
|
||||
return
|
||||
}
|
||||
if s.RefIdx == 0 {
|
||||
log.Fatalln("writing an unreferenced symbol", s.Name)
|
||||
}
|
||||
w.writeInt(int64(s.RefIdx))
|
||||
}
|
||||
|
||||
// relocByOff sorts relocations by their offsets.
|
||||
type relocByOff []Reloc
|
||||
|
||||
|
|
@ -510,17 +162,11 @@ func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64)
|
|||
func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
|
||||
ls := s.(*LSym)
|
||||
rsym := f.(*LSym)
|
||||
if c.Link.Flag_go115newobj {
|
||||
fidx := c.Link.PosTable.FileIndex(rsym.Name)
|
||||
// Note the +1 here -- the value we're writing is going to be an
|
||||
// index into the DWARF line table file section, whose entries
|
||||
// are numbered starting at 1, not 0.
|
||||
ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
|
||||
} else {
|
||||
ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0)
|
||||
r := &ls.R[len(ls.R)-1]
|
||||
r.Type = objabi.R_DWARFFILEREF
|
||||
}
|
||||
}
|
||||
|
||||
func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
|
||||
|
|
@ -558,7 +204,6 @@ func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym,
|
|||
ctxt.Diag("dwarfSym of non-TEXT %v", s)
|
||||
}
|
||||
if s.Func.dwarfInfoSym == nil {
|
||||
if ctxt.Flag_go115newobj {
|
||||
s.Func.dwarfInfoSym = &LSym{
|
||||
Type: objabi.SDWARFINFO,
|
||||
}
|
||||
|
|
@ -573,14 +218,6 @@ func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym,
|
|||
s.Func.dwarfDebugLinesSym = &LSym{
|
||||
Type: objabi.SDWARFLINES,
|
||||
}
|
||||
} else {
|
||||
s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
|
||||
if ctxt.Flag_locationlists {
|
||||
s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name)
|
||||
}
|
||||
s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
|
||||
s.Func.dwarfDebugLinesSym = ctxt.LookupDerived(s, dwarf.DebugLinesPrefix+s.Name)
|
||||
}
|
||||
if s.WasInlined() {
|
||||
s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import (
|
|||
)
|
||||
|
||||
// Entry point of writing new object file.
|
||||
func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
|
||||
func WriteObjFile(ctxt *Link, b *bio.Writer, pkgpath string) {
|
||||
|
||||
debugAsmEmit(ctxt)
|
||||
|
||||
|
|
|
|||
|
|
@ -139,26 +139,7 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
|
|||
ctxt.Text = append(ctxt.Text, s)
|
||||
|
||||
// Set up DWARF entries for s
|
||||
info, loc, ranges, _, lines := ctxt.dwarfSym(s)
|
||||
|
||||
// When using new object files, the DWARF symbols are unnamed aux
|
||||
// symbols and don't need to be added to ctxt.Data.
|
||||
// But the old object file still needs them.
|
||||
if !ctxt.Flag_go115newobj {
|
||||
info.Type = objabi.SDWARFINFO
|
||||
info.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||
if loc != nil {
|
||||
loc.Type = objabi.SDWARFLOC
|
||||
loc.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||
ctxt.Data = append(ctxt.Data, loc)
|
||||
}
|
||||
ranges.Type = objabi.SDWARFRANGE
|
||||
ranges.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||
ctxt.Data = append(ctxt.Data, info, ranges)
|
||||
lines.Type = objabi.SDWARFLINES
|
||||
lines.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||
ctxt.Data = append(ctxt.Data, lines)
|
||||
}
|
||||
ctxt.dwarfSym(s)
|
||||
}
|
||||
|
||||
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
|
||||
|
|
|
|||
|
|
@ -165,10 +165,6 @@ func (ctxt *Link) Int64Sym(i int64) *LSym {
|
|||
// asm is set to true if this is called by the assembler (i.e. not the compiler),
|
||||
// in which case all the symbols are non-package (for now).
|
||||
func (ctxt *Link) NumberSyms(asm bool) {
|
||||
if !ctxt.Flag_go115newobj {
|
||||
return
|
||||
}
|
||||
|
||||
if ctxt.Headtype == objabi.Haix {
|
||||
// Data must be sorted to keep a constant order in TOC symbols.
|
||||
// As they are created during Progedit, two symbols can be switched between
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import (
|
|||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
|
|
@ -99,8 +98,6 @@ var (
|
|||
|
||||
benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
|
||||
benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof")
|
||||
|
||||
flagGo115Newobj = flag.Bool("go115newobj", true, "use new object file format")
|
||||
)
|
||||
|
||||
// Main is the main entry point for the linker code.
|
||||
|
|
@ -140,10 +137,6 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
|
||||
objabi.Flagparse(usage)
|
||||
|
||||
if !*flagGo115Newobj {
|
||||
oldlink()
|
||||
}
|
||||
|
||||
switch *flagHeadType {
|
||||
case "":
|
||||
case "windowsgui":
|
||||
|
|
@ -415,48 +408,3 @@ func startProfile() {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke the old linker and exit.
|
||||
func oldlink() {
|
||||
linker := os.Args[0]
|
||||
if strings.HasSuffix(linker, "link") {
|
||||
linker = linker[:len(linker)-4] + "oldlink"
|
||||
} else if strings.HasSuffix(linker, "link.exe") {
|
||||
linker = linker[:len(linker)-8] + "oldlink.exe"
|
||||
} else {
|
||||
log.Fatal("cannot find oldlink. arg0=", linker)
|
||||
}
|
||||
|
||||
// Copy args, filter out -go115newobj flag
|
||||
args := make([]string, 0, len(os.Args)-1)
|
||||
skipNext := false
|
||||
for i, a := range os.Args {
|
||||
if i == 0 {
|
||||
continue // skip arg0
|
||||
}
|
||||
if skipNext {
|
||||
skipNext = false
|
||||
continue
|
||||
}
|
||||
if a == "-go115newobj" {
|
||||
skipNext = true
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(a, "-go115newobj=") {
|
||||
continue
|
||||
}
|
||||
args = append(args, a)
|
||||
}
|
||||
|
||||
cmd := exec.Command(linker, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
if _, ok := err.(*exec.ExitError); ok {
|
||||
os.Exit(2) // would be nice to use ExitError.ExitCode(), but that is too new
|
||||
}
|
||||
log.Fatal("invoke oldlink failed:", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1914,7 +1914,7 @@ func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, uni
|
|||
r := goobj2.NewReaderFromBytes(roObject, readonly)
|
||||
if r == nil {
|
||||
if len(roObject) >= 8 && bytes.Equal(roObject[:8], []byte("\x00go114ld")) {
|
||||
log.Fatalf("found object file %s in old format, but -go115newobj is true\nset -go115newobj consistently in all -gcflags, -asmflags, and -ldflags", f.File().Name())
|
||||
log.Fatalf("found object file %s in old format", f.File().Name())
|
||||
}
|
||||
panic("cannot read object file")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -535,30 +535,6 @@ func TestStrictDup(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestOldLink(t *testing.T) {
|
||||
// Test that old object file format still works.
|
||||
// TODO(go115newobj): delete.
|
||||
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "TestOldLink")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
src := filepath.Join(tmpdir, "main.go")
|
||||
err = ioutil.WriteFile(src, []byte("package main; func main(){}\n"), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "run", "-gcflags=all=-go115newobj=false", "-asmflags=all=-go115newobj=false", "-ldflags=-go115newobj=false", src)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Errorf("%v: %v:\n%s", cmd.Args, err, out)
|
||||
}
|
||||
}
|
||||
|
||||
const testFuncAlignSrc = `
|
||||
package main
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -335,11 +335,11 @@ func TestGoLib(t *testing.T) {
|
|||
}
|
||||
|
||||
// Check that a symbol has a given name, accepting both
|
||||
// new and old objects.
|
||||
// TODO(go115newobj): remove.
|
||||
// with (for packaged symbols) and without index (for
|
||||
// non-package symbols).
|
||||
func matchSymName(symname, want string) bool {
|
||||
return symname == want ||
|
||||
strings.HasPrefix(symname, want+"#") // new style, with index
|
||||
strings.HasPrefix(symname, want+"#")
|
||||
}
|
||||
|
||||
const testexec = `
|
||||
|
|
|
|||
|
|
@ -286,9 +286,8 @@ func TestDisasmGoobj(t *testing.T) {
|
|||
t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
// TODO(go115newobj): drop old object file support.
|
||||
need := []string{
|
||||
`main(#\d+)?\(SB\)`, // either new or old object file
|
||||
`main#\d+\(SB\)`,
|
||||
`fmthello\.go:6`,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
// Copyright 2009 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.
|
||||
|
||||
/*
|
||||
Link, typically invoked as ``go tool link,'' reads the Go archive or object
|
||||
for a package main, along with its dependencies, and combines them
|
||||
into an executable binary.
|
||||
|
||||
Command Line
|
||||
|
||||
Usage:
|
||||
|
||||
go tool link [flags] main.a
|
||||
|
||||
Flags:
|
||||
|
||||
-B note
|
||||
Add an ELF_NT_GNU_BUILD_ID note when using ELF.
|
||||
The value should start with 0x and be an even number of hex digits.
|
||||
-D address
|
||||
Set data segment address.
|
||||
-E entry
|
||||
Set entry symbol name.
|
||||
-H type
|
||||
Set executable format type.
|
||||
The default format is inferred from GOOS and GOARCH.
|
||||
On Windows, -H windowsgui writes a "GUI binary" instead of a "console binary."
|
||||
-I interpreter
|
||||
Set the ELF dynamic linker to use.
|
||||
-L dir1 -L dir2
|
||||
Search for imported packages in dir1, dir2, etc,
|
||||
after consulting $GOROOT/pkg/$GOOS_$GOARCH.
|
||||
-R quantum
|
||||
Set address rounding quantum.
|
||||
-T address
|
||||
Set text segment address.
|
||||
-V
|
||||
Print linker version and exit.
|
||||
-X importpath.name=value
|
||||
Set the value of the string variable in importpath named name to value.
|
||||
This is only effective if the variable is declared in the source code either uninitialized
|
||||
or initialized to a constant string expression. -X will not work if the initializer makes
|
||||
a function call or refers to other variables.
|
||||
Note that before Go 1.5 this option took two separate arguments.
|
||||
-a
|
||||
Disassemble output.
|
||||
-buildid id
|
||||
Record id as Go toolchain build id.
|
||||
-buildmode mode
|
||||
Set build mode (default exe).
|
||||
-c
|
||||
Dump call graphs.
|
||||
-compressdwarf
|
||||
Compress DWARF if possible (default true).
|
||||
-cpuprofile file
|
||||
Write CPU profile to file.
|
||||
-d
|
||||
Disable generation of dynamic executables.
|
||||
The emitted code is the same in either case; the option
|
||||
controls only whether a dynamic header is included.
|
||||
The dynamic header is on by default, even without any
|
||||
references to dynamic libraries, because many common
|
||||
system tools now assume the presence of the header.
|
||||
-debugtramp int
|
||||
Debug trampolines.
|
||||
-dumpdep
|
||||
Dump symbol dependency graph.
|
||||
-extar ar
|
||||
Set the external archive program (default "ar").
|
||||
Used only for -buildmode=c-archive.
|
||||
-extld linker
|
||||
Set the external linker (default "clang" or "gcc").
|
||||
-extldflags flags
|
||||
Set space-separated flags to pass to the external linker.
|
||||
-f
|
||||
Ignore version mismatch in the linked archives.
|
||||
-g
|
||||
Disable Go package data checks.
|
||||
-importcfg file
|
||||
Read import configuration from file.
|
||||
In the file, set packagefile, packageshlib to specify import resolution.
|
||||
-installsuffix suffix
|
||||
Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix
|
||||
instead of $GOROOT/pkg/$GOOS_$GOARCH.
|
||||
-k symbol
|
||||
Set field tracking symbol. Use this flag when GOEXPERIMENT=fieldtrack is set.
|
||||
-libgcc file
|
||||
Set name of compiler support library.
|
||||
This is only used in internal link mode.
|
||||
If not set, default value comes from running the compiler,
|
||||
which may be set by the -extld option.
|
||||
Set to "none" to use no support library.
|
||||
-linkmode mode
|
||||
Set link mode (internal, external, auto).
|
||||
This sets the linking mode as described in cmd/cgo/doc.go.
|
||||
-linkshared
|
||||
Link against installed Go shared libraries (experimental).
|
||||
-memprofile file
|
||||
Write memory profile to file.
|
||||
-memprofilerate rate
|
||||
Set runtime.MemProfileRate to rate.
|
||||
-msan
|
||||
Link with C/C++ memory sanitizer support.
|
||||
-n
|
||||
Dump symbol table.
|
||||
-o file
|
||||
Write output to file (default a.out, or a.out.exe on Windows).
|
||||
-pluginpath path
|
||||
The path name used to prefix exported plugin symbols.
|
||||
-r dir1:dir2:...
|
||||
Set the ELF dynamic linker search path.
|
||||
-race
|
||||
Link with race detection libraries.
|
||||
-s
|
||||
Omit the symbol table and debug information.
|
||||
-shared
|
||||
Generated shared object (implies -linkmode external; experimental).
|
||||
-tmpdir dir
|
||||
Write temporary files to dir.
|
||||
Temporary files are only used in external linking mode.
|
||||
-u
|
||||
Reject unsafe packages.
|
||||
-v
|
||||
Print trace of linker operations.
|
||||
-w
|
||||
Omit the DWARF symbol table.
|
||||
*/
|
||||
package main
|
||||
|
|
@ -1,874 +0,0 @@
|
|||
// Inferno utils/6l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"debug/elf"
|
||||
"log"
|
||||
)
|
||||
|
||||
func PADDR(x uint32) uint32 {
|
||||
return x &^ 0x80000000
|
||||
}
|
||||
|
||||
func Addcall(ctxt *ld.Link, s *sym.Symbol, t *sym.Symbol) int64 {
|
||||
s.Attr |= sym.AttrReachable
|
||||
i := s.Size
|
||||
s.Size += 4
|
||||
s.Grow(s.Size)
|
||||
r := s.AddRel()
|
||||
r.Sym = t
|
||||
r.Off = int32(i)
|
||||
r.Type = objabi.R_CALL
|
||||
r.Siz = 4
|
||||
return i + int64(r.Siz)
|
||||
}
|
||||
|
||||
func gentext(ctxt *ld.Link) {
|
||||
if !ctxt.DynlinkingGo() {
|
||||
return
|
||||
}
|
||||
addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
|
||||
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
|
||||
// we're linking a module containing the runtime -> no need for
|
||||
// an init function
|
||||
return
|
||||
}
|
||||
addmoduledata.Attr |= sym.AttrReachable
|
||||
initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
|
||||
initfunc.Type = sym.STEXT
|
||||
initfunc.Attr |= sym.AttrLocal
|
||||
initfunc.Attr |= sym.AttrReachable
|
||||
o := func(op ...uint8) {
|
||||
for _, op1 := range op {
|
||||
initfunc.AddUint8(op1)
|
||||
}
|
||||
}
|
||||
// 0000000000000000 <local.dso_init>:
|
||||
// 0: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 7 <local.dso_init+0x7>
|
||||
// 3: R_X86_64_PC32 runtime.firstmoduledata-0x4
|
||||
o(0x48, 0x8d, 0x3d)
|
||||
initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 0)
|
||||
// 7: e8 00 00 00 00 callq c <local.dso_init+0xc>
|
||||
// 8: R_X86_64_PLT32 runtime.addmoduledata-0x4
|
||||
o(0xe8)
|
||||
Addcall(ctxt, initfunc, addmoduledata)
|
||||
// c: c3 retq
|
||||
o(0xc3)
|
||||
if ctxt.BuildMode == ld.BuildModePlugin {
|
||||
ctxt.Textp = append(ctxt.Textp, addmoduledata)
|
||||
}
|
||||
ctxt.Textp = append(ctxt.Textp, initfunc)
|
||||
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
|
||||
initarray_entry.Attr |= sym.AttrReachable
|
||||
initarray_entry.Attr |= sym.AttrLocal
|
||||
initarray_entry.Type = sym.SINITARR
|
||||
initarray_entry.AddAddr(ctxt.Arch, initfunc)
|
||||
}
|
||||
|
||||
func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == sym.SXREF {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 8
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add += int64(targ.Plt())
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX):
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
s.P[r.Off-2] = 0x8d
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to using GOT and hope for the best (CMOV*)
|
||||
// TODO: just needs relocation, no need to put in .dynsym
|
||||
addgotsym(ctxt, targ)
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += 4
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal {
|
||||
// For internal linking PIE, this R_ADDR relocation cannot
|
||||
// be resolved statically. We need to generate a dynamic
|
||||
// relocation. Let the code below handle it.
|
||||
break
|
||||
}
|
||||
return true
|
||||
|
||||
// Handle relocations found in Mach-O object files.
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
|
||||
// TODO: What is the difference between all these?
|
||||
r.Type = objabi.R_ADDR
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add = int64(targ.Plt())
|
||||
r.Type = objabi.R_PCREL
|
||||
return true
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
|
||||
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
|
||||
r.Type = objabi.R_PCREL
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||
ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
s.P[r.Off-2] = 0x8d
|
||||
r.Type = objabi.R_PCREL
|
||||
return true
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
}
|
||||
addgotsym(ctxt, targ)
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// nothing to do, the relocation will be laid out in reloc
|
||||
return true
|
||||
}
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
// External linker will do this relocation.
|
||||
return true
|
||||
}
|
||||
// Internal linking, for both ELF and Mach-O.
|
||||
// Build a PLT entry and change the relocation target to that entry.
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add = int64(targ.Plt())
|
||||
return true
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type == sym.STEXT && ctxt.IsELF {
|
||||
if ctxt.HeadType == objabi.Hsolaris {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add += int64(targ.Plt())
|
||||
return true
|
||||
}
|
||||
// The code is asking for the address of an external
|
||||
// function. We provide it with the address of the
|
||||
// correspondent GOT symbol.
|
||||
addgotsym(ctxt, targ)
|
||||
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
}
|
||||
|
||||
// Process dynamic relocations for the data sections.
|
||||
if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal {
|
||||
// When internally linking, generate dynamic relocations
|
||||
// for all typical R_ADDR relocations. The exception
|
||||
// are those R_ADDR that are created as part of generating
|
||||
// the dynamic relocations and must be resolved statically.
|
||||
//
|
||||
// There are three phases relevant to understanding this:
|
||||
//
|
||||
// dodata() // we are here
|
||||
// address() // symbol address assignment
|
||||
// reloc() // resolution of static R_ADDR relocs
|
||||
//
|
||||
// At this point symbol addresses have not been
|
||||
// assigned yet (as the final size of the .rela section
|
||||
// will affect the addresses), and so we cannot write
|
||||
// the Elf64_Rela.r_offset now. Instead we delay it
|
||||
// until after the 'address' phase of the linker is
|
||||
// complete. We do this via Addaddrplus, which creates
|
||||
// a new R_ADDR relocation which will be resolved in
|
||||
// the 'reloc' phase.
|
||||
//
|
||||
// These synthetic static R_ADDR relocs must be skipped
|
||||
// now, or else we will be caught in an infinite loop
|
||||
// of generating synthetic relocs for our synthetic
|
||||
// relocs.
|
||||
//
|
||||
// Furthermore, the rela sections contain dynamic
|
||||
// relocations with R_ADDR relocations on
|
||||
// Elf64_Rela.r_offset. This field should contain the
|
||||
// symbol offset as determined by reloc(), not the
|
||||
// final dynamically linked address as a dynamic
|
||||
// relocation would provide.
|
||||
switch s.Name {
|
||||
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
// Either internally linking a static executable,
|
||||
// in which case we can resolve these relocations
|
||||
// statically in the 'reloc' phase, or externally
|
||||
// linking, in which case the relocation will be
|
||||
// prepared in the 'reloc' phase and passed to the
|
||||
// external linker in the 'asmb' phase.
|
||||
if s.Type != sym.SDATA && s.Type != sym.SRODATA {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ctxt.IsELF {
|
||||
// Generate R_X86_64_RELATIVE relocations for best
|
||||
// efficiency in the dynamic linker.
|
||||
//
|
||||
// As noted above, symbol addresses have not been
|
||||
// assigned yet, so we can't generate the final reloc
|
||||
// entry yet. We ultimately want:
|
||||
//
|
||||
// r_offset = s + r.Off
|
||||
// r_info = R_X86_64_RELATIVE
|
||||
// r_addend = targ + r.Add
|
||||
//
|
||||
// The dynamic linker will set *offset = base address +
|
||||
// addend.
|
||||
//
|
||||
// AddAddrPlus is used for r_offset and r_addend to
|
||||
// generate new R_ADDR relocations that will update
|
||||
// these fields in the 'reloc' phase.
|
||||
rela := ctxt.Syms.Lookup(".rela", 0)
|
||||
rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
|
||||
if r.Siz == 8 {
|
||||
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
|
||||
} else {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
rela.AddAddrPlus(ctxt.Arch, targ, int64(r.Add))
|
||||
// Not mark r done here. So we still apply it statically,
|
||||
// so in the file content we'll also have the right offset
|
||||
// to the relocation target. So it can be examined statically
|
||||
// (e.g. go version).
|
||||
return true
|
||||
}
|
||||
|
||||
if ctxt.HeadType == objabi.Hdarwin && s.Size == int64(ctxt.Arch.PtrSize) && r.Off == 0 {
|
||||
// Mach-O relocations are a royal pain to lay out.
|
||||
// They use a compact stateful bytecode representation
|
||||
// that is too much bother to deal with.
|
||||
// Instead, interpret the C declaration
|
||||
// void *_Cvar_stderr = &stderr;
|
||||
// as making _Cvar_stderr the name of a GOT entry
|
||||
// for stderr. This is separate from the usual GOT entry,
|
||||
// just in case the C code assigns to the variable,
|
||||
// and of course it only works for single pointers,
|
||||
// but we only need to support cgo and that's all it needs.
|
||||
ld.Adddynsym(ctxt, targ)
|
||||
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
s.Type = got.Type
|
||||
s.Attr |= sym.AttrSubSymbol
|
||||
s.Outer = got
|
||||
s.Sub = got.Sub
|
||||
got.Sub = s
|
||||
s.Value = got.Size
|
||||
got.AddUint64(ctxt.Arch, 0)
|
||||
ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(targ.Dynid))
|
||||
r.Type = objabi.ElfRelocOffset // ignore during relocsym
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write64(uint64(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
case objabi.R_ADDR:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32)
|
||||
} else if r.Siz == 8 {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_64) | uint64(elfsym)<<32)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_TLS_LE:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_TPOFF32) | uint64(elfsym)<<32)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_TLS_IE:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_GOTTPOFF) | uint64(elfsym)<<32)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_CALL:
|
||||
if r.Siz == 4 {
|
||||
if r.Xsym.Type == sym.SDYNIMPORT {
|
||||
if ctxt.DynlinkingGo() {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
|
||||
} else {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
|
||||
}
|
||||
} else {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_PCREL:
|
||||
if r.Siz == 4 {
|
||||
if r.Xsym.Type == sym.SDYNIMPORT && r.Xsym.ElfType() == elf.STT_FUNC {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
|
||||
} else {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_GOTPCREL:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Out.Write64(uint64(r.Xadd))
|
||||
return true
|
||||
}
|
||||
|
||||
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_PCREL || r.Type == objabi.R_GOTPCREL || 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_X86_64_RELOC_UNSIGNED << 28
|
||||
|
||||
case objabi.R_CALL:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
|
||||
|
||||
// NOTE: Only works with 'external' relocation. Forced above.
|
||||
case objabi.R_PCREL:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
|
||||
case objabi.R_GOTPCREL:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_X86_64_RELOC_GOT_LOAD << 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
|
||||
}
|
||||
|
||||
func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
var v uint32
|
||||
|
||||
rs := r.Xsym
|
||||
|
||||
if rs.Dynid < 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32(uint32(rs.Dynid))
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
||||
case objabi.R_DWARFSECREF:
|
||||
v = ld.IMAGE_REL_AMD64_SECREL
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if r.Siz == 8 {
|
||||
v = ld.IMAGE_REL_AMD64_ADDR64
|
||||
} else {
|
||||
v = ld.IMAGE_REL_AMD64_ADDR32
|
||||
}
|
||||
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
v = ld.IMAGE_REL_AMD64_REL32
|
||||
}
|
||||
|
||||
out.Write16(uint16(v))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
|
||||
return val, false
|
||||
}
|
||||
|
||||
func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
|
||||
log.Fatalf("unexpected relocation variant")
|
||||
return t
|
||||
}
|
||||
|
||||
func elfsetupplt(ctxt *ld.Link) {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
got := ctxt.Syms.Lookup(".got.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
// pushq got+8(IP)
|
||||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x35)
|
||||
plt.AddPCRelPlus(ctxt.Arch, got, 8)
|
||||
|
||||
// jmpq got+16(IP)
|
||||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddPCRelPlus(ctxt.Arch, got, 16)
|
||||
|
||||
// nopl 0(AX)
|
||||
plt.AddUint32(ctxt.Arch, 0x00401f0f)
|
||||
|
||||
// assume got->size == 0 too
|
||||
got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
|
||||
|
||||
got.AddUint64(ctxt.Arch, 0)
|
||||
got.AddUint64(ctxt.Arch, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
|
||||
if ctxt.IsELF {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
got := ctxt.Syms.Lookup(".got.plt", 0)
|
||||
rela := ctxt.Syms.Lookup(".rela.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
elfsetupplt(ctxt)
|
||||
}
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddPCRelPlus(ctxt.Arch, got, got.Size)
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
got.AddAddrPlus(ctxt.Arch, plt, plt.Size)
|
||||
|
||||
// pushq $x
|
||||
plt.AddUint8(0x68)
|
||||
|
||||
plt.AddUint32(ctxt.Arch, uint32((got.Size-24-8)/8))
|
||||
|
||||
// jmpq .plt
|
||||
plt.AddUint8(0xe9)
|
||||
|
||||
plt.AddUint32(ctxt.Arch, uint32(-(plt.Size + 4)))
|
||||
|
||||
// rela
|
||||
rela.AddAddrPlus(ctxt.Arch, got, got.Size-8)
|
||||
|
||||
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT)))
|
||||
rela.AddUint64(ctxt.Arch, 0)
|
||||
|
||||
s.SetPlt(int32(plt.Size - 16))
|
||||
} else if ctxt.HeadType == objabi.Hdarwin {
|
||||
// To do lazy symbol lookup right, we're supposed
|
||||
// to tell the dynamic loader which library each
|
||||
// symbol comes from and format the link info
|
||||
// section just so. I'm too lazy (ha!) to do that
|
||||
// so for now we'll just use non-lazy pointers,
|
||||
// which don't need to be told which library to use.
|
||||
//
|
||||
// https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
|
||||
// has details about what we're avoiding.
|
||||
|
||||
addgotsym(ctxt, s)
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
|
||||
ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
s.SetPlt(int32(plt.Size))
|
||||
|
||||
plt.AddUint8(0xff)
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddPCRelPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got()))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
s.SetGot(int32(got.Size))
|
||||
got.AddUint64(ctxt.Arch, 0)
|
||||
|
||||
if ctxt.IsELF {
|
||||
rela := ctxt.Syms.Lookup(".rela", 0)
|
||||
rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got()))
|
||||
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT)))
|
||||
rela.AddUint64(ctxt.Arch, 0)
|
||||
} else if ctxt.HeadType == objabi.Hdarwin {
|
||||
ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect := ld.Segtext.Sections[0]
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
// 0xCC is INT $3 - breakpoint instruction
|
||||
ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
|
||||
for _, sect = range ld.Segtext.Sections[1:] {
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
if ld.Segrelrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
|
||||
ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
|
||||
}
|
||||
|
||||
func asmb2(ctxt *ld.Link) {
|
||||
machlink := int64(0)
|
||||
if ctxt.HeadType == objabi.Hdarwin {
|
||||
machlink = ld.Domacholink(ctxt)
|
||||
}
|
||||
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Errorf(nil, "unknown header type %v", ctxt.HeadType)
|
||||
fallthrough
|
||||
|
||||
case objabi.Hplan9:
|
||||
break
|
||||
|
||||
case objabi.Hdarwin:
|
||||
ld.Flag8 = true /* 64-bit addresses */
|
||||
|
||||
case objabi.Hlinux,
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd,
|
||||
objabi.Hdragonfly,
|
||||
objabi.Hsolaris:
|
||||
ld.Flag8 = true /* 64-bit addresses */
|
||||
|
||||
case objabi.Hwindows:
|
||||
break
|
||||
}
|
||||
|
||||
ld.Symsize = 0
|
||||
ld.Spsize = 0
|
||||
ld.Lcsize = 0
|
||||
symo := int64(0)
|
||||
if !*ld.FlagS {
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
case objabi.Hplan9:
|
||||
*ld.FlagS = true
|
||||
symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
|
||||
case objabi.Hdarwin:
|
||||
symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
|
||||
|
||||
case objabi.Hlinux,
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd,
|
||||
objabi.Hdragonfly,
|
||||
objabi.Hsolaris:
|
||||
symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = ld.Rnd(symo, int64(*ld.FlagRound))
|
||||
|
||||
case objabi.Hwindows:
|
||||
symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = ld.Rnd(symo, ld.PEFILEALIGN)
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(symo)
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
if ctxt.IsELF {
|
||||
ctxt.Out.SeekSet(symo)
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Elfemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
// Do nothing
|
||||
|
||||
case objabi.Hdarwin:
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Machoemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(0)
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
case objabi.Hplan9: /* plan9 */
|
||||
magic := int32(4*26*26 + 7)
|
||||
|
||||
magic |= 0x00008000 /* fat header */
|
||||
ctxt.Out.Write32b(uint32(magic)) /* magic */
|
||||
ctxt.Out.Write32b(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||
ctxt.Out.Write32b(uint32(ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32b(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32b(uint32(ld.Symsize)) /* nsyms */
|
||||
vl := ld.Entryvalue(ctxt)
|
||||
ctxt.Out.Write32b(PADDR(uint32(vl))) /* va of entry */
|
||||
ctxt.Out.Write32b(uint32(ld.Spsize)) /* sp offsets */
|
||||
ctxt.Out.Write32b(uint32(ld.Lcsize)) /* line offsets */
|
||||
ctxt.Out.Write64b(uint64(vl)) /* va of entry */
|
||||
|
||||
case objabi.Hdarwin:
|
||||
ld.Asmbmacho(ctxt)
|
||||
|
||||
case objabi.Hlinux,
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd,
|
||||
objabi.Hdragonfly,
|
||||
objabi.Hsolaris:
|
||||
ld.Asmbelf(ctxt, symo)
|
||||
|
||||
case objabi.Hwindows:
|
||||
ld.Asmbpe(ctxt)
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
||||
func tlsIEtoLE(s *sym.Symbol, off, size int) {
|
||||
// Transform the PC-relative instruction into a constant load.
|
||||
// That is,
|
||||
//
|
||||
// MOVQ X(IP), REG -> MOVQ $Y, REG
|
||||
//
|
||||
// To determine the instruction and register, we study the op codes.
|
||||
// Consult an AMD64 instruction encoding guide to decipher this.
|
||||
if off < 3 {
|
||||
log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction")
|
||||
}
|
||||
op := s.P[off-3 : off]
|
||||
reg := op[2] >> 3
|
||||
|
||||
if op[1] == 0x8b || reg == 4 {
|
||||
// MOVQ
|
||||
if op[0] == 0x4c {
|
||||
op[0] = 0x49
|
||||
} else if size == 4 && op[0] == 0x44 {
|
||||
op[0] = 0x41
|
||||
}
|
||||
if op[1] == 0x8b {
|
||||
op[1] = 0xc7
|
||||
} else {
|
||||
op[1] = 0x81 // special case for SP
|
||||
}
|
||||
op[2] = 0xc0 | reg
|
||||
} else {
|
||||
// An alternate op is ADDQ. This is handled by GNU gold,
|
||||
// but right now is not generated by the Go compiler:
|
||||
// ADDQ X(IP), REG -> ADDQ $Y, REG
|
||||
// Consider adding support for it here.
|
||||
log.Fatalf("expected TLS IE op to be MOVQ, got %v", op)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
// Inferno utils/6l/l.h
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package amd64
|
||||
|
||||
const (
|
||||
maxAlign = 32 // max data alignment
|
||||
minAlign = 1 // min data alignment
|
||||
funcAlign = 16
|
||||
)
|
||||
|
||||
/* Used by ../internal/ld/dwarf.go */
|
||||
const (
|
||||
dwarfRegSP = 7
|
||||
dwarfRegLR = 16
|
||||
)
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
// Inferno utils/6l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
)
|
||||
|
||||
func Init() (*sys.Arch, ld.Arch) {
|
||||
arch := sys.ArchAMD64
|
||||
|
||||
theArch := ld.Arch{
|
||||
Funcalign: funcAlign,
|
||||
Maxalign: maxAlign,
|
||||
Minalign: minAlign,
|
||||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
Asmb: asmb,
|
||||
Asmb2: asmb2,
|
||||
Elfreloc1: elfreloc1,
|
||||
Elfsetupplt: elfsetupplt,
|
||||
Gentext: gentext,
|
||||
Machoreloc1: machoreloc1,
|
||||
PEreloc1: pereloc1,
|
||||
TLSIEtoLE: tlsIEtoLE,
|
||||
|
||||
Linuxdynld: "/lib64/ld-linux-x86-64.so.2",
|
||||
Freebsddynld: "/libexec/ld-elf.so.1",
|
||||
Openbsddynld: "/usr/libexec/ld.so",
|
||||
Netbsddynld: "/libexec/ld.elf_so",
|
||||
Dragonflydynld: "/usr/libexec/ld-elf.so.2",
|
||||
Solarisdynld: "/lib/amd64/ld.so.1",
|
||||
}
|
||||
|
||||
return arch, theArch
|
||||
}
|
||||
|
||||
func archinit(ctxt *ld.Link) {
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Exitf("unknown -H option: %v", ctxt.HeadType)
|
||||
|
||||
case objabi.Hplan9: /* plan 9 */
|
||||
ld.HEADR = 32 + 8
|
||||
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0x200000 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 0x200000
|
||||
}
|
||||
|
||||
case objabi.Hdarwin: /* apple MACH */
|
||||
ld.HEADR = ld.INITIAL_MACHO_HEADR
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 4096
|
||||
}
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0x1000000 + int64(ld.HEADR)
|
||||
}
|
||||
|
||||
case objabi.Hlinux, /* elf64 executable */
|
||||
objabi.Hfreebsd, /* freebsd */
|
||||
objabi.Hnetbsd, /* netbsd */
|
||||
objabi.Hopenbsd, /* openbsd */
|
||||
objabi.Hdragonfly, /* dragonfly */
|
||||
objabi.Hsolaris: /* solaris */
|
||||
ld.Elfinit(ctxt)
|
||||
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = (1 << 22) + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 4096
|
||||
}
|
||||
|
||||
case objabi.Hwindows: /* PE executable */
|
||||
// ld.HEADR, ld.FlagTextAddr, ld.FlagRound are set in ld.Peinit
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -1,786 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// This assembler:
|
||||
//
|
||||
// .align 2
|
||||
// local.dso_init:
|
||||
// ldr r0, .Lmoduledata
|
||||
// .Lloadfrom:
|
||||
// ldr r0, [r0]
|
||||
// b runtime.addmoduledata@plt
|
||||
// .align 2
|
||||
// .Lmoduledata:
|
||||
// .word local.moduledata(GOT_PREL) + (. - (.Lloadfrom + 4))
|
||||
// assembles to:
|
||||
//
|
||||
// 00000000 <local.dso_init>:
|
||||
// 0: e59f0004 ldr r0, [pc, #4] ; c <local.dso_init+0xc>
|
||||
// 4: e5900000 ldr r0, [r0]
|
||||
// 8: eafffffe b 0 <runtime.addmoduledata>
|
||||
// 8: R_ARM_JUMP24 runtime.addmoduledata
|
||||
// c: 00000004 .word 0x00000004
|
||||
// c: R_ARM_GOT_PREL local.moduledata
|
||||
|
||||
func gentext(ctxt *ld.Link) {
|
||||
if !ctxt.DynlinkingGo() {
|
||||
return
|
||||
}
|
||||
addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
|
||||
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
|
||||
// we're linking a module containing the runtime -> no need for
|
||||
// an init function
|
||||
return
|
||||
}
|
||||
addmoduledata.Attr |= sym.AttrReachable
|
||||
initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
|
||||
initfunc.Type = sym.STEXT
|
||||
initfunc.Attr |= sym.AttrLocal
|
||||
initfunc.Attr |= sym.AttrReachable
|
||||
o := func(op uint32) {
|
||||
initfunc.AddUint32(ctxt.Arch, op)
|
||||
}
|
||||
o(0xe59f0004)
|
||||
o(0xe08f0000)
|
||||
|
||||
o(0xeafffffe)
|
||||
rel := initfunc.AddRel()
|
||||
rel.Off = 8
|
||||
rel.Siz = 4
|
||||
rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
|
||||
rel.Type = objabi.R_CALLARM
|
||||
rel.Add = 0xeafffffe // vomit
|
||||
|
||||
o(0x00000000)
|
||||
rel = initfunc.AddRel()
|
||||
rel.Off = 12
|
||||
rel.Siz = 4
|
||||
rel.Sym = ctxt.Moduledata
|
||||
rel.Type = objabi.R_PCREL
|
||||
rel.Add = 4
|
||||
|
||||
if ctxt.BuildMode == ld.BuildModePlugin {
|
||||
ctxt.Textp = append(ctxt.Textp, addmoduledata)
|
||||
}
|
||||
ctxt.Textp = append(ctxt.Textp, initfunc)
|
||||
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
|
||||
initarray_entry.Attr |= sym.AttrReachable
|
||||
initarray_entry.Attr |= sym.AttrLocal
|
||||
initarray_entry.Type = sym.SINITARR
|
||||
initarray_entry.AddAddr(ctxt.Arch, initfunc)
|
||||
}
|
||||
|
||||
// Preserve highest 8 bits of a, and do addition to lower 24-bit
|
||||
// of a and b; used to adjust ARM branch instruction's target
|
||||
func braddoff(a int32, b int32) int32 {
|
||||
return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
|
||||
}
|
||||
|
||||
func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PLT32):
|
||||
r.Type = objabi.R_CALLARM
|
||||
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_THM_PC22): // R_ARM_THM_CALL
|
||||
ld.Exitf("R_ARM_THM_CALL, are you using -marm?")
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT32): // R_ARM_GOT_BREL
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
addgotsyminternal(ctxt, targ)
|
||||
} else {
|
||||
addgotsym(ctxt, targ)
|
||||
}
|
||||
|
||||
r.Type = objabi.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT_PREL): // GOT(nil) + A - nil
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
addgotsyminternal(ctxt, targ)
|
||||
} else {
|
||||
addgotsym(ctxt, targ)
|
||||
}
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += int64(targ.Got()) + 4
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTOFF): // R_ARM_GOTOFF32
|
||||
r.Type = objabi.R_GOTOFF
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTPC): // R_ARM_BASE_PREL
|
||||
r.Type = objabi.R_PCREL
|
||||
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += 4
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_CALL):
|
||||
r.Type = objabi.R_CALLARM
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_REL32): // R_ARM_REL32
|
||||
r.Type = objabi.R_PCREL
|
||||
|
||||
r.Add += 4
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_ABS32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
return true
|
||||
|
||||
// we can just ignore this, because we are targeting ARM V5+ anyway
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_V4BX):
|
||||
if r.Sym != nil {
|
||||
// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
|
||||
r.Sym.Type = 0
|
||||
}
|
||||
|
||||
r.Sym = nil
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PC24),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_JUMP24):
|
||||
r.Type = objabi.R_CALLARM
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
return true
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case objabi.R_CALLARM:
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
// External linker will do this relocation.
|
||||
return true
|
||||
}
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add = int64(targ.Plt())
|
||||
return true
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type != sym.SDATA {
|
||||
break
|
||||
}
|
||||
if ctxt.IsELF {
|
||||
ld.Adddynsym(ctxt, targ)
|
||||
rel := ctxt.Syms.Lookup(".rel", 0)
|
||||
rel.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
|
||||
rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
|
||||
r.Type = objabi.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write32(uint32(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
case objabi.R_ADDR:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write32(uint32(elf.R_ARM_ABS32) | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_PCREL:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write32(uint32(elf.R_ARM_REL32) | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_CALLARM:
|
||||
if r.Siz == 4 {
|
||||
if r.Add&0xff000000 == 0xeb000000 { // BL
|
||||
ctxt.Out.Write32(uint32(elf.R_ARM_CALL) | uint32(elfsym)<<8)
|
||||
} else {
|
||||
ctxt.Out.Write32(uint32(elf.R_ARM_JUMP24) | uint32(elfsym)<<8)
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_TLS_LE:
|
||||
ctxt.Out.Write32(uint32(elf.R_ARM_TLS_LE32) | uint32(elfsym)<<8)
|
||||
case objabi.R_TLS_IE:
|
||||
ctxt.Out.Write32(uint32(elf.R_ARM_TLS_IE32) | uint32(elfsym)<<8)
|
||||
case objabi.R_GOTPCREL:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write32(uint32(elf.R_ARM_GOT_PREL) | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func elfsetupplt(ctxt *ld.Link) {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
got := ctxt.Syms.Lookup(".got.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
// str lr, [sp, #-4]!
|
||||
plt.AddUint32(ctxt.Arch, 0xe52de004)
|
||||
|
||||
// ldr lr, [pc, #4]
|
||||
plt.AddUint32(ctxt.Arch, 0xe59fe004)
|
||||
|
||||
// add lr, pc, lr
|
||||
plt.AddUint32(ctxt.Arch, 0xe08fe00e)
|
||||
|
||||
// ldr pc, [lr, #8]!
|
||||
plt.AddUint32(ctxt.Arch, 0xe5bef008)
|
||||
|
||||
// .word &GLOBAL_OFFSET_TABLE[0] - .
|
||||
plt.AddPCRelPlus(ctxt.Arch, got, 4)
|
||||
|
||||
// the first .plt entry requires 3 .plt.got entries
|
||||
got.AddUint32(ctxt.Arch, 0)
|
||||
|
||||
got.AddUint32(ctxt.Arch, 0)
|
||||
got.AddUint32(ctxt.Arch, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
rs := r.Xsym
|
||||
|
||||
if rs.Dynid < 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32(uint32(rs.Dynid))
|
||||
|
||||
var v uint32
|
||||
switch r.Type {
|
||||
default:
|
||||
// unsupported relocation type
|
||||
return false
|
||||
|
||||
case objabi.R_DWARFSECREF:
|
||||
v = ld.IMAGE_REL_ARM_SECREL
|
||||
|
||||
case objabi.R_ADDR:
|
||||
v = ld.IMAGE_REL_ARM_ADDR32
|
||||
}
|
||||
|
||||
out.Write16(uint16(v))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// sign extend a 24-bit integer
|
||||
func signext24(x int64) int32 {
|
||||
return (int32(x) << 8) >> 8
|
||||
}
|
||||
|
||||
// encode an immediate in ARM's imm12 format. copied from ../../../internal/obj/arm/asm5.go
|
||||
func immrot(v uint32) uint32 {
|
||||
for i := 0; i < 16; i++ {
|
||||
if v&^0xff == 0 {
|
||||
return uint32(i<<8) | v | 1<<25
|
||||
}
|
||||
v = v<<2 | v>>30
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Convert the direct jump relocation r to refer to a trampoline if the target is too far
|
||||
func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
|
||||
switch r.Type {
|
||||
case objabi.R_CALLARM:
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
|
||||
if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
|
||||
// direct call too far, need to insert trampoline.
|
||||
// look up existing trampolines first. if we found one within the range
|
||||
// of direct call, we can reuse it. otherwise create a new one.
|
||||
offset := (signext24(r.Add&0xffffff) + 2) * 4
|
||||
var tramp *sym.Symbol
|
||||
for i := 0; ; i++ {
|
||||
name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i)
|
||||
tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
|
||||
if tramp.Type == sym.SDYNIMPORT {
|
||||
// don't reuse trampoline defined in other module
|
||||
continue
|
||||
}
|
||||
if tramp.Value == 0 {
|
||||
// either the trampoline does not exist -- we need to create one,
|
||||
// or found one the address which is not assigned -- this will be
|
||||
// laid down immediately after the current function. use this one.
|
||||
break
|
||||
}
|
||||
|
||||
t = (ld.Symaddr(tramp) - 8 - (s.Value + int64(r.Off))) / 4
|
||||
if t >= -0x800000 && t < 0x7fffff {
|
||||
// found an existing trampoline that is not too far
|
||||
// we can just use it
|
||||
break
|
||||
}
|
||||
}
|
||||
if tramp.Type == 0 {
|
||||
// trampoline does not exist, create one
|
||||
ctxt.AddTramp(tramp)
|
||||
if ctxt.DynlinkingGo() {
|
||||
if immrot(uint32(offset)) == 0 {
|
||||
ld.Errorf(s, "odd offset in dynlink direct call: %v+%d", r.Sym, offset)
|
||||
}
|
||||
gentrampdyn(ctxt.Arch, tramp, r.Sym, int64(offset))
|
||||
} else if ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE {
|
||||
gentramppic(ctxt.Arch, tramp, r.Sym, int64(offset))
|
||||
} else {
|
||||
gentramp(ctxt.Arch, ctxt.LinkMode, tramp, r.Sym, int64(offset))
|
||||
}
|
||||
}
|
||||
// modify reloc to point to tramp, which will be resolved later
|
||||
r.Sym = tramp
|
||||
r.Add = r.Add&0xff000000 | 0xfffffe // clear the offset embedded in the instruction
|
||||
r.Done = false
|
||||
}
|
||||
default:
|
||||
ld.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
|
||||
}
|
||||
}
|
||||
|
||||
// generate a trampoline to target+offset
|
||||
func gentramp(arch *sys.Arch, linkmode ld.LinkMode, tramp, target *sym.Symbol, offset int64) {
|
||||
tramp.Size = 12 // 3 instructions
|
||||
tramp.P = make([]byte, tramp.Size)
|
||||
t := ld.Symaddr(target) + offset
|
||||
o1 := uint32(0xe5900000 | 11<<12 | 15<<16) // MOVW (R15), R11 // R15 is actual pc + 8
|
||||
o2 := uint32(0xe12fff10 | 11) // JMP (R11)
|
||||
o3 := uint32(t) // WORD $target
|
||||
arch.ByteOrder.PutUint32(tramp.P, o1)
|
||||
arch.ByteOrder.PutUint32(tramp.P[4:], o2)
|
||||
arch.ByteOrder.PutUint32(tramp.P[8:], o3)
|
||||
|
||||
if linkmode == ld.LinkExternal {
|
||||
r := tramp.AddRel()
|
||||
r.Off = 8
|
||||
r.Type = objabi.R_ADDR
|
||||
r.Siz = 4
|
||||
r.Sym = target
|
||||
r.Add = offset
|
||||
}
|
||||
}
|
||||
|
||||
// generate a trampoline to target+offset in position independent code
|
||||
func gentramppic(arch *sys.Arch, tramp, target *sym.Symbol, offset int64) {
|
||||
tramp.Size = 16 // 4 instructions
|
||||
tramp.P = make([]byte, tramp.Size)
|
||||
o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 4) // MOVW 4(R15), R11 // R15 is actual pc + 8
|
||||
o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
|
||||
o3 := uint32(0xe12fff10 | 11) // JMP (R11)
|
||||
o4 := uint32(0) // WORD $(target-pc) // filled in with relocation
|
||||
arch.ByteOrder.PutUint32(tramp.P, o1)
|
||||
arch.ByteOrder.PutUint32(tramp.P[4:], o2)
|
||||
arch.ByteOrder.PutUint32(tramp.P[8:], o3)
|
||||
arch.ByteOrder.PutUint32(tramp.P[12:], o4)
|
||||
|
||||
r := tramp.AddRel()
|
||||
r.Off = 12
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Siz = 4
|
||||
r.Sym = target
|
||||
r.Add = offset + 4
|
||||
}
|
||||
|
||||
// generate a trampoline to target+offset in dynlink mode (using GOT)
|
||||
func gentrampdyn(arch *sys.Arch, tramp, target *sym.Symbol, offset int64) {
|
||||
tramp.Size = 20 // 5 instructions
|
||||
o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 8) // MOVW 8(R15), R11 // R15 is actual pc + 8
|
||||
o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
|
||||
o3 := uint32(0xe5900000 | 11<<12 | 11<<16) // MOVW (R11), R11
|
||||
o4 := uint32(0xe12fff10 | 11) // JMP (R11)
|
||||
o5 := uint32(0) // WORD $target@GOT // filled in with relocation
|
||||
o6 := uint32(0)
|
||||
if offset != 0 {
|
||||
// insert an instruction to add offset
|
||||
tramp.Size = 24 // 6 instructions
|
||||
o6 = o5
|
||||
o5 = o4
|
||||
o4 = 0xe2800000 | 11<<12 | 11<<16 | immrot(uint32(offset)) // ADD $offset, R11, R11
|
||||
o1 = uint32(0xe5900000 | 11<<12 | 15<<16 | 12) // MOVW 12(R15), R11
|
||||
}
|
||||
tramp.P = make([]byte, tramp.Size)
|
||||
arch.ByteOrder.PutUint32(tramp.P, o1)
|
||||
arch.ByteOrder.PutUint32(tramp.P[4:], o2)
|
||||
arch.ByteOrder.PutUint32(tramp.P[8:], o3)
|
||||
arch.ByteOrder.PutUint32(tramp.P[12:], o4)
|
||||
arch.ByteOrder.PutUint32(tramp.P[16:], o5)
|
||||
if offset != 0 {
|
||||
arch.ByteOrder.PutUint32(tramp.P[20:], o6)
|
||||
}
|
||||
|
||||
r := tramp.AddRel()
|
||||
r.Off = 16
|
||||
r.Type = objabi.R_GOTPCREL
|
||||
r.Siz = 4
|
||||
r.Sym = target
|
||||
r.Add = 8
|
||||
if offset != 0 {
|
||||
// increase reloc offset by 4 as we inserted an ADD instruction
|
||||
r.Off = 20
|
||||
r.Add = 12
|
||||
}
|
||||
}
|
||||
|
||||
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
switch r.Type {
|
||||
case objabi.R_CALLARM:
|
||||
r.Done = false
|
||||
|
||||
// set up addend for eventual relocation via outer symbol.
|
||||
rs := r.Sym
|
||||
|
||||
r.Xadd = int64(signext24(r.Add & 0xffffff))
|
||||
r.Xadd *= 4
|
||||
for rs.Outer != nil {
|
||||
r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
|
||||
rs = rs.Outer
|
||||
}
|
||||
|
||||
if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
|
||||
ld.Errorf(s, "missing section for %s", rs.Name)
|
||||
}
|
||||
r.Xsym = rs
|
||||
|
||||
if r.Xadd/4 > 0x7fffff || r.Xadd/4 < -0x800000 {
|
||||
ld.Errorf(s, "direct call too far %d", r.Xadd/4)
|
||||
}
|
||||
|
||||
return int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4)))), true
|
||||
}
|
||||
|
||||
return -1, false
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case objabi.R_CONST:
|
||||
return r.Add, true
|
||||
case objabi.R_GOTOFF:
|
||||
return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
|
||||
|
||||
// The following three arch specific relocations are only for generation of
|
||||
// Linux/ARM ELF's PLT entry (3 assembler instruction)
|
||||
case objabi.R_PLT0: // add ip, pc, #0xXX00000
|
||||
if ld.Symaddr(ctxt.Syms.Lookup(".got.plt", 0)) < ld.Symaddr(ctxt.Syms.Lookup(".plt", 0)) {
|
||||
ld.Errorf(s, ".got.plt should be placed after .plt section.")
|
||||
}
|
||||
return 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add)) >> 20)), true
|
||||
case objabi.R_PLT1: // add ip, ip, #0xYY000
|
||||
return 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+4)) >> 12)), true
|
||||
case objabi.R_PLT2: // ldr pc, [ip, #0xZZZ]!
|
||||
return 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+8))), true
|
||||
case objabi.R_CALLARM: // bl XXXXXX or b YYYYYY
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4
|
||||
if t > 0x7fffff || t < -0x800000 {
|
||||
ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
|
||||
}
|
||||
return int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&t))), true
|
||||
}
|
||||
|
||||
return val, false
|
||||
}
|
||||
|
||||
func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
|
||||
log.Fatalf("unexpected relocation variant")
|
||||
return t
|
||||
}
|
||||
|
||||
func addpltreloc(ctxt *ld.Link, plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, typ objabi.RelocType) {
|
||||
r := plt.AddRel()
|
||||
r.Sym = got
|
||||
r.Off = int32(plt.Size)
|
||||
r.Siz = 4
|
||||
r.Type = typ
|
||||
r.Add = int64(s.Got()) - 8
|
||||
|
||||
plt.Attr |= sym.AttrReachable
|
||||
plt.Size += 4
|
||||
plt.Grow(plt.Size)
|
||||
}
|
||||
|
||||
func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
|
||||
if ctxt.IsELF {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
got := ctxt.Syms.Lookup(".got.plt", 0)
|
||||
rel := ctxt.Syms.Lookup(".rel.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
elfsetupplt(ctxt)
|
||||
}
|
||||
|
||||
// .got entry
|
||||
s.SetGot(int32(got.Size))
|
||||
|
||||
// In theory, all GOT should point to the first PLT entry,
|
||||
// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
|
||||
// dynamic linker won't, so we'd better do it ourselves.
|
||||
got.AddAddrPlus(ctxt.Arch, plt, 0)
|
||||
|
||||
// .plt entry, this depends on the .got entry
|
||||
s.SetPlt(int32(plt.Size))
|
||||
|
||||
addpltreloc(ctxt, plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000
|
||||
addpltreloc(ctxt, plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000
|
||||
addpltreloc(ctxt, plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]!
|
||||
|
||||
// rel
|
||||
rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got()))
|
||||
|
||||
rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_JUMP_SLOT)))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsyminternal(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
s.SetGot(int32(got.Size))
|
||||
|
||||
got.AddAddrPlus(ctxt.Arch, s, 0)
|
||||
|
||||
if ctxt.IsELF {
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsyminternal: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
s.SetGot(int32(got.Size))
|
||||
got.AddUint32(ctxt.Arch, 0)
|
||||
|
||||
if ctxt.IsELF {
|
||||
rel := ctxt.Syms.Lookup(".rel", 0)
|
||||
rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got()))
|
||||
rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_GLOB_DAT)))
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect := ld.Segtext.Sections[0]
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
for _, sect = range ld.Segtext.Sections[1:] {
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
if ld.Segrelrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
|
||||
ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
|
||||
}
|
||||
|
||||
func asmb2(ctxt *ld.Link) {
|
||||
/* output symbol table */
|
||||
ld.Symsize = 0
|
||||
|
||||
ld.Lcsize = 0
|
||||
symo := uint32(0)
|
||||
if !*ld.FlagS {
|
||||
// TODO: rationalize
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
if ctxt.IsELF {
|
||||
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
|
||||
}
|
||||
|
||||
case objabi.Hplan9:
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
|
||||
case objabi.Hwindows:
|
||||
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(symo))
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
if ctxt.IsELF {
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Elfemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(0)
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
case objabi.Hplan9: /* plan 9 */
|
||||
ctxt.Out.Write32b(0x647) /* magic */
|
||||
ctxt.Out.Write32b(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||
ctxt.Out.Write32b(uint32(ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32b(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32b(uint32(ld.Symsize)) /* nsyms */
|
||||
ctxt.Out.Write32b(uint32(ld.Entryvalue(ctxt))) /* va of entry */
|
||||
ctxt.Out.Write32b(0)
|
||||
ctxt.Out.Write32b(uint32(ld.Lcsize))
|
||||
|
||||
case objabi.Hlinux,
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd:
|
||||
ld.Asmbelf(ctxt, int64(symo))
|
||||
|
||||
case objabi.Hwindows:
|
||||
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)
|
||||
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package arm
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// Inferno utils/5l/l.h
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
maxAlign = 8 // max data alignment
|
||||
minAlign = 1 // min data alignment
|
||||
funcAlign = 4 // single-instruction alignment
|
||||
)
|
||||
|
||||
/* Used by ../internal/ld/dwarf.go */
|
||||
const (
|
||||
dwarfRegSP = 13
|
||||
dwarfRegLR = 14
|
||||
)
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
// Inferno utils/5l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
)
|
||||
|
||||
func Init() (*sys.Arch, ld.Arch) {
|
||||
arch := sys.ArchARM
|
||||
|
||||
theArch := ld.Arch{
|
||||
Funcalign: funcAlign,
|
||||
Maxalign: maxAlign,
|
||||
Minalign: minAlign,
|
||||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
Trampoline: trampoline,
|
||||
Asmb: asmb,
|
||||
Asmb2: asmb2,
|
||||
Elfreloc1: elfreloc1,
|
||||
Elfsetupplt: elfsetupplt,
|
||||
Gentext: gentext,
|
||||
Machoreloc1: machoreloc1,
|
||||
PEreloc1: pereloc1,
|
||||
|
||||
Linuxdynld: "/lib/ld-linux.so.3", // 2 for OABI, 3 for EABI
|
||||
Freebsddynld: "/usr/libexec/ld-elf.so.1",
|
||||
Openbsddynld: "/usr/libexec/ld.so",
|
||||
Netbsddynld: "/libexec/ld.elf_so",
|
||||
Dragonflydynld: "XXX",
|
||||
Solarisdynld: "XXX",
|
||||
}
|
||||
|
||||
return arch, theArch
|
||||
}
|
||||
|
||||
func archinit(ctxt *ld.Link) {
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Exitf("unknown -H option: %v", ctxt.HeadType)
|
||||
|
||||
case objabi.Hplan9: /* plan 9 */
|
||||
ld.HEADR = 32
|
||||
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 4128
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 4096
|
||||
}
|
||||
|
||||
case objabi.Hlinux, /* arm elf */
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd:
|
||||
*ld.FlagD = false
|
||||
// with dynamic linking
|
||||
ld.Elfinit(ctxt)
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 0x10000
|
||||
}
|
||||
|
||||
case objabi.Hwindows: /* PE executable */
|
||||
// ld.HEADR, ld.FlagTextAddr, ld.FlagRound are set in ld.Peinit
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -1,946 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func gentext(ctxt *ld.Link) {
|
||||
if !ctxt.DynlinkingGo() {
|
||||
return
|
||||
}
|
||||
addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
|
||||
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
|
||||
// we're linking a module containing the runtime -> no need for
|
||||
// an init function
|
||||
return
|
||||
}
|
||||
addmoduledata.Attr |= sym.AttrReachable
|
||||
initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
|
||||
initfunc.Type = sym.STEXT
|
||||
initfunc.Attr |= sym.AttrLocal
|
||||
initfunc.Attr |= sym.AttrReachable
|
||||
o := func(op uint32) {
|
||||
initfunc.AddUint32(ctxt.Arch, op)
|
||||
}
|
||||
// 0000000000000000 <local.dso_init>:
|
||||
// 0: 90000000 adrp x0, 0 <runtime.firstmoduledata>
|
||||
// 0: R_AARCH64_ADR_PREL_PG_HI21 local.moduledata
|
||||
// 4: 91000000 add x0, x0, #0x0
|
||||
// 4: R_AARCH64_ADD_ABS_LO12_NC local.moduledata
|
||||
o(0x90000000)
|
||||
o(0x91000000)
|
||||
rel := initfunc.AddRel()
|
||||
rel.Off = 0
|
||||
rel.Siz = 8
|
||||
rel.Sym = ctxt.Moduledata
|
||||
rel.Type = objabi.R_ADDRARM64
|
||||
|
||||
// 8: 14000000 b 0 <runtime.addmoduledata>
|
||||
// 8: R_AARCH64_CALL26 runtime.addmoduledata
|
||||
o(0x14000000)
|
||||
rel = initfunc.AddRel()
|
||||
rel.Off = 8
|
||||
rel.Siz = 4
|
||||
rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
|
||||
rel.Type = objabi.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference
|
||||
|
||||
if ctxt.BuildMode == ld.BuildModePlugin {
|
||||
ctxt.Textp = append(ctxt.Textp, addmoduledata)
|
||||
}
|
||||
ctxt.Textp = append(ctxt.Textp, initfunc)
|
||||
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
|
||||
initarray_entry.Attr |= sym.AttrReachable
|
||||
initarray_entry.Attr |= sym.AttrLocal
|
||||
initarray_entry.Type = sym.SINITARR
|
||||
initarray_entry.AddAddr(ctxt.Arch, initfunc)
|
||||
}
|
||||
|
||||
func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == sym.SXREF {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 8
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add += int64(targ.Plt())
|
||||
}
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in callarm64", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_CALLARM64
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC):
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
// TODO: turn LDR of GOT entry into ADR of symbol itself
|
||||
}
|
||||
|
||||
// fall back to using GOT
|
||||
// TODO: just needs relocation, no need to put in .dynsym
|
||||
addgotsym(ctxt, targ)
|
||||
|
||||
r.Type = objabi.R_ARM64_GOT
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == sym.SXREF {
|
||||
ld.Errorf(s, "unknown symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ARM64_PCREL
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal {
|
||||
// For internal linking PIE, this R_ADDR relocation cannot
|
||||
// be resolved statically. We need to generate a dynamic
|
||||
// relocation. Let the code below handle it.
|
||||
break
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ARM64_LDST8
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ARM64_LDST32
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ARM64_LDST64
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ARM64_LDST128
|
||||
return true
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL,
|
||||
objabi.R_CALLARM64:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// nothing to do, the relocation will be laid out in reloc
|
||||
return true
|
||||
}
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
// External linker will do this relocation.
|
||||
return true
|
||||
}
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type == sym.STEXT && ctxt.IsELF {
|
||||
// The code is asking for the address of an external
|
||||
// function. We provide it with the address of the
|
||||
// correspondent GOT symbol.
|
||||
addgotsym(ctxt, targ)
|
||||
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
}
|
||||
|
||||
// Process dynamic relocations for the data sections.
|
||||
if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal {
|
||||
// When internally linking, generate dynamic relocations
|
||||
// for all typical R_ADDR relocations. The exception
|
||||
// are those R_ADDR that are created as part of generating
|
||||
// the dynamic relocations and must be resolved statically.
|
||||
//
|
||||
// There are three phases relevant to understanding this:
|
||||
//
|
||||
// dodata() // we are here
|
||||
// address() // symbol address assignment
|
||||
// reloc() // resolution of static R_ADDR relocs
|
||||
//
|
||||
// At this point symbol addresses have not been
|
||||
// assigned yet (as the final size of the .rela section
|
||||
// will affect the addresses), and so we cannot write
|
||||
// the Elf64_Rela.r_offset now. Instead we delay it
|
||||
// until after the 'address' phase of the linker is
|
||||
// complete. We do this via Addaddrplus, which creates
|
||||
// a new R_ADDR relocation which will be resolved in
|
||||
// the 'reloc' phase.
|
||||
//
|
||||
// These synthetic static R_ADDR relocs must be skipped
|
||||
// now, or else we will be caught in an infinite loop
|
||||
// of generating synthetic relocs for our synthetic
|
||||
// relocs.
|
||||
//
|
||||
// Furthermore, the rela sections contain dynamic
|
||||
// relocations with R_ADDR relocations on
|
||||
// Elf64_Rela.r_offset. This field should contain the
|
||||
// symbol offset as determined by reloc(), not the
|
||||
// final dynamically linked address as a dynamic
|
||||
// relocation would provide.
|
||||
switch s.Name {
|
||||
case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
// Either internally linking a static executable,
|
||||
// in which case we can resolve these relocations
|
||||
// statically in the 'reloc' phase, or externally
|
||||
// linking, in which case the relocation will be
|
||||
// prepared in the 'reloc' phase and passed to the
|
||||
// external linker in the 'asmb' phase.
|
||||
if s.Type != sym.SDATA && s.Type != sym.SRODATA {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ctxt.IsELF {
|
||||
// Generate R_AARCH64_RELATIVE relocations for best
|
||||
// efficiency in the dynamic linker.
|
||||
//
|
||||
// As noted above, symbol addresses have not been
|
||||
// assigned yet, so we can't generate the final reloc
|
||||
// entry yet. We ultimately want:
|
||||
//
|
||||
// r_offset = s + r.Off
|
||||
// r_info = R_AARCH64_RELATIVE
|
||||
// r_addend = targ + r.Add
|
||||
//
|
||||
// The dynamic linker will set *offset = base address +
|
||||
// addend.
|
||||
//
|
||||
// AddAddrPlus is used for r_offset and r_addend to
|
||||
// generate new R_ADDR relocations that will update
|
||||
// these fields in the 'reloc' phase.
|
||||
rela := ctxt.Syms.Lookup(".rela", 0)
|
||||
rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
|
||||
if r.Siz == 8 {
|
||||
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
|
||||
} else {
|
||||
ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
rela.AddAddrPlus(ctxt.Arch, targ, int64(r.Add))
|
||||
// Not mark r done here. So we still apply it statically,
|
||||
// so in the file content we'll also have the right offset
|
||||
// to the relocation target. So it can be examined statically
|
||||
// (e.g. go version).
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write64(uint64(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
case objabi.R_ADDR:
|
||||
switch r.Siz {
|
||||
case 4:
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_ABS32) | uint64(elfsym)<<32)
|
||||
case 8:
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_ABS64) | uint64(elfsym)<<32)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case objabi.R_ADDRARM64:
|
||||
// two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_ADR_PREL_PG_HI21) | uint64(elfsym)<<32)
|
||||
ctxt.Out.Write64(uint64(r.Xadd))
|
||||
ctxt.Out.Write64(uint64(sectoff + 4))
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_ADD_ABS_LO12_NC) | uint64(elfsym)<<32)
|
||||
case objabi.R_ARM64_TLS_LE:
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_TLSLE_MOVW_TPREL_G0) | uint64(elfsym)<<32)
|
||||
case objabi.R_ARM64_TLS_IE:
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) | uint64(elfsym)<<32)
|
||||
ctxt.Out.Write64(uint64(r.Xadd))
|
||||
ctxt.Out.Write64(uint64(sectoff + 4))
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) | uint64(elfsym)<<32)
|
||||
case objabi.R_ARM64_GOTPCREL:
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_ADR_GOT_PAGE) | uint64(elfsym)<<32)
|
||||
ctxt.Out.Write64(uint64(r.Xadd))
|
||||
ctxt.Out.Write64(uint64(sectoff + 4))
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_LD64_GOT_LO12_NC) | uint64(elfsym)<<32)
|
||||
case objabi.R_CALLARM64:
|
||||
if r.Siz != 4 {
|
||||
return false
|
||||
}
|
||||
ctxt.Out.Write64(uint64(elf.R_AARCH64_CALL26) | uint64(elfsym)<<32)
|
||||
|
||||
}
|
||||
ctxt.Out.Write64(uint64(r.Xadd))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
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_CALLARM64 || r.Type == objabi.R_ADDRARM64 {
|
||||
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_ARM64_RELOC_UNSIGNED << 28
|
||||
case objabi.R_CALLARM64:
|
||||
if r.Xadd != 0 {
|
||||
ld.Errorf(s, "ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd)
|
||||
}
|
||||
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
|
||||
case objabi.R_ADDRARM64:
|
||||
r.Siz = 4
|
||||
// Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21
|
||||
// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
|
||||
if r.Xadd != 0 {
|
||||
out.Write32(uint32(sectoff + 4))
|
||||
out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
|
||||
}
|
||||
out.Write32(uint32(sectoff + 4))
|
||||
out.Write32(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
|
||||
if r.Xadd != 0 {
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
|
||||
}
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_ARM64_RELOC_PAGE21 << 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
|
||||
}
|
||||
|
||||
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
switch r.Type {
|
||||
default:
|
||||
return val, false
|
||||
case objabi.R_ARM64_GOTPCREL:
|
||||
var o1, o2 uint32
|
||||
if ctxt.Arch.ByteOrder == binary.BigEndian {
|
||||
o1 = uint32(val >> 32)
|
||||
o2 = uint32(val)
|
||||
} else {
|
||||
o1 = uint32(val)
|
||||
o2 = uint32(val >> 32)
|
||||
}
|
||||
// Any relocation against a function symbol is redirected to
|
||||
// be against a local symbol instead (see putelfsym in
|
||||
// symtab.go) but unfortunately the system linker was buggy
|
||||
// when confronted with a R_AARCH64_ADR_GOT_PAGE relocation
|
||||
// against a local symbol until May 2015
|
||||
// (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So
|
||||
// we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp;
|
||||
// add + R_ADDRARM64.
|
||||
if !(r.Sym.IsFileLocal() || r.Sym.Attr.VisibilityHidden() || r.Sym.Attr.Local()) && r.Sym.Type == sym.STEXT && ctxt.DynlinkingGo() {
|
||||
if o2&0xffc00000 != 0xf9400000 {
|
||||
ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2)
|
||||
}
|
||||
o2 = 0x91000000 | (o2 & 0x000003ff)
|
||||
r.Type = objabi.R_ADDRARM64
|
||||
}
|
||||
if ctxt.Arch.ByteOrder == binary.BigEndian {
|
||||
val = int64(o1)<<32 | int64(o2)
|
||||
} else {
|
||||
val = int64(o2)<<32 | int64(o1)
|
||||
}
|
||||
fallthrough
|
||||
case objabi.R_ADDRARM64:
|
||||
r.Done = false
|
||||
|
||||
// set up addend for eventual relocation via outer symbol.
|
||||
rs := r.Sym
|
||||
r.Xadd = r.Add
|
||||
for rs.Outer != nil {
|
||||
r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
|
||||
rs = rs.Outer
|
||||
}
|
||||
|
||||
if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
|
||||
ld.Errorf(s, "missing section for %s", rs.Name)
|
||||
}
|
||||
r.Xsym = rs
|
||||
|
||||
// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
|
||||
// will make the linking fail because it thinks the code is not PIC even though
|
||||
// the BR26 relocation should be fully resolved at link time.
|
||||
// That is the reason why the next if block is disabled. When the bug in ld64
|
||||
// is fixed, we can enable this block and also enable duff's device in cmd/7g.
|
||||
if false && ctxt.HeadType == objabi.Hdarwin {
|
||||
var o0, o1 uint32
|
||||
|
||||
if ctxt.Arch.ByteOrder == binary.BigEndian {
|
||||
o0 = uint32(val >> 32)
|
||||
o1 = uint32(val)
|
||||
} else {
|
||||
o0 = uint32(val)
|
||||
o1 = uint32(val >> 32)
|
||||
}
|
||||
// Mach-O wants the addend to be encoded in the instruction
|
||||
// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
|
||||
// can only encode 24-bit of signed addend, but the instructions
|
||||
// supports 33-bit of signed addend, so we always encode the
|
||||
// addend in place.
|
||||
o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5)
|
||||
o1 |= uint32(r.Xadd&0xfff) << 10
|
||||
r.Xadd = 0
|
||||
|
||||
// when laid out, the instruction order must always be o1, o2.
|
||||
if ctxt.Arch.ByteOrder == binary.BigEndian {
|
||||
val = int64(o0)<<32 | int64(o1)
|
||||
} else {
|
||||
val = int64(o1)<<32 | int64(o0)
|
||||
}
|
||||
}
|
||||
|
||||
return val, true
|
||||
case objabi.R_CALLARM64,
|
||||
objabi.R_ARM64_TLS_LE,
|
||||
objabi.R_ARM64_TLS_IE:
|
||||
r.Done = false
|
||||
r.Xsym = r.Sym
|
||||
r.Xadd = r.Add
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case objabi.R_CONST:
|
||||
return r.Add, true
|
||||
|
||||
case objabi.R_GOTOFF:
|
||||
return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
|
||||
|
||||
case objabi.R_ADDRARM64:
|
||||
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
|
||||
if t >= 1<<32 || t < -1<<32 {
|
||||
ld.Errorf(s, "program too large, address relocation distance = %d", t)
|
||||
}
|
||||
|
||||
var o0, o1 uint32
|
||||
|
||||
if ctxt.Arch.ByteOrder == binary.BigEndian {
|
||||
o0 = uint32(val >> 32)
|
||||
o1 = uint32(val)
|
||||
} else {
|
||||
o0 = uint32(val)
|
||||
o1 = uint32(val >> 32)
|
||||
}
|
||||
|
||||
o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
|
||||
o1 |= uint32(t&0xfff) << 10
|
||||
|
||||
// when laid out, the instruction order must always be o1, o2.
|
||||
if ctxt.Arch.ByteOrder == binary.BigEndian {
|
||||
return int64(o0)<<32 | int64(o1), true
|
||||
}
|
||||
return int64(o1)<<32 | int64(o0), true
|
||||
|
||||
case objabi.R_ARM64_TLS_LE:
|
||||
r.Done = false
|
||||
if ctxt.HeadType == objabi.Hdarwin {
|
||||
ld.Errorf(s, "TLS reloc on unsupported OS %v", ctxt.HeadType)
|
||||
}
|
||||
// The TCB is two pointers. This is not documented anywhere, but is
|
||||
// de facto part of the ABI.
|
||||
v := r.Sym.Value + int64(2*ctxt.Arch.PtrSize)
|
||||
if v < 0 || v >= 32678 {
|
||||
ld.Errorf(s, "TLS offset out of range %d", v)
|
||||
}
|
||||
return val | (v << 5), true
|
||||
|
||||
case objabi.R_ARM64_TLS_IE:
|
||||
if ctxt.BuildMode == ld.BuildModePIE && ctxt.IsELF {
|
||||
// We are linking the final executable, so we
|
||||
// can optimize any TLS IE relocation to LE.
|
||||
r.Done = false
|
||||
if ctxt.HeadType != objabi.Hlinux {
|
||||
ld.Errorf(s, "TLS reloc on unsupported OS %v", ctxt.HeadType)
|
||||
}
|
||||
|
||||
// The TCB is two pointers. This is not documented anywhere, but is
|
||||
// de facto part of the ABI.
|
||||
v := ld.Symaddr(r.Sym) + int64(2*ctxt.Arch.PtrSize) + r.Add
|
||||
if v < 0 || v >= 32678 {
|
||||
ld.Errorf(s, "TLS offset out of range %d", v)
|
||||
}
|
||||
|
||||
var o0, o1 uint32
|
||||
if ctxt.Arch.ByteOrder == binary.BigEndian {
|
||||
o0 = uint32(val >> 32)
|
||||
o1 = uint32(val)
|
||||
} else {
|
||||
o0 = uint32(val)
|
||||
o1 = uint32(val >> 32)
|
||||
}
|
||||
|
||||
// R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21
|
||||
// turn ADRP to MOVZ
|
||||
o0 = 0xd2a00000 | uint32(o0&0x1f) | (uint32((v>>16)&0xffff) << 5)
|
||||
// R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC
|
||||
// turn LD64 to MOVK
|
||||
if v&3 != 0 {
|
||||
ld.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", v)
|
||||
}
|
||||
o1 = 0xf2800000 | uint32(o1&0x1f) | (uint32(v&0xffff) << 5)
|
||||
|
||||
// when laid out, the instruction order must always be o0, o1.
|
||||
if ctxt.Arch.ByteOrder == binary.BigEndian {
|
||||
return int64(o0)<<32 | int64(o1), true
|
||||
}
|
||||
return int64(o1)<<32 | int64(o0), true
|
||||
} else {
|
||||
log.Fatalf("cannot handle R_ARM64_TLS_IE (sym %s) when linking internally", s.Name)
|
||||
}
|
||||
|
||||
case objabi.R_CALLARM64:
|
||||
var t int64
|
||||
if r.Sym.Type == sym.SDYNIMPORT {
|
||||
t = (ld.Symaddr(ctxt.Syms.Lookup(".plt", 0)) + r.Add) - (s.Value + int64(r.Off))
|
||||
} else {
|
||||
t = (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off))
|
||||
}
|
||||
if t >= 1<<27 || t < -1<<27 {
|
||||
ld.Errorf(s, "program too large, call relocation distance = %d", t)
|
||||
}
|
||||
return val | ((t >> 2) & 0x03ffffff), true
|
||||
|
||||
case objabi.R_ARM64_GOT:
|
||||
if s.P[r.Off+3]&0x9f == 0x90 {
|
||||
// R_AARCH64_ADR_GOT_PAGE
|
||||
// patch instruction: adrp
|
||||
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
|
||||
if t >= 1<<32 || t < -1<<32 {
|
||||
ld.Errorf(s, "program too large, address relocation distance = %d", t)
|
||||
}
|
||||
var o0 uint32
|
||||
o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
|
||||
return val | int64(o0), true
|
||||
} else if s.P[r.Off+3] == 0xf9 {
|
||||
// R_AARCH64_LD64_GOT_LO12_NC
|
||||
// patch instruction: ldr
|
||||
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
|
||||
if t&7 != 0 {
|
||||
ld.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LD64_GOT_LO12_NC", t)
|
||||
}
|
||||
var o1 uint32
|
||||
o1 |= uint32(t&0xfff) << (10 - 3)
|
||||
return val | int64(uint64(o1)), true
|
||||
} else {
|
||||
ld.Errorf(s, "unsupported instruction for %v R_GOTARM64", s.P[r.Off:r.Off+4])
|
||||
}
|
||||
|
||||
case objabi.R_ARM64_PCREL:
|
||||
if s.P[r.Off+3]&0x9f == 0x90 {
|
||||
// R_AARCH64_ADR_PREL_PG_HI21
|
||||
// patch instruction: adrp
|
||||
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
|
||||
if t >= 1<<32 || t < -1<<32 {
|
||||
ld.Errorf(s, "program too large, address relocation distance = %d", t)
|
||||
}
|
||||
o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
|
||||
return val | int64(o0), true
|
||||
} else if s.P[r.Off+3]&0x91 == 0x91 {
|
||||
// R_AARCH64_ADD_ABS_LO12_NC
|
||||
// patch instruction: add
|
||||
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
|
||||
o1 := uint32(t&0xfff) << 10
|
||||
return val | int64(o1), true
|
||||
} else {
|
||||
ld.Errorf(s, "unsupported instruction for %v R_PCRELARM64", s.P[r.Off:r.Off+4])
|
||||
}
|
||||
|
||||
case objabi.R_ARM64_LDST8:
|
||||
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
|
||||
o0 := uint32(t&0xfff) << 10
|
||||
return val | int64(o0), true
|
||||
|
||||
case objabi.R_ARM64_LDST32:
|
||||
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
|
||||
if t&3 != 0 {
|
||||
ld.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST32_ABS_LO12_NC", t)
|
||||
}
|
||||
o0 := (uint32(t&0xfff) >> 2) << 10
|
||||
return val | int64(o0), true
|
||||
|
||||
case objabi.R_ARM64_LDST64:
|
||||
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
|
||||
if t&7 != 0 {
|
||||
ld.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST64_ABS_LO12_NC", t)
|
||||
}
|
||||
o0 := (uint32(t&0xfff) >> 3) << 10
|
||||
return val | int64(o0), true
|
||||
|
||||
case objabi.R_ARM64_LDST128:
|
||||
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
|
||||
if t&15 != 0 {
|
||||
ld.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST128_ABS_LO12_NC", t)
|
||||
}
|
||||
o0 := (uint32(t&0xfff) >> 4) << 10
|
||||
return val | int64(o0), true
|
||||
}
|
||||
|
||||
return val, false
|
||||
}
|
||||
|
||||
func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
|
||||
log.Fatalf("unexpected relocation variant")
|
||||
return -1
|
||||
}
|
||||
|
||||
func elfsetupplt(ctxt *ld.Link) {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
gotplt := ctxt.Syms.Lookup(".got.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
// stp x16, x30, [sp, #-16]!
|
||||
// identifying information
|
||||
plt.AddUint32(ctxt.Arch, 0xa9bf7bf0)
|
||||
|
||||
// the following two instructions (adrp + ldr) load *got[2] into x17
|
||||
// adrp x16, &got[0]
|
||||
plt.AddAddrPlus4(gotplt, 16)
|
||||
plt.SetUint32(ctxt.Arch, plt.Size-4, 0x90000010)
|
||||
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
|
||||
|
||||
// <imm> is the offset value of &got[2] to &got[0], the same below
|
||||
// ldr x17, [x16, <imm>]
|
||||
plt.AddAddrPlus4(gotplt, 16)
|
||||
plt.SetUint32(ctxt.Arch, plt.Size-4, 0xf9400211)
|
||||
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
|
||||
|
||||
// add x16, x16, <imm>
|
||||
plt.AddAddrPlus4(gotplt, 16)
|
||||
plt.SetUint32(ctxt.Arch, plt.Size-4, 0x91000210)
|
||||
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL
|
||||
|
||||
// br x17
|
||||
plt.AddUint32(ctxt.Arch, 0xd61f0220)
|
||||
|
||||
// 3 nop for place holder
|
||||
plt.AddUint32(ctxt.Arch, 0xd503201f)
|
||||
plt.AddUint32(ctxt.Arch, 0xd503201f)
|
||||
plt.AddUint32(ctxt.Arch, 0xd503201f)
|
||||
|
||||
// check gotplt.size == 0
|
||||
if gotplt.Size != 0 {
|
||||
ld.Errorf(gotplt, "got.plt is not empty at the very beginning")
|
||||
}
|
||||
gotplt.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
|
||||
|
||||
gotplt.AddUint64(ctxt.Arch, 0)
|
||||
gotplt.AddUint64(ctxt.Arch, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
|
||||
if ctxt.IsELF {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
gotplt := ctxt.Syms.Lookup(".got.plt", 0)
|
||||
rela := ctxt.Syms.Lookup(".rela.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
elfsetupplt(ctxt)
|
||||
}
|
||||
|
||||
// adrp x16, &got.plt[0]
|
||||
plt.AddAddrPlus4(gotplt, gotplt.Size)
|
||||
plt.SetUint32(ctxt.Arch, plt.Size-4, 0x90000010)
|
||||
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
|
||||
|
||||
// <offset> is the offset value of &got.plt[n] to &got.plt[0]
|
||||
// ldr x17, [x16, <offset>]
|
||||
plt.AddAddrPlus4(gotplt, gotplt.Size)
|
||||
plt.SetUint32(ctxt.Arch, plt.Size-4, 0xf9400211)
|
||||
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
|
||||
|
||||
// add x16, x16, <offset>
|
||||
plt.AddAddrPlus4(gotplt, gotplt.Size)
|
||||
plt.SetUint32(ctxt.Arch, plt.Size-4, 0x91000210)
|
||||
plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL
|
||||
|
||||
// br x17
|
||||
plt.AddUint32(ctxt.Arch, 0xd61f0220)
|
||||
|
||||
// add to got.plt: pointer to plt[0]
|
||||
gotplt.AddAddrPlus(ctxt.Arch, plt, 0)
|
||||
|
||||
// rela
|
||||
rela.AddAddrPlus(ctxt.Arch, gotplt, gotplt.Size-8)
|
||||
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
|
||||
rela.AddUint64(ctxt.Arch, 0)
|
||||
|
||||
s.SetPlt(int32(plt.Size - 16))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
s.SetGot(int32(got.Size))
|
||||
got.AddUint64(ctxt.Arch, 0)
|
||||
|
||||
if ctxt.IsELF {
|
||||
rela := ctxt.Syms.Lookup(".rela", 0)
|
||||
rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got()))
|
||||
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_GLOB_DAT)))
|
||||
rela.AddUint64(ctxt.Arch, 0)
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect := ld.Segtext.Sections[0]
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
for _, sect = range ld.Segtext.Sections[1:] {
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
if ld.Segrelrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
|
||||
ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
|
||||
}
|
||||
|
||||
func asmb2(ctxt *ld.Link) {
|
||||
machlink := uint32(0)
|
||||
if ctxt.HeadType == objabi.Hdarwin {
|
||||
machlink = uint32(ld.Domacholink(ctxt))
|
||||
}
|
||||
|
||||
/* output symbol table */
|
||||
ld.Symsize = 0
|
||||
|
||||
ld.Lcsize = 0
|
||||
symo := uint32(0)
|
||||
if !*ld.FlagS {
|
||||
// TODO: rationalize
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
if ctxt.IsELF {
|
||||
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
|
||||
}
|
||||
|
||||
case objabi.Hplan9:
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
|
||||
case objabi.Hdarwin:
|
||||
symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(symo))
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
if ctxt.IsELF {
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Elfemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Machoemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(0)
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
case objabi.Hplan9: /* plan 9 */
|
||||
ctxt.Out.Write32(0x647) /* magic */
|
||||
ctxt.Out.Write32(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||
ctxt.Out.Write32(uint32(ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32(uint32(ld.Symsize)) /* nsyms */
|
||||
ctxt.Out.Write32(uint32(ld.Entryvalue(ctxt))) /* va of entry */
|
||||
ctxt.Out.Write32(0)
|
||||
ctxt.Out.Write32(uint32(ld.Lcsize))
|
||||
|
||||
case objabi.Hlinux,
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd:
|
||||
ld.Asmbelf(ctxt, int64(symo))
|
||||
|
||||
case objabi.Hdarwin:
|
||||
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)
|
||||
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package arm64
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// cmd/9l/l.h from Vita Nuova.
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
maxAlign = 32 // max data alignment
|
||||
minAlign = 1 // min data alignment
|
||||
funcAlign = 16
|
||||
)
|
||||
|
||||
/* Used by ../internal/ld/dwarf.go */
|
||||
const (
|
||||
dwarfRegSP = 31
|
||||
dwarfRegLR = 30
|
||||
)
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
// Inferno utils/5l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
)
|
||||
|
||||
func Init() (*sys.Arch, ld.Arch) {
|
||||
arch := sys.ArchARM64
|
||||
|
||||
theArch := ld.Arch{
|
||||
Funcalign: funcAlign,
|
||||
Maxalign: maxAlign,
|
||||
Minalign: minAlign,
|
||||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
Asmb: asmb,
|
||||
Asmb2: asmb2,
|
||||
Elfreloc1: elfreloc1,
|
||||
Elfsetupplt: elfsetupplt,
|
||||
Gentext: gentext,
|
||||
Machoreloc1: machoreloc1,
|
||||
|
||||
Androiddynld: "/system/bin/linker64",
|
||||
Linuxdynld: "/lib/ld-linux-aarch64.so.1",
|
||||
|
||||
Freebsddynld: "/usr/libexec/ld-elf.so.1",
|
||||
Openbsddynld: "/usr/libexec/ld.so",
|
||||
Netbsddynld: "/libexec/ld.elf_so",
|
||||
Dragonflydynld: "XXX",
|
||||
Solarisdynld: "XXX",
|
||||
}
|
||||
|
||||
return arch, theArch
|
||||
}
|
||||
|
||||
func archinit(ctxt *ld.Link) {
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Exitf("unknown -H option: %v", ctxt.HeadType)
|
||||
|
||||
case objabi.Hplan9: /* plan 9 */
|
||||
ld.HEADR = 32
|
||||
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 4096 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 4096
|
||||
}
|
||||
|
||||
case objabi.Hlinux, /* arm64 elf */
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd:
|
||||
ld.Elfinit(ctxt)
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 0x10000
|
||||
}
|
||||
|
||||
case objabi.Hdarwin: /* apple MACH */
|
||||
ld.HEADR = ld.INITIAL_MACHO_HEADR
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 4096 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 4096
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
// Inferno utils/include/ar.h
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/include/ar.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
SARMAG = 8
|
||||
SAR_HDR = 16 + 44
|
||||
)
|
||||
|
||||
const (
|
||||
ARMAG = "!<arch>\n"
|
||||
)
|
||||
|
||||
type ArHdr struct {
|
||||
name string
|
||||
date string
|
||||
uid string
|
||||
gid string
|
||||
mode string
|
||||
size string
|
||||
fmag string
|
||||
}
|
||||
|
||||
// hostArchive reads an archive file holding host objects and links in
|
||||
// required objects. The general format is the same as a Go archive
|
||||
// file, but it has an armap listing symbols and the objects that
|
||||
// define them. This is used for the compiler support library
|
||||
// libgcc.a.
|
||||
func hostArchive(ctxt *Link, name string) {
|
||||
f, err := bio.Open(name)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// It's OK if we don't have a libgcc file at all.
|
||||
if ctxt.Debugvlog != 0 {
|
||||
ctxt.Logf("skipping libgcc file: %v\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
Exitf("cannot open file %s: %v", name, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var magbuf [len(ARMAG)]byte
|
||||
if _, err := io.ReadFull(f, magbuf[:]); err != nil {
|
||||
Exitf("file %s too short", name)
|
||||
}
|
||||
|
||||
if string(magbuf[:]) != ARMAG {
|
||||
Exitf("%s is not an archive file", name)
|
||||
}
|
||||
|
||||
var arhdr ArHdr
|
||||
l := nextar(f, f.Offset(), &arhdr)
|
||||
if l <= 0 {
|
||||
Exitf("%s missing armap", name)
|
||||
}
|
||||
|
||||
var armap archiveMap
|
||||
if arhdr.name == "/" || arhdr.name == "/SYM64/" {
|
||||
armap = readArmap(name, f, arhdr)
|
||||
} else {
|
||||
Exitf("%s missing armap", name)
|
||||
}
|
||||
|
||||
loaded := make(map[uint64]bool)
|
||||
any := true
|
||||
for any {
|
||||
var load []uint64
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
for i := range s.R {
|
||||
r := &s.R[i] // Copying sym.Reloc has measurable impact on performance
|
||||
if r.Sym != nil && r.Sym.Type == sym.SXREF {
|
||||
if off := armap[r.Sym.Name]; off != 0 && !loaded[off] {
|
||||
load = append(load, off)
|
||||
loaded[off] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, off := range load {
|
||||
l := nextar(f, int64(off), &arhdr)
|
||||
if l <= 0 {
|
||||
Exitf("%s missing archive entry at offset %d", name, off)
|
||||
}
|
||||
pname := fmt.Sprintf("%s(%s)", name, arhdr.name)
|
||||
l = atolwhex(arhdr.size)
|
||||
|
||||
libgcc := sym.Library{Pkg: "libgcc"}
|
||||
h := ldobj(ctxt, f, &libgcc, l, pname, name)
|
||||
f.MustSeek(h.off, 0)
|
||||
h.ld(ctxt, f, h.pkg, h.length, h.pn)
|
||||
}
|
||||
|
||||
any = len(load) > 0
|
||||
}
|
||||
}
|
||||
|
||||
// archiveMap is an archive symbol map: a mapping from symbol name to
|
||||
// offset within the archive file.
|
||||
type archiveMap map[string]uint64
|
||||
|
||||
// readArmap reads the archive symbol map.
|
||||
func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap {
|
||||
is64 := arhdr.name == "/SYM64/"
|
||||
wordSize := 4
|
||||
if is64 {
|
||||
wordSize = 8
|
||||
}
|
||||
|
||||
contents := make([]byte, atolwhex(arhdr.size))
|
||||
if _, err := io.ReadFull(f, contents); err != nil {
|
||||
Exitf("short read from %s", filename)
|
||||
}
|
||||
|
||||
var c uint64
|
||||
if is64 {
|
||||
c = binary.BigEndian.Uint64(contents)
|
||||
} else {
|
||||
c = uint64(binary.BigEndian.Uint32(contents))
|
||||
}
|
||||
contents = contents[wordSize:]
|
||||
|
||||
ret := make(archiveMap)
|
||||
|
||||
names := contents[c*uint64(wordSize):]
|
||||
for i := uint64(0); i < c; i++ {
|
||||
n := 0
|
||||
for names[n] != 0 {
|
||||
n++
|
||||
}
|
||||
name := string(names[:n])
|
||||
names = names[n+1:]
|
||||
|
||||
// For Mach-O and PE/386 files we strip a leading
|
||||
// underscore from the symbol name.
|
||||
if objabi.GOOS == "darwin" || (objabi.GOOS == "windows" && objabi.GOARCH == "386") {
|
||||
if name[0] == '_' && len(name) > 1 {
|
||||
name = name[1:]
|
||||
}
|
||||
}
|
||||
|
||||
var off uint64
|
||||
if is64 {
|
||||
off = binary.BigEndian.Uint64(contents)
|
||||
} else {
|
||||
off = uint64(binary.BigEndian.Uint32(contents))
|
||||
}
|
||||
contents = contents[wordSize:]
|
||||
|
||||
ret[name] = off
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// A BuildMode indicates the sort of object we are building.
|
||||
//
|
||||
// Possible build modes are the same as those for the -buildmode flag
|
||||
// in cmd/go, and are documented in 'go help buildmode'.
|
||||
type BuildMode uint8
|
||||
|
||||
const (
|
||||
BuildModeUnset BuildMode = iota
|
||||
BuildModeExe
|
||||
BuildModePIE
|
||||
BuildModeCArchive
|
||||
BuildModeCShared
|
||||
BuildModeShared
|
||||
BuildModePlugin
|
||||
)
|
||||
|
||||
func (mode *BuildMode) Set(s string) error {
|
||||
badmode := func() error {
|
||||
return fmt.Errorf("buildmode %s not supported on %s/%s", s, objabi.GOOS, objabi.GOARCH)
|
||||
}
|
||||
switch s {
|
||||
default:
|
||||
return fmt.Errorf("invalid buildmode: %q", s)
|
||||
case "exe":
|
||||
*mode = BuildModeExe
|
||||
case "pie":
|
||||
switch objabi.GOOS {
|
||||
case "aix", "android", "linux", "windows":
|
||||
case "darwin", "freebsd":
|
||||
switch objabi.GOARCH {
|
||||
case "amd64":
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
*mode = BuildModePIE
|
||||
case "c-archive":
|
||||
switch objabi.GOOS {
|
||||
case "aix", "darwin", "linux":
|
||||
case "freebsd":
|
||||
switch objabi.GOARCH {
|
||||
case "amd64":
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
case "windows":
|
||||
switch objabi.GOARCH {
|
||||
case "amd64", "386", "arm":
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
*mode = BuildModeCArchive
|
||||
case "c-shared":
|
||||
switch objabi.GOARCH {
|
||||
case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
*mode = BuildModeCShared
|
||||
case "shared":
|
||||
switch objabi.GOOS {
|
||||
case "linux":
|
||||
switch objabi.GOARCH {
|
||||
case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
*mode = BuildModeShared
|
||||
case "plugin":
|
||||
switch objabi.GOOS {
|
||||
case "linux":
|
||||
switch objabi.GOARCH {
|
||||
case "386", "amd64", "arm", "arm64", "s390x", "ppc64le":
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
case "darwin", "freebsd":
|
||||
switch objabi.GOARCH {
|
||||
case "amd64":
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
default:
|
||||
return badmode()
|
||||
}
|
||||
*mode = BuildModePlugin
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mode *BuildMode) String() string {
|
||||
switch *mode {
|
||||
case BuildModeUnset:
|
||||
return "" // avoid showing a default in usage message
|
||||
case BuildModeExe:
|
||||
return "exe"
|
||||
case BuildModePIE:
|
||||
return "pie"
|
||||
case BuildModeCArchive:
|
||||
return "c-archive"
|
||||
case BuildModeCShared:
|
||||
return "c-shared"
|
||||
case BuildModeShared:
|
||||
return "shared"
|
||||
case BuildModePlugin:
|
||||
return "plugin"
|
||||
}
|
||||
return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
|
||||
}
|
||||
|
||||
// LinkMode indicates whether an external linker is used for the final link.
|
||||
type LinkMode uint8
|
||||
|
||||
const (
|
||||
LinkAuto LinkMode = iota
|
||||
LinkInternal
|
||||
LinkExternal
|
||||
)
|
||||
|
||||
func (mode *LinkMode) Set(s string) error {
|
||||
switch s {
|
||||
default:
|
||||
return fmt.Errorf("invalid linkmode: %q", s)
|
||||
case "auto":
|
||||
*mode = LinkAuto
|
||||
case "internal":
|
||||
*mode = LinkInternal
|
||||
case "external":
|
||||
*mode = LinkExternal
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mode *LinkMode) String() string {
|
||||
switch *mode {
|
||||
case LinkAuto:
|
||||
return "auto"
|
||||
case LinkInternal:
|
||||
return "internal"
|
||||
case LinkExternal:
|
||||
return "external"
|
||||
}
|
||||
return fmt.Sprintf("LinkMode(%d)", uint8(*mode))
|
||||
}
|
||||
|
||||
// mustLinkExternal reports whether the program being linked requires
|
||||
// the external linker be used to complete the link.
|
||||
func mustLinkExternal(ctxt *Link) (res bool, reason string) {
|
||||
if ctxt.Debugvlog > 1 {
|
||||
defer func() {
|
||||
if res {
|
||||
log.Printf("external linking is forced by: %s\n", reason)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) {
|
||||
return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH)
|
||||
}
|
||||
|
||||
if *flagMsan {
|
||||
return true, "msan"
|
||||
}
|
||||
|
||||
// Internally linking cgo is incomplete on some architectures.
|
||||
// https://golang.org/issue/14449
|
||||
// https://golang.org/issue/21961
|
||||
if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64) {
|
||||
return true, objabi.GOARCH + " does not support internal cgo"
|
||||
}
|
||||
if iscgo && objabi.GOOS == "android" {
|
||||
return true, objabi.GOOS + " does not support internal cgo"
|
||||
}
|
||||
|
||||
// When the race flag is set, the LLVM tsan relocatable file is linked
|
||||
// into the final binary, which means external linking is required because
|
||||
// internal linking does not support it.
|
||||
if *flagRace && ctxt.Arch.InFamily(sys.PPC64) {
|
||||
return true, "race on " + objabi.GOARCH
|
||||
}
|
||||
|
||||
// Some build modes require work the internal linker cannot do (yet).
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCArchive:
|
||||
return true, "buildmode=c-archive"
|
||||
case BuildModeCShared:
|
||||
return true, "buildmode=c-shared"
|
||||
case BuildModePIE:
|
||||
switch objabi.GOOS + "/" + objabi.GOARCH {
|
||||
case "linux/amd64", "linux/arm64", "android/arm64":
|
||||
case "windows/386", "windows/amd64", "windows/arm":
|
||||
default:
|
||||
// Internal linking does not support TLS_IE.
|
||||
return true, "buildmode=pie"
|
||||
}
|
||||
case BuildModePlugin:
|
||||
return true, "buildmode=plugin"
|
||||
case BuildModeShared:
|
||||
return true, "buildmode=shared"
|
||||
}
|
||||
if ctxt.linkShared {
|
||||
return true, "dynamically linking with a shared library"
|
||||
}
|
||||
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// determineLinkMode sets ctxt.LinkMode.
|
||||
//
|
||||
// It is called after flags are processed and inputs are processed,
|
||||
// so the ctxt.LinkMode variable has an initial value from the -linkmode
|
||||
// flag and the iscgo externalobj variables are set.
|
||||
func determineLinkMode(ctxt *Link) {
|
||||
extNeeded, extReason := mustLinkExternal(ctxt)
|
||||
via := ""
|
||||
|
||||
if ctxt.LinkMode == LinkAuto {
|
||||
// The environment variable GO_EXTLINK_ENABLED controls the
|
||||
// default value of -linkmode. If it is not set when the
|
||||
// linker is called we take the value it was set to when
|
||||
// cmd/link was compiled. (See make.bash.)
|
||||
switch objabi.Getgoextlinkenabled() {
|
||||
case "0":
|
||||
ctxt.LinkMode = LinkInternal
|
||||
via = "via GO_EXTLINK_ENABLED "
|
||||
case "1":
|
||||
ctxt.LinkMode = LinkExternal
|
||||
via = "via GO_EXTLINK_ENABLED "
|
||||
default:
|
||||
if extNeeded || (iscgo && externalobj) {
|
||||
ctxt.LinkMode = LinkExternal
|
||||
} else {
|
||||
ctxt.LinkMode = LinkInternal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch ctxt.LinkMode {
|
||||
case LinkInternal:
|
||||
if extNeeded {
|
||||
Exitf("internal linking requested %sbut external linking required: %s", via, extReason)
|
||||
}
|
||||
case LinkExternal:
|
||||
switch {
|
||||
case objabi.GOARCH == "riscv64":
|
||||
Exitf("external linking not supported for %s/riscv64", objabi.GOOS)
|
||||
case objabi.GOARCH == "ppc64" && objabi.GOOS != "aix":
|
||||
Exitf("external linking not supported for %s/ppc64", objabi.GOOS)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,409 +0,0 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// deadcode marks all reachable symbols.
|
||||
//
|
||||
// The basis of the dead code elimination is a flood fill of symbols,
|
||||
// following their relocations, beginning at *flagEntrySymbol.
|
||||
//
|
||||
// This flood fill is wrapped in logic for pruning unused methods.
|
||||
// All methods are mentioned by relocations on their receiver's *rtype.
|
||||
// These relocations are specially defined as R_METHODOFF by the compiler
|
||||
// so we can detect and manipulated them here.
|
||||
//
|
||||
// There are three ways a method of a reachable type can be invoked:
|
||||
//
|
||||
// 1. direct call
|
||||
// 2. through a reachable interface type
|
||||
// 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.
|
||||
//
|
||||
// The second case is handled by decomposing all reachable interface
|
||||
// types into method signatures. Each encountered method is compared
|
||||
// against the interface method signatures, if it matches it is marked
|
||||
// as reachable. This is extremely conservative, but easy and correct.
|
||||
//
|
||||
// The third case is handled by looking to see if any of:
|
||||
// - 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.
|
||||
//
|
||||
// Any unreached text symbols are removed from ctxt.Textp.
|
||||
func deadcode(ctxt *Link) {
|
||||
if ctxt.Debugvlog != 0 {
|
||||
ctxt.Logf("deadcode\n")
|
||||
}
|
||||
|
||||
if *flagNewobj {
|
||||
deadcode2(ctxt)
|
||||
return
|
||||
}
|
||||
|
||||
d := &deadcodepass{
|
||||
ctxt: ctxt,
|
||||
ifaceMethod: make(map[methodsig]bool),
|
||||
}
|
||||
|
||||
// First, flood fill any symbols directly reachable in the call
|
||||
// graph from *flagEntrySymbol. Ignore all methods not directly called.
|
||||
d.init()
|
||||
d.flood()
|
||||
|
||||
methSym := ctxt.Syms.ROLookup("reflect.Value.Method", sym.SymVerABIInternal)
|
||||
methByNameSym := ctxt.Syms.ROLookup("reflect.Value.MethodByName", sym.SymVerABIInternal)
|
||||
reflectSeen := false
|
||||
|
||||
if ctxt.DynlinkingGo() {
|
||||
// Exported methods may satisfy interfaces we don't know
|
||||
// about yet when dynamically linking.
|
||||
reflectSeen = true
|
||||
}
|
||||
|
||||
for {
|
||||
if !reflectSeen {
|
||||
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.
|
||||
reflectSeen = true
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
var rem []methodref
|
||||
for _, m := range d.markableMethods {
|
||||
if (reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
|
||||
d.markMethod(m)
|
||||
} else {
|
||||
rem = append(rem, m)
|
||||
}
|
||||
}
|
||||
d.markableMethods = rem
|
||||
|
||||
if len(d.markQueue) == 0 {
|
||||
// No new work was discovered. Done.
|
||||
break
|
||||
}
|
||||
d.flood()
|
||||
}
|
||||
|
||||
// Remove all remaining unreached R_METHODOFF relocations.
|
||||
for _, m := range d.markableMethods {
|
||||
for _, r := range m.r {
|
||||
d.cleanupReloc(r)
|
||||
}
|
||||
}
|
||||
|
||||
if ctxt.BuildMode != BuildModeShared {
|
||||
// Keep a itablink if the symbol it points at is being kept.
|
||||
// (When BuildModeShared, always keep itablinks.)
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
if strings.HasPrefix(s.Name, "go.itablink.") {
|
||||
s.Attr.Set(sym.AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addToTextp(ctxt)
|
||||
}
|
||||
|
||||
func addToTextp(ctxt *Link) {
|
||||
// Remove dead text but keep file information (z symbols).
|
||||
textp := []*sym.Symbol{}
|
||||
for _, s := range ctxt.Textp {
|
||||
if s.Attr.Reachable() {
|
||||
textp = append(textp, s)
|
||||
}
|
||||
}
|
||||
|
||||
// Put reachable text symbols into Textp.
|
||||
// do it in postorder so that packages are laid down in dependency order
|
||||
// internal first, then everything else
|
||||
ctxt.Library = postorder(ctxt.Library)
|
||||
for _, doInternal := range [2]bool{true, false} {
|
||||
for _, lib := range ctxt.Library {
|
||||
if isRuntimeDepPkg(lib.Pkg) != doInternal {
|
||||
continue
|
||||
}
|
||||
libtextp := lib.Textp[:0]
|
||||
for _, s := range lib.Textp {
|
||||
if s.Attr.Reachable() {
|
||||
textp = append(textp, s)
|
||||
libtextp = append(libtextp, s)
|
||||
if s.Unit != nil {
|
||||
s.Unit.Textp = append(s.Unit.Textp, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, s := range lib.DupTextSyms {
|
||||
if s.Attr.Reachable() && !s.Attr.OnList() {
|
||||
textp = append(textp, s)
|
||||
libtextp = append(libtextp, s)
|
||||
if s.Unit != nil {
|
||||
s.Unit.Textp = append(s.Unit.Textp, s)
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
// dupok symbols may be defined in multiple packages. its
|
||||
// associated package is chosen sort of arbitrarily (the
|
||||
// first containing package that the linker loads). canonicalize
|
||||
// it here to the package with which it will be laid down
|
||||
// in text.
|
||||
s.File = objabi.PathToPrefix(lib.Pkg)
|
||||
}
|
||||
}
|
||||
lib.Textp = libtextp
|
||||
}
|
||||
}
|
||||
ctxt.Textp = textp
|
||||
|
||||
if len(ctxt.Shlibs) > 0 {
|
||||
// We might have overwritten some functions above (this tends to happen for the
|
||||
// autogenerated type equality/hashing functions) and we don't want to generated
|
||||
// pcln table entries for these any more so remove them from Textp.
|
||||
textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
|
||||
for _, s := range ctxt.Textp {
|
||||
if s.Type != sym.SDYNIMPORT {
|
||||
textp = append(textp, s)
|
||||
}
|
||||
}
|
||||
ctxt.Textp = textp
|
||||
}
|
||||
}
|
||||
|
||||
// methodref 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 methodref struct {
|
||||
m methodsig
|
||||
src *sym.Symbol // receiver type symbol
|
||||
r [3]*sym.Reloc // R_METHODOFF relocations to fields of runtime.method
|
||||
}
|
||||
|
||||
func (m methodref) ifn() *sym.Symbol { return m.r[1].Sym }
|
||||
|
||||
func (m methodref) isExported() bool {
|
||||
for _, r := range m.m {
|
||||
return unicode.IsUpper(r)
|
||||
}
|
||||
panic("methodref has no signature")
|
||||
}
|
||||
|
||||
// deadcodepass holds state for the deadcode flood fill.
|
||||
type deadcodepass struct {
|
||||
ctxt *Link
|
||||
markQueue []*sym.Symbol // symbols to flood fill in next pass
|
||||
ifaceMethod map[methodsig]bool // methods declared in reached interfaces
|
||||
markableMethods []methodref // methods of reached types
|
||||
reflectMethod bool
|
||||
}
|
||||
|
||||
func (d *deadcodepass) cleanupReloc(r *sym.Reloc) {
|
||||
if r.Sym.Attr.Reachable() {
|
||||
r.Type = objabi.R_ADDROFF
|
||||
} else {
|
||||
if d.ctxt.Debugvlog > 1 {
|
||||
d.ctxt.Logf("removing method %s\n", r.Sym.Name)
|
||||
}
|
||||
r.Sym = nil
|
||||
r.Siz = 0
|
||||
}
|
||||
}
|
||||
|
||||
// mark appends a symbol to the mark queue for flood filling.
|
||||
func (d *deadcodepass) mark(s, parent *sym.Symbol) {
|
||||
if s == nil || s.Attr.Reachable() {
|
||||
return
|
||||
}
|
||||
if s.Attr.ReflectMethod() {
|
||||
d.reflectMethod = true
|
||||
}
|
||||
if *flagDumpDep {
|
||||
p := "_"
|
||||
if parent != nil {
|
||||
p = parent.Name
|
||||
}
|
||||
fmt.Printf("%s -> %s\n", p, s.Name)
|
||||
}
|
||||
s.Attr |= sym.AttrReachable
|
||||
if d.ctxt.Reachparent != nil {
|
||||
d.ctxt.Reachparent[s] = parent
|
||||
}
|
||||
d.markQueue = append(d.markQueue, s)
|
||||
}
|
||||
|
||||
// markMethod marks a method as reachable.
|
||||
func (d *deadcodepass) markMethod(m methodref) {
|
||||
for _, r := range m.r {
|
||||
d.mark(r.Sym, m.src)
|
||||
r.Type = objabi.R_ADDROFF
|
||||
}
|
||||
}
|
||||
|
||||
// init marks all initial symbols as reachable.
|
||||
// In a typical binary, this is *flagEntrySymbol.
|
||||
func (d *deadcodepass) init() {
|
||||
var names []string
|
||||
|
||||
if d.ctxt.BuildMode == BuildModeShared {
|
||||
// Mark all symbols defined in this library as reachable when
|
||||
// building a shared library.
|
||||
for _, s := range d.ctxt.Syms.Allsym {
|
||||
if s.Type != 0 && s.Type != sym.SDYNIMPORT {
|
||||
d.mark(s, nil)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 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.
|
||||
exports := d.ctxt.Syms.ROLookup("go.plugin.exports", 0)
|
||||
if exports != nil {
|
||||
for i := range exports.R {
|
||||
d.mark(exports.R[i].Sym, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, s := range dynexp {
|
||||
d.mark(s, nil)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
// Mark symbol as a data/ABI0 symbol.
|
||||
d.mark(d.ctxt.Syms.ROLookup(name, 0), nil)
|
||||
// Also mark any Go functions (internal ABI).
|
||||
d.mark(d.ctxt.Syms.ROLookup(name, sym.SymVerABIInternal), nil)
|
||||
}
|
||||
}
|
||||
|
||||
// flood fills symbols reachable from the markQueue symbols.
|
||||
// As it goes, it collects methodref and interface method declarations.
|
||||
func (d *deadcodepass) flood() {
|
||||
for len(d.markQueue) > 0 {
|
||||
s := d.markQueue[0]
|
||||
d.markQueue = d.markQueue[1:]
|
||||
if s.Type == sym.STEXT {
|
||||
if d.ctxt.Debugvlog > 1 {
|
||||
d.ctxt.Logf("marktext %s\n", s.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' {
|
||||
if len(s.P) == 0 {
|
||||
// Probably a bug. The undefined symbol check
|
||||
// later will give a better error than deadcode.
|
||||
continue
|
||||
}
|
||||
if decodetypeKind(d.ctxt.Arch, s.P)&kindMask == kindInterface {
|
||||
for _, sig := range decodeIfaceMethods(d.ctxt.Arch, s) {
|
||||
if d.ctxt.Debugvlog > 1 {
|
||||
d.ctxt.Logf("reached iface method: %s\n", sig)
|
||||
}
|
||||
d.ifaceMethod[sig] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mpos := 0 // 0-3, the R_METHODOFF relocs of runtime.uncommontype
|
||||
var methods []methodref
|
||||
for i := range s.R {
|
||||
r := &s.R[i]
|
||||
if r.Sym == nil {
|
||||
continue
|
||||
}
|
||||
if r.Type == objabi.R_WEAKADDROFF {
|
||||
// An R_WEAKADDROFF relocation is not reason
|
||||
// enough to mark the pointed-to symbol as
|
||||
// reachable.
|
||||
continue
|
||||
}
|
||||
if r.Sym.Type == sym.SABIALIAS {
|
||||
// Patch this relocation through the
|
||||
// ABI alias before marking.
|
||||
r.Sym = resolveABIAlias(r.Sym)
|
||||
}
|
||||
if r.Type != objabi.R_METHODOFF {
|
||||
d.mark(r.Sym, s)
|
||||
continue
|
||||
}
|
||||
// Collect rtype pointers to methods for
|
||||
// later processing in deadcode.
|
||||
if mpos == 0 {
|
||||
m := methodref{src: s}
|
||||
m.r[0] = r
|
||||
methods = append(methods, m)
|
||||
} else {
|
||||
methods[len(methods)-1].r[mpos] = r
|
||||
}
|
||||
mpos++
|
||||
if mpos == len(methodref{}.r) {
|
||||
mpos = 0
|
||||
}
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
// Decode runtime type information for type methods
|
||||
// to help work out which methods can be called
|
||||
// dynamically via interfaces.
|
||||
methodsigs := decodetypeMethods(d.ctxt.Arch, s)
|
||||
if len(methods) != len(methodsigs) {
|
||||
panic(fmt.Sprintf("%q has %d method relocations for %d methods", s.Name, len(methods), len(methodsigs)))
|
||||
}
|
||||
for i, m := range methodsigs {
|
||||
name := string(m)
|
||||
name = name[:strings.Index(name, "(")]
|
||||
if !strings.HasSuffix(methods[i].ifn().Name, name) {
|
||||
panic(fmt.Sprintf("%q relocation for %q does not match method %q", s.Name, methods[i].ifn().Name, name))
|
||||
}
|
||||
methods[i].m = m
|
||||
}
|
||||
d.markableMethods = append(d.markableMethods, methods...)
|
||||
}
|
||||
|
||||
if s.FuncInfo != nil {
|
||||
for i := range s.FuncInfo.Funcdata {
|
||||
d.mark(s.FuncInfo.Funcdata[i], s)
|
||||
}
|
||||
}
|
||||
d.mark(s.Gotype, s)
|
||||
d.mark(s.Sub, s)
|
||||
d.mark(s.Outer, s)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,441 +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/dwarf"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/loader"
|
||||
"cmd/oldlink/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
|
||||
rtmp []loader.Reloc
|
||||
|
||||
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)
|
||||
if !d.ldr.IsDup(s) {
|
||||
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 {
|
||||
d.ReadRelocs(exportsIdx)
|
||||
for i := 0; i < len(d.rtmp); i++ {
|
||||
d.mark(d.rtmp[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)
|
||||
}
|
||||
|
||||
// DWARF constant DIE symbols are not referenced, but needed by
|
||||
// the dwarf pass.
|
||||
if !*FlagW {
|
||||
for _, lib := range d.ctxt.Library {
|
||||
names = append(names, dwarf.ConstInfoPrefix+lib.Pkg)
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
symRelocs := []loader.Reloc{}
|
||||
auxSyms := []loader.Sym{}
|
||||
for !d.wq.empty() {
|
||||
symIdx := d.wq.pop()
|
||||
|
||||
d.reflectSeen = d.reflectSeen || d.ldr.IsReflectMethod(symIdx)
|
||||
|
||||
relocs := d.ldr.Relocs(symIdx)
|
||||
symRelocs = relocs.ReadAll(symRelocs)
|
||||
|
||||
if d.ldr.IsGoType(symIdx) {
|
||||
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, symRelocs) {
|
||||
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 := symRelocs[i]
|
||||
if r.Type == objabi.R_WEAKADDROFF {
|
||||
continue
|
||||
}
|
||||
if r.Type == 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 r.Type == 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)
|
||||
}
|
||||
auxSyms = d.ldr.ReadAuxSyms(symIdx, auxSyms)
|
||||
for i := 0; i < len(auxSyms); i++ {
|
||||
d.mark(auxSyms[i], 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.
|
||||
d.mark(d.ldr.OuterSym(symIdx), symIdx)
|
||||
d.mark(d.ldr.SubSym(symIdx), symIdx)
|
||||
|
||||
if len(methods) != 0 {
|
||||
// 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, symRelocs)
|
||||
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.Reachable.Has(symIdx) {
|
||||
d.wq.push(symIdx)
|
||||
d.ldr.Reachable.Set(symIdx)
|
||||
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) {
|
||||
d.ReadRelocs(m.src)
|
||||
d.mark(d.rtmp[m.r].Sym, m.src)
|
||||
d.mark(d.rtmp[m.r+1].Sym, m.src)
|
||||
d.mark(d.rtmp[m.r+2].Sym, m.src)
|
||||
}
|
||||
|
||||
func deadcode2(ctxt *Link) {
|
||||
ldr := ctxt.loader
|
||||
d := deadcodePass2{ctxt: ctxt, ldr: ldr}
|
||||
d.init()
|
||||
d.flood()
|
||||
|
||||
callSym := ldr.Lookup("reflect.Value.Call", sym.SymVerABIInternal)
|
||||
methSym := ldr.Lookup("reflect.Value.Method", 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 || (callSym != 0 && ldr.Reachable.Has(callSym)) || (methSym != 0 && ldr.Reachable.Has(methSym))
|
||||
|
||||
// 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.Reachable.Has(relocs.At(0).Sym) {
|
||||
ldr.Reachable.Set(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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, symRelocs []loader.Reloc, off, size, count int) []methodsig {
|
||||
var buf bytes.Buffer
|
||||
var methods []methodsig
|
||||
for i := 0; i < count; i++ {
|
||||
buf.WriteString(decodetypeName2(ldr, symIdx, symRelocs, off))
|
||||
mtypSym := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off+4))
|
||||
// FIXME: add some sort of caching here, since we may see some of the
|
||||
// same symbols over time for param types.
|
||||
d.ReadRelocs(mtypSym)
|
||||
mp := ldr.Data(mtypSym)
|
||||
|
||||
buf.WriteRune('(')
|
||||
inCount := decodetypeFuncInCount(arch, mp)
|
||||
for i := 0; i < inCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
a := d.decodetypeFuncInType2(ldr, arch, mtypSym, d.rtmp, i)
|
||||
buf.WriteString(ldr.SymName(a))
|
||||
}
|
||||
buf.WriteString(") (")
|
||||
outCount := decodetypeFuncOutCount(arch, mp)
|
||||
for i := 0; i < outCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
a := d.decodetypeFuncOutType2(ldr, arch, mtypSym, d.rtmp, 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, symRelocs []loader.Reloc) []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, symRelocs, int32(commonsize(arch)+arch.PtrSize))
|
||||
if rel.Sym == 0 {
|
||||
return nil
|
||||
}
|
||||
if rel.Sym != 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, symRelocs, off, sizeofIMethod, numMethods)
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []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, symRelocs, off, sizeofMethod, mcount)
|
||||
}
|
||||
|
||||
func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Reloc {
|
||||
for j := 0; j < len(symRelocs); j++ {
|
||||
rel := symRelocs[j]
|
||||
if rel.Off == off {
|
||||
return rel
|
||||
}
|
||||
}
|
||||
return loader.Reloc{}
|
||||
}
|
||||
|
||||
func decodeRelocSym2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Sym {
|
||||
return decodeReloc2(ldr, symIdx, symRelocs, off).Sym
|
||||
}
|
||||
|
||||
// decodetypeName2 decodes the name from a reflect.name.
|
||||
func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int) string {
|
||||
r := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off))
|
||||
if r == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
data := ldr.Data(r)
|
||||
namelen := int(uint16(data[1])<<8 | uint16(data[2]))
|
||||
return string(data[3 : 3+namelen])
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
|
||||
uadd := commonsize(arch) + 4
|
||||
if arch.PtrSize == 8 {
|
||||
uadd += 4
|
||||
}
|
||||
if decodetypeHasUncommon(arch, ldr.Data(symIdx)) {
|
||||
uadd += uncommonSize()
|
||||
}
|
||||
return decodeRelocSym2(ldr, symIdx, symRelocs, int32(uadd+i*arch.PtrSize))
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) decodetypeFuncOutType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
|
||||
return d.decodetypeFuncInType2(ldr, arch, symIdx, symRelocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
|
||||
}
|
||||
|
||||
// readRelocs reads the relocations for the specified symbol into the
|
||||
// deadcode relocs work array. Use with care, since the work array
|
||||
// is a singleton.
|
||||
func (d *deadcodePass2) ReadRelocs(symIdx loader.Sym) {
|
||||
relocs := d.ldr.Relocs(symIdx)
|
||||
d.rtmp = relocs.ReadAll(d.rtmp)
|
||||
}
|
||||
|
|
@ -1,374 +0,0 @@
|
|||
// Copyright 2012 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/oldlink/internal/sym"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Decoding the type.* symbols. This has to be in sync with
|
||||
// ../../runtime/type.go, or more specifically, with what
|
||||
// cmd/compile/internal/gc/reflect.go stuffs in these.
|
||||
|
||||
// tflag is documented in reflect/type.go.
|
||||
//
|
||||
// tflag values must be kept in sync with copies in:
|
||||
// cmd/compile/internal/gc/reflect.go
|
||||
// cmd/oldlink/internal/ld/decodesym.go
|
||||
// reflect/type.go
|
||||
// runtime/type.go
|
||||
const (
|
||||
tflagUncommon = 1 << 0
|
||||
tflagExtraStar = 1 << 1
|
||||
)
|
||||
|
||||
func decodeReloc(s *sym.Symbol, off int32) *sym.Reloc {
|
||||
for i := range s.R {
|
||||
if s.R[i].Off == off {
|
||||
return &s.R[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeRelocSym(s *sym.Symbol, off int32) *sym.Symbol {
|
||||
r := decodeReloc(s, off)
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return r.Sym
|
||||
}
|
||||
|
||||
func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 {
|
||||
switch sz {
|
||||
case 2:
|
||||
return uint64(arch.ByteOrder.Uint16(p))
|
||||
case 4:
|
||||
return uint64(arch.ByteOrder.Uint32(p))
|
||||
case 8:
|
||||
return arch.ByteOrder.Uint64(p)
|
||||
default:
|
||||
Exitf("dwarf: decode inuxi %d", sz)
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
func commonsize(arch *sys.Arch) int { return 4*arch.PtrSize + 8 + 8 } // runtime._type
|
||||
func structfieldSize(arch *sys.Arch) int { return 3 * arch.PtrSize } // runtime.structfield
|
||||
func uncommonSize() int { return 4 + 2 + 2 + 4 + 4 } // runtime.uncommontype
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetypeKind(arch *sys.Arch, p []byte) uint8 {
|
||||
return p[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 {
|
||||
return p[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.size
|
||||
func decodetypeSize(arch *sys.Arch, p []byte) int64 {
|
||||
return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10
|
||||
}
|
||||
|
||||
// Type.commonType.ptrdata
|
||||
func decodetypePtrdata(arch *sys.Arch, p []byte) int64 {
|
||||
return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
|
||||
}
|
||||
|
||||
// Type.commonType.tflag
|
||||
func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool {
|
||||
return p[2*arch.PtrSize+4]&tflagUncommon != 0
|
||||
}
|
||||
|
||||
// Find the elf.Section of a given shared library that contains a given address.
|
||||
func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
|
||||
for _, shlib := range ctxt.Shlibs {
|
||||
if shlib.Path == path {
|
||||
for _, sect := range shlib.File.Sections {
|
||||
if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
|
||||
return sect
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type.commonType.gc
|
||||
func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte {
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
addr := decodetypeGcprogShlib(ctxt, s)
|
||||
sect := findShlibSection(ctxt, s.File, addr)
|
||||
if sect != nil {
|
||||
// A gcprog is a 4-byte uint32 indicating length, followed by
|
||||
// the actual program.
|
||||
progsize := make([]byte, 4)
|
||||
sect.ReadAt(progsize, int64(addr-sect.Addr))
|
||||
progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
|
||||
sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
|
||||
return append(progsize, progbytes...)
|
||||
}
|
||||
Exitf("cannot find gcprog for %s", s.Name)
|
||||
return nil
|
||||
}
|
||||
return decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)).P
|
||||
}
|
||||
|
||||
func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 {
|
||||
if ctxt.Arch.Family == sys.ARM64 {
|
||||
for _, shlib := range ctxt.Shlibs {
|
||||
if shlib.Path == s.File {
|
||||
return shlib.gcdataAddresses[s]
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return decodeInuxi(ctxt.Arch, s.P[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)
|
||||
ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
|
||||
sect := findShlibSection(ctxt, s.File, addr)
|
||||
if sect != nil {
|
||||
r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
|
||||
sect.ReadAt(r, int64(addr-sect.Addr))
|
||||
return r
|
||||
}
|
||||
Exitf("cannot find gcmask for %s", s.Name)
|
||||
return nil
|
||||
}
|
||||
mask := decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
|
||||
return mask.P
|
||||
}
|
||||
|
||||
// Type.ArrayType.elem and Type.SliceType.Elem
|
||||
func decodetypeArrayElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
func decodetypeArrayLen(arch *sys.Arch, s *sym.Symbol) int64 {
|
||||
return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
|
||||
}
|
||||
|
||||
// Type.PtrType.elem
|
||||
func decodetypePtrElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
// Type.MapType.key, elem
|
||||
func decodetypeMapKey(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
func decodetypeMapValue(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38
|
||||
}
|
||||
|
||||
// Type.ChanType.elem
|
||||
func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
||||
return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
// Type.FuncType.dotdotdot
|
||||
func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
|
||||
return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
|
||||
}
|
||||
|
||||
// Type.FuncType.inCount
|
||||
func decodetypeFuncInCount(arch *sys.Arch, p []byte) int {
|
||||
return int(decodeInuxi(arch, p[commonsize(arch):], 2))
|
||||
}
|
||||
|
||||
func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
|
||||
return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
|
||||
}
|
||||
|
||||
func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
|
||||
uadd := commonsize(arch) + 4
|
||||
if arch.PtrSize == 8 {
|
||||
uadd += 4
|
||||
}
|
||||
if decodetypeHasUncommon(arch, s.P) {
|
||||
uadd += uncommonSize()
|
||||
}
|
||||
return decodeRelocSym(s, int32(uadd+i*arch.PtrSize))
|
||||
}
|
||||
|
||||
func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
|
||||
return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s.P))
|
||||
}
|
||||
|
||||
// Type.StructType.fields.Slice::length
|
||||
func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int {
|
||||
return int(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
|
||||
}
|
||||
|
||||
func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int {
|
||||
off := commonsize(arch) + 4*arch.PtrSize
|
||||
if decodetypeHasUncommon(arch, s.P) {
|
||||
off += uncommonSize()
|
||||
}
|
||||
off += i * structfieldSize(arch)
|
||||
return off
|
||||
}
|
||||
|
||||
// decodetypeStr returns the contents of an rtype's str field (a nameOff).
|
||||
func decodetypeStr(arch *sys.Arch, s *sym.Symbol) string {
|
||||
str := decodetypeName(s, 4*arch.PtrSize+8)
|
||||
if s.P[2*arch.PtrSize+4]&tflagExtraStar != 0 {
|
||||
return str[1:]
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// decodetypeName decodes the name from a reflect.name.
|
||||
func decodetypeName(s *sym.Symbol, off int) string {
|
||||
r := decodeReloc(s, int32(off))
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
data := r.Sym.P
|
||||
namelen := int(uint16(data[1])<<8 | uint16(data[2]))
|
||||
return string(data[3 : 3+namelen])
|
||||
}
|
||||
|
||||
func decodetypeStructFieldName(arch *sys.Arch, s *sym.Symbol, i int) string {
|
||||
off := decodetypeStructFieldArrayOff(arch, s, i)
|
||||
return decodetypeName(s, off)
|
||||
}
|
||||
|
||||
func decodetypeStructFieldType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
|
||||
off := decodetypeStructFieldArrayOff(arch, s, i)
|
||||
return decodeRelocSym(s, int32(off+arch.PtrSize))
|
||||
}
|
||||
|
||||
func decodetypeStructFieldOffs(arch *sys.Arch, s *sym.Symbol, i int) int64 {
|
||||
return decodetypeStructFieldOffsAnon(arch, s, i) >> 1
|
||||
}
|
||||
|
||||
func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 {
|
||||
off := decodetypeStructFieldArrayOff(arch, s, i)
|
||||
return int64(decodeInuxi(arch, s.P[off+2*arch.PtrSize:], arch.PtrSize))
|
||||
}
|
||||
|
||||
// InterfaceType.methods.length
|
||||
func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
|
||||
return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
|
||||
}
|
||||
|
||||
// methodsig is a fully qualified typed method signature, like
|
||||
// "Visit(type.go/ast.Node) (type.go/ast.Visitor)".
|
||||
type methodsig string
|
||||
|
||||
// Matches runtime/typekind.go and reflect.Kind.
|
||||
const (
|
||||
kindArray = 17
|
||||
kindChan = 18
|
||||
kindFunc = 19
|
||||
kindInterface = 20
|
||||
kindMap = 21
|
||||
kindPtr = 22
|
||||
kindSlice = 23
|
||||
kindStruct = 25
|
||||
kindMask = (1 << 5) - 1
|
||||
)
|
||||
|
||||
// decodeMethodSig decodes an array of method signature information.
|
||||
// Each element of the array is size bytes. The first 4 bytes is a
|
||||
// nameOff for the method name, and the next 4 bytes is a typeOff for
|
||||
// the function type.
|
||||
//
|
||||
// Conveniently this is the layout of both runtime.method and runtime.imethod.
|
||||
func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []methodsig {
|
||||
var buf bytes.Buffer
|
||||
var methods []methodsig
|
||||
for i := 0; i < count; i++ {
|
||||
buf.WriteString(decodetypeName(s, off))
|
||||
mtypSym := decodeRelocSym(s, int32(off+4))
|
||||
|
||||
buf.WriteRune('(')
|
||||
inCount := decodetypeFuncInCount(arch, mtypSym.P)
|
||||
for i := 0; i < inCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(decodetypeFuncInType(arch, mtypSym, i).Name)
|
||||
}
|
||||
buf.WriteString(") (")
|
||||
outCount := decodetypeFuncOutCount(arch, mtypSym.P)
|
||||
for i := 0; i < outCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(decodetypeFuncOutType(arch, mtypSym, i).Name)
|
||||
}
|
||||
buf.WriteRune(')')
|
||||
|
||||
off += size
|
||||
methods = append(methods, methodsig(buf.String()))
|
||||
buf.Reset()
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
|
||||
if decodetypeKind(arch, s.P)&kindMask != kindInterface {
|
||||
panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
|
||||
}
|
||||
r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize))
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if r.Sym != s {
|
||||
panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
|
||||
}
|
||||
off := int(r.Add) // array of reflect.imethod values
|
||||
numMethods := int(decodetypeIfaceMethodCount(arch, s.P))
|
||||
sizeofIMethod := 4 + 4
|
||||
return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
|
||||
}
|
||||
|
||||
func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
|
||||
if !decodetypeHasUncommon(arch, s.P) {
|
||||
panic(fmt.Sprintf("no methods on %q", s.Name))
|
||||
}
|
||||
off := commonsize(arch) // reflect.rtype
|
||||
switch decodetypeKind(arch, s.P) & kindMask {
|
||||
case kindStruct: // reflect.structType
|
||||
off += 4 * arch.PtrSize
|
||||
case kindPtr: // reflect.ptrType
|
||||
off += arch.PtrSize
|
||||
case kindFunc: // reflect.funcType
|
||||
off += arch.PtrSize // 4 bytes, pointer aligned
|
||||
case kindSlice: // reflect.sliceType
|
||||
off += arch.PtrSize
|
||||
case kindArray: // reflect.arrayType
|
||||
off += 3 * arch.PtrSize
|
||||
case kindChan: // reflect.chanType
|
||||
off += 2 * arch.PtrSize
|
||||
case kindMap: // reflect.mapType
|
||||
off += 4*arch.PtrSize + 8
|
||||
case kindInterface: // reflect.interfaceType
|
||||
off += 3 * arch.PtrSize
|
||||
default:
|
||||
// just Sizeof(rtype)
|
||||
}
|
||||
|
||||
mcount := int(decodeInuxi(arch, s.P[off+4:], 2))
|
||||
moff := int(decodeInuxi(arch, s.P[off+4+2+2:], 4))
|
||||
off += moff // offset to array of reflect.method values
|
||||
const sizeofMethod = 4 * 4 // sizeof reflect.method in program
|
||||
return decodeMethodSig(arch, s, off, sizeofMethod, mcount)
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,37 +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.
|
||||
|
||||
// +build !wasm,!windows
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const syscallExecSupported = true
|
||||
|
||||
// execArchive invokes the archiver tool with syscall.Exec(), with
|
||||
// the expectation that this is the last thing that takes place
|
||||
// in the linking operation.
|
||||
func (ctxt *Link) execArchive(argv []string) {
|
||||
var err error
|
||||
argv0 := argv[0]
|
||||
if filepath.Base(argv0) == argv0 {
|
||||
argv0, err = exec.LookPath(argv0)
|
||||
if err != nil {
|
||||
Exitf("cannot find %s: %v", argv[0], err)
|
||||
}
|
||||
}
|
||||
if ctxt.Debugvlog != 0 {
|
||||
ctxt.Logf("invoking archiver with syscall.Exec()\n")
|
||||
}
|
||||
err = syscall.Exec(argv0, argv, os.Environ())
|
||||
if err != nil {
|
||||
Exitf("running %s failed: %v", argv[0], err)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +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.
|
||||
|
||||
// +build wasm windows
|
||||
|
||||
package ld
|
||||
|
||||
const syscallExecSupported = false
|
||||
|
||||
func (ctxt *Link) execArchive(argv []string) {
|
||||
panic("should never arrive here")
|
||||
}
|
||||
|
|
@ -1,442 +0,0 @@
|
|||
// Copyright 2009 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.
|
||||
|
||||
// go-specific code shared across loaders (5l, 6l, 8l).
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// go-specific code shared across loaders (5l, 6l, 8l).
|
||||
|
||||
// replace all "". with pkg.
|
||||
func expandpkg(t0 string, pkg string) string {
|
||||
return strings.Replace(t0, `"".`, pkg+".", -1)
|
||||
}
|
||||
|
||||
func resolveABIAlias(s *sym.Symbol) *sym.Symbol {
|
||||
if s.Type != sym.SABIALIAS {
|
||||
return s
|
||||
}
|
||||
target := s.R[0].Sym
|
||||
if target.Type == sym.SABIALIAS {
|
||||
panic(fmt.Sprintf("ABI alias %s references another ABI alias %s", s, target))
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// generate debugging section in binary.
|
||||
// once the dust settles, try to move some code to
|
||||
// libmach, so that other linkers and ar can share.
|
||||
|
||||
func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) {
|
||||
if *flagG {
|
||||
return
|
||||
}
|
||||
|
||||
if int64(int(length)) != length {
|
||||
fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
|
||||
if *flagU {
|
||||
errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
bdata := make([]byte, length)
|
||||
if _, err := io.ReadFull(f, bdata); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
|
||||
if *flagU {
|
||||
errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
data := string(bdata)
|
||||
|
||||
// process header lines
|
||||
for data != "" {
|
||||
var line string
|
||||
if i := strings.Index(data, "\n"); i >= 0 {
|
||||
line, data = data[:i], data[i+1:]
|
||||
} else {
|
||||
line, data = data, ""
|
||||
}
|
||||
if line == "safe" {
|
||||
lib.Safe = true
|
||||
}
|
||||
if line == "main" {
|
||||
lib.Main = true
|
||||
}
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// look for cgo section
|
||||
p0 := strings.Index(data, "\n$$ // cgo")
|
||||
var p1 int
|
||||
if p0 >= 0 {
|
||||
p0 += p1
|
||||
i := strings.IndexByte(data[p0+1:], '\n')
|
||||
if i < 0 {
|
||||
fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
|
||||
if *flagU {
|
||||
errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
p0 += 1 + i
|
||||
|
||||
p1 = strings.Index(data[p0:], "\n$$")
|
||||
if p1 < 0 {
|
||||
p1 = strings.Index(data[p0:], "\n!\n")
|
||||
}
|
||||
if p1 < 0 {
|
||||
fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
|
||||
if *flagU {
|
||||
errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
p1 += p0
|
||||
loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
|
||||
}
|
||||
}
|
||||
|
||||
func loadcgo(ctxt *Link, file string, pkg string, p string) {
|
||||
var directives [][]string
|
||||
if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err)
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
// Find cgo_export symbols. They are roots in the deadcode pass.
|
||||
for _, f := range directives {
|
||||
switch f[0] {
|
||||
case "cgo_export_static", "cgo_export_dynamic":
|
||||
if len(f) < 2 || len(f) > 3 {
|
||||
continue
|
||||
}
|
||||
local := f[1]
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
|
||||
if local == "main" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
local = expandpkg(local, pkg)
|
||||
if f[0] == "cgo_export_static" {
|
||||
ctxt.cgo_export_static[local] = true
|
||||
} else {
|
||||
ctxt.cgo_export_dynamic[local] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if *flagNewobj {
|
||||
// Record the directives. We'll process them later after Symbols are created.
|
||||
ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives})
|
||||
} else {
|
||||
setCgoAttr(ctxt, ctxt.Syms.Lookup, file, pkg, directives)
|
||||
}
|
||||
}
|
||||
|
||||
// Set symbol attributes or flags based on cgo directives.
|
||||
func setCgoAttr(ctxt *Link, lookup func(string, int) *sym.Symbol, file string, pkg string, directives [][]string) {
|
||||
for _, f := range directives {
|
||||
switch f[0] {
|
||||
case "cgo_import_dynamic":
|
||||
if len(f) < 2 || len(f) > 4 {
|
||||
break
|
||||
}
|
||||
|
||||
local := f[1]
|
||||
remote := local
|
||||
if len(f) > 2 {
|
||||
remote = f[2]
|
||||
}
|
||||
lib := ""
|
||||
if len(f) > 3 {
|
||||
lib = f[3]
|
||||
}
|
||||
|
||||
if *FlagD {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
if local == "_" && remote == "_" {
|
||||
// allow #pragma dynimport _ _ "foo.so"
|
||||
// to force a link of foo.so.
|
||||
havedynamic = 1
|
||||
|
||||
if ctxt.HeadType == objabi.Hdarwin {
|
||||
machoadddynlib(lib, ctxt.LinkMode)
|
||||
} else {
|
||||
dynlib = append(dynlib, lib)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
local = expandpkg(local, pkg)
|
||||
q := ""
|
||||
if i := strings.Index(remote, "#"); i >= 0 {
|
||||
remote, q = remote[:i], remote[i+1:]
|
||||
}
|
||||
s := lookup(local, 0)
|
||||
if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS || s.Type == sym.SHOSTOBJ {
|
||||
s.SetDynimplib(lib)
|
||||
s.SetExtname(remote)
|
||||
s.SetDynimpvers(q)
|
||||
if s.Type != sym.SHOSTOBJ {
|
||||
s.Type = sym.SDYNIMPORT
|
||||
}
|
||||
havedynamic = 1
|
||||
}
|
||||
|
||||
continue
|
||||
|
||||
case "cgo_import_static":
|
||||
if len(f) != 2 {
|
||||
break
|
||||
}
|
||||
local := f[1]
|
||||
|
||||
s := lookup(local, 0)
|
||||
s.Type = sym.SHOSTOBJ
|
||||
s.Size = 0
|
||||
continue
|
||||
|
||||
case "cgo_export_static", "cgo_export_dynamic":
|
||||
if len(f) < 2 || len(f) > 3 {
|
||||
break
|
||||
}
|
||||
local := f[1]
|
||||
remote := local
|
||||
if len(f) > 2 {
|
||||
remote = f[2]
|
||||
}
|
||||
local = expandpkg(local, pkg)
|
||||
|
||||
// The compiler arranges for an ABI0 wrapper
|
||||
// to be available for all cgo-exported
|
||||
// functions. Link.loadlib will resolve any
|
||||
// ABI aliases we find here (since we may not
|
||||
// yet know it's an alias).
|
||||
s := lookup(local, 0)
|
||||
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
|
||||
if s == lookup("main", 0) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// export overrides import, for openbsd/cgo.
|
||||
// see issue 4878.
|
||||
if s.Dynimplib() != "" {
|
||||
s.ResetDyninfo()
|
||||
s.SetExtname("")
|
||||
s.Type = 0
|
||||
}
|
||||
|
||||
if !s.Attr.CgoExport() {
|
||||
s.SetExtname(remote)
|
||||
} else if s.Extname() != remote {
|
||||
fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote)
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
if f[0] == "cgo_export_static" {
|
||||
s.Attr |= sym.AttrCgoExportStatic
|
||||
} else {
|
||||
s.Attr |= sym.AttrCgoExportDynamic
|
||||
}
|
||||
continue
|
||||
|
||||
case "cgo_dynamic_linker":
|
||||
if len(f) != 2 {
|
||||
break
|
||||
}
|
||||
|
||||
if *flagInterpreter == "" {
|
||||
if interpreter != "" && interpreter != f[1] {
|
||||
fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
interpreter = f[1]
|
||||
}
|
||||
continue
|
||||
|
||||
case "cgo_ldflag":
|
||||
if len(f) != 2 {
|
||||
break
|
||||
}
|
||||
ldflag = append(ldflag, f[1])
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f)
|
||||
nerrors++
|
||||
}
|
||||
}
|
||||
|
||||
var seenlib = make(map[string]bool)
|
||||
|
||||
func adddynlib(ctxt *Link, lib string) {
|
||||
if seenlib[lib] || ctxt.LinkMode == LinkExternal {
|
||||
return
|
||||
}
|
||||
seenlib[lib] = true
|
||||
|
||||
if ctxt.IsELF {
|
||||
s := ctxt.Syms.Lookup(".dynstr", 0)
|
||||
if s.Size == 0 {
|
||||
Addstring(s, "")
|
||||
}
|
||||
Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
|
||||
} else {
|
||||
Errorf(nil, "adddynlib: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func Adddynsym(ctxt *Link, s *sym.Symbol) {
|
||||
if s.Dynid >= 0 || ctxt.LinkMode == LinkExternal {
|
||||
return
|
||||
}
|
||||
|
||||
if ctxt.IsELF {
|
||||
elfadddynsym(ctxt, s)
|
||||
} else if ctxt.HeadType == objabi.Hdarwin {
|
||||
Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname())
|
||||
} else if ctxt.HeadType == objabi.Hwindows {
|
||||
// already taken care of
|
||||
} else {
|
||||
Errorf(s, "adddynsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func fieldtrack(ctxt *Link) {
|
||||
// record field tracking references
|
||||
var buf bytes.Buffer
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
if strings.HasPrefix(s.Name, "go.track.") {
|
||||
s.Attr |= sym.AttrSpecial // do not lay out in data segment
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
if s.Attr.Reachable() {
|
||||
buf.WriteString(s.Name[9:])
|
||||
for p := ctxt.Reachparent[s]; p != nil; p = ctxt.Reachparent[p] {
|
||||
buf.WriteString("\t")
|
||||
buf.WriteString(p.Name)
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
|
||||
s.Type = sym.SCONST
|
||||
s.Value = 0
|
||||
}
|
||||
}
|
||||
|
||||
if *flagFieldTrack == "" {
|
||||
return
|
||||
}
|
||||
s := ctxt.Syms.ROLookup(*flagFieldTrack, 0)
|
||||
if s == nil || !s.Attr.Reachable() {
|
||||
return
|
||||
}
|
||||
s.Type = sym.SDATA
|
||||
addstrdata(ctxt, *flagFieldTrack, buf.String())
|
||||
}
|
||||
|
||||
func (ctxt *Link) addexport() {
|
||||
// Track undefined external symbols during external link.
|
||||
if ctxt.LinkMode == LinkExternal {
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() {
|
||||
continue
|
||||
}
|
||||
if s.Type != sym.STEXT {
|
||||
continue
|
||||
}
|
||||
for i := range s.R {
|
||||
r := &s.R[i]
|
||||
if r.Sym != nil && r.Sym.Type == sym.Sxxx {
|
||||
r.Sym.Type = sym.SUNDEFEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(aix)
|
||||
if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix {
|
||||
return
|
||||
}
|
||||
|
||||
for _, exp := range dynexp {
|
||||
Adddynsym(ctxt, exp)
|
||||
}
|
||||
for _, lib := range dynlib {
|
||||
adddynlib(ctxt, lib)
|
||||
}
|
||||
}
|
||||
|
||||
type Pkg struct {
|
||||
mark bool
|
||||
checked bool
|
||||
path string
|
||||
impby []*Pkg
|
||||
}
|
||||
|
||||
var pkgall []*Pkg
|
||||
|
||||
func (p *Pkg) cycle() *Pkg {
|
||||
if p.checked {
|
||||
return nil
|
||||
}
|
||||
|
||||
if p.mark {
|
||||
nerrors++
|
||||
fmt.Printf("import cycle:\n")
|
||||
fmt.Printf("\t%s\n", p.path)
|
||||
return p
|
||||
}
|
||||
|
||||
p.mark = true
|
||||
for _, q := range p.impby {
|
||||
if bad := q.cycle(); bad != nil {
|
||||
p.mark = false
|
||||
p.checked = true
|
||||
fmt.Printf("\timports %s\n", p.path)
|
||||
if bad == p {
|
||||
return nil
|
||||
}
|
||||
return bad
|
||||
}
|
||||
}
|
||||
|
||||
p.checked = true
|
||||
p.mark = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func importcycles() {
|
||||
for _, p := range pkgall {
|
||||
p.cycle()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/oldlink/internal/sym"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (ctxt *Link) readImportCfg(file string) {
|
||||
ctxt.PackageFile = make(map[string]string)
|
||||
ctxt.PackageShlib = make(map[string]string)
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Fatalf("-importcfg: %v", err)
|
||||
}
|
||||
|
||||
for lineNum, line := range strings.Split(string(data), "\n") {
|
||||
lineNum++ // 1-based
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
var verb, args string
|
||||
if i := strings.Index(line, " "); i < 0 {
|
||||
verb = line
|
||||
} else {
|
||||
verb, args = line[:i], strings.TrimSpace(line[i+1:])
|
||||
}
|
||||
var before, after string
|
||||
if i := strings.Index(args, "="); i >= 0 {
|
||||
before, after = args[:i], args[i+1:]
|
||||
}
|
||||
switch verb {
|
||||
default:
|
||||
log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
|
||||
case "packagefile":
|
||||
if before == "" || after == "" {
|
||||
log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
|
||||
}
|
||||
ctxt.PackageFile[before] = after
|
||||
case "packageshlib":
|
||||
if before == "" || after == "" {
|
||||
log.Fatalf(`%s:%d: invalid packageshlib: syntax is "packageshlib path=filename"`, file, lineNum)
|
||||
}
|
||||
ctxt.PackageShlib[before] = after
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pkgname(ctxt *Link, lib string) string {
|
||||
name := path.Clean(lib)
|
||||
|
||||
// When using importcfg, we have the final package name.
|
||||
if ctxt.PackageFile != nil {
|
||||
return name
|
||||
}
|
||||
|
||||
// runtime.a -> runtime, runtime.6 -> runtime
|
||||
pkg := name
|
||||
if len(pkg) >= 2 && pkg[len(pkg)-2] == '.' {
|
||||
pkg = pkg[:len(pkg)-2]
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
|
||||
func findlib(ctxt *Link, lib string) (string, bool) {
|
||||
name := path.Clean(lib)
|
||||
|
||||
var pname string
|
||||
isshlib := false
|
||||
|
||||
if ctxt.linkShared && ctxt.PackageShlib[name] != "" {
|
||||
pname = ctxt.PackageShlib[name]
|
||||
isshlib = true
|
||||
} else if ctxt.PackageFile != nil {
|
||||
pname = ctxt.PackageFile[name]
|
||||
if pname == "" {
|
||||
ctxt.Logf("cannot find package %s (using -importcfg)\n", name)
|
||||
return "", false
|
||||
}
|
||||
} else {
|
||||
if filepath.IsAbs(name) {
|
||||
pname = name
|
||||
} else {
|
||||
pkg := pkgname(ctxt, lib)
|
||||
// Add .a if needed; the new -importcfg modes
|
||||
// do not put .a into the package name anymore.
|
||||
// This only matters when people try to mix
|
||||
// compiles using -importcfg with links not using -importcfg,
|
||||
// such as when running quick things like
|
||||
// 'go tool compile x.go && go tool link x.o'
|
||||
// by hand against a standard library built using -importcfg.
|
||||
if !strings.HasSuffix(name, ".a") && !strings.HasSuffix(name, ".o") {
|
||||
name += ".a"
|
||||
}
|
||||
// try dot, -L "libdir", and then goroot.
|
||||
for _, dir := range ctxt.Libdir {
|
||||
if ctxt.linkShared {
|
||||
pname = filepath.Join(dir, pkg+".shlibname")
|
||||
if _, err := os.Stat(pname); err == nil {
|
||||
isshlib = true
|
||||
break
|
||||
}
|
||||
}
|
||||
pname = filepath.Join(dir, name)
|
||||
if _, err := os.Stat(pname); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
pname = filepath.Clean(pname)
|
||||
}
|
||||
|
||||
return pname, isshlib
|
||||
}
|
||||
|
||||
func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
|
||||
pkg := pkgname(ctxt, lib)
|
||||
|
||||
// already loaded?
|
||||
if l := ctxt.LibraryByPkg[pkg]; l != nil {
|
||||
return l
|
||||
}
|
||||
|
||||
pname, isshlib := findlib(ctxt, lib)
|
||||
|
||||
if ctxt.Debugvlog > 1 {
|
||||
ctxt.Logf("addlib: %s %s pulls in %s isshlib %v\n", obj, src, pname, isshlib)
|
||||
}
|
||||
|
||||
if isshlib {
|
||||
return addlibpath(ctxt, src, obj, "", pkg, pname)
|
||||
}
|
||||
return addlibpath(ctxt, src, obj, pname, pkg, "")
|
||||
}
|
||||
|
||||
/*
|
||||
* add library to library list, return added library.
|
||||
* srcref: src file referring to package
|
||||
* objref: object file referring to package
|
||||
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
|
||||
* pkg: package import path, e.g. container/vector
|
||||
* shlib: path to shared library, or .shlibname file holding path
|
||||
*/
|
||||
func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlib string) *sym.Library {
|
||||
if l := ctxt.LibraryByPkg[pkg]; l != nil {
|
||||
return l
|
||||
}
|
||||
|
||||
if ctxt.Debugvlog > 1 {
|
||||
ctxt.Logf("addlibpath: srcref: %s objref: %s file: %s pkg: %s shlib: %s\n", srcref, objref, file, pkg, shlib)
|
||||
}
|
||||
|
||||
l := &sym.Library{}
|
||||
ctxt.LibraryByPkg[pkg] = l
|
||||
ctxt.Library = append(ctxt.Library, l)
|
||||
l.Objref = objref
|
||||
l.Srcref = srcref
|
||||
l.File = file
|
||||
l.Pkg = pkg
|
||||
if shlib != "" {
|
||||
if strings.HasSuffix(shlib, ".shlibname") {
|
||||
data, err := ioutil.ReadFile(shlib)
|
||||
if err != nil {
|
||||
Errorf(nil, "cannot read %s: %v", shlib, err)
|
||||
}
|
||||
shlib = strings.TrimSpace(string(data))
|
||||
}
|
||||
l.Shlib = shlib
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func atolwhex(s string) int64 {
|
||||
n, _ := strconv.ParseInt(s, 0, 64)
|
||||
return n
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,187 +0,0 @@
|
|||
// Derived from Inferno utils/6l/l.h and related files.
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/loader"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Shlib struct {
|
||||
Path string
|
||||
Hash []byte
|
||||
Deps []string
|
||||
File *elf.File
|
||||
gcdataAddresses map[*sym.Symbol]uint64
|
||||
}
|
||||
|
||||
// Link holds the context for writing object code from a compiler
|
||||
// or for reading that input into the linker.
|
||||
type Link struct {
|
||||
Out *OutBuf
|
||||
|
||||
Syms *sym.Symbols
|
||||
|
||||
Arch *sys.Arch
|
||||
Debugvlog int
|
||||
Bso *bufio.Writer
|
||||
|
||||
Loaded bool // set after all inputs have been loaded as symbols
|
||||
|
||||
IsELF bool
|
||||
HeadType objabi.HeadType
|
||||
|
||||
linkShared bool // link against installed Go shared libraries
|
||||
LinkMode LinkMode
|
||||
BuildMode BuildMode
|
||||
canUsePlugins bool // initialized when Loaded is set to true
|
||||
compressDWARF bool
|
||||
|
||||
Tlsg *sym.Symbol
|
||||
Libdir []string
|
||||
Library []*sym.Library
|
||||
LibraryByPkg map[string]*sym.Library
|
||||
Shlibs []Shlib
|
||||
Tlsoffset int
|
||||
Textp []*sym.Symbol
|
||||
Filesyms []*sym.Symbol
|
||||
Moduledata *sym.Symbol
|
||||
|
||||
PackageFile map[string]string
|
||||
PackageShlib map[string]string
|
||||
|
||||
tramps []*sym.Symbol // trampolines
|
||||
|
||||
// unresolvedSymSet is a set of erroneous unresolved references.
|
||||
// Used to avoid duplicated error messages.
|
||||
unresolvedSymSet map[unresolvedSymKey]bool
|
||||
|
||||
// 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.
|
||||
|
||||
relocbuf []byte // temporary buffer for applying relocations
|
||||
|
||||
loader *loader.Loader
|
||||
cgodata []cgodata // cgo directives to load, three strings are args for loadcgo
|
||||
|
||||
cgo_export_static map[string]bool
|
||||
cgo_export_dynamic map[string]bool
|
||||
}
|
||||
|
||||
type cgodata struct {
|
||||
file string
|
||||
pkg string
|
||||
directives [][]string
|
||||
}
|
||||
|
||||
type unresolvedSymKey struct {
|
||||
from *sym.Symbol // Symbol that referenced unresolved "to"
|
||||
to *sym.Symbol // Unresolved symbol referenced by "from"
|
||||
}
|
||||
|
||||
// ErrorUnresolved prints unresolved symbol error for r.Sym that is referenced from s.
|
||||
func (ctxt *Link) ErrorUnresolved(s *sym.Symbol, r *sym.Reloc) {
|
||||
if ctxt.unresolvedSymSet == nil {
|
||||
ctxt.unresolvedSymSet = make(map[unresolvedSymKey]bool)
|
||||
}
|
||||
|
||||
k := unresolvedSymKey{from: s, to: r.Sym}
|
||||
if !ctxt.unresolvedSymSet[k] {
|
||||
ctxt.unresolvedSymSet[k] = true
|
||||
|
||||
// Try to find symbol under another ABI.
|
||||
var reqABI, haveABI obj.ABI
|
||||
haveABI = ^obj.ABI(0)
|
||||
reqABI, ok := sym.VersionToABI(int(r.Sym.Version))
|
||||
if ok {
|
||||
for abi := obj.ABI(0); abi < obj.ABICount; abi++ {
|
||||
v := sym.ABIToVersion(abi)
|
||||
if v == -1 {
|
||||
continue
|
||||
}
|
||||
if rs := ctxt.Syms.ROLookup(r.Sym.Name, v); rs != nil && rs.Type != sym.Sxxx && rs.Type != sym.SXREF {
|
||||
haveABI = abi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Give a special error message for main symbol (see #24809).
|
||||
if r.Sym.Name == "main.main" {
|
||||
Errorf(s, "function main is undeclared in the main package")
|
||||
} else if haveABI != ^obj.ABI(0) {
|
||||
Errorf(s, "relocation target %s not defined for %s (but is defined for %s)", r.Sym.Name, reqABI, haveABI)
|
||||
} else {
|
||||
Errorf(s, "relocation target %s not defined", r.Sym.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The smallest possible offset from the hardware stack pointer to a local
|
||||
// variable on the stack. Architectures that use a link register save its value
|
||||
// on the stack in the function prologue and so always have a pointer between
|
||||
// the hardware stack pointer and the local variable area.
|
||||
func (ctxt *Link) FixedFrameSize() int64 {
|
||||
switch ctxt.Arch.Family {
|
||||
case sys.AMD64, sys.I386:
|
||||
return 0
|
||||
case sys.PPC64:
|
||||
// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
|
||||
// just use that much stack always on ppc64x.
|
||||
return int64(4 * ctxt.Arch.PtrSize)
|
||||
default:
|
||||
return int64(ctxt.Arch.PtrSize)
|
||||
}
|
||||
}
|
||||
|
||||
func (ctxt *Link) Logf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(ctxt.Bso, format, args...)
|
||||
ctxt.Bso.Flush()
|
||||
}
|
||||
|
||||
func addImports(ctxt *Link, l *sym.Library, pn string) {
|
||||
pkg := objabi.PathToPrefix(l.Pkg)
|
||||
for _, importStr := range l.ImportStrings {
|
||||
lib := addlib(ctxt, pkg, pn, importStr)
|
||||
if lib != nil {
|
||||
l.Imports = append(l.Imports, lib)
|
||||
}
|
||||
}
|
||||
l.ImportStrings = nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,462 +0,0 @@
|
|||
// Copyright 2015 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"
|
||||
"compress/zlib"
|
||||
"debug/macho"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
pageAlign = 12 // 4096 = 1 << 12
|
||||
)
|
||||
|
||||
type loadCmd struct {
|
||||
Cmd macho.LoadCmd
|
||||
Len uint32
|
||||
}
|
||||
|
||||
type dyldInfoCmd struct {
|
||||
Cmd macho.LoadCmd
|
||||
Len uint32
|
||||
RebaseOff, RebaseLen uint32
|
||||
BindOff, BindLen uint32
|
||||
WeakBindOff, WeakBindLen uint32
|
||||
LazyBindOff, LazyBindLen uint32
|
||||
ExportOff, ExportLen uint32
|
||||
}
|
||||
|
||||
type linkEditDataCmd struct {
|
||||
Cmd macho.LoadCmd
|
||||
Len uint32
|
||||
DataOff, DataLen uint32
|
||||
}
|
||||
|
||||
type encryptionInfoCmd struct {
|
||||
Cmd macho.LoadCmd
|
||||
Len uint32
|
||||
CryptOff, CryptLen uint32
|
||||
CryptId uint32
|
||||
}
|
||||
|
||||
type loadCmdReader struct {
|
||||
offset, next int64
|
||||
f *os.File
|
||||
order binary.ByteOrder
|
||||
}
|
||||
|
||||
func (r *loadCmdReader) Next() (loadCmd, error) {
|
||||
var cmd loadCmd
|
||||
|
||||
r.offset = r.next
|
||||
if _, err := r.f.Seek(r.offset, 0); err != nil {
|
||||
return cmd, err
|
||||
}
|
||||
if err := binary.Read(r.f, r.order, &cmd); err != nil {
|
||||
return cmd, err
|
||||
}
|
||||
r.next = r.offset + int64(cmd.Len)
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func (r loadCmdReader) ReadAt(offset int64, data interface{}) error {
|
||||
if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Read(r.f, r.order, data)
|
||||
}
|
||||
|
||||
func (r loadCmdReader) WriteAt(offset int64, data interface{}) error {
|
||||
if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(r.f, r.order, data)
|
||||
}
|
||||
|
||||
// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable.
|
||||
//
|
||||
// With internal linking, DWARF is embedded into the executable, this lets us do the
|
||||
// same for external linking.
|
||||
// exef is the file of the executable with no DWARF. It must have enough room in the macho
|
||||
// header to add the DWARF sections. (Use ld's -headerpad option)
|
||||
// exem is the macho representation of exef.
|
||||
// dsym is the path to the macho file containing DWARF from dsymutil.
|
||||
// outexe is the path where the combined executable should be saved.
|
||||
func machoCombineDwarf(ctxt *Link, exef *os.File, exem *macho.File, dsym, outexe string) error {
|
||||
dwarff, err := os.Open(dsym)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dwarff.Close()
|
||||
outf, err := os.OpenFile(outexe, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outf.Close()
|
||||
dwarfm, err := macho.NewFile(dwarff)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dwarfm.Close()
|
||||
|
||||
// The string table needs to be the last thing in the file
|
||||
// for code signing to work. So we'll need to move the
|
||||
// linkedit section, but all the others can be copied directly.
|
||||
linkseg := exem.Segment("__LINKEDIT")
|
||||
if linkseg == nil {
|
||||
return fmt.Errorf("missing __LINKEDIT segment")
|
||||
}
|
||||
|
||||
if _, err := exef.Seek(0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.CopyN(outf, exef, int64(linkseg.Offset)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
realdwarf := dwarfm.Segment("__DWARF")
|
||||
if realdwarf == nil {
|
||||
return fmt.Errorf("missing __DWARF segment")
|
||||
}
|
||||
|
||||
// Try to compress the DWARF sections. This includes some Apple
|
||||
// proprietary sections like __apple_types.
|
||||
compressedSects, compressedBytes, err := machoCompressSections(ctxt, dwarfm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now copy the dwarf data into the output.
|
||||
// Kernel requires all loaded segments to be page-aligned in the file,
|
||||
// even though we mark this one as being 0 bytes of virtual address space.
|
||||
dwarfstart := machoCalcStart(realdwarf.Offset, linkseg.Offset, pageAlign)
|
||||
if _, err := outf.Seek(dwarfstart, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := dwarff.Seek(int64(realdwarf.Offset), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write out the compressed sections, or the originals if we gave up
|
||||
// on compressing them.
|
||||
var dwarfsize uint64
|
||||
if compressedBytes != nil {
|
||||
dwarfsize = uint64(len(compressedBytes))
|
||||
if _, err := outf.Write(compressedBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil {
|
||||
return err
|
||||
}
|
||||
dwarfsize = realdwarf.Filesz
|
||||
}
|
||||
|
||||
// And finally the linkedit section.
|
||||
if _, err := exef.Seek(int64(linkseg.Offset), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
linkstart := machoCalcStart(linkseg.Offset, uint64(dwarfstart)+dwarfsize, pageAlign)
|
||||
if _, err := outf.Seek(linkstart, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(outf, exef); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now we need to update the headers.
|
||||
textsect := exem.Section("__text")
|
||||
if textsect == nil {
|
||||
return fmt.Errorf("missing __text section")
|
||||
}
|
||||
|
||||
cmdOffset := unsafe.Sizeof(exem.FileHeader)
|
||||
if is64bit := exem.Magic == macho.Magic64; is64bit {
|
||||
// mach_header_64 has one extra uint32.
|
||||
cmdOffset += unsafe.Sizeof(exem.Magic)
|
||||
}
|
||||
dwarfCmdOffset := uint32(cmdOffset) + exem.FileHeader.Cmdsz
|
||||
availablePadding := textsect.Offset - dwarfCmdOffset
|
||||
if availablePadding < realdwarf.Len {
|
||||
return fmt.Errorf("no room to add dwarf info. Need at least %d padding bytes, found %d", realdwarf.Len, availablePadding)
|
||||
}
|
||||
// First, copy the dwarf load command into the header. It will be
|
||||
// updated later with new offsets and lengths as necessary.
|
||||
if _, err := outf.Seek(int64(dwarfCmdOffset), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.CopyN(outf, bytes.NewReader(realdwarf.Raw()), int64(realdwarf.Len)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := outf.Seek(int64(unsafe.Offsetof(exem.FileHeader.Ncmd)), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(outf, exem.ByteOrder, exem.Ncmd+1); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(outf, exem.ByteOrder, exem.Cmdsz+realdwarf.Len); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reader := loadCmdReader{next: int64(cmdOffset), f: outf, order: exem.ByteOrder}
|
||||
for i := uint32(0); i < exem.Ncmd; i++ {
|
||||
cmd, err := reader.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
linkoffset := uint64(linkstart) - linkseg.Offset
|
||||
switch cmd.Cmd {
|
||||
case macho.LoadCmdSegment64:
|
||||
err = machoUpdateSegment(reader, linkseg, linkoffset, &macho.Segment64{}, &macho.Section64{})
|
||||
case macho.LoadCmdSegment:
|
||||
err = machoUpdateSegment(reader, linkseg, linkoffset, &macho.Segment32{}, &macho.Section32{})
|
||||
case LC_DYLD_INFO, LC_DYLD_INFO_ONLY:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff")
|
||||
case macho.LoadCmdSymtab:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &macho.SymtabCmd{}, "Symoff", "Stroff")
|
||||
case macho.LoadCmdDysymtab:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &macho.DysymtabCmd{}, "Tocoffset", "Modtaboff", "Extrefsymoff", "Indirectsymoff", "Extreloff", "Locreloff")
|
||||
case LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &linkEditDataCmd{}, "DataOff")
|
||||
case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &encryptionInfoCmd{}, "CryptOff")
|
||||
case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB, LC_SYMSEG, LC_LOADFVMLIB, LC_IDFVMLIB, LC_IDENT, LC_FVMFILE, LC_PREPAGE, LC_ID_DYLINKER, LC_ROUTINES, LC_SUB_FRAMEWORK, LC_SUB_UMBRELLA, LC_SUB_CLIENT, LC_SUB_LIBRARY, LC_TWOLEVEL_HINTS, LC_PREBIND_CKSUM, LC_ROUTINES_64, LC_LAZY_LOAD_DYLIB, LC_LOAD_UPWARD_DYLIB, LC_DYLD_ENVIRONMENT, LC_LINKER_OPTION, LC_LINKER_OPTIMIZATION_HINT, LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS, LC_VERSION_NOTE, LC_BUILD_VERSION:
|
||||
// Nothing to update
|
||||
default:
|
||||
err = fmt.Errorf("unknown load command 0x%x (%s)", int(cmd.Cmd), cmd.Cmd)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Do the final update of the DWARF segment's load command.
|
||||
return machoUpdateDwarfHeader(&reader, compressedSects, dwarfsize, dwarfstart, realdwarf)
|
||||
}
|
||||
|
||||
// machoCompressSections tries to compress the DWARF segments in dwarfm,
|
||||
// returning the updated sections and segment contents, nils if the sections
|
||||
// weren't compressed, or an error if there was a problem reading dwarfm.
|
||||
func machoCompressSections(ctxt *Link, dwarfm *macho.File) ([]*macho.Section, []byte, error) {
|
||||
if !ctxt.compressDWARF {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
dwarfseg := dwarfm.Segment("__DWARF")
|
||||
var sects []*macho.Section
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, sect := range dwarfm.Sections {
|
||||
if sect.Seg != "__DWARF" {
|
||||
continue
|
||||
}
|
||||
|
||||
// As of writing, there are no relocations in dsymutil's output
|
||||
// so there's no point in worrying about them. Bail out if that
|
||||
// changes.
|
||||
if sect.Nreloc != 0 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
data, err := sect.Data()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
compressed, contents, err := machoCompressSection(data)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
newSec := *sect
|
||||
newSec.Offset = uint32(dwarfseg.Offset) + uint32(buf.Len())
|
||||
newSec.Addr = dwarfseg.Addr + uint64(buf.Len())
|
||||
if compressed {
|
||||
newSec.Name = "__z" + sect.Name[2:]
|
||||
newSec.Size = uint64(len(contents))
|
||||
}
|
||||
sects = append(sects, &newSec)
|
||||
buf.Write(contents)
|
||||
}
|
||||
return sects, buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// machoCompressSection compresses secBytes if it results in less data.
|
||||
func machoCompressSection(sectBytes []byte) (compressed bool, contents []byte, err error) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("ZLIB")
|
||||
var sizeBytes [8]byte
|
||||
binary.BigEndian.PutUint64(sizeBytes[:], uint64(len(sectBytes)))
|
||||
buf.Write(sizeBytes[:])
|
||||
|
||||
z := zlib.NewWriter(&buf)
|
||||
if _, err := z.Write(sectBytes); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
if err := z.Close(); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
if buf.Len() >= len(sectBytes) {
|
||||
return false, sectBytes, nil
|
||||
}
|
||||
return true, buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// machoUpdateSegment updates the load command for a moved segment.
|
||||
// Only the linkedit segment should move, and it should have 0 sections.
|
||||
// seg should be a macho.Segment32 or macho.Segment64 as appropriate.
|
||||
// sect should be a macho.Section32 or macho.Section64 as appropriate.
|
||||
func machoUpdateSegment(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64, seg, sect interface{}) error {
|
||||
if err := r.ReadAt(0, seg); err != nil {
|
||||
return err
|
||||
}
|
||||
segValue := reflect.ValueOf(seg)
|
||||
offset := reflect.Indirect(segValue).FieldByName("Offset")
|
||||
|
||||
// Only the linkedit segment moved, anything before that is fine.
|
||||
if offset.Uint() < linkseg.Offset {
|
||||
return nil
|
||||
}
|
||||
offset.SetUint(offset.Uint() + linkoffset)
|
||||
if err := r.WriteAt(0, seg); err != nil {
|
||||
return err
|
||||
}
|
||||
// There shouldn't be any sections, but just to make sure...
|
||||
return machoUpdateSections(r, segValue, reflect.ValueOf(sect), linkoffset, nil)
|
||||
}
|
||||
|
||||
func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset uint64, compressedSects []*macho.Section) error {
|
||||
iseg := reflect.Indirect(seg)
|
||||
nsect := iseg.FieldByName("Nsect").Uint()
|
||||
if nsect == 0 {
|
||||
return nil
|
||||
}
|
||||
sectOffset := int64(iseg.Type().Size())
|
||||
|
||||
isect := reflect.Indirect(sect)
|
||||
offsetField := isect.FieldByName("Offset")
|
||||
reloffField := isect.FieldByName("Reloff")
|
||||
addrField := isect.FieldByName("Addr")
|
||||
nameField := isect.FieldByName("Name")
|
||||
sizeField := isect.FieldByName("Size")
|
||||
sectSize := int64(isect.Type().Size())
|
||||
for i := uint64(0); i < nsect; i++ {
|
||||
if err := r.ReadAt(sectOffset, sect.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
if compressedSects != nil {
|
||||
cSect := compressedSects[i]
|
||||
var name [16]byte
|
||||
copy(name[:], []byte(cSect.Name))
|
||||
nameField.Set(reflect.ValueOf(name))
|
||||
sizeField.SetUint(cSect.Size)
|
||||
if cSect.Offset != 0 {
|
||||
offsetField.SetUint(uint64(cSect.Offset) + deltaOffset)
|
||||
}
|
||||
if cSect.Addr != 0 {
|
||||
addrField.SetUint(cSect.Addr)
|
||||
}
|
||||
} else {
|
||||
if offsetField.Uint() != 0 {
|
||||
offsetField.SetUint(offsetField.Uint() + deltaOffset)
|
||||
}
|
||||
if reloffField.Uint() != 0 {
|
||||
reloffField.SetUint(reloffField.Uint() + deltaOffset)
|
||||
}
|
||||
if addrField.Uint() != 0 {
|
||||
addrField.SetUint(addrField.Uint())
|
||||
}
|
||||
}
|
||||
if err := r.WriteAt(sectOffset, sect.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
sectOffset += sectSize
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// machoUpdateDwarfHeader updates the DWARF segment load command.
|
||||
func machoUpdateDwarfHeader(r *loadCmdReader, compressedSects []*macho.Section, dwarfsize uint64, dwarfstart int64, realdwarf *macho.Segment) error {
|
||||
var seg, sect interface{}
|
||||
cmd, err := r.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cmd.Cmd == macho.LoadCmdSegment64 {
|
||||
seg = new(macho.Segment64)
|
||||
sect = new(macho.Section64)
|
||||
} else {
|
||||
seg = new(macho.Segment32)
|
||||
sect = new(macho.Section32)
|
||||
}
|
||||
if err := r.ReadAt(0, seg); err != nil {
|
||||
return err
|
||||
}
|
||||
segv := reflect.ValueOf(seg).Elem()
|
||||
segv.FieldByName("Offset").SetUint(uint64(dwarfstart))
|
||||
|
||||
if compressedSects != nil {
|
||||
var segSize uint64
|
||||
for _, newSect := range compressedSects {
|
||||
segSize += newSect.Size
|
||||
}
|
||||
segv.FieldByName("Filesz").SetUint(segSize)
|
||||
} else {
|
||||
segv.FieldByName("Filesz").SetUint(dwarfsize)
|
||||
}
|
||||
|
||||
// We want the DWARF segment to be considered non-loadable, so
|
||||
// force vmaddr and vmsize to zero. In addition, set the initial
|
||||
// protection to zero so as to make the dynamic loader happy,
|
||||
// since otherwise it may complain that that the vm size and file
|
||||
// size don't match for the segment. See issues 21647 and 32673
|
||||
// for more context. Also useful to refer to the Apple dynamic
|
||||
// loader source, specifically ImageLoaderMachO::sniffLoadCommands
|
||||
// in ImageLoaderMachO.cpp (various versions can be found online, see
|
||||
// https://opensource.apple.com/source/dyld/dyld-519.2.2/src/ImageLoaderMachO.cpp.auto.html
|
||||
// as one example).
|
||||
segv.FieldByName("Addr").SetUint(0)
|
||||
segv.FieldByName("Memsz").SetUint(0)
|
||||
segv.FieldByName("Prot").SetUint(0)
|
||||
|
||||
if err := r.WriteAt(0, seg); err != nil {
|
||||
return err
|
||||
}
|
||||
return machoUpdateSections(*r, segv, reflect.ValueOf(sect), uint64(dwarfstart)-realdwarf.Offset, compressedSects)
|
||||
}
|
||||
|
||||
func machoUpdateLoadCommand(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64, cmd interface{}, fields ...string) error {
|
||||
if err := r.ReadAt(0, cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
value := reflect.Indirect(reflect.ValueOf(cmd))
|
||||
|
||||
for _, name := range fields {
|
||||
field := value.FieldByName(name)
|
||||
if fieldval := field.Uint(); fieldval >= linkseg.Offset {
|
||||
field.SetUint(fieldval + linkoffset)
|
||||
}
|
||||
}
|
||||
if err := r.WriteAt(0, cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func machoCalcStart(origAddr, newAddr uint64, alignExp uint32) int64 {
|
||||
align := uint64(1 << alignExp)
|
||||
origMod, newMod := origAddr%align, newAddr%align
|
||||
if origMod == newMod {
|
||||
return int64(newAddr)
|
||||
}
|
||||
return int64(newAddr + align + origMod - newMod)
|
||||
}
|
||||
|
|
@ -1,338 +0,0 @@
|
|||
// Inferno utils/6l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
pkglistfornote []byte
|
||||
windowsgui bool // writes a "GUI binary" instead of a "console binary"
|
||||
ownTmpDir bool // set to true if tmp dir created by linker (e.g. no -tmpdir)
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
|
||||
}
|
||||
|
||||
// Flags used by the linker. The exported flags are used by the architecture-specific packages.
|
||||
var (
|
||||
flagBuildid = flag.String("buildid", "", "record `id` as Go toolchain build id")
|
||||
|
||||
flagOutfile = flag.String("o", "", "write output to `file`")
|
||||
flagPluginPath = flag.String("pluginpath", "", "full path name for plugin")
|
||||
|
||||
flagInstallSuffix = flag.String("installsuffix", "", "set package directory `suffix`")
|
||||
flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph")
|
||||
flagRace = flag.Bool("race", false, "enable race detector")
|
||||
flagMsan = flag.Bool("msan", false, "enable MSan interface")
|
||||
|
||||
flagFieldTrack = flag.String("k", "", "set field tracking `symbol`")
|
||||
flagLibGCC = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable")
|
||||
flagTmpdir = flag.String("tmpdir", "", "use `directory` for temporary files")
|
||||
|
||||
flagExtld = flag.String("extld", "", "use `linker` when linking in external mode")
|
||||
flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker")
|
||||
flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive")
|
||||
|
||||
flagA = flag.Bool("a", false, "disassemble output")
|
||||
FlagC = flag.Bool("c", false, "dump call graph")
|
||||
FlagD = flag.Bool("d", false, "disable dynamic executable")
|
||||
flagF = flag.Bool("f", false, "ignore version mismatch")
|
||||
flagG = flag.Bool("g", false, "disable go package data checks")
|
||||
flagH = flag.Bool("h", false, "halt on error")
|
||||
flagN = flag.Bool("n", false, "dump symbol table")
|
||||
FlagS = flag.Bool("s", false, "disable symbol table")
|
||||
flagU = flag.Bool("u", false, "reject unsafe packages")
|
||||
FlagW = flag.Bool("w", false, "disable DWARF generation")
|
||||
Flag8 bool // use 64-bit addresses in symbol table
|
||||
flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
|
||||
FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
|
||||
FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
|
||||
flagNewobj = flag.Bool("newobj", false, "use new object file format")
|
||||
|
||||
FlagRound = flag.Int("R", -1, "set address rounding `quantum`")
|
||||
FlagTextAddr = flag.Int64("T", -1, "set text segment `address`")
|
||||
flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
|
||||
|
||||
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
|
||||
memprofile = flag.String("memprofile", "", "write memory profile to `file`")
|
||||
memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
|
||||
)
|
||||
|
||||
// Main is the main entry point for the linker code.
|
||||
func Main(arch *sys.Arch, theArch Arch) {
|
||||
thearch = theArch
|
||||
ctxt := linknew(arch)
|
||||
ctxt.Bso = bufio.NewWriter(os.Stdout)
|
||||
|
||||
// For testing behavior of go command when tools crash silently.
|
||||
// Undocumented, not in standard flag parser to avoid
|
||||
// exposing in usage message.
|
||||
for _, arg := range os.Args {
|
||||
if arg == "-crash_for_testing" {
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
final := gorootFinal()
|
||||
addstrdata1(ctxt, "runtime/internal/sys.DefaultGoroot="+final)
|
||||
addstrdata1(ctxt, "cmd/internal/objabi.defaultGOROOT="+final)
|
||||
|
||||
// TODO(matloob): define these above and then check flag values here
|
||||
if ctxt.Arch.Family == sys.AMD64 && objabi.GOOS == "plan9" {
|
||||
flag.BoolVar(&Flag8, "8", false, "use 64-bit addresses in symbol table")
|
||||
}
|
||||
flagHeadType := flag.String("H", "", "set header `type`")
|
||||
flag.BoolVar(&ctxt.linkShared, "linkshared", false, "link against installed Go shared libraries")
|
||||
flag.Var(&ctxt.LinkMode, "linkmode", "set link `mode`")
|
||||
flag.Var(&ctxt.BuildMode, "buildmode", "set build `mode`")
|
||||
flag.BoolVar(&ctxt.compressDWARF, "compressdwarf", true, "compress DWARF if possible")
|
||||
objabi.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
|
||||
objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) })
|
||||
objabi.AddVersionFlag() // -V
|
||||
objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
|
||||
objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog)
|
||||
objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg)
|
||||
|
||||
objabi.Flagparse(usage)
|
||||
|
||||
switch *flagHeadType {
|
||||
case "":
|
||||
case "windowsgui":
|
||||
ctxt.HeadType = objabi.Hwindows
|
||||
windowsgui = true
|
||||
default:
|
||||
if err := ctxt.HeadType.Set(*flagHeadType); err != nil {
|
||||
Errorf(nil, "%v", err)
|
||||
usage()
|
||||
}
|
||||
}
|
||||
|
||||
if objabi.Fieldtrack_enabled != 0 {
|
||||
ctxt.Reachparent = make(map[*sym.Symbol]*sym.Symbol)
|
||||
}
|
||||
checkStrictDups = *FlagStrictDups
|
||||
|
||||
startProfile()
|
||||
if ctxt.BuildMode == BuildModeUnset {
|
||||
ctxt.BuildMode = BuildModeExe
|
||||
}
|
||||
|
||||
if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 {
|
||||
usage()
|
||||
}
|
||||
|
||||
if *flagOutfile == "" {
|
||||
*flagOutfile = "a.out"
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
*flagOutfile += ".exe"
|
||||
}
|
||||
}
|
||||
|
||||
interpreter = *flagInterpreter
|
||||
|
||||
libinit(ctxt) // creates outfile
|
||||
|
||||
if ctxt.HeadType == objabi.Hunknown {
|
||||
ctxt.HeadType.Set(objabi.GOOS)
|
||||
}
|
||||
|
||||
ctxt.computeTLSOffset()
|
||||
thearch.Archinit(ctxt)
|
||||
|
||||
if ctxt.linkShared && !ctxt.IsELF {
|
||||
Exitf("-linkshared can only be used on elf systems")
|
||||
}
|
||||
|
||||
if ctxt.Debugvlog != 0 {
|
||||
ctxt.Logf("HEADER = -H%d -T0x%x -R0x%x\n", ctxt.HeadType, uint64(*FlagTextAddr), uint32(*FlagRound))
|
||||
}
|
||||
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeShared:
|
||||
for i := 0; i < flag.NArg(); i++ {
|
||||
arg := flag.Arg(i)
|
||||
parts := strings.SplitN(arg, "=", 2)
|
||||
var pkgpath, file string
|
||||
if len(parts) == 1 {
|
||||
pkgpath, file = "main", arg
|
||||
} else {
|
||||
pkgpath, file = parts[0], parts[1]
|
||||
}
|
||||
pkglistfornote = append(pkglistfornote, pkgpath...)
|
||||
pkglistfornote = append(pkglistfornote, '\n')
|
||||
addlibpath(ctxt, "command line", "command line", file, pkgpath, "")
|
||||
}
|
||||
case BuildModePlugin:
|
||||
addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "")
|
||||
default:
|
||||
addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "")
|
||||
}
|
||||
ctxt.loadlib()
|
||||
|
||||
deadcode(ctxt)
|
||||
if *flagNewobj {
|
||||
ctxt.loadlibfull() // XXX do it here for now
|
||||
}
|
||||
ctxt.linksetup()
|
||||
ctxt.dostrdata()
|
||||
|
||||
dwarfGenerateDebugInfo(ctxt)
|
||||
if objabi.Fieldtrack_enabled != 0 {
|
||||
fieldtrack(ctxt)
|
||||
}
|
||||
ctxt.mangleTypeSym()
|
||||
ctxt.callgraph()
|
||||
|
||||
ctxt.doelf()
|
||||
if ctxt.HeadType == objabi.Hdarwin {
|
||||
ctxt.domacho()
|
||||
}
|
||||
ctxt.dostkcheck()
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
ctxt.dope()
|
||||
ctxt.windynrelocsyms()
|
||||
}
|
||||
if ctxt.HeadType == objabi.Haix {
|
||||
ctxt.doxcoff()
|
||||
}
|
||||
|
||||
ctxt.addexport()
|
||||
thearch.Gentext(ctxt) // trampolines, call stubs, etc.
|
||||
ctxt.textbuildid()
|
||||
ctxt.textaddress()
|
||||
ctxt.pclntab()
|
||||
ctxt.findfunctab()
|
||||
ctxt.typelink()
|
||||
ctxt.symtab()
|
||||
ctxt.buildinfo()
|
||||
ctxt.dodata()
|
||||
order := ctxt.address()
|
||||
dwarfcompress(ctxt)
|
||||
filesize := ctxt.layout(order)
|
||||
|
||||
// Write out the output file.
|
||||
// It is split into two parts (Asmb and Asmb2). The first
|
||||
// part writes most of the content (sections and segments),
|
||||
// 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 {
|
||||
// Asmb will redirect symbols to the output file mmap, and relocations
|
||||
// will be applied directly there.
|
||||
thearch.Asmb(ctxt)
|
||||
ctxt.reloc()
|
||||
ctxt.Out.Munmap()
|
||||
} else {
|
||||
// If we don't mmap, we need to apply relocations before
|
||||
// writing out.
|
||||
ctxt.reloc()
|
||||
thearch.Asmb(ctxt)
|
||||
}
|
||||
thearch.Asmb2(ctxt)
|
||||
|
||||
ctxt.undef()
|
||||
ctxt.hostlink()
|
||||
if ctxt.Debugvlog != 0 {
|
||||
ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym))
|
||||
ctxt.Logf("%d liveness data\n", liveness)
|
||||
}
|
||||
ctxt.Bso.Flush()
|
||||
ctxt.archive()
|
||||
|
||||
errorexit()
|
||||
}
|
||||
|
||||
type Rpath struct {
|
||||
set bool
|
||||
val string
|
||||
}
|
||||
|
||||
func (r *Rpath) Set(val string) error {
|
||||
r.set = true
|
||||
r.val = val
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Rpath) String() string {
|
||||
return r.val
|
||||
}
|
||||
|
||||
func startProfile() {
|
||||
if *cpuprofile != "" {
|
||||
f, err := os.Create(*cpuprofile)
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
AtExit(pprof.StopCPUProfile)
|
||||
}
|
||||
if *memprofile != "" {
|
||||
if *memprofilerate != 0 {
|
||||
runtime.MemProfileRate = int(*memprofilerate)
|
||||
}
|
||||
f, err := os.Create(*memprofile)
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
AtExit(func() {
|
||||
// Profile all outstanding allocations.
|
||||
runtime.GC()
|
||||
// compilebench parses the memory profile to extract memstats,
|
||||
// which are only written in the legacy pprof format.
|
||||
// See golang.org/issue/18641 and runtime/pprof/pprof.go:writeHeap.
|
||||
const writeLegacyFormat = 1
|
||||
if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
// Copyright 2017 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 (
|
||||
"bufio"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"encoding/binary"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// OutBuf is a buffered file writer.
|
||||
//
|
||||
// It is simlar to the Writer in cmd/internal/bio with a few small differences.
|
||||
//
|
||||
// First, it tracks the output architecture and uses it to provide
|
||||
// endian helpers.
|
||||
//
|
||||
// Second, it provides a very cheap offset counter that doesn't require
|
||||
// any system calls to read the value.
|
||||
//
|
||||
// It also mmaps the output file (if available). The intended usage is:
|
||||
// - Mmap the output file
|
||||
// - Write the content
|
||||
// - possibly apply any edits in the output buffer
|
||||
// - Munmap the output file
|
||||
// - possibly write more content to the file, which will not be edited later.
|
||||
type OutBuf struct {
|
||||
arch *sys.Arch
|
||||
off int64
|
||||
w *bufio.Writer
|
||||
buf []byte // backing store of mmap'd output file
|
||||
f *os.File
|
||||
encbuf [8]byte // temp buffer used by WriteN methods
|
||||
}
|
||||
|
||||
func (out *OutBuf) SeekSet(p int64) {
|
||||
if p == out.off {
|
||||
return
|
||||
}
|
||||
if out.buf == nil {
|
||||
out.Flush()
|
||||
if _, err := out.f.Seek(p, 0); err != nil {
|
||||
Exitf("seeking to %d in %s: %v", p, out.f.Name(), err)
|
||||
}
|
||||
}
|
||||
out.off = p
|
||||
}
|
||||
|
||||
func (out *OutBuf) Offset() int64 {
|
||||
return out.off
|
||||
}
|
||||
|
||||
// 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)
|
||||
out.off += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
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++
|
||||
}
|
||||
}
|
||||
|
||||
// WriteByte is an alias for Write8 to fulfill the io.ByteWriter interface.
|
||||
func (out *OutBuf) WriteByte(v byte) error {
|
||||
out.Write8(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (out *OutBuf) Write16(v uint16) {
|
||||
out.arch.ByteOrder.PutUint16(out.encbuf[:], v)
|
||||
out.Write(out.encbuf[:2])
|
||||
}
|
||||
|
||||
func (out *OutBuf) Write32(v uint32) {
|
||||
out.arch.ByteOrder.PutUint32(out.encbuf[:], v)
|
||||
out.Write(out.encbuf[:4])
|
||||
}
|
||||
|
||||
func (out *OutBuf) Write32b(v uint32) {
|
||||
binary.BigEndian.PutUint32(out.encbuf[:], v)
|
||||
out.Write(out.encbuf[:4])
|
||||
}
|
||||
|
||||
func (out *OutBuf) Write64(v uint64) {
|
||||
out.arch.ByteOrder.PutUint64(out.encbuf[:], v)
|
||||
out.Write(out.encbuf[:8])
|
||||
}
|
||||
|
||||
func (out *OutBuf) Write64b(v uint64) {
|
||||
binary.BigEndian.PutUint64(out.encbuf[:], v)
|
||||
out.Write(out.encbuf[:8])
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
n, _ := out.w.WriteString(s)
|
||||
out.off += int64(n)
|
||||
}
|
||||
|
||||
// WriteStringN writes the first n bytes of s.
|
||||
// If n is larger than len(s) then it is padded with zero bytes.
|
||||
func (out *OutBuf) WriteStringN(s string, n int) {
|
||||
out.WriteStringPad(s, n, zeros[:])
|
||||
}
|
||||
|
||||
// WriteStringPad writes the first n bytes of s.
|
||||
// If n is larger than len(s) then it is padded with the bytes in pad (repeated as needed).
|
||||
func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) {
|
||||
if len(s) >= n {
|
||||
out.WriteString(s[:n])
|
||||
} else {
|
||||
out.WriteString(s)
|
||||
n -= len(s)
|
||||
for n > len(pad) {
|
||||
out.Write(pad)
|
||||
n -= len(pad)
|
||||
|
||||
}
|
||||
out.Write(pad[:n])
|
||||
}
|
||||
}
|
||||
|
||||
// WriteSym writes the content of a Symbol, then changes the Symbol's content
|
||||
// to point to the output buffer that we just wrote, so we can apply further
|
||||
// edit to the symbol content.
|
||||
// If the output file is not Mmap'd, just writes the content.
|
||||
func (out *OutBuf) WriteSym(s *sym.Symbol) {
|
||||
if out.buf != nil {
|
||||
start := out.off
|
||||
out.Write(s.P)
|
||||
s.P = out.buf[start:out.off]
|
||||
s.Attr.Set(sym.AttrReadOnly, false)
|
||||
} else {
|
||||
out.Write(s.P)
|
||||
}
|
||||
}
|
||||
|
||||
func (out *OutBuf) Flush() {
|
||||
var err error
|
||||
if out.buf != nil {
|
||||
err = out.Msync()
|
||||
} else {
|
||||
err = out.w.Flush()
|
||||
}
|
||||
if err != nil {
|
||||
Exitf("flushing %s: %v", out.f.Name(), err)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +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.
|
||||
|
||||
// +build darwin dragonfly freebsd linux openbsd
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (out *OutBuf) Mmap(filesize uint64) error {
|
||||
err := out.f.Truncate(int64(filesize))
|
||||
if err != nil {
|
||||
Exitf("resize output file failed: %v", err)
|
||||
}
|
||||
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() {
|
||||
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)
|
||||
if err != nil {
|
||||
Exitf("seek output file failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (out *OutBuf) Msync() error {
|
||||
// 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(len(out.buf)), syscall.MS_SYNC)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,15 +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.
|
||||
|
||||
// +build !darwin,!dragonfly,!freebsd,!linux,!openbsd,!windows
|
||||
|
||||
package ld
|
||||
|
||||
import "errors"
|
||||
|
||||
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") }
|
||||
|
|
@ -1,49 +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 (
|
||||
"reflect"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (out *OutBuf) Mmap(filesize uint64) error {
|
||||
err := out.f.Truncate(int64(filesize))
|
||||
if err != nil {
|
||||
Exitf("resize output file failed: %v", err)
|
||||
}
|
||||
|
||||
low, high := uint32(filesize), uint32(filesize>>32)
|
||||
fmap, err := syscall.CreateFileMapping(syscall.Handle(out.f.Fd()), nil, syscall.PAGE_READONLY, high, low, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.CloseHandle(fmap)
|
||||
|
||||
ptr, err := syscall.MapViewOfFile(fmap, syscall.FILE_MAP_READ|syscall.FILE_MAP_WRITE, 0, 0, uintptr(filesize))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*(*reflect.SliceHeader)(unsafe.Pointer(&out.buf)) = reflect.SliceHeader{Data: ptr, Len: int(filesize), Cap: int(filesize)}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (out *OutBuf) Munmap() {
|
||||
if out.buf == nil {
|
||||
return
|
||||
}
|
||||
err := syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&out.buf[0])))
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
|
@ -1,530 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/src"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ftabaddstring(ftab *sym.Symbol, s string) int32 {
|
||||
start := len(ftab.P)
|
||||
ftab.Grow(int64(start + len(s) + 1)) // make room for s plus trailing NUL
|
||||
copy(ftab.P[start:], s)
|
||||
return int32(start)
|
||||
}
|
||||
|
||||
// numberfile assigns a file number to the file if it hasn't been assigned already.
|
||||
func numberfile(ctxt *Link, file *sym.Symbol) {
|
||||
if file.Type != sym.SFILEPATH {
|
||||
ctxt.Filesyms = append(ctxt.Filesyms, file)
|
||||
file.Value = int64(len(ctxt.Filesyms))
|
||||
file.Type = sym.SFILEPATH
|
||||
path := file.Name[len(src.FileSymPrefix):]
|
||||
file.Name = expandGoroot(path)
|
||||
}
|
||||
}
|
||||
|
||||
func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
|
||||
// Give files numbers.
|
||||
for _, f := range files {
|
||||
numberfile(ctxt, f)
|
||||
}
|
||||
|
||||
buf := make([]byte, binary.MaxVarintLen32)
|
||||
newval := int32(-1)
|
||||
var out sym.Pcdata
|
||||
it := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
|
||||
for it.Init(d.P); !it.Done; it.Next() {
|
||||
// value delta
|
||||
oldval := it.Value
|
||||
|
||||
var val int32
|
||||
if oldval == -1 {
|
||||
val = -1
|
||||
} else {
|
||||
if oldval < 0 || oldval >= int32(len(files)) {
|
||||
log.Fatalf("bad pcdata %d", oldval)
|
||||
}
|
||||
val = int32(files[oldval].Value)
|
||||
}
|
||||
|
||||
dv := val - newval
|
||||
newval = val
|
||||
|
||||
// value
|
||||
n := binary.PutVarint(buf, int64(dv))
|
||||
out.P = append(out.P, buf[:n]...)
|
||||
|
||||
// pc delta
|
||||
pc := (it.NextPC - it.PC) / it.PCScale
|
||||
n = binary.PutUvarint(buf, uint64(pc))
|
||||
out.P = append(out.P, buf[:n]...)
|
||||
}
|
||||
|
||||
// terminating value delta
|
||||
// we want to write varint-encoded 0, which is just 0
|
||||
out.P = append(out.P, 0)
|
||||
|
||||
*d = out
|
||||
}
|
||||
|
||||
// onlycsymbol reports whether this is a symbol that is referenced by C code.
|
||||
func onlycsymbol(s *sym.Symbol) bool {
|
||||
switch s.Name {
|
||||
case "_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2":
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "_cgoexp_") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func emitPcln(ctxt *Link, s *sym.Symbol) bool {
|
||||
if s == nil {
|
||||
return true
|
||||
}
|
||||
if ctxt.BuildMode == BuildModePlugin && ctxt.HeadType == objabi.Hdarwin && onlycsymbol(s) {
|
||||
return false
|
||||
}
|
||||
// We want to generate func table entries only for the "lowest level" symbols,
|
||||
// not containers of subsymbols.
|
||||
return !s.Attr.Container()
|
||||
}
|
||||
|
||||
// pclntab initializes the pclntab symbol with
|
||||
// runtime function and file name information.
|
||||
|
||||
var pclntabZpcln sym.FuncInfo
|
||||
|
||||
// These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
|
||||
var pclntabNfunc int32
|
||||
var pclntabFiletabOffset int32
|
||||
var pclntabPclntabOffset int32
|
||||
var pclntabFirstFunc *sym.Symbol
|
||||
var pclntabLastFunc *sym.Symbol
|
||||
|
||||
func (ctxt *Link) pclntab() {
|
||||
funcdataBytes := int64(0)
|
||||
ftab := ctxt.Syms.Lookup("runtime.pclntab", 0)
|
||||
ftab.Type = sym.SPCLNTAB
|
||||
ftab.Attr |= sym.AttrReachable
|
||||
|
||||
// See golang.org/s/go12symtab for the format. Briefly:
|
||||
// 8-byte header
|
||||
// nfunc [thearch.ptrsize bytes]
|
||||
// function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
|
||||
// end PC [thearch.ptrsize bytes]
|
||||
// offset to file table [4 bytes]
|
||||
|
||||
// Find container symbols and mark them as such.
|
||||
for _, s := range ctxt.Textp {
|
||||
if s.Outer != nil {
|
||||
s.Outer.Attr |= sym.AttrContainer
|
||||
}
|
||||
}
|
||||
|
||||
// Gather some basic stats and info.
|
||||
var nfunc int32
|
||||
prevSect := ctxt.Textp[0].Sect
|
||||
for _, s := range ctxt.Textp {
|
||||
if !emitPcln(ctxt, s) {
|
||||
continue
|
||||
}
|
||||
nfunc++
|
||||
if pclntabFirstFunc == nil {
|
||||
pclntabFirstFunc = s
|
||||
}
|
||||
if s.Sect != prevSect {
|
||||
// With multiple text sections, the external linker may insert functions
|
||||
// between the sections, which are not known by Go. This leaves holes in
|
||||
// the PC range covered by the func table. We need to generate an entry
|
||||
// to mark the hole.
|
||||
nfunc++
|
||||
prevSect = s.Sect
|
||||
}
|
||||
}
|
||||
|
||||
pclntabNfunc = nfunc
|
||||
ftab.Grow(8 + int64(ctxt.Arch.PtrSize) + int64(nfunc)*2*int64(ctxt.Arch.PtrSize) + int64(ctxt.Arch.PtrSize) + 4)
|
||||
ftab.SetUint32(ctxt.Arch, 0, 0xfffffffb)
|
||||
ftab.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC))
|
||||
ftab.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize))
|
||||
ftab.SetUint(ctxt.Arch, 8, uint64(nfunc))
|
||||
pclntabPclntabOffset = int32(8 + ctxt.Arch.PtrSize)
|
||||
|
||||
funcnameoff := make(map[string]int32)
|
||||
nameToOffset := func(name string) int32 {
|
||||
nameoff, ok := funcnameoff[name]
|
||||
if !ok {
|
||||
nameoff = ftabaddstring(ftab, name)
|
||||
funcnameoff[name] = nameoff
|
||||
}
|
||||
return nameoff
|
||||
}
|
||||
|
||||
pctaboff := make(map[string]uint32)
|
||||
writepctab := func(off int32, p []byte) int32 {
|
||||
start, ok := pctaboff[string(p)]
|
||||
if !ok {
|
||||
if len(p) > 0 {
|
||||
start = uint32(len(ftab.P))
|
||||
ftab.AddBytes(p)
|
||||
}
|
||||
pctaboff[string(p)] = start
|
||||
}
|
||||
newoff := int32(ftab.SetUint32(ctxt.Arch, int64(off), start))
|
||||
return newoff
|
||||
}
|
||||
|
||||
nfunc = 0 // repurpose nfunc as a running index
|
||||
prevFunc := ctxt.Textp[0]
|
||||
for _, s := range ctxt.Textp {
|
||||
if !emitPcln(ctxt, s) {
|
||||
continue
|
||||
}
|
||||
|
||||
if s.Sect != prevFunc.Sect {
|
||||
// With multiple text sections, there may be a hole here in the address
|
||||
// space (see the comment above). We use an invalid funcoff value to
|
||||
// mark the hole.
|
||||
// See also runtime/symtab.go:findfunc
|
||||
ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), prevFunc, prevFunc.Size)
|
||||
ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), ^uint64(0))
|
||||
nfunc++
|
||||
}
|
||||
prevFunc = s
|
||||
|
||||
pcln := s.FuncInfo
|
||||
if pcln == nil {
|
||||
pcln = &pclntabZpcln
|
||||
}
|
||||
|
||||
if len(pcln.InlTree) > 0 {
|
||||
if len(pcln.Pcdata) <= objabi.PCDATA_InlTreeIndex {
|
||||
// Create inlining pcdata table.
|
||||
pcdata := make([]sym.Pcdata, objabi.PCDATA_InlTreeIndex+1)
|
||||
copy(pcdata, pcln.Pcdata)
|
||||
pcln.Pcdata = pcdata
|
||||
}
|
||||
|
||||
if len(pcln.Funcdataoff) <= objabi.FUNCDATA_InlTree {
|
||||
// Create inline tree funcdata.
|
||||
funcdata := make([]*sym.Symbol, objabi.FUNCDATA_InlTree+1)
|
||||
funcdataoff := make([]int64, objabi.FUNCDATA_InlTree+1)
|
||||
copy(funcdata, pcln.Funcdata)
|
||||
copy(funcdataoff, pcln.Funcdataoff)
|
||||
pcln.Funcdata = funcdata
|
||||
pcln.Funcdataoff = funcdataoff
|
||||
}
|
||||
}
|
||||
|
||||
funcstart := int32(len(ftab.P))
|
||||
funcstart += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1) // align to ptrsize
|
||||
|
||||
ftab.SetAddr(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), s)
|
||||
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
|
||||
// and package debug/gosym.
|
||||
|
||||
// fixed size of struct, checked below
|
||||
off := funcstart
|
||||
|
||||
end := funcstart + int32(ctxt.Arch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(ctxt.Arch.PtrSize)
|
||||
if len(pcln.Funcdata) > 0 && (end&int32(ctxt.Arch.PtrSize-1) != 0) {
|
||||
end += 4
|
||||
}
|
||||
ftab.Grow(int64(end))
|
||||
|
||||
// entry uintptr
|
||||
off = int32(ftab.SetAddr(ctxt.Arch, int64(off), s))
|
||||
|
||||
// name int32
|
||||
nameoff := nameToOffset(s.Name)
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(nameoff)))
|
||||
|
||||
// args int32
|
||||
// TODO: Move into funcinfo.
|
||||
args := uint32(0)
|
||||
if s.FuncInfo != nil {
|
||||
args = uint32(s.FuncInfo.Args)
|
||||
}
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args))
|
||||
|
||||
// deferreturn
|
||||
deferreturn := uint32(0)
|
||||
lastWasmAddr := uint32(0)
|
||||
for _, r := range s.R {
|
||||
if ctxt.Arch.Family == sys.Wasm && r.Type == objabi.R_ADDR {
|
||||
// Wasm does not have a live variable set at the deferreturn
|
||||
// call itself. Instead it has one identified by the
|
||||
// resumption point immediately preceding the deferreturn.
|
||||
// The wasm code has a R_ADDR relocation which is used to
|
||||
// set the resumption point to PC_B.
|
||||
lastWasmAddr = uint32(r.Add)
|
||||
}
|
||||
if r.Type.IsDirectCall() && r.Sym != nil && r.Sym.Name == "runtime.deferreturn" {
|
||||
if ctxt.Arch.Family == sys.Wasm {
|
||||
deferreturn = lastWasmAddr - 1
|
||||
} else {
|
||||
// Note: the relocation target is in the call instruction, but
|
||||
// is not necessarily the whole instruction (for instance, on
|
||||
// x86 the relocation applies to bytes [1:5] of the 5 byte call
|
||||
// instruction).
|
||||
deferreturn = uint32(r.Off)
|
||||
switch ctxt.Arch.Family {
|
||||
case sys.AMD64, sys.I386:
|
||||
deferreturn--
|
||||
case sys.PPC64, sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64:
|
||||
// no change
|
||||
case sys.RISCV64:
|
||||
// TODO(jsing): The JALR instruction is marked with
|
||||
// R_CALLRISCV, whereas the actual reloc is currently
|
||||
// one instruction earlier starting with the AUIPC.
|
||||
deferreturn -= 4
|
||||
case sys.S390X:
|
||||
deferreturn -= 2
|
||||
default:
|
||||
panic(fmt.Sprint("Unhandled architecture:", ctxt.Arch.Family))
|
||||
}
|
||||
}
|
||||
break // only need one
|
||||
}
|
||||
}
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), deferreturn))
|
||||
|
||||
if pcln != &pclntabZpcln {
|
||||
renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
|
||||
if false {
|
||||
// Sanity check the new numbering
|
||||
it := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
|
||||
for it.Init(pcln.Pcfile.P); !it.Done; it.Next() {
|
||||
if it.Value < 1 || it.Value > int32(len(ctxt.Filesyms)) {
|
||||
Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.Value, len(ctxt.Filesyms))
|
||||
errorexit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(pcln.InlTree) > 0 {
|
||||
inlTreeSym := ctxt.Syms.Lookup("inltree."+s.Name, 0)
|
||||
inlTreeSym.Type = sym.SRODATA
|
||||
inlTreeSym.Attr |= sym.AttrReachable | sym.AttrDuplicateOK
|
||||
|
||||
for i, call := range pcln.InlTree {
|
||||
// Usually, call.File is already numbered since the file
|
||||
// shows up in the Pcfile table. However, two inlined calls
|
||||
// might overlap exactly so that only the innermost file
|
||||
// appears in the Pcfile table. In that case, this assigns
|
||||
// the outer file a number.
|
||||
numberfile(ctxt, call.File)
|
||||
nameoff := nameToOffset(call.Func)
|
||||
|
||||
inlTreeSym.SetUint16(ctxt.Arch, int64(i*20+0), uint16(call.Parent))
|
||||
inlTreeSym.SetUint8(ctxt.Arch, int64(i*20+2), uint8(objabi.GetFuncID(call.Func, "")))
|
||||
// byte 3 is unused
|
||||
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+4), uint32(call.File.Value))
|
||||
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+8), uint32(call.Line))
|
||||
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+12), uint32(nameoff))
|
||||
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+16), uint32(call.ParentPC))
|
||||
}
|
||||
|
||||
pcln.Funcdata[objabi.FUNCDATA_InlTree] = inlTreeSym
|
||||
pcln.Pcdata[objabi.PCDATA_InlTreeIndex] = pcln.Pcinline
|
||||
}
|
||||
|
||||
// pcdata
|
||||
off = writepctab(off, pcln.Pcsp.P)
|
||||
off = writepctab(off, pcln.Pcfile.P)
|
||||
off = writepctab(off, pcln.Pcline.P)
|
||||
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(len(pcln.Pcdata))))
|
||||
|
||||
// funcID uint8
|
||||
var file string
|
||||
if s.FuncInfo != nil && len(s.FuncInfo.File) > 0 {
|
||||
file = s.FuncInfo.File[0].Name
|
||||
}
|
||||
funcID := objabi.GetFuncID(s.Name, file)
|
||||
|
||||
off = int32(ftab.SetUint8(ctxt.Arch, int64(off), uint8(funcID)))
|
||||
|
||||
// unused
|
||||
off += 2
|
||||
|
||||
// nfuncdata must be the final entry.
|
||||
off = int32(ftab.SetUint8(ctxt.Arch, int64(off), uint8(len(pcln.Funcdata))))
|
||||
for i := range pcln.Pcdata {
|
||||
off = writepctab(off, pcln.Pcdata[i].P)
|
||||
}
|
||||
|
||||
// funcdata, must be pointer-aligned and we're only int32-aligned.
|
||||
// Missing funcdata will be 0 (nil pointer).
|
||||
if len(pcln.Funcdata) > 0 {
|
||||
if off&int32(ctxt.Arch.PtrSize-1) != 0 {
|
||||
off += 4
|
||||
}
|
||||
for i := range pcln.Funcdata {
|
||||
dataoff := int64(off) + int64(ctxt.Arch.PtrSize)*int64(i)
|
||||
if pcln.Funcdata[i] == nil {
|
||||
ftab.SetUint(ctxt.Arch, dataoff, uint64(pcln.Funcdataoff[i]))
|
||||
continue
|
||||
}
|
||||
// TODO: Dedup.
|
||||
funcdataBytes += pcln.Funcdata[i].Size
|
||||
ftab.SetAddrPlus(ctxt.Arch, dataoff, pcln.Funcdata[i], pcln.Funcdataoff[i])
|
||||
}
|
||||
off += int32(len(pcln.Funcdata)) * int32(ctxt.Arch.PtrSize)
|
||||
}
|
||||
|
||||
if off != end {
|
||||
Errorf(s, "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), ctxt.Arch.PtrSize)
|
||||
errorexit()
|
||||
}
|
||||
|
||||
nfunc++
|
||||
}
|
||||
|
||||
last := ctxt.Textp[len(ctxt.Textp)-1]
|
||||
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, last.Size)
|
||||
|
||||
// Start file table.
|
||||
start := int32(len(ftab.P))
|
||||
|
||||
start += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1)
|
||||
pclntabFiletabOffset = start
|
||||
ftab.SetUint32(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint32(start))
|
||||
|
||||
ftab.Grow(int64(start) + (int64(len(ctxt.Filesyms))+1)*4)
|
||||
ftab.SetUint32(ctxt.Arch, int64(start), uint32(len(ctxt.Filesyms)+1))
|
||||
for i := len(ctxt.Filesyms) - 1; i >= 0; i-- {
|
||||
s := ctxt.Filesyms[i]
|
||||
ftab.SetUint32(ctxt.Arch, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name)))
|
||||
}
|
||||
|
||||
ftab.Size = int64(len(ftab.P))
|
||||
|
||||
if ctxt.Debugvlog != 0 {
|
||||
ctxt.Logf("pclntab=%d bytes, funcdata total %d bytes\n", ftab.Size, funcdataBytes)
|
||||
}
|
||||
}
|
||||
|
||||
func gorootFinal() string {
|
||||
root := objabi.GOROOT
|
||||
if final := os.Getenv("GOROOT_FINAL"); final != "" {
|
||||
root = final
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
func expandGoroot(s string) string {
|
||||
const n = len("$GOROOT")
|
||||
if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
|
||||
return filepath.ToSlash(filepath.Join(gorootFinal(), s[n:]))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
const (
|
||||
BUCKETSIZE = 256 * MINFUNC
|
||||
SUBBUCKETS = 16
|
||||
SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
|
||||
NOIDX = 0x7fffffff
|
||||
)
|
||||
|
||||
// findfunctab generates a lookup table to quickly find the containing
|
||||
// function for a pc. See src/runtime/symtab.go:findfunc for details.
|
||||
func (ctxt *Link) findfunctab() {
|
||||
t := ctxt.Syms.Lookup("runtime.findfunctab", 0)
|
||||
t.Type = sym.SRODATA
|
||||
t.Attr |= sym.AttrReachable
|
||||
t.Attr |= sym.AttrLocal
|
||||
|
||||
// find min and max address
|
||||
min := ctxt.Textp[0].Value
|
||||
lastp := ctxt.Textp[len(ctxt.Textp)-1]
|
||||
max := lastp.Value + lastp.Size
|
||||
|
||||
// for each subbucket, compute the minimum of all symbol indexes
|
||||
// that map to that subbucket.
|
||||
n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
|
||||
|
||||
indexes := make([]int32, n)
|
||||
for i := int32(0); i < n; i++ {
|
||||
indexes[i] = NOIDX
|
||||
}
|
||||
idx := int32(0)
|
||||
for i, s := range ctxt.Textp {
|
||||
if !emitPcln(ctxt, s) {
|
||||
continue
|
||||
}
|
||||
p := s.Value
|
||||
var e *sym.Symbol
|
||||
i++
|
||||
if i < len(ctxt.Textp) {
|
||||
e = ctxt.Textp[i]
|
||||
}
|
||||
for !emitPcln(ctxt, e) && i < len(ctxt.Textp) {
|
||||
e = ctxt.Textp[i]
|
||||
i++
|
||||
}
|
||||
q := max
|
||||
if e != nil {
|
||||
q = e.Value
|
||||
}
|
||||
|
||||
//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
|
||||
for ; p < q; p += SUBBUCKETSIZE {
|
||||
i = int((p - min) / SUBBUCKETSIZE)
|
||||
if indexes[i] > idx {
|
||||
indexes[i] = idx
|
||||
}
|
||||
}
|
||||
|
||||
i = int((q - 1 - min) / SUBBUCKETSIZE)
|
||||
if indexes[i] > idx {
|
||||
indexes[i] = idx
|
||||
}
|
||||
idx++
|
||||
}
|
||||
|
||||
// allocate table
|
||||
nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
|
||||
|
||||
t.Grow(4*int64(nbuckets) + int64(n))
|
||||
|
||||
// fill in table
|
||||
for i := int32(0); i < nbuckets; i++ {
|
||||
base := indexes[i*SUBBUCKETS]
|
||||
if base == NOIDX {
|
||||
Errorf(nil, "hole in findfunctab")
|
||||
}
|
||||
t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base))
|
||||
for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
|
||||
idx = indexes[i*SUBBUCKETS+j]
|
||||
if idx == NOIDX {
|
||||
Errorf(nil, "hole in findfunctab")
|
||||
}
|
||||
if idx-base >= 256 {
|
||||
Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
|
||||
}
|
||||
|
||||
t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,109 +0,0 @@
|
|||
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"log"
|
||||
)
|
||||
|
||||
func linknew(arch *sys.Arch) *Link {
|
||||
ctxt := &Link{
|
||||
Syms: sym.NewSymbols(),
|
||||
Out: &OutBuf{arch: arch},
|
||||
Arch: arch,
|
||||
LibraryByPkg: make(map[string]*sym.Library),
|
||||
}
|
||||
|
||||
if objabi.GOARCH != arch.Name {
|
||||
log.Fatalf("invalid objabi.GOARCH %s (want %s)", objabi.GOARCH, arch.Name)
|
||||
}
|
||||
|
||||
AtExit(func() {
|
||||
if nerrors > 0 && ctxt.Out.f != nil {
|
||||
ctxt.Out.f.Close()
|
||||
mayberemoveoutfile()
|
||||
}
|
||||
})
|
||||
|
||||
return ctxt
|
||||
}
|
||||
|
||||
// computeTLSOffset records the thread-local storage offset.
|
||||
// Not used for Android where the TLS offset is determined at runtime.
|
||||
func (ctxt *Link) computeTLSOffset() {
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
log.Fatalf("unknown thread-local storage offset for %v", ctxt.HeadType)
|
||||
|
||||
case objabi.Hplan9, objabi.Hwindows, objabi.Hjs, objabi.Haix:
|
||||
break
|
||||
|
||||
case objabi.Hlinux,
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd,
|
||||
objabi.Hdragonfly,
|
||||
objabi.Hsolaris:
|
||||
/*
|
||||
* ELF uses TLS offset negative from FS.
|
||||
* Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
|
||||
* Known to low-level assembly in package runtime and runtime/cgo.
|
||||
*/
|
||||
ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
|
||||
|
||||
case objabi.Hdarwin:
|
||||
/*
|
||||
* OS X system constants - offset from 0(GS) to our TLS.
|
||||
*/
|
||||
switch ctxt.Arch.Family {
|
||||
default:
|
||||
log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
|
||||
|
||||
/*
|
||||
* For x86, Apple has reserved a slot in the TLS for Go. See issue 23617.
|
||||
* That slot is at offset 0x30 on amd64.
|
||||
* The slot will hold the G pointer.
|
||||
* These constants should match those in runtime/sys_darwin_{386,amd64}.s
|
||||
* and runtime/cgo/gcc_darwin_{386,amd64}.c.
|
||||
*/
|
||||
case sys.AMD64:
|
||||
ctxt.Tlsoffset = 0x30
|
||||
|
||||
case sys.ARM64:
|
||||
ctxt.Tlsoffset = 0 // dummy value, not needed
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,713 +0,0 @@
|
|||
// Inferno utils/6l/span.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Symbol table.
|
||||
|
||||
func putelfstr(s string) int {
|
||||
if len(Elfstrdat) == 0 && s != "" {
|
||||
// first entry must be empty string
|
||||
putelfstr("")
|
||||
}
|
||||
|
||||
off := len(Elfstrdat)
|
||||
Elfstrdat = append(Elfstrdat, s...)
|
||||
Elfstrdat = append(Elfstrdat, 0)
|
||||
return off
|
||||
}
|
||||
|
||||
func putelfsyment(out *OutBuf, off int, addr int64, size int64, info int, shndx int, other int) {
|
||||
if elf64 {
|
||||
out.Write32(uint32(off))
|
||||
out.Write8(uint8(info))
|
||||
out.Write8(uint8(other))
|
||||
out.Write16(uint16(shndx))
|
||||
out.Write64(uint64(addr))
|
||||
out.Write64(uint64(size))
|
||||
Symsize += ELF64SYMSIZE
|
||||
} else {
|
||||
out.Write32(uint32(off))
|
||||
out.Write32(uint32(addr))
|
||||
out.Write32(uint32(size))
|
||||
out.Write8(uint8(info))
|
||||
out.Write8(uint8(other))
|
||||
out.Write16(uint16(shndx))
|
||||
Symsize += ELF32SYMSIZE
|
||||
}
|
||||
}
|
||||
|
||||
var numelfsym = 1 // 0 is reserved
|
||||
|
||||
var elfbind int
|
||||
|
||||
func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go_ *sym.Symbol) {
|
||||
var typ int
|
||||
|
||||
switch t {
|
||||
default:
|
||||
return
|
||||
|
||||
case TextSym:
|
||||
typ = STT_FUNC
|
||||
|
||||
case DataSym, BSSSym:
|
||||
typ = STT_OBJECT
|
||||
|
||||
case UndefinedSym:
|
||||
// ElfType is only set for symbols read from Go shared libraries, but
|
||||
// for other symbols it is left as STT_NOTYPE which is fine.
|
||||
typ = int(x.ElfType())
|
||||
|
||||
case TLSSym:
|
||||
typ = STT_TLS
|
||||
}
|
||||
|
||||
size := x.Size
|
||||
if t == UndefinedSym {
|
||||
size = 0
|
||||
}
|
||||
|
||||
xo := x
|
||||
for xo.Outer != nil {
|
||||
xo = xo.Outer
|
||||
}
|
||||
|
||||
var elfshnum int
|
||||
if xo.Type == sym.SDYNIMPORT || xo.Type == sym.SHOSTOBJ || xo.Type == sym.SUNDEFEXT {
|
||||
elfshnum = SHN_UNDEF
|
||||
} else {
|
||||
if xo.Sect == nil {
|
||||
Errorf(x, "missing section in putelfsym")
|
||||
return
|
||||
}
|
||||
if xo.Sect.Elfsect == nil {
|
||||
Errorf(x, "missing ELF section in putelfsym")
|
||||
return
|
||||
}
|
||||
elfshnum = xo.Sect.Elfsect.(*ElfShdr).shnum
|
||||
}
|
||||
|
||||
// One pass for each binding: STB_LOCAL, STB_GLOBAL,
|
||||
// maybe one day STB_WEAK.
|
||||
bind := STB_GLOBAL
|
||||
|
||||
if x.IsFileLocal() || x.Attr.VisibilityHidden() || x.Attr.Local() {
|
||||
bind = STB_LOCAL
|
||||
}
|
||||
|
||||
// In external linking mode, we have to invoke gcc with -rdynamic
|
||||
// to get the exported symbols put into the dynamic symbol table.
|
||||
// To avoid filling the dynamic table with lots of unnecessary symbols,
|
||||
// mark all Go symbols local (not global) in the final executable.
|
||||
// But when we're dynamically linking, we need all those global symbols.
|
||||
if !ctxt.DynlinkingGo() && ctxt.LinkMode == LinkExternal && !x.Attr.CgoExportStatic() && elfshnum != SHN_UNDEF {
|
||||
bind = STB_LOCAL
|
||||
}
|
||||
|
||||
if ctxt.LinkMode == LinkExternal && elfshnum != SHN_UNDEF {
|
||||
addr -= int64(xo.Sect.Vaddr)
|
||||
}
|
||||
other := STV_DEFAULT
|
||||
if x.Attr.VisibilityHidden() {
|
||||
// TODO(mwhudson): We only set AttrVisibilityHidden in ldelf, i.e. when
|
||||
// internally linking. But STV_HIDDEN visibility only matters in object
|
||||
// files and shared libraries, and as we are a long way from implementing
|
||||
// internal linking for shared libraries and only create object files when
|
||||
// externally linking, I don't think this makes a lot of sense.
|
||||
other = STV_HIDDEN
|
||||
}
|
||||
if ctxt.Arch.Family == sys.PPC64 && typ == STT_FUNC && x.Attr.Shared() && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
|
||||
// On ppc64 the top three bits of the st_other field indicate how
|
||||
// many instructions separate the global and local entry points. In
|
||||
// our case it is two instructions, indicated by the value 3.
|
||||
// The conditions here match those in preprocess in
|
||||
// cmd/internal/obj/ppc64/obj9.go, which is where the
|
||||
// instructions are inserted.
|
||||
other |= 3 << 5
|
||||
}
|
||||
|
||||
// When dynamically linking, we create Symbols by reading the names from
|
||||
// the symbol tables of the shared libraries and so the names need to
|
||||
// match exactly. Tools like DTrace will have to wait for now.
|
||||
if !ctxt.DynlinkingGo() {
|
||||
// Rewrite · to . for ASCII-only tools like DTrace (sigh)
|
||||
s = strings.Replace(s, "·", ".", -1)
|
||||
}
|
||||
|
||||
if ctxt.DynlinkingGo() && bind == STB_GLOBAL && elfbind == STB_LOCAL && x.Type == sym.STEXT {
|
||||
// When dynamically linking, we want references to functions defined
|
||||
// in this module to always be to the function object, not to the
|
||||
// PLT. We force this by writing an additional local symbol for every
|
||||
// global function symbol and making all relocations against the
|
||||
// global symbol refer to this local symbol instead (see
|
||||
// (*sym.Symbol).ElfsymForReloc). This is approximately equivalent to the
|
||||
// ELF linker -Bsymbolic-functions option, but that is buggy on
|
||||
// several platforms.
|
||||
putelfsyment(ctxt.Out, putelfstr("local."+s), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other)
|
||||
x.LocalElfsym = int32(numelfsym)
|
||||
numelfsym++
|
||||
return
|
||||
} else if bind != elfbind {
|
||||
return
|
||||
}
|
||||
|
||||
putelfsyment(ctxt.Out, putelfstr(s), addr, size, bind<<4|typ&0xf, elfshnum, other)
|
||||
x.Elfsym = int32(numelfsym)
|
||||
numelfsym++
|
||||
}
|
||||
|
||||
func putelfsectionsym(out *OutBuf, s *sym.Symbol, shndx int) {
|
||||
putelfsyment(out, 0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
|
||||
s.Elfsym = int32(numelfsym)
|
||||
numelfsym++
|
||||
}
|
||||
|
||||
func Asmelfsym(ctxt *Link) {
|
||||
// the first symbol entry is reserved
|
||||
putelfsyment(ctxt.Out, 0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
|
||||
|
||||
dwarfaddelfsectionsyms(ctxt)
|
||||
|
||||
// Some linkers will add a FILE sym if one is not present.
|
||||
// Avoid having the working directory inserted into the symbol table.
|
||||
// It is added with a name to avoid problems with external linking
|
||||
// encountered on some versions of Solaris. See issue #14957.
|
||||
putelfsyment(ctxt.Out, putelfstr("go.go"), 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0)
|
||||
numelfsym++
|
||||
|
||||
elfbind = STB_LOCAL
|
||||
genasmsym(ctxt, putelfsym)
|
||||
|
||||
elfbind = STB_GLOBAL
|
||||
elfglobalsymndx = numelfsym
|
||||
genasmsym(ctxt, putelfsym)
|
||||
}
|
||||
|
||||
func putplan9sym(ctxt *Link, x *sym.Symbol, s string, typ SymbolType, addr int64, go_ *sym.Symbol) {
|
||||
t := int(typ)
|
||||
switch typ {
|
||||
case TextSym, DataSym, BSSSym:
|
||||
if x.IsFileLocal() {
|
||||
t += 'a' - 'A'
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case AutoSym, ParamSym, FrameSym:
|
||||
l := 4
|
||||
if ctxt.HeadType == objabi.Hplan9 && ctxt.Arch.Family == sys.AMD64 && !Flag8 {
|
||||
ctxt.Out.Write32b(uint32(addr >> 32))
|
||||
l = 8
|
||||
}
|
||||
|
||||
ctxt.Out.Write32b(uint32(addr))
|
||||
ctxt.Out.Write8(uint8(t + 0x80)) /* 0x80 is variable length */
|
||||
|
||||
ctxt.Out.WriteString(s)
|
||||
ctxt.Out.Write8(0)
|
||||
|
||||
Symsize += int32(l) + 1 + int32(len(s)) + 1
|
||||
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func Asmplan9sym(ctxt *Link) {
|
||||
genasmsym(ctxt, putplan9sym)
|
||||
}
|
||||
|
||||
var symt *sym.Symbol
|
||||
|
||||
type byPkg []*sym.Library
|
||||
|
||||
func (libs byPkg) Len() int {
|
||||
return len(libs)
|
||||
}
|
||||
|
||||
func (libs byPkg) Less(a, b int) bool {
|
||||
return libs[a].Pkg < libs[b].Pkg
|
||||
}
|
||||
|
||||
func (libs byPkg) Swap(a, b int) {
|
||||
libs[a], libs[b] = libs[b], libs[a]
|
||||
}
|
||||
|
||||
// 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
|
||||
nsections := int64(0)
|
||||
|
||||
for _, sect := range Segtext.Sections {
|
||||
if sect.Name == ".text" {
|
||||
nsections++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
t.Grow(3 * nsections * int64(ctxt.Arch.PtrSize))
|
||||
|
||||
off := int64(0)
|
||||
n := 0
|
||||
|
||||
// The vaddr for each text section is the difference between the section's
|
||||
// Vaddr and the Vaddr for the first text section as determined at compile
|
||||
// time.
|
||||
|
||||
// The symbol for the first text section is named runtime.text as before.
|
||||
// Additional text sections are named runtime.text.n where n is the
|
||||
// order of creation starting with 1. These symbols provide the section's
|
||||
// address after relocation by the linker.
|
||||
|
||||
textbase := Segtext.Sections[0].Vaddr
|
||||
for _, sect := range Segtext.Sections {
|
||||
if sect.Name != ".text" {
|
||||
break
|
||||
}
|
||||
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")
|
||||
}
|
||||
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)
|
||||
}
|
||||
off = t.SetAddr(ctxt.Arch, off, s)
|
||||
}
|
||||
n++
|
||||
}
|
||||
return uint32(n)
|
||||
}
|
||||
|
||||
func (ctxt *Link) symtab() {
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCArchive, BuildModeCShared:
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
// Create a new entry in the .init_array section that points to the
|
||||
// library initializer function.
|
||||
if s.Name == *flagEntrySymbol && ctxt.HeadType != objabi.Haix {
|
||||
addinitarrdata(ctxt, 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)
|
||||
|
||||
// garbage collection symbols
|
||||
s := ctxt.Syms.Lookup("runtime.gcdata", 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)
|
||||
|
||||
// pseudo-symbols to mark locations of type, string, and go string data.
|
||||
var symtype *sym.Symbol
|
||||
var symtyperel *sym.Symbol
|
||||
if !ctxt.DynlinkingGo() {
|
||||
if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
|
||||
s = ctxt.Syms.Lookup("type.*", 0)
|
||||
|
||||
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
|
||||
} else {
|
||||
s = ctxt.Syms.Lookup("type.*", 0)
|
||||
|
||||
s.Type = sym.STYPE
|
||||
s.Size = 0
|
||||
s.Attr |= sym.AttrReachable
|
||||
symtype = s
|
||||
symtyperel = s
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
var (
|
||||
symgostring = groupSym("go.string.*", sym.SGOSTRING)
|
||||
symgofunc = groupSym("go.func.*", sym.SGOFUNC)
|
||||
symgcbits = groupSym("runtime.gcbits.*", sym.SGCBITS)
|
||||
)
|
||||
|
||||
var symgofuncrel *sym.Symbol
|
||||
if !ctxt.DynlinkingGo() {
|
||||
if ctxt.UseRelro() {
|
||||
symgofuncrel = groupSym("go.funcrel.*", sym.SGOFUNCRELRO)
|
||||
} else {
|
||||
symgofuncrel = symgofunc
|
||||
}
|
||||
}
|
||||
|
||||
symitablink := ctxt.Syms.Lookup("runtime.itablink", 0)
|
||||
symitablink.Type = sym.SITABLINK
|
||||
|
||||
symt = ctxt.Syms.Lookup("runtime.symtab", 0)
|
||||
symt.Attr |= sym.AttrLocal
|
||||
symt.Type = sym.SSYMTAB
|
||||
symt.Size = 0
|
||||
symt.Attr |= sym.AttrReachable
|
||||
|
||||
nitablinks := 0
|
||||
|
||||
// assign specific types so that they sort together.
|
||||
// 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
|
||||
}
|
||||
|
||||
if !s.Attr.Reachable() || s.Attr.Special() || s.Type != sym.SRODATA {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(s.Name, "type."):
|
||||
if !ctxt.DynlinkingGo() {
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
}
|
||||
if ctxt.UseRelro() {
|
||||
s.Type = sym.STYPERELRO
|
||||
s.Outer = symtyperel
|
||||
} else {
|
||||
s.Type = sym.STYPE
|
||||
s.Outer = symtype
|
||||
}
|
||||
|
||||
case strings.HasPrefix(s.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
|
||||
|
||||
case strings.HasPrefix(s.Name, "go.itablink."):
|
||||
nitablinks++
|
||||
s.Type = sym.SITABLINK
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
s.Outer = symitablink
|
||||
|
||||
case strings.HasPrefix(s.Name, "go.string."):
|
||||
s.Type = sym.SGOSTRING
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
s.Outer = symgostring
|
||||
|
||||
case strings.HasPrefix(s.Name, "runtime.gcbits."):
|
||||
s.Type = sym.SGCBITS
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
s.Outer = symgcbits
|
||||
|
||||
case strings.HasSuffix(s.Name, "·f"):
|
||||
if !ctxt.DynlinkingGo() {
|
||||
s.Attr |= sym.AttrNotInSymbolTable
|
||||
}
|
||||
if ctxt.UseRelro() {
|
||||
s.Type = sym.SGOFUNCRELRO
|
||||
s.Outer = symgofuncrel
|
||||
} else {
|
||||
s.Type = sym.SGOFUNC
|
||||
s.Outer = symgofunc
|
||||
}
|
||||
|
||||
case strings.HasPrefix(s.Name, "gcargs."),
|
||||
strings.HasPrefix(s.Name, "gclocals."),
|
||||
strings.HasPrefix(s.Name, "gclocals·"),
|
||||
strings.HasPrefix(s.Name, "inltree."),
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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.AddAddr(ctxt.Arch, hashsym)
|
||||
abihashgostr.AddUint(ctxt.Arch, uint64(hashsym.Size))
|
||||
}
|
||||
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)
|
||||
str.AddUint(ctxt.Arch, uint64(len(l.Hash)))
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// 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))
|
||||
// The ftab slice
|
||||
moduledata.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0), 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.AddUint(ctxt.Arch, uint64(len(ctxt.Filesyms))+1)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Filesyms))+1)
|
||||
// findfunctab
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.findfunctab", 0))
|
||||
// minpc, maxpc
|
||||
moduledata.AddAddr(ctxt.Arch, pclntabFirstFunc)
|
||||
moduledata.AddAddrPlus(ctxt.Arch, pclntabLastFunc, pclntabLastFunc.Size)
|
||||
// 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))
|
||||
|
||||
if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
|
||||
// Add R_REF 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)
|
||||
}
|
||||
addRef("runtime.rodata")
|
||||
addRef("runtime.erodata")
|
||||
addRef("runtime.epclntab")
|
||||
}
|
||||
|
||||
// text section information
|
||||
moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.textsectionmap", 0))
|
||||
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
|
||||
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.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)
|
||||
moduledata.AddAddr(ctxt.Arch, ptab)
|
||||
moduledata.AddUint(ctxt.Arch, nentries)
|
||||
moduledata.AddUint(ctxt.Arch, nentries)
|
||||
} else {
|
||||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
}
|
||||
if ctxt.BuildMode == BuildModePlugin {
|
||||
addgostring(ctxt, 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
|
||||
|
||||
for i, l := range ctxt.Library {
|
||||
// pkghashes[i].name
|
||||
addgostring(ctxt, 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)
|
||||
// pkghashes[i].runtimehash
|
||||
hash := ctxt.Syms.ROLookup("go.link.pkghash."+l.Pkg, 0)
|
||||
pkghashes.AddAddr(ctxt.Arch, hash)
|
||||
}
|
||||
moduledata.AddAddr(ctxt.Arch, pkghashes)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Library)))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Library)))
|
||||
} else {
|
||||
moduledata.AddUint(ctxt.Arch, 0) // pluginpath
|
||||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
moduledata.AddUint(ctxt.Arch, 0) // pkghashes slice
|
||||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
}
|
||||
if len(ctxt.Shlibs) > 0 {
|
||||
thismodulename := filepath.Base(*flagOutfile)
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeExe, BuildModePIE:
|
||||
// When linking an executable, outfile is just "a.out". Make
|
||||
// it something slightly more comprehensible.
|
||||
thismodulename = "the executable"
|
||||
}
|
||||
addgostring(ctxt, 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
|
||||
|
||||
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)
|
||||
|
||||
// modulehashes[i].linktimehash
|
||||
addgostring(ctxt, 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
|
||||
modulehashes.AddAddr(ctxt.Arch, abihash)
|
||||
}
|
||||
|
||||
moduledata.AddAddr(ctxt.Arch, modulehashes)
|
||||
moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Shlibs)))
|
||||
moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Shlibs)))
|
||||
} else {
|
||||
moduledata.AddUint(ctxt.Arch, 0) // modulename
|
||||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
moduledata.AddUint(ctxt.Arch, 0) // moduleshashes slice
|
||||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
moduledata.AddUint(ctxt.Arch, 0)
|
||||
}
|
||||
|
||||
hasmain := ctxt.BuildMode == BuildModeExe || ctxt.BuildMode == BuildModePIE
|
||||
if hasmain {
|
||||
moduledata.AddUint8(1)
|
||||
} else {
|
||||
moduledata.AddUint8(0)
|
||||
}
|
||||
|
||||
// The rest of moduledata is zero initialized.
|
||||
// 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)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func isStaticTemp(name string) bool {
|
||||
if i := strings.LastIndex(name, "/"); i >= 0 {
|
||||
name = name[i:]
|
||||
}
|
||||
return strings.Contains(name, "..stmp_")
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
// A small test program that uses the net/http package. There is
|
||||
// nothing special about net/http here, this is just a convenient way
|
||||
// to pull in a lot of code.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
type statusHandler int
|
||||
|
||||
func (h *statusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(int(*h))
|
||||
}
|
||||
|
||||
func main() {
|
||||
status := statusHandler(http.StatusNotFound)
|
||||
s := httptest.NewServer(&status)
|
||||
defer s.Close()
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
func undefined()
|
||||
|
||||
func defined1() int {
|
||||
// To check multiple errors for a single symbol,
|
||||
// reference undefined more than once.
|
||||
undefined()
|
||||
undefined()
|
||||
return 0
|
||||
}
|
||||
|
||||
func defined2() {
|
||||
undefined()
|
||||
undefined()
|
||||
}
|
||||
|
||||
func init() {
|
||||
_ = defined1()
|
||||
defined2()
|
||||
}
|
||||
|
||||
// The "main" function remains undeclared.
|
||||
|
|
@ -1 +0,0 @@
|
|||
// This file is needed to make "go build" work for package with external functions.
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package a
|
||||
|
||||
const Always = true
|
||||
|
||||
var Count int
|
||||
|
||||
type FuncReturningInt func() int
|
||||
|
||||
var PointerToConstIf FuncReturningInt
|
||||
|
||||
func ConstIf() int {
|
||||
if Always {
|
||||
return 1
|
||||
}
|
||||
var imdead [4]int
|
||||
imdead[Count] = 1
|
||||
return imdead[0]
|
||||
}
|
||||
|
||||
func CallConstIf() int {
|
||||
Count += 3
|
||||
return ConstIf()
|
||||
}
|
||||
|
||||
func Another() {
|
||||
defer func() { PointerToConstIf = ConstIf; Count += 1 }()
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package main
|
||||
|
||||
import "cmd/oldlink/internal/ld/testdata/issue25459/a"
|
||||
|
||||
var Glob int
|
||||
|
||||
func main() {
|
||||
a.Another()
|
||||
Glob += a.ConstIf() + a.CallConstIf()
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package b
|
||||
|
||||
var q int
|
||||
|
||||
func Top(x int) int {
|
||||
q += 1
|
||||
if q != x {
|
||||
return 3
|
||||
}
|
||||
return 4
|
||||
}
|
||||
|
||||
func OOO(x int) int {
|
||||
defer func() { q += x & 7 }()
|
||||
return Top(x + 1)
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
b "cmd/oldlink/internal/ld/testdata/issue26237/b.dir"
|
||||
)
|
||||
|
||||
var skyx int
|
||||
|
||||
func main() {
|
||||
skyx += b.OOO(skyx)
|
||||
if b.Top(1) == 99 {
|
||||
fmt.Printf("Beware the Jabberwock, my son!\n")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +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.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/NSAppearance.h>
|
||||
|
||||
BOOL function(void) {
|
||||
#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED > 101300)
|
||||
NSAppearance *darkAppearance;
|
||||
if (@available(macOS 10.14, *)) {
|
||||
darkAppearance = [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
|
||||
}
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
|
|
@ -1,19 +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 lib
|
||||
|
||||
/*
|
||||
#cgo darwin CFLAGS: -D__MAC_OS_X_VERSION_MAX_ALLOWED=101450
|
||||
#cgo darwin LDFLAGS: -framework Foundation -framework AppKit
|
||||
#include "stdlib.h"
|
||||
int function(void);
|
||||
*/
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
func DoC() {
|
||||
C.function()
|
||||
fmt.Println("called c function")
|
||||
}
|
||||
|
|
@ -1,11 +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 main
|
||||
|
||||
import "cmd/oldlink/internal/ld/testdata/issue32233/lib"
|
||||
|
||||
func main() {
|
||||
lib.DoC()
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type byTypeStr []typelinkSortKey
|
||||
|
||||
type typelinkSortKey struct {
|
||||
TypeStr string
|
||||
Type *sym.Symbol
|
||||
}
|
||||
|
||||
func (s byTypeStr) Less(i, j int) bool { return s[i].TypeStr < s[j].TypeStr }
|
||||
func (s byTypeStr) Len() int { return len(s) }
|
||||
func (s byTypeStr) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// typelink generates the typelink table which is used by reflect.typelinks().
|
||||
// Types that should be added to the typelinks table are marked with the
|
||||
// MakeTypelink attribute by the compiler.
|
||||
func (ctxt *Link) typelink() {
|
||||
typelinks := byTypeStr{}
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
if s.Attr.Reachable() && s.Attr.MakeTypelink() {
|
||||
typelinks = append(typelinks, typelinkSortKey{decodetypeStr(ctxt.Arch, s), s})
|
||||
}
|
||||
}
|
||||
sort.Sort(typelinks)
|
||||
|
||||
tl := ctxt.Syms.Lookup("runtime.typelink", 0)
|
||||
tl.Type = sym.STYPELINK
|
||||
tl.Attr |= sym.AttrReachable | sym.AttrLocal
|
||||
tl.Size = int64(4 * len(typelinks))
|
||||
tl.P = make([]byte, tl.Size)
|
||||
tl.R = make([]sym.Reloc, len(typelinks))
|
||||
for i, s := range typelinks {
|
||||
r := &tl.R[i]
|
||||
r.Sym = s.Type
|
||||
r.Off = int32(i * 4)
|
||||
r.Siz = 4
|
||||
r.Type = objabi.R_ADDROFF
|
||||
}
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/oldlink/internal/sym"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var atExitFuncs []func()
|
||||
|
||||
func AtExit(f func()) {
|
||||
atExitFuncs = append(atExitFuncs, f)
|
||||
}
|
||||
|
||||
// runAtExitFuncs runs the queued set of AtExit functions.
|
||||
func runAtExitFuncs() {
|
||||
for i := len(atExitFuncs) - 1; i >= 0; i-- {
|
||||
atExitFuncs[i]()
|
||||
}
|
||||
atExitFuncs = nil
|
||||
}
|
||||
|
||||
// Exit exits with code after executing all atExitFuncs.
|
||||
func Exit(code int) {
|
||||
runAtExitFuncs()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// Exitf logs an error message then calls Exit(2).
|
||||
func Exitf(format string, a ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, os.Args[0]+": "+format+"\n", a...)
|
||||
nerrors++
|
||||
Exit(2)
|
||||
}
|
||||
|
||||
// Errorf logs an error message.
|
||||
//
|
||||
// If more than 20 errors have been printed, exit with an error.
|
||||
//
|
||||
// Logging an error means that on exit cmd/link will delete any
|
||||
// output file and return a non-zero error code.
|
||||
func Errorf(s *sym.Symbol, format string, args ...interface{}) {
|
||||
if s != nil {
|
||||
format = s.Name + ": " + format
|
||||
}
|
||||
format += "\n"
|
||||
fmt.Fprintf(os.Stderr, format, args...)
|
||||
nerrors++
|
||||
if *flagH {
|
||||
panic("error")
|
||||
}
|
||||
if nerrors > 20 {
|
||||
Exitf("too many errors")
|
||||
}
|
||||
}
|
||||
|
||||
func artrim(x []byte) string {
|
||||
i := 0
|
||||
j := len(x)
|
||||
for i < len(x) && x[i] == ' ' {
|
||||
i++
|
||||
}
|
||||
for j > i && x[j-1] == ' ' {
|
||||
j--
|
||||
}
|
||||
return string(x[i:j])
|
||||
}
|
||||
|
||||
func stringtouint32(x []uint32, s string) {
|
||||
for i := 0; len(s) > 0; i++ {
|
||||
var buf [4]byte
|
||||
s = s[copy(buf[:], s):]
|
||||
x[i] = binary.LittleEndian.Uint32(buf[:])
|
||||
}
|
||||
}
|
||||
|
||||
// contains reports whether v is in s.
|
||||
func contains(s []string, v string) bool {
|
||||
for _, x := range s {
|
||||
if x == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// implements sort.Interface, for sorting symbols by name.
|
||||
type byName []*sym.Symbol
|
||||
|
||||
func (s byName) Len() int { return len(s) }
|
||||
func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byName) Less(i, j int) bool { return s[i].Name < s[j].Name }
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,629 +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 loader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
// Sym encapsulates a global symbol index, used to identify a specific
|
||||
// Go symbol. The 0-valued Sym is corresponds to an invalid symbol.
|
||||
type Sym int
|
||||
|
||||
// Relocs encapsulates the set of relocations on a given symbol; an
|
||||
// instance of this type is returned by the Loader Relocs() method.
|
||||
type Relocs struct {
|
||||
Count int // number of relocs
|
||||
|
||||
li int // local index of symbol whose relocs we're examining
|
||||
r *oReader // object reader for containing package
|
||||
l *Loader // loader
|
||||
|
||||
ext *sym.Symbol // external symbol if not nil
|
||||
}
|
||||
|
||||
// Reloc contains the payload for a specific relocation.
|
||||
// TODO: replace this with sym.Reloc, once we change the
|
||||
// relocation target from "*sym.Symbol" to "loader.Sym" in sym.Reloc.
|
||||
type Reloc struct {
|
||||
Off int32 // offset to rewrite
|
||||
Size uint8 // number of bytes to rewrite: 0, 1, 2, or 4
|
||||
Type objabi.RelocType // the relocation type
|
||||
Add int64 // addend
|
||||
Sym Sym // global index of symbol the reloc addresses
|
||||
}
|
||||
|
||||
// oReader is a wrapper type of obj.Reader, along with some
|
||||
// extra information.
|
||||
// TODO: rename to objReader once the old one is gone?
|
||||
type oReader struct {
|
||||
//*goobj2.Reader
|
||||
unit *sym.CompilationUnit
|
||||
version int // version of static symbol
|
||||
flags uint32 // read from object file
|
||||
pkgprefix string
|
||||
rcache []Sym // cache mapping local PkgNone symbol to resolved Sym
|
||||
}
|
||||
|
||||
type objIdx struct {
|
||||
r *oReader
|
||||
i Sym // start index
|
||||
e Sym // end index
|
||||
}
|
||||
|
||||
type nameVer struct {
|
||||
name string
|
||||
v int
|
||||
}
|
||||
|
||||
type bitmap []uint32
|
||||
|
||||
// set the i-th bit.
|
||||
func (bm bitmap) Set(i Sym) {
|
||||
n, r := uint(i)/32, uint(i)%32
|
||||
bm[n] |= 1 << r
|
||||
}
|
||||
|
||||
// whether the i-th bit is set.
|
||||
func (bm bitmap) Has(i Sym) bool {
|
||||
n, r := uint(i)/32, uint(i)%32
|
||||
return bm[n]&(1<<r) != 0
|
||||
}
|
||||
|
||||
func makeBitmap(n int) bitmap {
|
||||
return make(bitmap, (n+31)/32)
|
||||
}
|
||||
|
||||
// A Loader loads new object files and resolves indexed symbol references.
|
||||
type Loader struct {
|
||||
start map[*oReader]Sym // map from object file to its start index
|
||||
objs []objIdx // sorted by start index (i.e. objIdx.i)
|
||||
max Sym // current max index
|
||||
extStart Sym // from this index on, the symbols are externally defined
|
||||
extSyms []nameVer // externally defined symbols
|
||||
builtinSyms []Sym // global index of builtin symbols
|
||||
ocache int // index (into 'objs') of most recent lookup
|
||||
|
||||
symsByName [2]map[string]Sym // map symbol name to index, two maps are for ABI0 and ABIInternal
|
||||
extStaticSyms map[nameVer]Sym // externally defined static symbols, keyed by name
|
||||
overwrite map[Sym]Sym // overwrite[i]=j if symbol j overwrites symbol i
|
||||
|
||||
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
|
||||
|
||||
objByPkg map[string]*oReader // map package path to its Go object reader
|
||||
|
||||
Syms []*sym.Symbol // indexed symbols. XXX we still make sym.Symbol for now.
|
||||
|
||||
anonVersion int // most recently assigned ext static sym pseudo-version
|
||||
|
||||
Reachable bitmap // bitmap of reachable symbols, indexed by global index
|
||||
|
||||
// Used to implement field tracking; created during deadcode if
|
||||
// field tracking is enabled. Reachparent[K] contains the index of
|
||||
// the symbol that triggered the marking of symbol K as live.
|
||||
Reachparent []Sym
|
||||
|
||||
relocBatch []sym.Reloc // for bulk allocation of relocations
|
||||
|
||||
flags uint32
|
||||
|
||||
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
|
||||
}
|
||||
|
||||
const (
|
||||
// Loader.flags
|
||||
FlagStrictDups = 1 << iota
|
||||
)
|
||||
|
||||
func NewLoader(flags uint32) *Loader {
|
||||
log.Fatal("-newobj in oldlink should not be used")
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Return the start index in the global index space for a given object file.
|
||||
func (l *Loader) startIndex(r *oReader) Sym {
|
||||
return l.start[r]
|
||||
}
|
||||
|
||||
// Add a symbol with a given index, return if it is added.
|
||||
func (l *Loader) AddSym(name string, ver int, i Sym, r *oReader, dupok bool, typ sym.SymKind) bool {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Add an external symbol (without index). Return the index of newly added
|
||||
// symbol, or 0 if not added.
|
||||
func (l *Loader) AddExtSym(name string, ver int) Sym {
|
||||
static := ver >= sym.SymVerStatic
|
||||
if static {
|
||||
if _, ok := l.extStaticSyms[nameVer{name, ver}]; ok {
|
||||
return 0
|
||||
}
|
||||
} else {
|
||||
if _, ok := l.symsByName[ver][name]; ok {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
i := l.max + 1
|
||||
if static {
|
||||
l.extStaticSyms[nameVer{name, ver}] = i
|
||||
} else {
|
||||
l.symsByName[ver][name] = i
|
||||
}
|
||||
l.max++
|
||||
if l.extStart == 0 {
|
||||
l.extStart = i
|
||||
}
|
||||
l.extSyms = append(l.extSyms, nameVer{name, ver})
|
||||
l.growSyms(int(i))
|
||||
return i
|
||||
}
|
||||
|
||||
func (l *Loader) IsExternal(i Sym) bool {
|
||||
return l.extStart != 0 && i >= l.extStart
|
||||
}
|
||||
|
||||
// Ensure Syms slice has enough space.
|
||||
func (l *Loader) growSyms(i int) {
|
||||
n := len(l.Syms)
|
||||
if n > i {
|
||||
return
|
||||
}
|
||||
l.Syms = append(l.Syms, make([]*sym.Symbol, i+1-n)...)
|
||||
}
|
||||
|
||||
// Convert a local index to a global index.
|
||||
func (l *Loader) toGlobal(r *oReader, i int) Sym {
|
||||
g := l.startIndex(r) + Sym(i)
|
||||
if ov, ok := l.overwrite[g]; ok {
|
||||
return ov
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
// Convert a global index to a local index.
|
||||
func (l *Loader) toLocal(i Sym) (*oReader, int) {
|
||||
if ov, ok := l.overwrite[i]; ok {
|
||||
i = ov
|
||||
}
|
||||
if l.IsExternal(i) {
|
||||
return nil, int(i - l.extStart)
|
||||
}
|
||||
oc := l.ocache
|
||||
if oc != 0 && i >= l.objs[oc].i && i <= l.objs[oc].e {
|
||||
return l.objs[oc].r, int(i - l.objs[oc].i)
|
||||
}
|
||||
// Search for the local object holding index i.
|
||||
// Below k is the first one that has its start index > i,
|
||||
// so k-1 is the one we want.
|
||||
k := sort.Search(len(l.objs), func(k int) bool {
|
||||
return l.objs[k].i > i
|
||||
})
|
||||
l.ocache = k - 1
|
||||
return l.objs[k-1].r, int(i - l.objs[k-1].i)
|
||||
}
|
||||
|
||||
// Look up a symbol by name, return global index, or 0 if not found.
|
||||
// This is more like Syms.ROLookup than Lookup -- it doesn't create
|
||||
// new symbol.
|
||||
func (l *Loader) Lookup(name string, ver int) Sym {
|
||||
if ver >= sym.SymVerStatic || ver < 0 {
|
||||
return l.extStaticSyms[nameVer{name, ver}]
|
||||
}
|
||||
return l.symsByName[ver][name]
|
||||
}
|
||||
|
||||
// Returns whether i is a dup of another symbol, and i is not
|
||||
// "primary", i.e. Lookup i by name will not return i.
|
||||
func (l *Loader) IsDup(i Sym) bool {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Check that duplicate symbols have same contents.
|
||||
func (l *Loader) checkdup(name string, i Sym, r *oReader, dup Sym) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func (l *Loader) NStrictDupMsgs() int { return l.strictDupMsgs }
|
||||
|
||||
// Number of total symbols.
|
||||
func (l *Loader) NSym() int {
|
||||
return int(l.max + 1)
|
||||
}
|
||||
|
||||
// Number of defined Go symbols.
|
||||
func (l *Loader) NDef() int {
|
||||
return int(l.extStart)
|
||||
}
|
||||
|
||||
// Returns the raw (unpatched) name of the i-th symbol.
|
||||
func (l *Loader) RawSymName(i Sym) string {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Returns the (patched) name of the i-th symbol.
|
||||
func (l *Loader) SymName(i Sym) string {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Returns the type of the i-th symbol.
|
||||
func (l *Loader) SymType(i Sym) sym.SymKind {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Returns the attributes of the i-th symbol.
|
||||
func (l *Loader) SymAttr(i Sym) uint8 {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Returns whether the i-th symbol has ReflectMethod attribute set.
|
||||
func (l *Loader) IsReflectMethod(i Sym) bool {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Returns whether this is a Go type symbol.
|
||||
func (l *Loader) IsGoType(i Sym) bool {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Returns whether this is a "go.itablink.*" symbol.
|
||||
func (l *Loader) IsItabLink(i Sym) bool {
|
||||
if _, ok := l.itablink[i]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns the symbol content of the i-th symbol. i is global index.
|
||||
func (l *Loader) Data(i Sym) []byte {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Returns the number of aux symbols given a global index.
|
||||
func (l *Loader) NAux(i Sym) int {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Returns the referred symbol of the j-th aux symbol of the i-th
|
||||
// symbol.
|
||||
func (l *Loader) AuxSym(i Sym, j int) Sym {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// ReadAuxSyms reads the aux symbol ids for the specified symbol into the
|
||||
// slice passed as a parameter. If the slice capacity is not large enough, a new
|
||||
// larger slice will be allocated. Final slice is returned.
|
||||
func (l *Loader) ReadAuxSyms(symIdx Sym, dst []Sym) []Sym {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// OuterSym gets the outer symbol for host object loaded symbols.
|
||||
func (l *Loader) OuterSym(i Sym) Sym {
|
||||
sym := l.Syms[i]
|
||||
if sym != nil && sym.Outer != nil {
|
||||
outer := sym.Outer
|
||||
return l.Lookup(outer.Name, int(outer.Version))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// SubSym gets the subsymbol for host object loaded symbols.
|
||||
func (l *Loader) SubSym(i Sym) Sym {
|
||||
sym := l.Syms[i]
|
||||
if sym != nil && sym.Sub != nil {
|
||||
sub := sym.Sub
|
||||
return l.Lookup(sub.Name, int(sub.Version))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Initialize Reachable bitmap for running deadcode pass.
|
||||
func (l *Loader) InitReachable() {
|
||||
l.Reachable = makeBitmap(l.NSym())
|
||||
}
|
||||
|
||||
// At method returns the j-th reloc for a global symbol.
|
||||
func (relocs *Relocs) At(j int) Reloc {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// ReadAll method reads all relocations for a symbol into the
|
||||
// specified slice. If the slice capacity is not large enough, a new
|
||||
// larger slice will be allocated. Final slice is returned.
|
||||
func (relocs *Relocs) ReadAll(dst []Reloc) []Reloc {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Relocs returns a Relocs object for the given global sym.
|
||||
func (l *Loader) Relocs(i Sym) Relocs {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Preload a package: add autolibs, add symbols to the symbol table.
|
||||
// Does not read symbol data yet.
|
||||
func (l *Loader) Preload(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Make sure referenced symbols are added. Most of them should already be added.
|
||||
// This should only be needed for referenced external symbols.
|
||||
func (l *Loader) LoadRefs(arch *sys.Arch, syms *sym.Symbols) {
|
||||
for _, o := range l.objs[1:] {
|
||||
loadObjRefs(l, o.r, arch, syms)
|
||||
}
|
||||
}
|
||||
|
||||
func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch, syms *sym.Symbols) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func abiToVer(abi uint16, localSymVersion int) int {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
|
||||
}
|
||||
s.Type = sym.SRODATA
|
||||
s.Attr |= sym.AttrLocal
|
||||
switch s.Name[:5] {
|
||||
case "$f32.":
|
||||
if uint64(uint32(x)) != x {
|
||||
log.Panicf("$-symbol %s too large: %d", s.Name, x)
|
||||
}
|
||||
s.AddUint32(arch, uint32(x))
|
||||
case "$f64.", "$i64.":
|
||||
s.AddUint64(arch, x)
|
||||
default:
|
||||
log.Panicf("unrecognized $-symbol: %s", s.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load full contents.
|
||||
func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
||||
// create all Symbols first.
|
||||
l.growSyms(l.NSym())
|
||||
|
||||
nr := 0 // total number of sym.Reloc's we'll need
|
||||
for _, o := range l.objs[1:] {
|
||||
nr += loadObjSyms(l, syms, o.r)
|
||||
}
|
||||
|
||||
// allocate a single large slab of relocations for all live symbols
|
||||
l.relocBatch = make([]sym.Reloc, nr)
|
||||
|
||||
// external symbols
|
||||
for i := l.extStart; i <= l.max; i++ {
|
||||
if s := l.Syms[i]; s != nil {
|
||||
s.Attr.Set(sym.AttrReachable, l.Reachable.Has(i))
|
||||
continue // already loaded from external object
|
||||
}
|
||||
nv := l.extSyms[i-l.extStart]
|
||||
if l.Reachable.Has(i) || strings.HasPrefix(nv.name, "gofile..") { // XXX file symbols are used but not marked
|
||||
s := syms.Newsym(nv.name, nv.v)
|
||||
preprocess(arch, s)
|
||||
s.Attr.Set(sym.AttrReachable, l.Reachable.Has(i))
|
||||
l.Syms[i] = s
|
||||
}
|
||||
}
|
||||
|
||||
// load contents of defined symbols
|
||||
for _, o := range l.objs[1:] {
|
||||
loadObjFull(l, o.r)
|
||||
}
|
||||
|
||||
// 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 := l.extStart; i <= l.max; i++ {
|
||||
if s := l.Syms[i]; s != nil && s.Attr.Reachable() {
|
||||
for ri := range s.R {
|
||||
r := &s.R[ri]
|
||||
if r.Sym != nil && r.Sym.Type == sym.SABIALIAS {
|
||||
r.Sym = r.Sym.R[0].Sym
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Nil out overwritten symbols.
|
||||
// Overwritten Go symbols aren't a problem (as they're lazy loaded), but
|
||||
// symbols loaded from host object loaders are fully loaded, and we might
|
||||
// have multiple symbols with the same name. This loop nils them out.
|
||||
for oldI := range l.overwrite {
|
||||
l.Syms[oldI] = nil
|
||||
}
|
||||
|
||||
// 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. Along the way, update the version from the
|
||||
// negative anon version to something larger than sym.SymVerStatic
|
||||
// (needed so that sym.symbol.IsFileLocal() works properly).
|
||||
anonVerReplacement := syms.IncVersion()
|
||||
for _, s := range l.Syms {
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
if s.Name != "" && s.Version >= 0 {
|
||||
syms.Add(s)
|
||||
}
|
||||
if s.Version < 0 {
|
||||
s.Version = int16(anonVerReplacement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// addNewSym adds a new sym.Symbol to the i-th index in the list of symbols.
|
||||
func (l *Loader) addNewSym(i Sym, syms *sym.Symbols, name string, ver int, unit *sym.CompilationUnit, t sym.SymKind) *sym.Symbol {
|
||||
s := syms.Newsym(name, ver)
|
||||
if s.Type != 0 && s.Type != sym.SXREF {
|
||||
fmt.Println("symbol already processed:", unit.Lib, i, s)
|
||||
panic("symbol already processed")
|
||||
}
|
||||
if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
|
||||
t = s.Type
|
||||
}
|
||||
s.Type = t
|
||||
s.Unit = unit
|
||||
l.growSyms(int(i))
|
||||
l.Syms[i] = s
|
||||
return s
|
||||
}
|
||||
|
||||
// loadObjSyms creates sym.Symbol objects for the live Syms in the
|
||||
// object corresponding to object reader "r". Return value is the
|
||||
// number of sym.Reloc entries required for all the new symbols.
|
||||
func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// LoadSymbol loads a single symbol by name.
|
||||
// This function should only be used by the host object loaders.
|
||||
// NB: This function does NOT set the symbol as reachable.
|
||||
func (l *Loader) LoadSymbol(name string, version int, syms *sym.Symbols) *sym.Symbol {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// LookupOrCreate looks up a symbol by name, and creates one if not found.
|
||||
// Either way, it will also create a sym.Symbol for it, if not already.
|
||||
// This should only be called when interacting with parts of the linker
|
||||
// that still works on sym.Symbols (i.e. internal cgo linking, for now).
|
||||
func (l *Loader) LookupOrCreate(name string, version int, syms *sym.Symbols) *sym.Symbol {
|
||||
i := l.Lookup(name, version)
|
||||
if i != 0 {
|
||||
// symbol exists
|
||||
if int(i) < len(l.Syms) && l.Syms[i] != nil {
|
||||
return l.Syms[i] // already loaded
|
||||
}
|
||||
if l.IsExternal(i) {
|
||||
panic("Can't load an external symbol.")
|
||||
}
|
||||
return l.LoadSymbol(name, version, syms)
|
||||
}
|
||||
i = l.AddExtSym(name, version)
|
||||
s := syms.Newsym(name, version)
|
||||
l.Syms[i] = s
|
||||
return s
|
||||
}
|
||||
|
||||
// Create creates a symbol with the specified name, returning a
|
||||
// sym.Symbol object for it. This method is intended for static/hidden
|
||||
// symbols discovered while loading host objects. We can see more than
|
||||
// one instance of a given static symbol with the same name/version,
|
||||
// so we can't add them to the lookup tables "as is". Instead assign
|
||||
// them fictitious (unique) versions, starting at -1 and decreasing by
|
||||
// one for each newly created symbol, and record them in the
|
||||
// extStaticSyms hash.
|
||||
func (l *Loader) Create(name string, syms *sym.Symbols) *sym.Symbol {
|
||||
i := l.max + 1
|
||||
l.max++
|
||||
if l.extStart == 0 {
|
||||
l.extStart = i
|
||||
}
|
||||
|
||||
// Assign a new unique negative version -- this is to mark the
|
||||
// symbol so that it can be skipped when ExtractSymbols is adding
|
||||
// ext syms to the sym.Symbols hash.
|
||||
l.anonVersion--
|
||||
ver := l.anonVersion
|
||||
l.extSyms = append(l.extSyms, nameVer{name, ver})
|
||||
l.growSyms(int(i))
|
||||
s := syms.Newsym(name, ver)
|
||||
l.Syms[i] = s
|
||||
l.extStaticSyms[nameVer{name, ver}] = i
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func loadObjFull(l *Loader, r *oReader) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
var emptyPkg = []byte(`"".`)
|
||||
|
||||
func patchDWARFName1(p []byte, r *oReader) ([]byte, int) {
|
||||
// This is kind of ugly. Really the package name should not
|
||||
// even be included here.
|
||||
if len(p) < 1 || p[0] != dwarf.DW_ABRV_FUNCTION {
|
||||
return p, -1
|
||||
}
|
||||
e := bytes.IndexByte(p, 0)
|
||||
if e == -1 {
|
||||
return p, -1
|
||||
}
|
||||
if !bytes.Contains(p[:e], emptyPkg) {
|
||||
return p, -1
|
||||
}
|
||||
pkgprefix := []byte(r.pkgprefix)
|
||||
patched := bytes.Replace(p[:e], emptyPkg, pkgprefix, -1)
|
||||
return append(patched, p[e:]...), e
|
||||
}
|
||||
|
||||
func patchDWARFName(s *sym.Symbol, r *oReader) {
|
||||
patched, e := patchDWARFName1(s.P, r)
|
||||
if e == -1 {
|
||||
return
|
||||
}
|
||||
s.P = patched
|
||||
s.Attr.Set(sym.AttrReadOnly, false)
|
||||
delta := int64(len(s.P)) - s.Size
|
||||
s.Size = int64(len(s.P))
|
||||
for i := range s.R {
|
||||
r := &s.R[i]
|
||||
if r.Off > int32(e) {
|
||||
r.Off += int32(delta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For debugging.
|
||||
func (l *Loader) Dump() {
|
||||
fmt.Println("objs")
|
||||
for _, obj := range l.objs {
|
||||
if obj.r != nil {
|
||||
fmt.Println(obj.i, obj.r.unit.Lib)
|
||||
}
|
||||
}
|
||||
fmt.Println("syms")
|
||||
for i, s := range l.Syms {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
if s != nil {
|
||||
fmt.Println(i, s, s.Type)
|
||||
} else {
|
||||
fmt.Println(i, l.SymName(Sym(i)), "<not loaded>")
|
||||
}
|
||||
}
|
||||
fmt.Println("overwrite:", l.overwrite)
|
||||
fmt.Println("symsByName")
|
||||
for name, i := range l.symsByName[0] {
|
||||
fmt.Println(i, name, 0)
|
||||
}
|
||||
for name, i := range l.symsByName[1] {
|
||||
fmt.Println(i, name, 1)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,794 +0,0 @@
|
|||
// Copyright 2017 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 loadmacho implements a Mach-O file reader.
|
||||
package loadmacho
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/loader"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
)
|
||||
|
||||
/*
|
||||
Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
|
||||
http://code.swtch.com/plan9port/src/tip/src/libmach/
|
||||
|
||||
Copyright © 2004 Russ Cox.
|
||||
Portions Copyright © 2008-2010 Google Inc.
|
||||
Portions Copyright © 2010 The Go Authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld
|
||||
const (
|
||||
MACHO_X86_64_RELOC_UNSIGNED = 0
|
||||
MACHO_X86_64_RELOC_SIGNED = 1
|
||||
MACHO_FAKE_GOTPCREL = 100
|
||||
)
|
||||
|
||||
type ldMachoObj struct {
|
||||
f *bio.Reader
|
||||
base int64 // off in f where Mach-O begins
|
||||
length int64 // length of Mach-O
|
||||
is64 bool
|
||||
name string
|
||||
e binary.ByteOrder
|
||||
cputype uint
|
||||
subcputype uint
|
||||
filetype uint32
|
||||
flags uint32
|
||||
cmd []ldMachoCmd
|
||||
ncmd uint
|
||||
}
|
||||
|
||||
type ldMachoCmd struct {
|
||||
type_ int
|
||||
off uint32
|
||||
size uint32
|
||||
seg ldMachoSeg
|
||||
sym ldMachoSymtab
|
||||
dsym ldMachoDysymtab
|
||||
}
|
||||
|
||||
type ldMachoSeg struct {
|
||||
name string
|
||||
vmaddr uint64
|
||||
vmsize uint64
|
||||
fileoff uint32
|
||||
filesz uint32
|
||||
maxprot uint32
|
||||
initprot uint32
|
||||
nsect uint32
|
||||
flags uint32
|
||||
sect []ldMachoSect
|
||||
}
|
||||
|
||||
type ldMachoSect struct {
|
||||
name string
|
||||
segname string
|
||||
addr uint64
|
||||
size uint64
|
||||
off uint32
|
||||
align uint32
|
||||
reloff uint32
|
||||
nreloc uint32
|
||||
flags uint32
|
||||
res1 uint32
|
||||
res2 uint32
|
||||
sym *sym.Symbol
|
||||
rel []ldMachoRel
|
||||
}
|
||||
|
||||
type ldMachoRel struct {
|
||||
addr uint32
|
||||
symnum uint32
|
||||
pcrel uint8
|
||||
length uint8
|
||||
extrn uint8
|
||||
type_ uint8
|
||||
scattered uint8
|
||||
value uint32
|
||||
}
|
||||
|
||||
type ldMachoSymtab struct {
|
||||
symoff uint32
|
||||
nsym uint32
|
||||
stroff uint32
|
||||
strsize uint32
|
||||
str []byte
|
||||
sym []ldMachoSym
|
||||
}
|
||||
|
||||
type ldMachoSym struct {
|
||||
name string
|
||||
type_ uint8
|
||||
sectnum uint8
|
||||
desc uint16
|
||||
kind int8
|
||||
value uint64
|
||||
sym *sym.Symbol
|
||||
}
|
||||
|
||||
type ldMachoDysymtab struct {
|
||||
ilocalsym uint32
|
||||
nlocalsym uint32
|
||||
iextdefsym uint32
|
||||
nextdefsym uint32
|
||||
iundefsym uint32
|
||||
nundefsym uint32
|
||||
tocoff uint32
|
||||
ntoc uint32
|
||||
modtaboff uint32
|
||||
nmodtab uint32
|
||||
extrefsymoff uint32
|
||||
nextrefsyms uint32
|
||||
indirectsymoff uint32
|
||||
nindirectsyms uint32
|
||||
extreloff uint32
|
||||
nextrel uint32
|
||||
locreloff uint32
|
||||
nlocrel uint32
|
||||
indir []uint32
|
||||
}
|
||||
|
||||
// ldMachoSym.type_
|
||||
const (
|
||||
N_EXT = 0x01
|
||||
N_TYPE = 0x1e
|
||||
N_STAB = 0xe0
|
||||
)
|
||||
|
||||
// ldMachoSym.desc
|
||||
const (
|
||||
N_WEAK_REF = 0x40
|
||||
N_WEAK_DEF = 0x80
|
||||
)
|
||||
|
||||
const (
|
||||
LdMachoCpuVax = 1
|
||||
LdMachoCpu68000 = 6
|
||||
LdMachoCpu386 = 7
|
||||
LdMachoCpuAmd64 = 0x1000007
|
||||
LdMachoCpuMips = 8
|
||||
LdMachoCpu98000 = 10
|
||||
LdMachoCpuHppa = 11
|
||||
LdMachoCpuArm = 12
|
||||
LdMachoCpu88000 = 13
|
||||
LdMachoCpuSparc = 14
|
||||
LdMachoCpu860 = 15
|
||||
LdMachoCpuAlpha = 16
|
||||
LdMachoCpuPower = 18
|
||||
LdMachoCmdSegment = 1
|
||||
LdMachoCmdSymtab = 2
|
||||
LdMachoCmdSymseg = 3
|
||||
LdMachoCmdThread = 4
|
||||
LdMachoCmdDysymtab = 11
|
||||
LdMachoCmdSegment64 = 25
|
||||
LdMachoFileObject = 1
|
||||
LdMachoFileExecutable = 2
|
||||
LdMachoFileFvmlib = 3
|
||||
LdMachoFileCore = 4
|
||||
LdMachoFilePreload = 5
|
||||
)
|
||||
|
||||
func unpackcmd(p []byte, m *ldMachoObj, c *ldMachoCmd, type_ uint, sz uint) int {
|
||||
e4 := m.e.Uint32
|
||||
e8 := m.e.Uint64
|
||||
|
||||
c.type_ = int(type_)
|
||||
c.size = uint32(sz)
|
||||
switch type_ {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case LdMachoCmdSegment:
|
||||
if sz < 56 {
|
||||
return -1
|
||||
}
|
||||
c.seg.name = cstring(p[8:24])
|
||||
c.seg.vmaddr = uint64(e4(p[24:]))
|
||||
c.seg.vmsize = uint64(e4(p[28:]))
|
||||
c.seg.fileoff = e4(p[32:])
|
||||
c.seg.filesz = e4(p[36:])
|
||||
c.seg.maxprot = e4(p[40:])
|
||||
c.seg.initprot = e4(p[44:])
|
||||
c.seg.nsect = e4(p[48:])
|
||||
c.seg.flags = e4(p[52:])
|
||||
c.seg.sect = make([]ldMachoSect, c.seg.nsect)
|
||||
if uint32(sz) < 56+c.seg.nsect*68 {
|
||||
return -1
|
||||
}
|
||||
p = p[56:]
|
||||
var s *ldMachoSect
|
||||
for i := 0; uint32(i) < c.seg.nsect; i++ {
|
||||
s = &c.seg.sect[i]
|
||||
s.name = cstring(p[0:16])
|
||||
s.segname = cstring(p[16:32])
|
||||
s.addr = uint64(e4(p[32:]))
|
||||
s.size = uint64(e4(p[36:]))
|
||||
s.off = e4(p[40:])
|
||||
s.align = e4(p[44:])
|
||||
s.reloff = e4(p[48:])
|
||||
s.nreloc = e4(p[52:])
|
||||
s.flags = e4(p[56:])
|
||||
s.res1 = e4(p[60:])
|
||||
s.res2 = e4(p[64:])
|
||||
p = p[68:]
|
||||
}
|
||||
|
||||
case LdMachoCmdSegment64:
|
||||
if sz < 72 {
|
||||
return -1
|
||||
}
|
||||
c.seg.name = cstring(p[8:24])
|
||||
c.seg.vmaddr = e8(p[24:])
|
||||
c.seg.vmsize = e8(p[32:])
|
||||
c.seg.fileoff = uint32(e8(p[40:]))
|
||||
c.seg.filesz = uint32(e8(p[48:]))
|
||||
c.seg.maxprot = e4(p[56:])
|
||||
c.seg.initprot = e4(p[60:])
|
||||
c.seg.nsect = e4(p[64:])
|
||||
c.seg.flags = e4(p[68:])
|
||||
c.seg.sect = make([]ldMachoSect, c.seg.nsect)
|
||||
if uint32(sz) < 72+c.seg.nsect*80 {
|
||||
return -1
|
||||
}
|
||||
p = p[72:]
|
||||
var s *ldMachoSect
|
||||
for i := 0; uint32(i) < c.seg.nsect; i++ {
|
||||
s = &c.seg.sect[i]
|
||||
s.name = cstring(p[0:16])
|
||||
s.segname = cstring(p[16:32])
|
||||
s.addr = e8(p[32:])
|
||||
s.size = e8(p[40:])
|
||||
s.off = e4(p[48:])
|
||||
s.align = e4(p[52:])
|
||||
s.reloff = e4(p[56:])
|
||||
s.nreloc = e4(p[60:])
|
||||
s.flags = e4(p[64:])
|
||||
s.res1 = e4(p[68:])
|
||||
s.res2 = e4(p[72:])
|
||||
|
||||
// p+76 is reserved
|
||||
p = p[80:]
|
||||
}
|
||||
|
||||
case LdMachoCmdSymtab:
|
||||
if sz < 24 {
|
||||
return -1
|
||||
}
|
||||
c.sym.symoff = e4(p[8:])
|
||||
c.sym.nsym = e4(p[12:])
|
||||
c.sym.stroff = e4(p[16:])
|
||||
c.sym.strsize = e4(p[20:])
|
||||
|
||||
case LdMachoCmdDysymtab:
|
||||
if sz < 80 {
|
||||
return -1
|
||||
}
|
||||
c.dsym.ilocalsym = e4(p[8:])
|
||||
c.dsym.nlocalsym = e4(p[12:])
|
||||
c.dsym.iextdefsym = e4(p[16:])
|
||||
c.dsym.nextdefsym = e4(p[20:])
|
||||
c.dsym.iundefsym = e4(p[24:])
|
||||
c.dsym.nundefsym = e4(p[28:])
|
||||
c.dsym.tocoff = e4(p[32:])
|
||||
c.dsym.ntoc = e4(p[36:])
|
||||
c.dsym.modtaboff = e4(p[40:])
|
||||
c.dsym.nmodtab = e4(p[44:])
|
||||
c.dsym.extrefsymoff = e4(p[48:])
|
||||
c.dsym.nextrefsyms = e4(p[52:])
|
||||
c.dsym.indirectsymoff = e4(p[56:])
|
||||
c.dsym.nindirectsyms = e4(p[60:])
|
||||
c.dsym.extreloff = e4(p[64:])
|
||||
c.dsym.nextrel = e4(p[68:])
|
||||
c.dsym.locreloff = e4(p[72:])
|
||||
c.dsym.nlocrel = e4(p[76:])
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func macholoadrel(m *ldMachoObj, sect *ldMachoSect) int {
|
||||
if sect.rel != nil || sect.nreloc == 0 {
|
||||
return 0
|
||||
}
|
||||
rel := make([]ldMachoRel, sect.nreloc)
|
||||
n := int(sect.nreloc * 8)
|
||||
buf := make([]byte, n)
|
||||
m.f.MustSeek(m.base+int64(sect.reloff), 0)
|
||||
if _, err := io.ReadFull(m.f, buf); err != nil {
|
||||
return -1
|
||||
}
|
||||
for i := uint32(0); i < sect.nreloc; i++ {
|
||||
r := &rel[i]
|
||||
p := buf[i*8:]
|
||||
r.addr = m.e.Uint32(p)
|
||||
|
||||
// TODO(rsc): Wrong interpretation for big-endian bitfields?
|
||||
if r.addr&0x80000000 != 0 {
|
||||
// scatterbrained relocation
|
||||
r.scattered = 1
|
||||
|
||||
v := r.addr >> 24
|
||||
r.addr &= 0xFFFFFF
|
||||
r.type_ = uint8(v & 0xF)
|
||||
v >>= 4
|
||||
r.length = 1 << (v & 3)
|
||||
v >>= 2
|
||||
r.pcrel = uint8(v & 1)
|
||||
r.value = m.e.Uint32(p[4:])
|
||||
} else {
|
||||
v := m.e.Uint32(p[4:])
|
||||
r.symnum = v & 0xFFFFFF
|
||||
v >>= 24
|
||||
r.pcrel = uint8(v & 1)
|
||||
v >>= 1
|
||||
r.length = 1 << (v & 3)
|
||||
v >>= 2
|
||||
r.extrn = uint8(v & 1)
|
||||
v >>= 1
|
||||
r.type_ = uint8(v)
|
||||
}
|
||||
}
|
||||
|
||||
sect.rel = rel
|
||||
return 0
|
||||
}
|
||||
|
||||
func macholoaddsym(m *ldMachoObj, d *ldMachoDysymtab) int {
|
||||
n := int(d.nindirectsyms)
|
||||
|
||||
p := make([]byte, n*4)
|
||||
m.f.MustSeek(m.base+int64(d.indirectsymoff), 0)
|
||||
if _, err := io.ReadFull(m.f, p); err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
d.indir = make([]uint32, n)
|
||||
for i := 0; i < n; i++ {
|
||||
d.indir[i] = m.e.Uint32(p[4*i:])
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int {
|
||||
if symtab.sym != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
strbuf := make([]byte, symtab.strsize)
|
||||
m.f.MustSeek(m.base+int64(symtab.stroff), 0)
|
||||
if _, err := io.ReadFull(m.f, strbuf); err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
symsize := 12
|
||||
if m.is64 {
|
||||
symsize = 16
|
||||
}
|
||||
n := int(symtab.nsym * uint32(symsize))
|
||||
symbuf := make([]byte, n)
|
||||
m.f.MustSeek(m.base+int64(symtab.symoff), 0)
|
||||
if _, err := io.ReadFull(m.f, symbuf); err != nil {
|
||||
return -1
|
||||
}
|
||||
sym := make([]ldMachoSym, symtab.nsym)
|
||||
p := symbuf
|
||||
for i := uint32(0); i < symtab.nsym; i++ {
|
||||
s := &sym[i]
|
||||
v := m.e.Uint32(p)
|
||||
if v >= symtab.strsize {
|
||||
return -1
|
||||
}
|
||||
s.name = cstring(strbuf[v:])
|
||||
s.type_ = p[4]
|
||||
s.sectnum = p[5]
|
||||
s.desc = m.e.Uint16(p[6:])
|
||||
if m.is64 {
|
||||
s.value = m.e.Uint64(p[8:])
|
||||
} else {
|
||||
s.value = uint64(m.e.Uint32(p[8:]))
|
||||
}
|
||||
p = p[symsize:]
|
||||
}
|
||||
|
||||
symtab.str = strbuf
|
||||
symtab.sym = sym
|
||||
return 0
|
||||
}
|
||||
|
||||
func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) ([]*sym.Symbol, error) {
|
||||
newSym := func(name string, version int) *sym.Symbol {
|
||||
return l.LookupOrCreate(name, version, syms)
|
||||
}
|
||||
return load(arch, syms.IncVersion(), newSym, f, pkg, length, pn)
|
||||
}
|
||||
|
||||
func LoadOld(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
|
||||
return load(arch, syms.IncVersion(), syms.Lookup, f, pkg, length, pn)
|
||||
}
|
||||
|
||||
// load the Mach-O file pn from f.
|
||||
// Symbols are written into syms, and a slice of the text symbols is returned.
|
||||
func load(arch *sys.Arch, localSymVersion int, lookup func(string, int) *sym.Symbol, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
|
||||
errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
|
||||
return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...))
|
||||
}
|
||||
|
||||
base := f.Offset()
|
||||
|
||||
var hdr [7 * 4]uint8
|
||||
if _, err := io.ReadFull(f, hdr[:]); err != nil {
|
||||
return errorf("reading hdr: %v", err)
|
||||
}
|
||||
|
||||
var e binary.ByteOrder
|
||||
if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
||||
e = binary.BigEndian
|
||||
} else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
||||
e = binary.LittleEndian
|
||||
} else {
|
||||
return errorf("bad magic - not mach-o file")
|
||||
}
|
||||
|
||||
is64 := e.Uint32(hdr[:]) == 0xFEEDFACF
|
||||
ncmd := e.Uint32(hdr[4*4:])
|
||||
cmdsz := e.Uint32(hdr[5*4:])
|
||||
if ncmd > 0x10000 || cmdsz >= 0x01000000 {
|
||||
return errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
|
||||
}
|
||||
|
||||
if is64 {
|
||||
f.MustSeek(4, 1) // skip reserved word in header
|
||||
}
|
||||
|
||||
m := &ldMachoObj{
|
||||
f: f,
|
||||
e: e,
|
||||
cputype: uint(e.Uint32(hdr[1*4:])),
|
||||
subcputype: uint(e.Uint32(hdr[2*4:])),
|
||||
filetype: e.Uint32(hdr[3*4:]),
|
||||
ncmd: uint(ncmd),
|
||||
flags: e.Uint32(hdr[6*4:]),
|
||||
is64: is64,
|
||||
base: base,
|
||||
length: length,
|
||||
name: pn,
|
||||
}
|
||||
|
||||
switch arch.Family {
|
||||
default:
|
||||
return errorf("mach-o %s unimplemented", arch.Name)
|
||||
|
||||
case sys.AMD64:
|
||||
if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
|
||||
return errorf("mach-o object but not amd64")
|
||||
}
|
||||
}
|
||||
|
||||
m.cmd = make([]ldMachoCmd, ncmd)
|
||||
cmdp := make([]byte, cmdsz)
|
||||
if _, err := io.ReadFull(f, cmdp); err != nil {
|
||||
return errorf("reading cmds: %v", err)
|
||||
}
|
||||
|
||||
// read and parse load commands
|
||||
var c *ldMachoCmd
|
||||
|
||||
var symtab *ldMachoSymtab
|
||||
var dsymtab *ldMachoDysymtab
|
||||
|
||||
off := uint32(len(hdr))
|
||||
for i := uint32(0); i < ncmd; i++ {
|
||||
ty := e.Uint32(cmdp)
|
||||
sz := e.Uint32(cmdp[4:])
|
||||
m.cmd[i].off = off
|
||||
unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz))
|
||||
cmdp = cmdp[sz:]
|
||||
off += sz
|
||||
if ty == LdMachoCmdSymtab {
|
||||
if symtab != nil {
|
||||
return errorf("multiple symbol tables")
|
||||
}
|
||||
|
||||
symtab = &m.cmd[i].sym
|
||||
macholoadsym(m, symtab)
|
||||
}
|
||||
|
||||
if ty == LdMachoCmdDysymtab {
|
||||
dsymtab = &m.cmd[i].dsym
|
||||
macholoaddsym(m, dsymtab)
|
||||
}
|
||||
|
||||
if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
|
||||
if c != nil {
|
||||
return errorf("multiple load commands")
|
||||
}
|
||||
|
||||
c = &m.cmd[i]
|
||||
}
|
||||
}
|
||||
|
||||
// load text and data segments into memory.
|
||||
// they are not as small as the load commands, but we'll need
|
||||
// the memory anyway for the symbol images, so we might
|
||||
// as well use one large chunk.
|
||||
if c == nil {
|
||||
return errorf("no load command")
|
||||
}
|
||||
|
||||
if symtab == nil {
|
||||
// our work is done here - no symbols means nothing can refer to this file
|
||||
return
|
||||
}
|
||||
|
||||
if int64(c.seg.fileoff+c.seg.filesz) >= length {
|
||||
return errorf("load segment out of range")
|
||||
}
|
||||
|
||||
f.MustSeek(m.base+int64(c.seg.fileoff), 0)
|
||||
dat := make([]byte, c.seg.filesz)
|
||||
if _, err := io.ReadFull(f, dat); err != nil {
|
||||
return errorf("cannot load object data: %v", err)
|
||||
}
|
||||
|
||||
for i := uint32(0); i < c.seg.nsect; i++ {
|
||||
sect := &c.seg.sect[i]
|
||||
if sect.segname != "__TEXT" && sect.segname != "__DATA" {
|
||||
continue
|
||||
}
|
||||
if sect.name == "__eh_frame" {
|
||||
continue
|
||||
}
|
||||
name := fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
|
||||
s := lookup(name, localSymVersion)
|
||||
if s.Type != 0 {
|
||||
return errorf("duplicate %s/%s", sect.segname, sect.name)
|
||||
}
|
||||
|
||||
if sect.flags&0xff == 1 { // S_ZEROFILL
|
||||
s.P = make([]byte, sect.size)
|
||||
} else {
|
||||
s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size]
|
||||
}
|
||||
s.Size = int64(len(s.P))
|
||||
|
||||
if sect.segname == "__TEXT" {
|
||||
if sect.name == "__text" {
|
||||
s.Type = sym.STEXT
|
||||
} else {
|
||||
s.Type = sym.SRODATA
|
||||
}
|
||||
} else {
|
||||
if sect.name == "__bss" {
|
||||
s.Type = sym.SNOPTRBSS
|
||||
s.P = s.P[:0]
|
||||
} else {
|
||||
s.Type = sym.SNOPTRDATA
|
||||
}
|
||||
}
|
||||
|
||||
sect.sym = s
|
||||
}
|
||||
|
||||
// enter sub-symbols into symbol table.
|
||||
// have to guess sizes from next symbol.
|
||||
for i := uint32(0); i < symtab.nsym; i++ {
|
||||
machsym := &symtab.sym[i]
|
||||
if machsym.type_&N_STAB != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: check sym->type against outer->type.
|
||||
name := machsym.name
|
||||
|
||||
if name[0] == '_' && name[1] != '\x00' {
|
||||
name = name[1:]
|
||||
}
|
||||
v := 0
|
||||
if machsym.type_&N_EXT == 0 {
|
||||
v = localSymVersion
|
||||
}
|
||||
s := lookup(name, v)
|
||||
if machsym.type_&N_EXT == 0 {
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
}
|
||||
if machsym.desc&(N_WEAK_REF|N_WEAK_DEF) != 0 {
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
}
|
||||
machsym.sym = s
|
||||
if machsym.sectnum == 0 { // undefined
|
||||
continue
|
||||
}
|
||||
if uint32(machsym.sectnum) > c.seg.nsect {
|
||||
return errorf("reference to invalid section %d", machsym.sectnum)
|
||||
}
|
||||
|
||||
sect := &c.seg.sect[machsym.sectnum-1]
|
||||
outer := sect.sym
|
||||
if outer == nil {
|
||||
continue // ignore reference to invalid section
|
||||
}
|
||||
|
||||
if s.Outer != nil {
|
||||
if s.Attr.DuplicateOK() {
|
||||
continue
|
||||
}
|
||||
return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name)
|
||||
}
|
||||
|
||||
s.Type = outer.Type
|
||||
s.Attr |= sym.AttrSubSymbol
|
||||
s.Sub = outer.Sub
|
||||
outer.Sub = s
|
||||
s.Outer = outer
|
||||
s.Value = int64(machsym.value - sect.addr)
|
||||
if !s.Attr.CgoExportDynamic() {
|
||||
s.SetDynimplib("") // satisfy dynimport
|
||||
}
|
||||
if outer.Type == sym.STEXT {
|
||||
if s.Attr.External() && !s.Attr.DuplicateOK() {
|
||||
return errorf("%v: duplicate symbol definition", s)
|
||||
}
|
||||
s.Attr |= sym.AttrExternal
|
||||
}
|
||||
|
||||
machsym.sym = s
|
||||
}
|
||||
|
||||
// Sort outer lists by address, adding to textp.
|
||||
// This keeps textp in increasing address order.
|
||||
for i := 0; uint32(i) < c.seg.nsect; i++ {
|
||||
sect := &c.seg.sect[i]
|
||||
s := sect.sym
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
if s.Sub != nil {
|
||||
s.Sub = sym.SortSub(s.Sub)
|
||||
|
||||
// assign sizes, now that we know symbols in sorted order.
|
||||
for s1 := s.Sub; s1 != nil; s1 = s1.Sub {
|
||||
if s1.Sub != nil {
|
||||
s1.Size = s1.Sub.Value - s1.Value
|
||||
} else {
|
||||
s1.Size = s.Value + s.Size - s1.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.Type == sym.STEXT {
|
||||
if s.Attr.OnList() {
|
||||
return errorf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
textp = append(textp, s)
|
||||
for s1 := s.Sub; s1 != nil; s1 = s1.Sub {
|
||||
if s1.Attr.OnList() {
|
||||
return errorf("symbol %s listed multiple times", s1.Name)
|
||||
}
|
||||
s1.Attr |= sym.AttrOnList
|
||||
textp = append(textp, s1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load relocations
|
||||
for i := 0; uint32(i) < c.seg.nsect; i++ {
|
||||
sect := &c.seg.sect[i]
|
||||
s := sect.sym
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
macholoadrel(m, sect)
|
||||
if sect.rel == nil {
|
||||
continue
|
||||
}
|
||||
r := make([]sym.Reloc, sect.nreloc)
|
||||
rpi := 0
|
||||
for j := uint32(0); j < sect.nreloc; j++ {
|
||||
rp := &r[rpi]
|
||||
rel := §.rel[j]
|
||||
if rel.scattered != 0 {
|
||||
// mach-o only uses scattered relocation on 32-bit platforms,
|
||||
// which are no longer supported.
|
||||
return errorf("%v: unexpected scattered relocation", s)
|
||||
}
|
||||
|
||||
rp.Siz = rel.length
|
||||
rp.Type = objabi.MachoRelocOffset + (objabi.RelocType(rel.type_) << 1) + objabi.RelocType(rel.pcrel)
|
||||
rp.Off = int32(rel.addr)
|
||||
|
||||
// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
|
||||
if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
|
||||
// Calculate the addend as the offset into the section.
|
||||
//
|
||||
// The rip-relative offset stored in the object file is encoded
|
||||
// as follows:
|
||||
//
|
||||
// movsd 0x00000360(%rip),%xmm0
|
||||
//
|
||||
// To get the absolute address of the value this rip-relative address is pointing
|
||||
// to, we must add the address of the next instruction to it. This is done by
|
||||
// taking the address of the relocation and adding 4 to it (since the rip-relative
|
||||
// offset can at most be 32 bits long). To calculate the offset into the section the
|
||||
// relocation is referencing, we subtract the vaddr of the start of the referenced
|
||||
// section found in the original object file.
|
||||
//
|
||||
// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
|
||||
secaddr := c.seg.sect[rel.symnum-1].addr
|
||||
|
||||
rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr)
|
||||
} else {
|
||||
rp.Add = int64(int32(e.Uint32(s.P[rp.Off:])))
|
||||
}
|
||||
|
||||
// An unsigned internal relocation has a value offset
|
||||
// by the section address.
|
||||
if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_UNSIGNED {
|
||||
secaddr := c.seg.sect[rel.symnum-1].addr
|
||||
rp.Add -= int64(secaddr)
|
||||
}
|
||||
|
||||
if rel.extrn == 0 {
|
||||
if rel.symnum < 1 || rel.symnum > c.seg.nsect {
|
||||
return errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
|
||||
}
|
||||
|
||||
rp.Sym = c.seg.sect[rel.symnum-1].sym
|
||||
if rp.Sym == nil {
|
||||
return errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
|
||||
}
|
||||
} else {
|
||||
if rel.symnum >= symtab.nsym {
|
||||
return errorf("invalid relocation: symbol reference out of range")
|
||||
}
|
||||
|
||||
rp.Sym = symtab.sym[rel.symnum].sym
|
||||
}
|
||||
|
||||
rpi++
|
||||
}
|
||||
|
||||
sort.Sort(sym.RelocByOff(r[:rpi]))
|
||||
s.R = r
|
||||
s.R = s.R[:rpi]
|
||||
}
|
||||
|
||||
return textp, nil
|
||||
}
|
||||
|
||||
func cstring(x []byte) string {
|
||||
i := bytes.IndexByte(x, '\x00')
|
||||
if i >= 0 {
|
||||
x = x[:i]
|
||||
}
|
||||
return string(x)
|
||||
}
|
||||
|
|
@ -1,513 +0,0 @@
|
|||
// Copyright 2010 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 loadpe implements a PE/COFF file reader.
|
||||
package loadpe
|
||||
|
||||
import (
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/loader"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"debug/pe"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 (same with IMAGE_SYM_DTYPE_POINTER and IMAGE_SYM_DTYPE_FUNCTION)
|
||||
IMAGE_SYM_UNDEFINED = 0
|
||||
IMAGE_SYM_ABSOLUTE = -1
|
||||
IMAGE_SYM_DEBUG = -2
|
||||
IMAGE_SYM_TYPE_NULL = 0
|
||||
IMAGE_SYM_TYPE_VOID = 1
|
||||
IMAGE_SYM_TYPE_CHAR = 2
|
||||
IMAGE_SYM_TYPE_SHORT = 3
|
||||
IMAGE_SYM_TYPE_INT = 4
|
||||
IMAGE_SYM_TYPE_LONG = 5
|
||||
IMAGE_SYM_TYPE_FLOAT = 6
|
||||
IMAGE_SYM_TYPE_DOUBLE = 7
|
||||
IMAGE_SYM_TYPE_STRUCT = 8
|
||||
IMAGE_SYM_TYPE_UNION = 9
|
||||
IMAGE_SYM_TYPE_ENUM = 10
|
||||
IMAGE_SYM_TYPE_MOE = 11
|
||||
IMAGE_SYM_TYPE_BYTE = 12
|
||||
IMAGE_SYM_TYPE_WORD = 13
|
||||
IMAGE_SYM_TYPE_UINT = 14
|
||||
IMAGE_SYM_TYPE_DWORD = 15
|
||||
IMAGE_SYM_TYPE_PCODE = 32768
|
||||
IMAGE_SYM_DTYPE_NULL = 0
|
||||
IMAGE_SYM_DTYPE_POINTER = 0x10
|
||||
IMAGE_SYM_DTYPE_FUNCTION = 0x20
|
||||
IMAGE_SYM_DTYPE_ARRAY = 0x30
|
||||
IMAGE_SYM_CLASS_END_OF_FUNCTION = -1
|
||||
IMAGE_SYM_CLASS_NULL = 0
|
||||
IMAGE_SYM_CLASS_AUTOMATIC = 1
|
||||
IMAGE_SYM_CLASS_EXTERNAL = 2
|
||||
IMAGE_SYM_CLASS_STATIC = 3
|
||||
IMAGE_SYM_CLASS_REGISTER = 4
|
||||
IMAGE_SYM_CLASS_EXTERNAL_DEF = 5
|
||||
IMAGE_SYM_CLASS_LABEL = 6
|
||||
IMAGE_SYM_CLASS_UNDEFINED_LABEL = 7
|
||||
IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8
|
||||
IMAGE_SYM_CLASS_ARGUMENT = 9
|
||||
IMAGE_SYM_CLASS_STRUCT_TAG = 10
|
||||
IMAGE_SYM_CLASS_MEMBER_OF_UNION = 11
|
||||
IMAGE_SYM_CLASS_UNION_TAG = 12
|
||||
IMAGE_SYM_CLASS_TYPE_DEFINITION = 13
|
||||
IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14
|
||||
IMAGE_SYM_CLASS_ENUM_TAG = 15
|
||||
IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 16
|
||||
IMAGE_SYM_CLASS_REGISTER_PARAM = 17
|
||||
IMAGE_SYM_CLASS_BIT_FIELD = 18
|
||||
IMAGE_SYM_CLASS_FAR_EXTERNAL = 68 /* Not in PECOFF v8 spec */
|
||||
IMAGE_SYM_CLASS_BLOCK = 100
|
||||
IMAGE_SYM_CLASS_FUNCTION = 101
|
||||
IMAGE_SYM_CLASS_END_OF_STRUCT = 102
|
||||
IMAGE_SYM_CLASS_FILE = 103
|
||||
IMAGE_SYM_CLASS_SECTION = 104
|
||||
IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105
|
||||
IMAGE_SYM_CLASS_CLR_TOKEN = 107
|
||||
IMAGE_REL_I386_ABSOLUTE = 0x0000
|
||||
IMAGE_REL_I386_DIR16 = 0x0001
|
||||
IMAGE_REL_I386_REL16 = 0x0002
|
||||
IMAGE_REL_I386_DIR32 = 0x0006
|
||||
IMAGE_REL_I386_DIR32NB = 0x0007
|
||||
IMAGE_REL_I386_SEG12 = 0x0009
|
||||
IMAGE_REL_I386_SECTION = 0x000A
|
||||
IMAGE_REL_I386_SECREL = 0x000B
|
||||
IMAGE_REL_I386_TOKEN = 0x000C
|
||||
IMAGE_REL_I386_SECREL7 = 0x000D
|
||||
IMAGE_REL_I386_REL32 = 0x0014
|
||||
IMAGE_REL_AMD64_ABSOLUTE = 0x0000
|
||||
IMAGE_REL_AMD64_ADDR64 = 0x0001
|
||||
IMAGE_REL_AMD64_ADDR32 = 0x0002
|
||||
IMAGE_REL_AMD64_ADDR32NB = 0x0003
|
||||
IMAGE_REL_AMD64_REL32 = 0x0004
|
||||
IMAGE_REL_AMD64_REL32_1 = 0x0005
|
||||
IMAGE_REL_AMD64_REL32_2 = 0x0006
|
||||
IMAGE_REL_AMD64_REL32_3 = 0x0007
|
||||
IMAGE_REL_AMD64_REL32_4 = 0x0008
|
||||
IMAGE_REL_AMD64_REL32_5 = 0x0009
|
||||
IMAGE_REL_AMD64_SECTION = 0x000A
|
||||
IMAGE_REL_AMD64_SECREL = 0x000B
|
||||
IMAGE_REL_AMD64_SECREL7 = 0x000C
|
||||
IMAGE_REL_AMD64_TOKEN = 0x000D
|
||||
IMAGE_REL_AMD64_SREL32 = 0x000E
|
||||
IMAGE_REL_AMD64_PAIR = 0x000F
|
||||
IMAGE_REL_AMD64_SSPAN32 = 0x0010
|
||||
IMAGE_REL_ARM_ABSOLUTE = 0x0000
|
||||
IMAGE_REL_ARM_ADDR32 = 0x0001
|
||||
IMAGE_REL_ARM_ADDR32NB = 0x0002
|
||||
IMAGE_REL_ARM_BRANCH24 = 0x0003
|
||||
IMAGE_REL_ARM_BRANCH11 = 0x0004
|
||||
IMAGE_REL_ARM_SECTION = 0x000E
|
||||
IMAGE_REL_ARM_SECREL = 0x000F
|
||||
IMAGE_REL_ARM_MOV32 = 0x0010
|
||||
IMAGE_REL_THUMB_MOV32 = 0x0011
|
||||
IMAGE_REL_THUMB_BRANCH20 = 0x0012
|
||||
IMAGE_REL_THUMB_BRANCH24 = 0x0014
|
||||
IMAGE_REL_THUMB_BLX23 = 0x0015
|
||||
IMAGE_REL_ARM_PAIR = 0x0016
|
||||
)
|
||||
|
||||
// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld, ideally in debug/pe.
|
||||
const (
|
||||
IMAGE_SCN_CNT_CODE = 0x00000020
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
|
||||
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
|
||||
IMAGE_SCN_MEM_DISCARDABLE = 0x02000000
|
||||
IMAGE_SCN_MEM_EXECUTE = 0x20000000
|
||||
IMAGE_SCN_MEM_READ = 0x40000000
|
||||
IMAGE_SCN_MEM_WRITE = 0x80000000
|
||||
)
|
||||
|
||||
// TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating peBiobuf
|
||||
|
||||
// peBiobuf makes bio.Reader look like io.ReaderAt.
|
||||
type peBiobuf bio.Reader
|
||||
|
||||
func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
|
||||
ret := ((*bio.Reader)(f)).MustSeek(off, 0)
|
||||
if ret < 0 {
|
||||
return 0, errors.New("fail to seek")
|
||||
}
|
||||
n, err := f.Read(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
|
||||
lookup := func(name string, version int) *sym.Symbol {
|
||||
return l.LookupOrCreate(name, version, syms)
|
||||
}
|
||||
return load(arch, lookup, syms.IncVersion(), input, pkg, length, pn)
|
||||
}
|
||||
|
||||
func LoadOld(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
|
||||
return load(arch, syms.Lookup, syms.IncVersion(), input, pkg, length, pn)
|
||||
}
|
||||
|
||||
// load loads the PE file pn from input.
|
||||
// Symbols are written into syms, and a slice of the text symbols is returned.
|
||||
// If an .rsrc section is found, its symbol is returned as rsrc.
|
||||
func load(arch *sys.Arch, lookup func(string, int) *sym.Symbol, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
|
||||
sectsyms := make(map[*pe.Section]*sym.Symbol)
|
||||
sectdata := make(map[*pe.Section][]byte)
|
||||
|
||||
// Some input files are archives containing multiple of
|
||||
// object files, and pe.NewFile seeks to the start of
|
||||
// input file and get confused. Create section reader
|
||||
// to stop pe.NewFile looking before current position.
|
||||
sr := io.NewSectionReader((*peBiobuf)(input), input.Offset(), 1<<63-1)
|
||||
|
||||
// TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details)
|
||||
f, err := pe.NewFile(sr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// TODO return error if found .cormeta
|
||||
|
||||
// create symbols for mapped sections
|
||||
for _, sect := range f.Sections {
|
||||
if sect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if sect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
|
||||
// This has been seen for .idata sections, which we
|
||||
// want to ignore. See issues 5106 and 5273.
|
||||
continue
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
|
||||
s := lookup(name, localSymVersion)
|
||||
|
||||
switch sect.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
|
||||
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
|
||||
s.Type = sym.SRODATA
|
||||
|
||||
case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
|
||||
s.Type = sym.SNOPTRBSS
|
||||
|
||||
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
|
||||
s.Type = sym.SNOPTRDATA
|
||||
|
||||
case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
|
||||
s.Type = sym.STEXT
|
||||
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
|
||||
}
|
||||
|
||||
if s.Type != sym.SNOPTRBSS {
|
||||
data, err := sect.Data()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sectdata[sect] = data
|
||||
s.P = data
|
||||
}
|
||||
s.Size = int64(sect.Size)
|
||||
sectsyms[sect] = s
|
||||
if sect.Name == ".rsrc" {
|
||||
rsrc = s
|
||||
}
|
||||
}
|
||||
|
||||
// load relocations
|
||||
for _, rsect := range f.Sections {
|
||||
if _, found := sectsyms[rsect]; !found {
|
||||
continue
|
||||
}
|
||||
if rsect.NumberOfRelocations == 0 {
|
||||
continue
|
||||
}
|
||||
if rsect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
|
||||
continue
|
||||
}
|
||||
if rsect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
|
||||
// This has been seen for .idata sections, which we
|
||||
// want to ignore. See issues 5106 and 5273.
|
||||
continue
|
||||
}
|
||||
|
||||
rs := make([]sym.Reloc, rsect.NumberOfRelocations)
|
||||
for j, r := range rsect.Relocs {
|
||||
rp := &rs[j]
|
||||
if int(r.SymbolTableIndex) >= len(f.COFFSymbols) {
|
||||
return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
|
||||
}
|
||||
pesym := &f.COFFSymbols[r.SymbolTableIndex]
|
||||
gosym, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if gosym == nil {
|
||||
name, err := pesym.FullName(f.StringTable)
|
||||
if err != nil {
|
||||
name = string(pesym.Name[:])
|
||||
}
|
||||
return nil, nil, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
|
||||
}
|
||||
|
||||
rp.Sym = gosym
|
||||
rp.Siz = 4
|
||||
rp.Off = int32(r.VirtualAddress)
|
||||
switch arch.Family {
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
|
||||
case sys.I386, sys.AMD64:
|
||||
switch r.Type {
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
|
||||
|
||||
case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
|
||||
IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
|
||||
IMAGE_REL_AMD64_ADDR32NB:
|
||||
rp.Type = objabi.R_PCREL
|
||||
|
||||
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
|
||||
|
||||
case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
|
||||
rp.Type = objabi.R_ADDR
|
||||
|
||||
// load addend from image
|
||||
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
|
||||
|
||||
case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
|
||||
rp.Siz = 8
|
||||
|
||||
rp.Type = objabi.R_ADDR
|
||||
|
||||
// load addend from image
|
||||
rp.Add = int64(binary.LittleEndian.Uint64(sectdata[rsect][rp.Off:]))
|
||||
}
|
||||
|
||||
case sys.ARM:
|
||||
switch r.Type {
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
|
||||
|
||||
case IMAGE_REL_ARM_SECREL:
|
||||
rp.Type = objabi.R_PCREL
|
||||
|
||||
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
|
||||
|
||||
case IMAGE_REL_ARM_ADDR32:
|
||||
rp.Type = objabi.R_ADDR
|
||||
|
||||
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
|
||||
|
||||
case IMAGE_REL_ARM_BRANCH24:
|
||||
rp.Type = objabi.R_CALLARM
|
||||
|
||||
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
|
||||
}
|
||||
}
|
||||
|
||||
// ld -r could generate multiple section symbols for the
|
||||
// same section but with different values, we have to take
|
||||
// that into account
|
||||
if issect(pesym) {
|
||||
rp.Add += int64(pesym.Value)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(sym.RelocByOff(rs[:rsect.NumberOfRelocations]))
|
||||
|
||||
s := sectsyms[rsect]
|
||||
s.R = rs
|
||||
s.R = s.R[:rsect.NumberOfRelocations]
|
||||
}
|
||||
|
||||
// enter sub-symbols into symbol table.
|
||||
for i, numaux := 0, 0; i < len(f.COFFSymbols); i += numaux + 1 {
|
||||
pesym := &f.COFFSymbols[i]
|
||||
|
||||
numaux = int(pesym.NumberOfAuxSymbols)
|
||||
|
||||
name, err := pesym.FullName(f.StringTable)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if issect(pesym) {
|
||||
continue
|
||||
}
|
||||
if int(pesym.SectionNumber) > len(f.Sections) {
|
||||
continue
|
||||
}
|
||||
if pesym.SectionNumber == IMAGE_SYM_DEBUG {
|
||||
continue
|
||||
}
|
||||
var sect *pe.Section
|
||||
if pesym.SectionNumber > 0 {
|
||||
sect = f.Sections[pesym.SectionNumber-1]
|
||||
if _, found := sectsyms[sect]; !found {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
s, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if pesym.SectionNumber == 0 { // extern
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
s.SetPlt(-2) // flag for dynimport in PE object files.
|
||||
}
|
||||
if s.Type == sym.SXREF && pesym.Value > 0 { // global data
|
||||
s.Type = sym.SNOPTRDATA
|
||||
s.Size = int64(pesym.Value)
|
||||
}
|
||||
|
||||
continue
|
||||
} else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) {
|
||||
sect = f.Sections[pesym.SectionNumber-1]
|
||||
if _, found := sectsyms[sect]; !found {
|
||||
return nil, nil, fmt.Errorf("%s: %v: missing sect.sym", pn, s)
|
||||
}
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("%s: %v: sectnum < 0!", pn, s)
|
||||
}
|
||||
|
||||
if sect == nil {
|
||||
return nil, rsrc, nil
|
||||
}
|
||||
|
||||
if s.Outer != nil {
|
||||
if s.Attr.DuplicateOK() {
|
||||
continue
|
||||
}
|
||||
return nil, nil, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sectsyms[sect].Name)
|
||||
}
|
||||
|
||||
sectsym := sectsyms[sect]
|
||||
s.Sub = sectsym.Sub
|
||||
sectsym.Sub = s
|
||||
s.Type = sectsym.Type
|
||||
s.Attr |= sym.AttrSubSymbol
|
||||
s.Value = int64(pesym.Value)
|
||||
s.Size = 4
|
||||
s.Outer = sectsym
|
||||
if sectsym.Type == sym.STEXT {
|
||||
if s.Attr.External() && !s.Attr.DuplicateOK() {
|
||||
return nil, nil, fmt.Errorf("%s: duplicate symbol definition", s.Name)
|
||||
}
|
||||
s.Attr |= sym.AttrExternal
|
||||
}
|
||||
}
|
||||
|
||||
// Sort outer lists by address, adding to textp.
|
||||
// This keeps textp in increasing address order.
|
||||
for _, sect := range f.Sections {
|
||||
s := sectsyms[sect]
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
if s.Sub != nil {
|
||||
s.Sub = sym.SortSub(s.Sub)
|
||||
}
|
||||
if s.Type == sym.STEXT {
|
||||
if s.Attr.OnList() {
|
||||
return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
textp = append(textp, s)
|
||||
for s = s.Sub; s != nil; s = s.Sub {
|
||||
if s.Attr.OnList() {
|
||||
return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
textp = append(textp, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return textp, rsrc, nil
|
||||
}
|
||||
|
||||
func issect(s *pe.COFFSymbol) bool {
|
||||
return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.'
|
||||
}
|
||||
|
||||
func readpesym(arch *sys.Arch, lookup func(string, int) *sym.Symbol, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]*sym.Symbol, localSymVersion int) (*sym.Symbol, error) {
|
||||
symname, err := pesym.FullName(f.StringTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var name string
|
||||
if issect(pesym) {
|
||||
name = sectsyms[f.Sections[pesym.SectionNumber-1]].Name
|
||||
} else {
|
||||
name = symname
|
||||
switch arch.Family {
|
||||
case sys.AMD64:
|
||||
if name == "__imp___acrt_iob_func" {
|
||||
// Do not rename __imp___acrt_iob_func into __acrt_iob_func,
|
||||
// because __imp___acrt_iob_func symbol is real
|
||||
// (see commit b295099 from git://git.code.sf.net/p/mingw-w64/mingw-w64 for details).
|
||||
} else {
|
||||
name = strings.TrimPrefix(name, "__imp_") // __imp_Name => Name
|
||||
}
|
||||
case sys.I386:
|
||||
if name == "__imp____acrt_iob_func" {
|
||||
// Do not rename __imp____acrt_iob_func into ___acrt_iob_func,
|
||||
// because __imp____acrt_iob_func symbol is real
|
||||
// (see commit b295099 from git://git.code.sf.net/p/mingw-w64/mingw-w64 for details).
|
||||
} else {
|
||||
name = strings.TrimPrefix(name, "__imp_") // __imp_Name => Name
|
||||
}
|
||||
if name[0] == '_' {
|
||||
name = name[1:] // _Name => Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove last @XXX
|
||||
if i := strings.LastIndex(name, "@"); i >= 0 {
|
||||
name = name[:i]
|
||||
}
|
||||
|
||||
var s *sym.Symbol
|
||||
switch pesym.Type {
|
||||
default:
|
||||
return nil, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type)
|
||||
|
||||
case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
|
||||
switch pesym.StorageClass {
|
||||
case IMAGE_SYM_CLASS_EXTERNAL: //global
|
||||
s = lookup(name, 0)
|
||||
|
||||
case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
|
||||
s = lookup(name, localSymVersion)
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass)
|
||||
}
|
||||
}
|
||||
|
||||
if s != nil && s.Type == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) {
|
||||
s.Type = sym.SXREF
|
||||
}
|
||||
if strings.HasPrefix(symname, "__imp_") {
|
||||
s.SetGot(-2) // flag for __imp_
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
|
@ -1,238 +0,0 @@
|
|||
// Copyright 2018 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 loadxcoff implements a XCOFF file reader.
|
||||
package loadxcoff
|
||||
|
||||
import (
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/loader"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/xcoff"
|
||||
)
|
||||
|
||||
// ldSection is an XCOFF section with its symbols.
|
||||
type ldSection struct {
|
||||
xcoff.Section
|
||||
sym *sym.Symbol
|
||||
}
|
||||
|
||||
// TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating xcoffBiobuf
|
||||
|
||||
// xcoffBiobuf makes bio.Reader look like io.ReaderAt.
|
||||
type xcoffBiobuf bio.Reader
|
||||
|
||||
func (f *xcoffBiobuf) ReadAt(p []byte, off int64) (int, error) {
|
||||
ret := ((*bio.Reader)(f)).MustSeek(off, 0)
|
||||
if ret < 0 {
|
||||
return 0, errors.New("fail to seek")
|
||||
}
|
||||
n, err := f.Read(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Load loads xcoff files with the indexed object files.
|
||||
func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
|
||||
lookup := func(name string, version int) *sym.Symbol {
|
||||
return l.LookupOrCreate(name, version, syms)
|
||||
}
|
||||
return load(arch, lookup, syms.IncVersion(), input, pkg, length, pn)
|
||||
}
|
||||
|
||||
// LoadOld uses the old version of object loading.
|
||||
func LoadOld(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
|
||||
return load(arch, syms.Lookup, syms.IncVersion(), input, pkg, length, pn)
|
||||
}
|
||||
|
||||
// loads the Xcoff file pn from f.
|
||||
// Symbols are written into syms, and a slice of the text symbols is returned.
|
||||
func load(arch *sys.Arch, lookup func(string, int) *sym.Symbol, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
|
||||
errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
|
||||
return nil, fmt.Errorf("loadxcoff: %v: %v", pn, fmt.Sprintf(str, args...))
|
||||
}
|
||||
|
||||
var ldSections []*ldSection
|
||||
|
||||
f, err := xcoff.NewFile((*xcoffBiobuf)(input))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
for _, sect := range f.Sections {
|
||||
//only text, data and bss section
|
||||
if sect.Type < xcoff.STYP_TEXT || sect.Type > xcoff.STYP_BSS {
|
||||
continue
|
||||
}
|
||||
lds := new(ldSection)
|
||||
lds.Section = *sect
|
||||
name := fmt.Sprintf("%s(%s)", pkg, lds.Name)
|
||||
s := lookup(name, localSymVersion)
|
||||
|
||||
switch lds.Type {
|
||||
default:
|
||||
return errorf("unrecognized section type 0x%x", lds.Type)
|
||||
case xcoff.STYP_TEXT:
|
||||
s.Type = sym.STEXT
|
||||
case xcoff.STYP_DATA:
|
||||
s.Type = sym.SNOPTRDATA
|
||||
case xcoff.STYP_BSS:
|
||||
s.Type = sym.SNOPTRBSS
|
||||
}
|
||||
|
||||
s.Size = int64(lds.Size)
|
||||
if s.Type != sym.SNOPTRBSS {
|
||||
data, err := lds.Section.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.P = data
|
||||
}
|
||||
|
||||
lds.sym = s
|
||||
ldSections = append(ldSections, lds)
|
||||
}
|
||||
|
||||
// sx = symbol from file
|
||||
// s = symbol for syms
|
||||
for _, sx := range f.Symbols {
|
||||
// get symbol type
|
||||
stype, errmsg := getSymbolType(f, sx)
|
||||
if errmsg != "" {
|
||||
return errorf("error reading symbol %s: %s", sx.Name, errmsg)
|
||||
}
|
||||
if stype == sym.Sxxx {
|
||||
continue
|
||||
}
|
||||
|
||||
s := lookup(sx.Name, 0)
|
||||
|
||||
// Text symbol
|
||||
if s.Type == sym.STEXT {
|
||||
if s.Attr.OnList() {
|
||||
return errorf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
textp = append(textp, s)
|
||||
}
|
||||
}
|
||||
|
||||
// Read relocations
|
||||
for _, sect := range ldSections {
|
||||
// TODO(aix): Dwarf section relocation if needed
|
||||
if sect.Type != xcoff.STYP_TEXT && sect.Type != xcoff.STYP_DATA {
|
||||
continue
|
||||
}
|
||||
rs := make([]sym.Reloc, sect.Nreloc)
|
||||
for i, rx := range sect.Relocs {
|
||||
r := &rs[i]
|
||||
|
||||
r.Sym = lookup(rx.Symbol.Name, 0)
|
||||
if uint64(int32(rx.VirtualAddress)) != rx.VirtualAddress {
|
||||
return errorf("virtual address of a relocation is too big: 0x%x", rx.VirtualAddress)
|
||||
}
|
||||
r.Off = int32(rx.VirtualAddress)
|
||||
switch rx.Type {
|
||||
default:
|
||||
return errorf("section %s: unknown relocation of type 0x%x", sect.Name, rx.Type)
|
||||
case xcoff.R_POS:
|
||||
// Reloc the address of r.Sym
|
||||
// Length should be 64
|
||||
if rx.Length != 64 {
|
||||
return errorf("section %s: relocation R_POS has length different from 64: %d", sect.Name, rx.Length)
|
||||
}
|
||||
r.Siz = 8
|
||||
r.Type = objabi.R_CONST
|
||||
r.Add = int64(rx.Symbol.Value)
|
||||
|
||||
case xcoff.R_RBR:
|
||||
r.Siz = 4
|
||||
r.Type = objabi.R_CALLPOWER
|
||||
r.Add = 0 //
|
||||
|
||||
}
|
||||
}
|
||||
s := sect.sym
|
||||
s.R = rs
|
||||
s.R = s.R[:sect.Nreloc]
|
||||
}
|
||||
return textp, nil
|
||||
|
||||
}
|
||||
|
||||
// Convert symbol xcoff type to sym.SymKind
|
||||
// Returns nil if this shouldn't be added into syms (like .file or .dw symbols )
|
||||
func getSymbolType(f *xcoff.File, s *xcoff.Symbol) (stype sym.SymKind, err string) {
|
||||
// .file symbol
|
||||
if s.SectionNumber == -2 {
|
||||
if s.StorageClass == xcoff.C_FILE {
|
||||
return sym.Sxxx, ""
|
||||
}
|
||||
return sym.Sxxx, "unrecognised StorageClass for sectionNumber = -2"
|
||||
}
|
||||
|
||||
// extern symbols
|
||||
// TODO(aix)
|
||||
if s.SectionNumber == 0 {
|
||||
return sym.Sxxx, ""
|
||||
}
|
||||
|
||||
sectType := f.Sections[s.SectionNumber-1].SectionHeader.Type
|
||||
switch sectType {
|
||||
default:
|
||||
return sym.Sxxx, fmt.Sprintf("getSymbolType for Section type 0x%x not implemented", sectType)
|
||||
case xcoff.STYP_DWARF, xcoff.STYP_DEBUG:
|
||||
return sym.Sxxx, ""
|
||||
case xcoff.STYP_DATA, xcoff.STYP_BSS, xcoff.STYP_TEXT:
|
||||
}
|
||||
|
||||
switch s.StorageClass {
|
||||
default:
|
||||
return sym.Sxxx, fmt.Sprintf("getSymbolType for Storage class 0x%x not implemented", s.StorageClass)
|
||||
case xcoff.C_HIDEXT, xcoff.C_EXT, xcoff.C_WEAKEXT:
|
||||
switch s.AuxCSect.StorageMappingClass {
|
||||
default:
|
||||
return sym.Sxxx, fmt.Sprintf("getSymbolType for Storage class 0x%x and Storage Map 0x%x not implemented", s.StorageClass, s.AuxCSect.StorageMappingClass)
|
||||
|
||||
// Program Code
|
||||
case xcoff.XMC_PR:
|
||||
if sectType == xcoff.STYP_TEXT {
|
||||
return sym.STEXT, ""
|
||||
}
|
||||
return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_PR", sectType, s.StorageClass)
|
||||
|
||||
// Read/Write Data
|
||||
case xcoff.XMC_RW:
|
||||
if sectType == xcoff.STYP_DATA {
|
||||
return sym.SDATA, ""
|
||||
}
|
||||
if sectType == xcoff.STYP_BSS {
|
||||
return sym.SBSS, ""
|
||||
}
|
||||
return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_RW", sectType, s.StorageClass)
|
||||
|
||||
// Function descriptor
|
||||
case xcoff.XMC_DS:
|
||||
if sectType == xcoff.STYP_DATA {
|
||||
return sym.SDATA, ""
|
||||
}
|
||||
return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_DS", sectType, s.StorageClass)
|
||||
|
||||
// TOC anchor and TOC entry
|
||||
case xcoff.XMC_TC0, xcoff.XMC_TE:
|
||||
if sectType == xcoff.STYP_DATA {
|
||||
return sym.SXCOFFTOC, ""
|
||||
}
|
||||
return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_DS", sectType, s.StorageClass)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2016 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package mips
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func gentext(ctxt *ld.Link) {
|
||||
return
|
||||
}
|
||||
|
||||
func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
log.Fatalf("adddynrel not implemented")
|
||||
return false
|
||||
}
|
||||
|
||||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write32(uint32(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
case objabi.R_ADDR:
|
||||
if r.Siz != 4 {
|
||||
return false
|
||||
}
|
||||
ctxt.Out.Write32(uint32(elf.R_MIPS_32) | uint32(elfsym)<<8)
|
||||
case objabi.R_ADDRMIPS:
|
||||
ctxt.Out.Write32(uint32(elf.R_MIPS_LO16) | uint32(elfsym)<<8)
|
||||
case objabi.R_ADDRMIPSU:
|
||||
ctxt.Out.Write32(uint32(elf.R_MIPS_HI16) | uint32(elfsym)<<8)
|
||||
case objabi.R_ADDRMIPSTLS:
|
||||
ctxt.Out.Write32(uint32(elf.R_MIPS_TLS_TPREL_LO16) | uint32(elfsym)<<8)
|
||||
case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
|
||||
ctxt.Out.Write32(uint32(elf.R_MIPS_26) | uint32(elfsym)<<8)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func elfsetupplt(ctxt *ld.Link) {
|
||||
return
|
||||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func applyrel(arch *sys.Arch, r *sym.Reloc, s *sym.Symbol, val int64, t int64) int64 {
|
||||
o := arch.ByteOrder.Uint32(s.P[r.Off:])
|
||||
switch r.Type {
|
||||
case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSTLS:
|
||||
return int64(o&0xffff0000 | uint32(t)&0xffff)
|
||||
case objabi.R_ADDRMIPSU:
|
||||
return int64(o&0xffff0000 | uint32((t+(1<<15))>>16)&0xffff)
|
||||
case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
|
||||
return int64(o&0xfc000000 | uint32(t>>2)&^0xfc000000)
|
||||
default:
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
switch r.Type {
|
||||
default:
|
||||
return val, false
|
||||
case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU:
|
||||
r.Done = false
|
||||
|
||||
// set up addend for eventual relocation via outer symbol.
|
||||
rs := r.Sym
|
||||
r.Xadd = r.Add
|
||||
for rs.Outer != nil {
|
||||
r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
|
||||
rs = rs.Outer
|
||||
}
|
||||
|
||||
if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
|
||||
ld.Errorf(s, "missing section for %s", rs.Name)
|
||||
}
|
||||
r.Xsym = rs
|
||||
return applyrel(ctxt.Arch, r, s, val, r.Xadd), true
|
||||
case objabi.R_ADDRMIPSTLS, objabi.R_CALLMIPS, objabi.R_JMPMIPS:
|
||||
r.Done = false
|
||||
r.Xsym = r.Sym
|
||||
r.Xadd = r.Add
|
||||
return applyrel(ctxt.Arch, r, s, val, r.Add), true
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case objabi.R_CONST:
|
||||
return r.Add, true
|
||||
case objabi.R_GOTOFF:
|
||||
return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
|
||||
case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU:
|
||||
t := ld.Symaddr(r.Sym) + r.Add
|
||||
return applyrel(ctxt.Arch, r, s, val, t), true
|
||||
case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
|
||||
t := ld.Symaddr(r.Sym) + r.Add
|
||||
|
||||
if t&3 != 0 {
|
||||
ld.Errorf(s, "direct call is not aligned: %s %x", r.Sym.Name, t)
|
||||
}
|
||||
|
||||
// check if target address is in the same 256 MB region as the next instruction
|
||||
if (s.Value+int64(r.Off)+4)&0xf0000000 != (t & 0xf0000000) {
|
||||
ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
|
||||
}
|
||||
|
||||
return applyrel(ctxt.Arch, r, s, val, t), true
|
||||
case objabi.R_ADDRMIPSTLS:
|
||||
// thread pointer is at 0x7000 offset from the start of TLS data area
|
||||
t := ld.Symaddr(r.Sym) + r.Add - 0x7000
|
||||
if t < -32768 || t >= 32678 {
|
||||
ld.Errorf(s, "TLS offset out of range %d", t)
|
||||
}
|
||||
return applyrel(ctxt.Arch, r, s, val, t), true
|
||||
}
|
||||
|
||||
return val, false
|
||||
}
|
||||
|
||||
func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
|
||||
return -1
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect := ld.Segtext.Sections[0]
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
for _, sect = range ld.Segtext.Sections[1:] {
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
|
||||
ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
|
||||
}
|
||||
|
||||
func asmb2(ctxt *ld.Link) {
|
||||
/* output symbol table */
|
||||
ld.Symsize = 0
|
||||
|
||||
ld.Lcsize = 0
|
||||
symo := uint32(0)
|
||||
if !*ld.FlagS {
|
||||
if !ctxt.IsELF {
|
||||
ld.Errorf(nil, "unsupported executable format")
|
||||
}
|
||||
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
|
||||
|
||||
ctxt.Out.SeekSet(int64(symo))
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Elfemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(0)
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Errorf(nil, "unsupported operating system")
|
||||
case objabi.Hlinux:
|
||||
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)
|
||||
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2016 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package mips
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// cmd/9l/l.h from Vita Nuova.
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2016 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
MaxAlign = 32 // max data alignment
|
||||
MinAlign = 1 // min data alignment
|
||||
FuncAlign = 4
|
||||
)
|
||||
|
||||
/* Used by ../internal/ld/dwarf.go */
|
||||
const (
|
||||
DWARFREGSP = 29
|
||||
DWARFREGLR = 31
|
||||
)
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
// Inferno utils/5l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2016 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package mips
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
)
|
||||
|
||||
func Init() (*sys.Arch, ld.Arch) {
|
||||
arch := sys.ArchMIPS
|
||||
if objabi.GOARCH == "mipsle" {
|
||||
arch = sys.ArchMIPSLE
|
||||
}
|
||||
|
||||
theArch := ld.Arch{
|
||||
Funcalign: FuncAlign,
|
||||
Maxalign: MaxAlign,
|
||||
Minalign: MinAlign,
|
||||
Dwarfregsp: DWARFREGSP,
|
||||
Dwarfreglr: DWARFREGLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
Asmb: asmb,
|
||||
Asmb2: asmb2,
|
||||
Elfreloc1: elfreloc1,
|
||||
Elfsetupplt: elfsetupplt,
|
||||
Gentext: gentext,
|
||||
Machoreloc1: machoreloc1,
|
||||
|
||||
Linuxdynld: "/lib/ld.so.1",
|
||||
|
||||
Freebsddynld: "XXX",
|
||||
Openbsddynld: "XXX",
|
||||
Netbsddynld: "XXX",
|
||||
Dragonflydynld: "XXX",
|
||||
Solarisdynld: "XXX",
|
||||
}
|
||||
|
||||
return arch, theArch
|
||||
}
|
||||
|
||||
func archinit(ctxt *ld.Link) {
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Exitf("unknown -H option: %v", ctxt.HeadType)
|
||||
case objabi.Hlinux: /* mips elf */
|
||||
ld.Elfinit(ctxt)
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 0x10000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,278 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package mips64
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func gentext(ctxt *ld.Link) {}
|
||||
|
||||
func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
log.Fatalf("adddynrel not implemented")
|
||||
return false
|
||||
}
|
||||
|
||||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
// mips64 ELF relocation (endian neutral)
|
||||
// offset uint64
|
||||
// sym uint32
|
||||
// ssym uint8
|
||||
// type3 uint8
|
||||
// type2 uint8
|
||||
// type uint8
|
||||
// addend int64
|
||||
|
||||
ctxt.Out.Write64(uint64(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
ctxt.Out.Write32(uint32(elfsym))
|
||||
ctxt.Out.Write8(0)
|
||||
ctxt.Out.Write8(0)
|
||||
ctxt.Out.Write8(0)
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
case objabi.R_ADDR:
|
||||
switch r.Siz {
|
||||
case 4:
|
||||
ctxt.Out.Write8(uint8(elf.R_MIPS_32))
|
||||
case 8:
|
||||
ctxt.Out.Write8(uint8(elf.R_MIPS_64))
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case objabi.R_ADDRMIPS:
|
||||
ctxt.Out.Write8(uint8(elf.R_MIPS_LO16))
|
||||
case objabi.R_ADDRMIPSU:
|
||||
ctxt.Out.Write8(uint8(elf.R_MIPS_HI16))
|
||||
case objabi.R_ADDRMIPSTLS:
|
||||
ctxt.Out.Write8(uint8(elf.R_MIPS_TLS_TPREL_LO16))
|
||||
case objabi.R_CALLMIPS,
|
||||
objabi.R_JMPMIPS:
|
||||
ctxt.Out.Write8(uint8(elf.R_MIPS_26))
|
||||
}
|
||||
ctxt.Out.Write64(uint64(r.Xadd))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func elfsetupplt(ctxt *ld.Link) {
|
||||
return
|
||||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
switch r.Type {
|
||||
default:
|
||||
return val, false
|
||||
case objabi.R_ADDRMIPS,
|
||||
objabi.R_ADDRMIPSU:
|
||||
r.Done = false
|
||||
|
||||
// set up addend for eventual relocation via outer symbol.
|
||||
rs := r.Sym
|
||||
r.Xadd = r.Add
|
||||
for rs.Outer != nil {
|
||||
r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
|
||||
rs = rs.Outer
|
||||
}
|
||||
|
||||
if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
|
||||
ld.Errorf(s, "missing section for %s", rs.Name)
|
||||
}
|
||||
r.Xsym = rs
|
||||
|
||||
return val, true
|
||||
case objabi.R_ADDRMIPSTLS,
|
||||
objabi.R_CALLMIPS,
|
||||
objabi.R_JMPMIPS:
|
||||
r.Done = false
|
||||
r.Xsym = r.Sym
|
||||
r.Xadd = r.Add
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case objabi.R_CONST:
|
||||
return r.Add, true
|
||||
case objabi.R_GOTOFF:
|
||||
return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
|
||||
case objabi.R_ADDRMIPS,
|
||||
objabi.R_ADDRMIPSU:
|
||||
t := ld.Symaddr(r.Sym) + r.Add
|
||||
o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:])
|
||||
if r.Type == objabi.R_ADDRMIPS {
|
||||
return int64(o1&0xffff0000 | uint32(t)&0xffff), true
|
||||
}
|
||||
return int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff), true
|
||||
case objabi.R_ADDRMIPSTLS:
|
||||
// thread pointer is at 0x7000 offset from the start of TLS data area
|
||||
t := ld.Symaddr(r.Sym) + r.Add - 0x7000
|
||||
if t < -32768 || t >= 32678 {
|
||||
ld.Errorf(s, "TLS offset out of range %d", t)
|
||||
}
|
||||
o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:])
|
||||
return int64(o1&0xffff0000 | uint32(t)&0xffff), true
|
||||
case objabi.R_CALLMIPS,
|
||||
objabi.R_JMPMIPS:
|
||||
// Low 26 bits = (S + A) >> 2
|
||||
t := ld.Symaddr(r.Sym) + r.Add
|
||||
o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:])
|
||||
return int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000), true
|
||||
}
|
||||
|
||||
return val, false
|
||||
}
|
||||
|
||||
func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
|
||||
return -1
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect := ld.Segtext.Sections[0]
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
for _, sect = range ld.Segtext.Sections[1:] {
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
if ld.Segrelrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
|
||||
ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
|
||||
}
|
||||
|
||||
func asmb2(ctxt *ld.Link) {
|
||||
/* output symbol table */
|
||||
ld.Symsize = 0
|
||||
|
||||
ld.Lcsize = 0
|
||||
symo := uint32(0)
|
||||
if !*ld.FlagS {
|
||||
// TODO: rationalize
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
if ctxt.IsELF {
|
||||
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
|
||||
}
|
||||
|
||||
case objabi.Hplan9:
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(symo))
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
if ctxt.IsELF {
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Elfemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(0)
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
case objabi.Hplan9: /* plan 9 */
|
||||
magic := uint32(4*18*18 + 7)
|
||||
if ctxt.Arch == sys.ArchMIPS64LE {
|
||||
magic = uint32(4*26*26 + 7)
|
||||
}
|
||||
ctxt.Out.Write32(magic) /* magic */
|
||||
ctxt.Out.Write32(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||
ctxt.Out.Write32(uint32(ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32(uint32(ld.Symsize)) /* nsyms */
|
||||
ctxt.Out.Write32(uint32(ld.Entryvalue(ctxt))) /* va of entry */
|
||||
ctxt.Out.Write32(0)
|
||||
ctxt.Out.Write32(uint32(ld.Lcsize))
|
||||
|
||||
case objabi.Hlinux,
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd:
|
||||
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)
|
||||
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package mips64
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// cmd/9l/l.h from Vita Nuova.
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
maxAlign = 32 // max data alignment
|
||||
minAlign = 1 // min data alignment
|
||||
funcAlign = 8
|
||||
)
|
||||
|
||||
/* Used by ../internal/ld/dwarf.go */
|
||||
const (
|
||||
dwarfRegSP = 29
|
||||
dwarfRegLR = 31
|
||||
)
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
// Inferno utils/5l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package mips64
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
)
|
||||
|
||||
func Init() (*sys.Arch, ld.Arch) {
|
||||
arch := sys.ArchMIPS64
|
||||
if objabi.GOARCH == "mips64le" {
|
||||
arch = sys.ArchMIPS64LE
|
||||
}
|
||||
|
||||
theArch := ld.Arch{
|
||||
Funcalign: funcAlign,
|
||||
Maxalign: maxAlign,
|
||||
Minalign: minAlign,
|
||||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
Adddynrel: adddynrel,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
Asmb: asmb,
|
||||
Asmb2: asmb2,
|
||||
Elfreloc1: elfreloc1,
|
||||
Elfsetupplt: elfsetupplt,
|
||||
Gentext: gentext,
|
||||
Machoreloc1: machoreloc1,
|
||||
|
||||
Linuxdynld: "/lib64/ld64.so.1",
|
||||
Freebsddynld: "XXX",
|
||||
Openbsddynld: "XXX",
|
||||
Netbsddynld: "XXX",
|
||||
Dragonflydynld: "XXX",
|
||||
Solarisdynld: "XXX",
|
||||
}
|
||||
|
||||
return arch, theArch
|
||||
}
|
||||
|
||||
func archinit(ctxt *ld.Link) {
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Exitf("unknown -H option: %v", ctxt.HeadType)
|
||||
|
||||
case objabi.Hplan9: /* plan 9 */
|
||||
ld.HEADR = 32
|
||||
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 16*1024 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 16 * 1024
|
||||
}
|
||||
|
||||
case objabi.Hlinux: /* mips64 elf */
|
||||
ld.Elfinit(ctxt)
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 0x10000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,664 +0,0 @@
|
|||
// Copyright 2013 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 objfile reads Go object files for the Go linker, cmd/link.
|
||||
//
|
||||
// This package is similar to cmd/internal/objfile which also reads
|
||||
// Go object files.
|
||||
package objfile
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"fmt"
|
||||
"internal/unsafeheader"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
startmagic = "\x00go114ld"
|
||||
endmagic = "\xffgo114ld"
|
||||
)
|
||||
|
||||
var emptyPkg = []byte(`"".`)
|
||||
|
||||
// objReader reads Go object files.
|
||||
type objReader struct {
|
||||
rd *bio.Reader
|
||||
arch *sys.Arch
|
||||
syms *sym.Symbols
|
||||
lib *sym.Library
|
||||
unit *sym.CompilationUnit
|
||||
pn string
|
||||
dupSym *sym.Symbol
|
||||
localSymVersion int
|
||||
flags int
|
||||
strictDupMsgs int
|
||||
dataSize int
|
||||
|
||||
// rdBuf is used by readString and readSymName as scratch for reading strings.
|
||||
rdBuf []byte
|
||||
|
||||
// List of symbol references for the file being read.
|
||||
refs []*sym.Symbol
|
||||
data []byte
|
||||
reloc []sym.Reloc
|
||||
pcdata []sym.Pcdata
|
||||
funcdata []*sym.Symbol
|
||||
funcdataoff []int64
|
||||
file []*sym.Symbol
|
||||
pkgpref string // objabi.PathToPrefix(r.lib.Pkg) + "."
|
||||
|
||||
roObject []byte // from read-only mmap of object file (may be nil)
|
||||
roOffset int64 // offset into readonly object data examined so far
|
||||
|
||||
dataReadOnly bool // whether data is backed by read-only memory
|
||||
}
|
||||
|
||||
// Flags to enable optional behavior during object loading/reading.
|
||||
|
||||
const (
|
||||
NoFlag int = iota
|
||||
|
||||
// Sanity-check duplicate symbol contents, issuing warning
|
||||
// when duplicates have different lengths or contents.
|
||||
StrictDupsWarnFlag
|
||||
|
||||
// Similar to StrictDupsWarnFlag, but issue fatal error.
|
||||
StrictDupsErrFlag
|
||||
)
|
||||
|
||||
// Load loads an object file f into library lib.
|
||||
// The symbols loaded are added to syms.
|
||||
func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) int {
|
||||
start := f.Offset()
|
||||
roObject := f.SliceRO(uint64(length))
|
||||
if roObject != nil {
|
||||
f.MustSeek(int64(-length), os.SEEK_CUR)
|
||||
}
|
||||
r := &objReader{
|
||||
rd: f,
|
||||
lib: lib,
|
||||
unit: unit,
|
||||
arch: arch,
|
||||
syms: syms,
|
||||
pn: pn,
|
||||
dupSym: &sym.Symbol{Name: ".dup"},
|
||||
localSymVersion: syms.IncVersion(),
|
||||
flags: flags,
|
||||
roObject: roObject,
|
||||
pkgpref: objabi.PathToPrefix(lib.Pkg) + ".",
|
||||
}
|
||||
r.loadObjFile()
|
||||
if roObject != nil {
|
||||
if r.roOffset != length {
|
||||
log.Fatalf("%s: unexpected end at %d, want %d", pn, r.roOffset, start+length)
|
||||
}
|
||||
r.rd.MustSeek(int64(length), os.SEEK_CUR)
|
||||
} else if f.Offset() != start+length {
|
||||
log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length)
|
||||
}
|
||||
return r.strictDupMsgs
|
||||
}
|
||||
|
||||
func (r *objReader) loadObjFile() {
|
||||
// Magic header
|
||||
var buf [8]uint8
|
||||
r.readFull(buf[:])
|
||||
if string(buf[:]) != startmagic {
|
||||
if string(buf[:]) == goobj2.Magic {
|
||||
log.Fatalf("found object file %s in new format, but -go115newobj is false\nset -go115newobj consistently in all -gcflags, -asmflags, and -ldflags", r.pn)
|
||||
}
|
||||
log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
|
||||
}
|
||||
|
||||
// Version
|
||||
c, err := r.readByte()
|
||||
if err != nil || c != 1 {
|
||||
log.Fatalf("%s: invalid file version number %d", r.pn, c)
|
||||
}
|
||||
|
||||
// Autolib
|
||||
for {
|
||||
lib := r.readString()
|
||||
if lib == "" {
|
||||
break
|
||||
}
|
||||
r.lib.ImportStrings = append(r.lib.ImportStrings, lib)
|
||||
}
|
||||
|
||||
// DWARF strings
|
||||
count := r.readInt()
|
||||
r.unit.DWARFFileTable = make([]string, count)
|
||||
for i := 0; i < count; i++ {
|
||||
// TODO: This should probably be a call to mkROString.
|
||||
r.unit.DWARFFileTable[i] = r.readString()
|
||||
}
|
||||
|
||||
// Symbol references
|
||||
r.refs = []*sym.Symbol{nil} // zeroth ref is nil
|
||||
for {
|
||||
c, err := r.peek(1)
|
||||
if err != nil {
|
||||
log.Fatalf("%s: peeking: %v", r.pn, err)
|
||||
}
|
||||
if c[0] == 0xff {
|
||||
r.readByte()
|
||||
break
|
||||
}
|
||||
r.readRef()
|
||||
}
|
||||
|
||||
// Lengths
|
||||
r.readSlices()
|
||||
|
||||
// Data section
|
||||
err = r.readDataSection()
|
||||
if err != nil {
|
||||
log.Fatalf("%s: error reading %s", r.pn, err)
|
||||
}
|
||||
|
||||
// Defined symbols
|
||||
for {
|
||||
c, err := r.peek(1)
|
||||
if err != nil {
|
||||
log.Fatalf("%s: peeking: %v", r.pn, err)
|
||||
}
|
||||
if c[0] == 0xff {
|
||||
break
|
||||
}
|
||||
r.readSym()
|
||||
}
|
||||
|
||||
// Magic footer
|
||||
buf = [8]uint8{}
|
||||
r.readFull(buf[:])
|
||||
if string(buf[:]) != endmagic {
|
||||
log.Fatalf("%s: invalid file end", r.pn)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *objReader) readSlices() {
|
||||
r.dataSize = r.readInt()
|
||||
n := r.readInt()
|
||||
r.reloc = make([]sym.Reloc, n)
|
||||
n = r.readInt()
|
||||
r.pcdata = make([]sym.Pcdata, n)
|
||||
_ = r.readInt() // TODO: remove on next object file rev (autom count)
|
||||
n = r.readInt()
|
||||
r.funcdata = make([]*sym.Symbol, n)
|
||||
r.funcdataoff = make([]int64, n)
|
||||
n = r.readInt()
|
||||
r.file = make([]*sym.Symbol, n)
|
||||
}
|
||||
|
||||
func (r *objReader) readDataSection() (err error) {
|
||||
if r.roObject != nil {
|
||||
r.data, r.dataReadOnly, err =
|
||||
r.roObject[r.roOffset:r.roOffset+int64(r.dataSize)], true, nil
|
||||
r.roOffset += int64(r.dataSize)
|
||||
return
|
||||
}
|
||||
r.data, r.dataReadOnly, err = r.rd.Slice(uint64(r.dataSize))
|
||||
return
|
||||
}
|
||||
|
||||
// Symbols are prefixed so their content doesn't get confused with the magic footer.
|
||||
const symPrefix = 0xfe
|
||||
|
||||
func (r *objReader) readSym() {
|
||||
var c byte
|
||||
var err error
|
||||
if c, err = r.readByte(); c != symPrefix || err != nil {
|
||||
log.Fatalln("readSym out of sync")
|
||||
}
|
||||
if c, err = r.readByte(); err != nil {
|
||||
log.Fatalln("error reading input: ", err)
|
||||
}
|
||||
t := sym.AbiSymKindToSymKind[c]
|
||||
s := r.readSymIndex()
|
||||
flags := r.readInt()
|
||||
dupok := flags&1 != 0
|
||||
local := flags&2 != 0
|
||||
makeTypelink := flags&4 != 0
|
||||
size := r.readInt()
|
||||
typ := r.readSymIndex()
|
||||
data := r.readData()
|
||||
nreloc := r.readInt()
|
||||
isdup := false
|
||||
|
||||
var dup *sym.Symbol
|
||||
if s.Type != 0 && s.Type != sym.SXREF {
|
||||
if (t == sym.SDATA || t == sym.SBSS || t == sym.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
|
||||
if s.Size < int64(size) {
|
||||
s.Size = int64(size)
|
||||
}
|
||||
if typ != nil && s.Gotype == nil {
|
||||
s.Gotype = typ
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (s.Type == sym.SDATA || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
|
||||
goto overwrite
|
||||
}
|
||||
if s.Type != sym.SBSS && s.Type != sym.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
|
||||
log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn)
|
||||
}
|
||||
if len(s.P) > 0 {
|
||||
dup = s
|
||||
s = r.dupSym
|
||||
isdup = true
|
||||
}
|
||||
}
|
||||
|
||||
overwrite:
|
||||
s.File = r.pkgpref[:len(r.pkgpref)-1]
|
||||
s.Unit = r.unit
|
||||
if dupok {
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
}
|
||||
if t == sym.SXREF {
|
||||
log.Fatalf("bad sxref")
|
||||
}
|
||||
if t == 0 {
|
||||
log.Fatalf("missing type for %s in %s", s.Name, r.pn)
|
||||
}
|
||||
if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
|
||||
t = s.Type
|
||||
}
|
||||
s.Type = t
|
||||
if s.Size < int64(size) {
|
||||
s.Size = int64(size)
|
||||
}
|
||||
s.Attr.Set(sym.AttrLocal, local)
|
||||
s.Attr.Set(sym.AttrMakeTypelink, makeTypelink)
|
||||
if typ != nil {
|
||||
s.Gotype = typ
|
||||
}
|
||||
if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def
|
||||
dup.Gotype = typ
|
||||
}
|
||||
s.P = data
|
||||
s.Attr.Set(sym.AttrReadOnly, r.dataReadOnly)
|
||||
if nreloc > 0 {
|
||||
s.R = r.reloc[:nreloc:nreloc]
|
||||
if !isdup {
|
||||
r.reloc = r.reloc[nreloc:]
|
||||
}
|
||||
|
||||
for i := 0; i < nreloc; i++ {
|
||||
s.R[i] = sym.Reloc{
|
||||
Off: r.readInt32(),
|
||||
Siz: r.readUint8(),
|
||||
Type: objabi.RelocType(r.readInt32()),
|
||||
Add: r.readInt64(),
|
||||
Sym: r.readSymIndex(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.Type == sym.STEXT {
|
||||
s.FuncInfo = new(sym.FuncInfo)
|
||||
pc := s.FuncInfo
|
||||
|
||||
pc.Args = r.readInt32()
|
||||
pc.Locals = r.readInt32()
|
||||
s.Align = r.readInt32()
|
||||
if r.readUint8() != 0 {
|
||||
s.Attr |= sym.AttrNoSplit
|
||||
}
|
||||
flags := r.readInt()
|
||||
if flags&(1<<2) != 0 {
|
||||
s.Attr |= sym.AttrReflectMethod
|
||||
}
|
||||
if flags&(1<<3) != 0 {
|
||||
s.Attr |= sym.AttrShared
|
||||
}
|
||||
if flags&(1<<4) != 0 {
|
||||
s.Attr |= sym.AttrTopFrame
|
||||
}
|
||||
n := r.readInt()
|
||||
if n != 0 {
|
||||
log.Fatalf("stale object file: autom count nonzero")
|
||||
}
|
||||
|
||||
pc.Pcsp.P = r.readData()
|
||||
pc.Pcfile.P = r.readData()
|
||||
pc.Pcline.P = r.readData()
|
||||
pc.Pcinline.P = r.readData()
|
||||
n = r.readInt()
|
||||
pc.Pcdata = r.pcdata[:n:n]
|
||||
if !isdup {
|
||||
r.pcdata = r.pcdata[n:]
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
pc.Pcdata[i].P = r.readData()
|
||||
}
|
||||
n = r.readInt()
|
||||
pc.Funcdata = r.funcdata[:n:n]
|
||||
pc.Funcdataoff = r.funcdataoff[:n:n]
|
||||
if !isdup {
|
||||
r.funcdata = r.funcdata[n:]
|
||||
r.funcdataoff = r.funcdataoff[n:]
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
pc.Funcdata[i] = r.readSymIndex()
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
pc.Funcdataoff[i] = r.readInt64()
|
||||
}
|
||||
n = r.readInt()
|
||||
pc.File = r.file[:n:n]
|
||||
if !isdup {
|
||||
r.file = r.file[n:]
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
pc.File[i] = r.readSymIndex()
|
||||
}
|
||||
n = r.readInt()
|
||||
pc.InlTree = make([]sym.InlinedCall, n)
|
||||
for i := 0; i < n; i++ {
|
||||
pc.InlTree[i].Parent = r.readInt32()
|
||||
pc.InlTree[i].File = r.readSymIndex()
|
||||
pc.InlTree[i].Line = r.readInt32()
|
||||
pc.InlTree[i].Func = r.readSymIndex().Name
|
||||
pc.InlTree[i].ParentPC = r.readInt32()
|
||||
}
|
||||
|
||||
if !dupok {
|
||||
if s.Attr.OnList() {
|
||||
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
r.lib.Textp = append(r.lib.Textp, s)
|
||||
} else {
|
||||
// there may ba a dup in another package
|
||||
// put into a temp list and add to text later
|
||||
if !isdup {
|
||||
r.lib.DupTextSyms = append(r.lib.DupTextSyms, s)
|
||||
} else {
|
||||
r.lib.DupTextSyms = append(r.lib.DupTextSyms, dup)
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.Type == sym.SDWARFINFO {
|
||||
r.patchDWARFName(s)
|
||||
}
|
||||
|
||||
if isdup && r.flags&(StrictDupsWarnFlag|StrictDupsErrFlag) != 0 {
|
||||
// Compare the just-read symbol with the previously read
|
||||
// symbol of the same name, verifying that they have the same
|
||||
// payload. If not, issue a warning and possibly an error.
|
||||
if !bytes.Equal(s.P, dup.P) {
|
||||
reason := "same length but different contents"
|
||||
if len(s.P) != len(dup.P) {
|
||||
reason = fmt.Sprintf("new length %d != old length %d",
|
||||
len(data), len(dup.P))
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Unit.Lib, reason)
|
||||
|
||||
// For the moment, whitelist DWARF subprogram DIEs for
|
||||
// auto-generated wrapper functions. What seems to happen
|
||||
// here is that we get different line numbers on formal
|
||||
// params; I am guessing that the pos is being inherited
|
||||
// from the spot where the wrapper is needed.
|
||||
whitelist := (strings.HasPrefix(dup.Name, "go.info.go.interface") ||
|
||||
strings.HasPrefix(dup.Name, "go.info.go.builtin") ||
|
||||
strings.HasPrefix(dup.Name, "go.isstmt.go.builtin") ||
|
||||
strings.HasPrefix(dup.Name, "go.debuglines"))
|
||||
if !whitelist {
|
||||
r.strictDupMsgs++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *objReader) patchDWARFName(s *sym.Symbol) {
|
||||
// This is kind of ugly. Really the package name should not
|
||||
// even be included here.
|
||||
if s.Size < 1 || s.P[0] != dwarf.DW_ABRV_FUNCTION {
|
||||
return
|
||||
}
|
||||
e := bytes.IndexByte(s.P, 0)
|
||||
if e == -1 {
|
||||
return
|
||||
}
|
||||
p := bytes.Index(s.P[:e], emptyPkg)
|
||||
if p == -1 {
|
||||
return
|
||||
}
|
||||
pkgprefix := []byte(r.pkgpref)
|
||||
patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
|
||||
|
||||
s.P = append(patched, s.P[e:]...)
|
||||
delta := int64(len(s.P)) - s.Size
|
||||
s.Size = int64(len(s.P))
|
||||
for i := range s.R {
|
||||
r := &s.R[i]
|
||||
if r.Off > int32(e) {
|
||||
r.Off += int32(delta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *objReader) readFull(b []byte) {
|
||||
if r.roObject != nil {
|
||||
copy(b, r.roObject[r.roOffset:])
|
||||
r.roOffset += int64(len(b))
|
||||
return
|
||||
}
|
||||
_, err := io.ReadFull(r.rd, b)
|
||||
if err != nil {
|
||||
log.Fatalf("%s: error reading %s", r.pn, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *objReader) readByte() (byte, error) {
|
||||
if r.roObject != nil {
|
||||
b := r.roObject[r.roOffset]
|
||||
r.roOffset++
|
||||
return b, nil
|
||||
}
|
||||
return r.rd.ReadByte()
|
||||
}
|
||||
|
||||
func (r *objReader) peek(n int) ([]byte, error) {
|
||||
if r.roObject != nil {
|
||||
return r.roObject[r.roOffset : r.roOffset+int64(n)], nil
|
||||
}
|
||||
return r.rd.Peek(n)
|
||||
}
|
||||
|
||||
func (r *objReader) readRef() {
|
||||
if c, err := r.readByte(); c != symPrefix || err != nil {
|
||||
log.Fatalf("readSym out of sync")
|
||||
}
|
||||
name := r.readSymName()
|
||||
var v int
|
||||
if abi := r.readInt(); abi == -1 {
|
||||
// Static
|
||||
v = r.localSymVersion
|
||||
} else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {
|
||||
// Note that data symbols are "ABI0", which maps to version 0.
|
||||
v = abiver
|
||||
} else {
|
||||
log.Fatalf("invalid symbol ABI for %q: %d", name, abi)
|
||||
}
|
||||
s := r.syms.Lookup(name, v)
|
||||
r.refs = append(r.refs, s)
|
||||
|
||||
if s == nil || v == r.localSymVersion {
|
||||
return
|
||||
}
|
||||
if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
|
||||
x, err := strconv.ParseUint(s.Name[5:], 16, 64)
|
||||
if err != nil {
|
||||
log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
|
||||
}
|
||||
s.Type = sym.SRODATA
|
||||
s.Attr |= sym.AttrLocal
|
||||
switch s.Name[:5] {
|
||||
case "$f32.":
|
||||
if uint64(uint32(x)) != x {
|
||||
log.Panicf("$-symbol %s too large: %d", s.Name, x)
|
||||
}
|
||||
s.AddUint32(r.arch, uint32(x))
|
||||
case "$f64.", "$i64.":
|
||||
s.AddUint64(r.arch, x)
|
||||
default:
|
||||
log.Panicf("unrecognized $-symbol: %s", s.Name)
|
||||
}
|
||||
s.Attr.Set(sym.AttrReachable, false)
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "runtime.gcbits.") {
|
||||
s.Attr |= sym.AttrLocal
|
||||
}
|
||||
}
|
||||
|
||||
func (r *objReader) readInt64() int64 {
|
||||
uv := uint64(0)
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
log.Fatalf("corrupt input")
|
||||
}
|
||||
c, err := r.readByte()
|
||||
if err != nil {
|
||||
log.Fatalln("error reading input: ", err)
|
||||
}
|
||||
uv |= uint64(c&0x7F) << shift
|
||||
if c&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return int64(uv>>1) ^ (int64(uv<<63) >> 63)
|
||||
}
|
||||
|
||||
func (r *objReader) readInt() int {
|
||||
n := r.readInt64()
|
||||
if int64(int(n)) != n {
|
||||
log.Panicf("%v out of range for int", n)
|
||||
}
|
||||
return int(n)
|
||||
}
|
||||
|
||||
func (r *objReader) readInt32() int32 {
|
||||
n := r.readInt64()
|
||||
if int64(int32(n)) != n {
|
||||
log.Panicf("%v out of range for int32", n)
|
||||
}
|
||||
return int32(n)
|
||||
}
|
||||
|
||||
func (r *objReader) readInt16() int16 {
|
||||
n := r.readInt64()
|
||||
if int64(int16(n)) != n {
|
||||
log.Panicf("%v out of range for int16", n)
|
||||
}
|
||||
return int16(n)
|
||||
}
|
||||
|
||||
func (r *objReader) readUint8() uint8 {
|
||||
n := r.readInt64()
|
||||
if int64(uint8(n)) != n {
|
||||
log.Panicf("%v out of range for uint8", n)
|
||||
}
|
||||
return uint8(n)
|
||||
}
|
||||
|
||||
func (r *objReader) readString() string {
|
||||
n := r.readInt()
|
||||
if cap(r.rdBuf) < n {
|
||||
r.rdBuf = make([]byte, 2*n)
|
||||
}
|
||||
r.readFull(r.rdBuf[:n])
|
||||
return string(r.rdBuf[:n])
|
||||
}
|
||||
|
||||
func (r *objReader) readData() []byte {
|
||||
n := r.readInt()
|
||||
p := r.data[:n:n]
|
||||
r.data = r.data[n:]
|
||||
return p
|
||||
}
|
||||
|
||||
func mkROString(rodata []byte) string {
|
||||
if len(rodata) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var s string
|
||||
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
|
||||
hdr.Data = unsafe.Pointer(&rodata[0])
|
||||
hdr.Len = len(rodata)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// readSymName reads a symbol name, replacing all "". with pkg.
|
||||
func (r *objReader) readSymName() string {
|
||||
n := r.readInt()
|
||||
if n == 0 {
|
||||
r.readInt64()
|
||||
return ""
|
||||
}
|
||||
if cap(r.rdBuf) < n {
|
||||
r.rdBuf = make([]byte, 2*n)
|
||||
}
|
||||
sOffset := r.roOffset
|
||||
origName, err := r.peek(n)
|
||||
if err == bufio.ErrBufferFull {
|
||||
// Long symbol names are rare but exist. One source is type
|
||||
// symbols for types with long string forms. See #15104.
|
||||
origName = make([]byte, n)
|
||||
r.readFull(origName)
|
||||
} else if err != nil {
|
||||
log.Fatalf("%s: error reading symbol: %v", r.pn, err)
|
||||
}
|
||||
adjName := r.rdBuf[:0]
|
||||
nPkgRefs := 0
|
||||
for {
|
||||
i := bytes.Index(origName, emptyPkg)
|
||||
if i == -1 {
|
||||
var s string
|
||||
if r.roObject != nil && nPkgRefs == 0 {
|
||||
s = mkROString(r.roObject[sOffset : sOffset+int64(n)])
|
||||
} else {
|
||||
s = string(append(adjName, origName...))
|
||||
}
|
||||
// Read past the peeked origName, now that we're done with it,
|
||||
// using the rfBuf (also no longer used) as the scratch space.
|
||||
// TODO: use bufio.Reader.Discard if available instead?
|
||||
if err == nil {
|
||||
r.readFull(r.rdBuf[:n])
|
||||
}
|
||||
r.rdBuf = adjName[:0] // in case 2*n wasn't enough
|
||||
return s
|
||||
}
|
||||
nPkgRefs++
|
||||
adjName = append(adjName, origName[:i]...)
|
||||
adjName = append(adjName, r.pkgpref[:len(r.pkgpref)-1]...)
|
||||
adjName = append(adjName, '.')
|
||||
origName = origName[i+len(emptyPkg):]
|
||||
}
|
||||
}
|
||||
|
||||
// Reads the index of a symbol reference and resolves it to a symbol
|
||||
func (r *objReader) readSymIndex() *sym.Symbol {
|
||||
i := r.readInt()
|
||||
return r.refs[i]
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,74 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ppc64
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// cmd/9l/l.h from Vita Nuova.
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
maxAlign = 32 // max data alignment
|
||||
minAlign = 1 // min data alignment
|
||||
funcAlign = 16
|
||||
)
|
||||
|
||||
/* Used by ../internal/ld/dwarf.go */
|
||||
const (
|
||||
dwarfRegSP = 1
|
||||
dwarfRegLR = 65
|
||||
)
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
// Inferno utils/5l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ppc64
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
)
|
||||
|
||||
func Init() (*sys.Arch, ld.Arch) {
|
||||
arch := sys.ArchPPC64
|
||||
if objabi.GOARCH == "ppc64le" {
|
||||
arch = sys.ArchPPC64LE
|
||||
}
|
||||
|
||||
theArch := ld.Arch{
|
||||
Funcalign: funcAlign,
|
||||
Maxalign: maxAlign,
|
||||
Minalign: minAlign,
|
||||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
Asmb: asmb,
|
||||
Asmb2: asmb2,
|
||||
Elfreloc1: elfreloc1,
|
||||
Elfsetupplt: elfsetupplt,
|
||||
Gentext: gentext,
|
||||
Trampoline: trampoline,
|
||||
Machoreloc1: machoreloc1,
|
||||
Xcoffreloc1: xcoffreloc1,
|
||||
|
||||
// TODO(austin): ABI v1 uses /usr/lib/ld.so.1,
|
||||
Linuxdynld: "/lib64/ld64.so.1",
|
||||
|
||||
Freebsddynld: "XXX",
|
||||
Openbsddynld: "XXX",
|
||||
Netbsddynld: "XXX",
|
||||
Dragonflydynld: "XXX",
|
||||
Solarisdynld: "XXX",
|
||||
}
|
||||
|
||||
return arch, theArch
|
||||
}
|
||||
|
||||
func archinit(ctxt *ld.Link) {
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Exitf("unknown -H option: %v", ctxt.HeadType)
|
||||
|
||||
case objabi.Hplan9: /* plan 9 */
|
||||
ld.HEADR = 32
|
||||
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 4128
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 4096
|
||||
}
|
||||
|
||||
case objabi.Hlinux: /* ppc64 elf */
|
||||
ld.Elfinit(ctxt)
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 0x10000
|
||||
}
|
||||
|
||||
case objabi.Haix:
|
||||
ld.Xcoffinit(ctxt)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,168 +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 riscv64
|
||||
|
||||
import (
|
||||
"cmd/internal/obj/riscv"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func gentext(ctxt *ld.Link) {
|
||||
}
|
||||
|
||||
func adddynrela(ctxt *ld.Link, rel *sym.Symbol, s *sym.Symbol, r *sym.Reloc) {
|
||||
log.Fatalf("adddynrela not implemented")
|
||||
}
|
||||
|
||||
func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
log.Fatalf("adddynrel not implemented")
|
||||
return false
|
||||
}
|
||||
|
||||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
log.Fatalf("elfreloc1")
|
||||
return false
|
||||
}
|
||||
|
||||
func elfsetupplt(ctxt *ld.Link) {
|
||||
log.Fatalf("elfsetuplt")
|
||||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
log.Fatalf("machoreloc1 not implemented")
|
||||
return false
|
||||
}
|
||||
|
||||
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
|
||||
switch r.Type {
|
||||
case objabi.R_CALLRISCV:
|
||||
// Nothing to do.
|
||||
return val, true
|
||||
|
||||
case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE:
|
||||
pc := s.Value + int64(r.Off)
|
||||
off := ld.Symaddr(r.Sym) + r.Add - pc
|
||||
|
||||
// Generate AUIPC and second instruction immediates.
|
||||
low, high, err := riscv.Split32BitImmediate(off)
|
||||
if err != nil {
|
||||
ld.Errorf(s, "R_RISCV_PCREL_ relocation does not fit in 32-bits: %d", off)
|
||||
}
|
||||
|
||||
auipcImm, err := riscv.EncodeUImmediate(high)
|
||||
if err != nil {
|
||||
ld.Errorf(s, "cannot encode R_RISCV_PCREL_ AUIPC relocation offset for %s: %v", r.Sym.Name, err)
|
||||
}
|
||||
|
||||
var secondImm, secondImmMask int64
|
||||
switch r.Type {
|
||||
case objabi.R_RISCV_PCREL_ITYPE:
|
||||
secondImmMask = riscv.ITypeImmMask
|
||||
secondImm, err = riscv.EncodeIImmediate(low)
|
||||
if err != nil {
|
||||
ld.Errorf(s, "cannot encode R_RISCV_PCREL_ITYPE I-type instruction relocation offset for %s: %v", r.Sym.Name, err)
|
||||
}
|
||||
case objabi.R_RISCV_PCREL_STYPE:
|
||||
secondImmMask = riscv.STypeImmMask
|
||||
secondImm, err = riscv.EncodeSImmediate(low)
|
||||
if err != nil {
|
||||
ld.Errorf(s, "cannot encode R_RISCV_PCREL_STYPE S-type instruction relocation offset for %s: %v", r.Sym.Name, err)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown relocation type: %v", r.Type))
|
||||
}
|
||||
|
||||
auipc := int64(uint32(val))
|
||||
second := int64(uint32(val >> 32))
|
||||
|
||||
auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm))
|
||||
second = (second &^ secondImmMask) | int64(uint32(secondImm))
|
||||
|
||||
return second<<32 | auipc, true
|
||||
}
|
||||
|
||||
return val, false
|
||||
}
|
||||
|
||||
func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
|
||||
log.Fatalf("archrelocvariant")
|
||||
return -1
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect := ld.Segtext.Sections[0]
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
for _, sect = range ld.Segtext.Sections[1:] {
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
if ld.Segrelrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
|
||||
ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
|
||||
}
|
||||
|
||||
func asmb2(ctxt *ld.Link) {
|
||||
ld.Symsize = 0
|
||||
ld.Lcsize = 0
|
||||
symo := uint32(0)
|
||||
|
||||
if !*ld.FlagS {
|
||||
if !ctxt.IsELF {
|
||||
ld.Errorf(nil, "unsupported executable format")
|
||||
}
|
||||
|
||||
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
|
||||
ctxt.Out.SeekSet(int64(symo))
|
||||
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Elfemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(0)
|
||||
switch ctxt.HeadType {
|
||||
case objabi.Hlinux:
|
||||
ld.Asmbelf(ctxt, int64(symo))
|
||||
default:
|
||||
ld.Errorf(nil, "unsupported operating system")
|
||||
}
|
||||
ctxt.Out.Flush()
|
||||
|
||||
if *ld.FlagC {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +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 riscv64
|
||||
|
||||
const (
|
||||
maxAlign = 32 // max data alignment
|
||||
minAlign = 1
|
||||
funcAlign = 8
|
||||
|
||||
dwarfRegLR = 1
|
||||
dwarfRegSP = 2
|
||||
)
|
||||
|
|
@ -1,60 +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 riscv64
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
)
|
||||
|
||||
func Init() (*sys.Arch, ld.Arch) {
|
||||
arch := sys.ArchRISCV64
|
||||
|
||||
theArch := ld.Arch{
|
||||
Funcalign: funcAlign,
|
||||
Maxalign: maxAlign,
|
||||
Minalign: minAlign,
|
||||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
Asmb: asmb,
|
||||
Asmb2: asmb2,
|
||||
Elfreloc1: elfreloc1,
|
||||
Elfsetupplt: elfsetupplt,
|
||||
Gentext: gentext,
|
||||
Machoreloc1: machoreloc1,
|
||||
|
||||
Linuxdynld: "/lib/ld.so.1",
|
||||
|
||||
Freebsddynld: "XXX",
|
||||
Netbsddynld: "XXX",
|
||||
Openbsddynld: "XXX",
|
||||
Dragonflydynld: "XXX",
|
||||
Solarisdynld: "XXX",
|
||||
}
|
||||
|
||||
return arch, theArch
|
||||
}
|
||||
|
||||
func archinit(ctxt *ld.Link) {
|
||||
switch ctxt.HeadType {
|
||||
case objabi.Hlinux:
|
||||
ld.Elfinit(ctxt)
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 0x10000
|
||||
}
|
||||
default:
|
||||
ld.Exitf("unknown -H option: %v", ctxt.HeadType)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,574 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package s390x
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// gentext generates assembly to append the local moduledata to the global
|
||||
// moduledata linked list at initialization time. This is only done if the runtime
|
||||
// is in a different module.
|
||||
//
|
||||
// <go.link.addmoduledata>:
|
||||
// larl %r2, <local.moduledata>
|
||||
// jg <runtime.addmoduledata@plt>
|
||||
// undef
|
||||
//
|
||||
// The job of appending the moduledata is delegated to runtime.addmoduledata.
|
||||
func gentext(ctxt *ld.Link) {
|
||||
if !ctxt.DynlinkingGo() {
|
||||
return
|
||||
}
|
||||
addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
|
||||
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
|
||||
// we're linking a module containing the runtime -> no need for
|
||||
// an init function
|
||||
return
|
||||
}
|
||||
addmoduledata.Attr |= sym.AttrReachable
|
||||
initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
|
||||
initfunc.Type = sym.STEXT
|
||||
initfunc.Attr |= sym.AttrLocal
|
||||
initfunc.Attr |= sym.AttrReachable
|
||||
|
||||
// larl %r2, <local.moduledata>
|
||||
initfunc.AddUint8(0xc0)
|
||||
initfunc.AddUint8(0x20)
|
||||
lmd := initfunc.AddRel()
|
||||
lmd.InitExt()
|
||||
lmd.Off = int32(initfunc.Size)
|
||||
lmd.Siz = 4
|
||||
lmd.Sym = ctxt.Moduledata
|
||||
lmd.Type = objabi.R_PCREL
|
||||
lmd.Variant = sym.RV_390_DBL
|
||||
lmd.Add = 2 + int64(lmd.Siz)
|
||||
initfunc.AddUint32(ctxt.Arch, 0)
|
||||
|
||||
// jg <runtime.addmoduledata[@plt]>
|
||||
initfunc.AddUint8(0xc0)
|
||||
initfunc.AddUint8(0xf4)
|
||||
rel := initfunc.AddRel()
|
||||
rel.InitExt()
|
||||
rel.Off = int32(initfunc.Size)
|
||||
rel.Siz = 4
|
||||
rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
|
||||
rel.Type = objabi.R_CALL
|
||||
rel.Variant = sym.RV_390_DBL
|
||||
rel.Add = 2 + int64(rel.Siz)
|
||||
initfunc.AddUint32(ctxt.Arch, 0)
|
||||
|
||||
// undef (for debugging)
|
||||
initfunc.AddUint32(ctxt.Arch, 0)
|
||||
if ctxt.BuildMode == ld.BuildModePlugin {
|
||||
ctxt.Textp = append(ctxt.Textp, addmoduledata)
|
||||
}
|
||||
ctxt.Textp = append(ctxt.Textp, initfunc)
|
||||
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
|
||||
initarray_entry.Attr |= sym.AttrLocal
|
||||
initarray_entry.Attr |= sym.AttrReachable
|
||||
initarray_entry.Type = sym.SINITARR
|
||||
initarray_entry.AddAddr(ctxt.Arch, initfunc)
|
||||
}
|
||||
|
||||
func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
r.InitExt()
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d", r.Type)
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_12),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT12):
|
||||
ld.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_8),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_16),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC64):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += int64(r.Siz)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT16),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT64):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT16DBL),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32DBL):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_390_DBL
|
||||
r.Add += int64(r.Siz)
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add += int64(targ.Plt())
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT64):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += int64(r.Siz)
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add += int64(targ.Plt())
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_COPY):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GLOB_DAT):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_JMP_SLOT):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_RELATIVE):
|
||||
ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
|
||||
return false
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTOFF):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_GOTOFF
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPC):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += int64(r.Siz)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16DBL),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32DBL):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_390_DBL
|
||||
r.Add += int64(r.Siz)
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPCDBL):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_390_DBL
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += int64(r.Siz)
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTENT):
|
||||
addgotsym(ctxt, targ)
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Variant = sym.RV_390_DBL
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += int64(targ.Got())
|
||||
r.Add += int64(r.Siz)
|
||||
return true
|
||||
}
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write64(uint64(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
case objabi.R_TLS_LE:
|
||||
switch r.Siz {
|
||||
default:
|
||||
return false
|
||||
case 4:
|
||||
// WARNING - silently ignored by linker in ELF64
|
||||
ctxt.Out.Write64(uint64(elf.R_390_TLS_LE32) | uint64(elfsym)<<32)
|
||||
case 8:
|
||||
// WARNING - silently ignored by linker in ELF32
|
||||
ctxt.Out.Write64(uint64(elf.R_390_TLS_LE64) | uint64(elfsym)<<32)
|
||||
}
|
||||
case objabi.R_TLS_IE:
|
||||
switch r.Siz {
|
||||
default:
|
||||
return false
|
||||
case 4:
|
||||
ctxt.Out.Write64(uint64(elf.R_390_TLS_IEENT) | uint64(elfsym)<<32)
|
||||
}
|
||||
case objabi.R_ADDR:
|
||||
switch r.Siz {
|
||||
default:
|
||||
return false
|
||||
case 4:
|
||||
ctxt.Out.Write64(uint64(elf.R_390_32) | uint64(elfsym)<<32)
|
||||
case 8:
|
||||
ctxt.Out.Write64(uint64(elf.R_390_64) | uint64(elfsym)<<32)
|
||||
}
|
||||
case objabi.R_GOTPCREL:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write64(uint64(elf.R_390_GOTENT) | uint64(elfsym)<<32)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_PCREL, objabi.R_PCRELDBL, objabi.R_CALL:
|
||||
elfrel := elf.R_390_NONE
|
||||
isdbl := r.Variant&sym.RV_TYPE_MASK == sym.RV_390_DBL
|
||||
// TODO(mundaym): all DBL style relocations should be
|
||||
// signalled using the variant - see issue 14218.
|
||||
switch r.Type {
|
||||
case objabi.R_PCRELDBL, objabi.R_CALL:
|
||||
isdbl = true
|
||||
}
|
||||
if r.Xsym.Type == sym.SDYNIMPORT && (r.Xsym.ElfType() == elf.STT_FUNC || r.Type == objabi.R_CALL) {
|
||||
if isdbl {
|
||||
switch r.Siz {
|
||||
case 2:
|
||||
elfrel = elf.R_390_PLT16DBL
|
||||
case 4:
|
||||
elfrel = elf.R_390_PLT32DBL
|
||||
}
|
||||
} else {
|
||||
switch r.Siz {
|
||||
case 4:
|
||||
elfrel = elf.R_390_PLT32
|
||||
case 8:
|
||||
elfrel = elf.R_390_PLT64
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if isdbl {
|
||||
switch r.Siz {
|
||||
case 2:
|
||||
elfrel = elf.R_390_PC16DBL
|
||||
case 4:
|
||||
elfrel = elf.R_390_PC32DBL
|
||||
}
|
||||
} else {
|
||||
switch r.Siz {
|
||||
case 2:
|
||||
elfrel = elf.R_390_PC16
|
||||
case 4:
|
||||
elfrel = elf.R_390_PC32
|
||||
case 8:
|
||||
elfrel = elf.R_390_PC64
|
||||
}
|
||||
}
|
||||
}
|
||||
if elfrel == elf.R_390_NONE {
|
||||
return false // unsupported size/dbl combination
|
||||
}
|
||||
ctxt.Out.Write64(uint64(elfrel) | uint64(elfsym)<<32)
|
||||
}
|
||||
|
||||
ctxt.Out.Write64(uint64(r.Xadd))
|
||||
return true
|
||||
}
|
||||
|
||||
func elfsetupplt(ctxt *ld.Link) {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
if plt.Size == 0 {
|
||||
// stg %r1,56(%r15)
|
||||
plt.AddUint8(0xe3)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddUint8(0xf0)
|
||||
plt.AddUint8(0x38)
|
||||
plt.AddUint8(0x00)
|
||||
plt.AddUint8(0x24)
|
||||
// larl %r1,_GLOBAL_OFFSET_TABLE_
|
||||
plt.AddUint8(0xc0)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddPCRelPlus(ctxt.Arch, got, 6)
|
||||
// mvc 48(8,%r15),8(%r1)
|
||||
plt.AddUint8(0xd2)
|
||||
plt.AddUint8(0x07)
|
||||
plt.AddUint8(0xf0)
|
||||
plt.AddUint8(0x30)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddUint8(0x08)
|
||||
// lg %r1,16(%r1)
|
||||
plt.AddUint8(0xe3)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddUint8(0x00)
|
||||
plt.AddUint8(0x04)
|
||||
// br %r1
|
||||
plt.AddUint8(0x07)
|
||||
plt.AddUint8(0xf1)
|
||||
// nopr %r0
|
||||
plt.AddUint8(0x07)
|
||||
plt.AddUint8(0x00)
|
||||
// nopr %r0
|
||||
plt.AddUint8(0x07)
|
||||
plt.AddUint8(0x00)
|
||||
// nopr %r0
|
||||
plt.AddUint8(0x07)
|
||||
plt.AddUint8(0x00)
|
||||
|
||||
// assume got->size == 0 too
|
||||
got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
|
||||
|
||||
got.AddUint64(ctxt.Arch, 0)
|
||||
got.AddUint64(ctxt.Arch, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
return val, false
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case objabi.R_CONST:
|
||||
return r.Add, true
|
||||
case objabi.R_GOTOFF:
|
||||
return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
|
||||
}
|
||||
|
||||
return val, false
|
||||
}
|
||||
|
||||
func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
|
||||
switch r.Variant & sym.RV_TYPE_MASK {
|
||||
default:
|
||||
ld.Errorf(s, "unexpected relocation variant %d", r.Variant)
|
||||
return t
|
||||
|
||||
case sym.RV_NONE:
|
||||
return t
|
||||
|
||||
case sym.RV_390_DBL:
|
||||
if (t & 1) != 0 {
|
||||
ld.Errorf(s, "%s+%v is not 2-byte aligned", r.Sym.Name, r.Sym.Value)
|
||||
}
|
||||
return t >> 1
|
||||
}
|
||||
}
|
||||
|
||||
func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
|
||||
if ctxt.IsELF {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
rela := ctxt.Syms.Lookup(".rela.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
elfsetupplt(ctxt)
|
||||
}
|
||||
// larl %r1,_GLOBAL_OFFSET_TABLE_+index
|
||||
|
||||
plt.AddUint8(0xc0)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddPCRelPlus(ctxt.Arch, got, got.Size+6) // need variant?
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
got.AddAddrPlus(ctxt.Arch, plt, plt.Size+8) // weird but correct
|
||||
// lg %r1,0(%r1)
|
||||
plt.AddUint8(0xe3)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddUint8(0x00)
|
||||
plt.AddUint8(0x00)
|
||||
plt.AddUint8(0x04)
|
||||
// br %r1
|
||||
plt.AddUint8(0x07)
|
||||
plt.AddUint8(0xf1)
|
||||
// basr %r1,%r0
|
||||
plt.AddUint8(0x0d)
|
||||
plt.AddUint8(0x10)
|
||||
// lgf %r1,12(%r1)
|
||||
plt.AddUint8(0xe3)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddUint8(0x10)
|
||||
plt.AddUint8(0x0c)
|
||||
plt.AddUint8(0x00)
|
||||
plt.AddUint8(0x14)
|
||||
// jg .plt
|
||||
plt.AddUint8(0xc0)
|
||||
plt.AddUint8(0xf4)
|
||||
|
||||
plt.AddUint32(ctxt.Arch, uint32(-((plt.Size - 2) >> 1))) // roll-your-own relocation
|
||||
//.plt index
|
||||
plt.AddUint32(ctxt.Arch, uint32(rela.Size)) // rela size before current entry
|
||||
|
||||
// rela
|
||||
rela.AddAddrPlus(ctxt.Arch, got, got.Size-8)
|
||||
|
||||
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_JMP_SLOT)))
|
||||
rela.AddUint64(ctxt.Arch, 0)
|
||||
|
||||
s.SetPlt(int32(plt.Size - 32))
|
||||
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
s.SetGot(int32(got.Size))
|
||||
got.AddUint64(ctxt.Arch, 0)
|
||||
|
||||
if ctxt.IsELF {
|
||||
rela := ctxt.Syms.Lookup(".rela", 0)
|
||||
rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got()))
|
||||
rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_GLOB_DAT)))
|
||||
rela.AddUint64(ctxt.Arch, 0)
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect := ld.Segtext.Sections[0]
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
for _, sect = range ld.Segtext.Sections[1:] {
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
if ld.Segrelrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
|
||||
ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
|
||||
}
|
||||
|
||||
func asmb2(ctxt *ld.Link) {
|
||||
/* output symbol table */
|
||||
ld.Symsize = 0
|
||||
|
||||
ld.Lcsize = 0
|
||||
symo := uint32(0)
|
||||
if !*ld.FlagS {
|
||||
if !ctxt.IsELF {
|
||||
ld.Errorf(nil, "unsupported executable format")
|
||||
}
|
||||
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
|
||||
|
||||
ctxt.Out.SeekSet(int64(symo))
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Elfemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(0)
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Errorf(nil, "unsupported operating system")
|
||||
case objabi.Hlinux:
|
||||
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)
|
||||
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package s390x
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// cmd/9l/l.h from Vita Nuova.
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
maxAlign = 32 // max data alignment
|
||||
minAlign = 2 // min data alignment
|
||||
funcAlign = 16
|
||||
)
|
||||
|
||||
/* Used by ../internal/ld/dwarf.go */
|
||||
const (
|
||||
dwarfRegSP = 15
|
||||
dwarfRegLR = 14
|
||||
)
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
// Inferno utils/5l/obj.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package s390x
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
)
|
||||
|
||||
func Init() (*sys.Arch, ld.Arch) {
|
||||
arch := sys.ArchS390X
|
||||
|
||||
theArch := ld.Arch{
|
||||
Funcalign: funcAlign,
|
||||
Maxalign: maxAlign,
|
||||
Minalign: minAlign,
|
||||
Dwarfregsp: dwarfRegSP,
|
||||
Dwarfreglr: dwarfRegLR,
|
||||
|
||||
Adddynrel: adddynrel,
|
||||
Archinit: archinit,
|
||||
Archreloc: archreloc,
|
||||
Archrelocvariant: archrelocvariant,
|
||||
Asmb: asmb, // in asm.go
|
||||
Asmb2: asmb2, // in asm.go
|
||||
Elfreloc1: elfreloc1,
|
||||
Elfsetupplt: elfsetupplt,
|
||||
Gentext: gentext,
|
||||
Machoreloc1: machoreloc1,
|
||||
|
||||
Linuxdynld: "/lib64/ld64.so.1",
|
||||
|
||||
// not relevant for s390x
|
||||
Freebsddynld: "XXX",
|
||||
Openbsddynld: "XXX",
|
||||
Netbsddynld: "XXX",
|
||||
Dragonflydynld: "XXX",
|
||||
Solarisdynld: "XXX",
|
||||
}
|
||||
|
||||
return arch, theArch
|
||||
}
|
||||
|
||||
func archinit(ctxt *ld.Link) {
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
ld.Exitf("unknown -H option: %v", ctxt.HeadType)
|
||||
|
||||
case objabi.Hlinux: // s390x ELF
|
||||
ld.Elfinit(ctxt)
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 0x10000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
// Copyright 2017 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 sym
|
||||
|
||||
// Attribute is a set of common symbol attributes.
|
||||
type Attribute int32
|
||||
|
||||
const (
|
||||
// AttrDuplicateOK marks a symbol that can be present in multiple object
|
||||
// files.
|
||||
AttrDuplicateOK Attribute = 1 << iota
|
||||
// AttrExternal marks function symbols loaded from host object files.
|
||||
AttrExternal
|
||||
// AttrNoSplit marks functions that cannot split the stack; the linker
|
||||
// cares because it checks that there are no call chains of nosplit
|
||||
// functions that require more than StackLimit bytes (see
|
||||
// lib.go:dostkcheck)
|
||||
AttrNoSplit
|
||||
// AttrReachable marks symbols that are transitively referenced from the
|
||||
// entry points. Unreachable symbols are not written to the output.
|
||||
AttrReachable
|
||||
// AttrCgoExportDynamic and AttrCgoExportStatic mark symbols referenced
|
||||
// by directives written by cgo (in response to //export directives in
|
||||
// the source).
|
||||
AttrCgoExportDynamic
|
||||
AttrCgoExportStatic
|
||||
// AttrSpecial marks symbols that do not have their address (i.e. Value)
|
||||
// computed by the usual mechanism of data.go:dodata() &
|
||||
// data.go:address().
|
||||
AttrSpecial
|
||||
// AttrStackCheck is used by dostkcheck to only check each NoSplit
|
||||
// function's stack usage once.
|
||||
AttrStackCheck
|
||||
// AttrNotInSymbolTable marks symbols that are not written to the symbol table.
|
||||
AttrNotInSymbolTable
|
||||
// AttrOnList marks symbols that are on some list (such as the list of
|
||||
// all text symbols, or one of the lists of data symbols) and is
|
||||
// consulted to avoid bugs where a symbol is put on a list twice.
|
||||
AttrOnList
|
||||
// AttrLocal marks symbols that are only visible within the module
|
||||
// (executable or shared library) being linked. Only relevant when
|
||||
// dynamically linking Go code.
|
||||
AttrLocal
|
||||
// AttrReflectMethod marks certain methods from the reflect package that
|
||||
// can be used to call arbitrary methods. If no symbol with this bit set
|
||||
// is marked as reachable, more dead code elimination can be done.
|
||||
AttrReflectMethod
|
||||
// AttrMakeTypelink Amarks types that should be added to the typelink
|
||||
// table. See typelinks.go:typelinks().
|
||||
AttrMakeTypelink
|
||||
// AttrShared marks symbols compiled with the -shared option.
|
||||
AttrShared
|
||||
// AttrVisibilityHidden symbols are ELF symbols with
|
||||
// visibility set to STV_HIDDEN. They become local symbols in
|
||||
// the final executable. Only relevant when internally linking
|
||||
// on an ELF platform.
|
||||
AttrVisibilityHidden
|
||||
// AttrSubSymbol mostly means that the symbol appears on the Sub list of some
|
||||
// other symbol. Unfortunately, it's not 100% reliable; at least, it's not set
|
||||
// correctly for the .TOC. symbol in Link.dodata. Usually the Outer field of the
|
||||
// symbol points to the symbol whose list it is on, but that it is not set for the
|
||||
// symbols added to .windynamic in initdynimport in pe.go.
|
||||
//
|
||||
// TODO(mwhudson): fix the inconsistencies noticed above.
|
||||
//
|
||||
// Sub lists are used when loading host objects (sections from the host object
|
||||
// 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.
|
||||
//
|
||||
// TODO(mwhudson): perhaps a better name for this is AttrNonGoSymbol.
|
||||
AttrSubSymbol
|
||||
// AttrContainer is set on text symbols that are present as the .Outer for some
|
||||
// other symbol.
|
||||
AttrContainer
|
||||
// AttrTopFrame means that the function is an entry point and unwinders
|
||||
// should stop when they hit this function.
|
||||
AttrTopFrame
|
||||
// AttrReadOnly indicates whether the symbol's content (Symbol.P) is backed by
|
||||
// read-only memory.
|
||||
AttrReadOnly
|
||||
// 19 attributes defined so far.
|
||||
)
|
||||
|
||||
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
|
||||
func (a Attribute) External() bool { return a&AttrExternal != 0 }
|
||||
func (a Attribute) NoSplit() bool { return a&AttrNoSplit != 0 }
|
||||
func (a Attribute) Reachable() bool { return a&AttrReachable != 0 }
|
||||
func (a Attribute) CgoExportDynamic() bool { return a&AttrCgoExportDynamic != 0 }
|
||||
func (a Attribute) CgoExportStatic() bool { return a&AttrCgoExportStatic != 0 }
|
||||
func (a Attribute) Special() bool { return a&AttrSpecial != 0 }
|
||||
func (a Attribute) StackCheck() bool { return a&AttrStackCheck != 0 }
|
||||
func (a Attribute) NotInSymbolTable() bool { return a&AttrNotInSymbolTable != 0 }
|
||||
func (a Attribute) OnList() bool { return a&AttrOnList != 0 }
|
||||
func (a Attribute) Local() bool { return a&AttrLocal != 0 }
|
||||
func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 }
|
||||
func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
|
||||
func (a Attribute) Shared() bool { return a&AttrShared != 0 }
|
||||
func (a Attribute) VisibilityHidden() bool { return a&AttrVisibilityHidden != 0 }
|
||||
func (a Attribute) SubSymbol() bool { return a&AttrSubSymbol != 0 }
|
||||
func (a Attribute) Container() bool { return a&AttrContainer != 0 }
|
||||
func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 }
|
||||
func (a Attribute) ReadOnly() bool { return a&AttrReadOnly != 0 }
|
||||
|
||||
func (a Attribute) CgoExport() bool {
|
||||
return a.CgoExportDynamic() || a.CgoExportStatic()
|
||||
}
|
||||
|
||||
func (a *Attribute) Set(flag Attribute, value bool) {
|
||||
if value {
|
||||
*a |= flag
|
||||
} else {
|
||||
*a &^= flag
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +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 sym
|
||||
|
||||
import "cmd/internal/dwarf"
|
||||
|
||||
// CompilationUnit is an abstraction used by DWARF to represent a chunk of
|
||||
// debug-related data. We create a CompilationUnit per Object file in a
|
||||
// library (so, one for all the Go code, one for each assembly file, etc.).
|
||||
type CompilationUnit struct {
|
||||
Pkg string // The package name, eg ("fmt", or "runtime")
|
||||
Lib *Library // Our library
|
||||
Consts *Symbol // Package constants DIEs
|
||||
PCs []dwarf.Range // PC ranges, relative to Textp[0]
|
||||
DWInfo *dwarf.DWDie // CU root DIE
|
||||
FuncDIEs []*Symbol // Function DIE subtrees
|
||||
AbsFnDIEs []*Symbol // Abstract function DIE subtrees
|
||||
RangeSyms []*Symbol // Symbols for debug_range
|
||||
Textp []*Symbol // Text symbols in this CU
|
||||
DWARFFileTable []string // The file table used to generate the .debug_lines
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright 2017 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 sym
|
||||
|
||||
type Library struct {
|
||||
Objref string
|
||||
Srcref string
|
||||
File string
|
||||
Pkg string
|
||||
Shlib string
|
||||
Hash string
|
||||
ImportStrings []string
|
||||
Imports []*Library
|
||||
Textp []*Symbol // text symbols defined in this library
|
||||
DupTextSyms []*Symbol // dupok text symbols defined in this library
|
||||
Main bool
|
||||
Safe bool
|
||||
Units []*CompilationUnit
|
||||
}
|
||||
|
||||
func (l Library) String() string {
|
||||
return l.Pkg
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
// Copyright 2017 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 sym
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"debug/elf"
|
||||
)
|
||||
|
||||
// Reloc is a relocation.
|
||||
//
|
||||
// The typical Reloc rewrites part of a symbol at offset Off to address Sym.
|
||||
// A Reloc is stored in a slice on the Symbol it rewrites.
|
||||
//
|
||||
// Relocations are generated by the compiler as the type
|
||||
// cmd/internal/obj.Reloc, which is encoded into the object file wire
|
||||
// format and decoded by the linker into this type. A separate type is
|
||||
// used to hold linker-specific state about the relocation.
|
||||
//
|
||||
// Some relocations are created by cmd/link.
|
||||
type Reloc struct {
|
||||
Off int32 // offset to rewrite
|
||||
Siz uint8 // number of bytes to rewrite, 1, 2, or 4
|
||||
Done bool // set to true when relocation is complete
|
||||
Type objabi.RelocType // the relocation type
|
||||
Add int64 // addend
|
||||
Sym *Symbol // symbol the relocation addresses
|
||||
*relocExt // extra fields (see below), may be nil, call InitExt before use
|
||||
}
|
||||
|
||||
// relocExt contains extra fields in Reloc that are used only in
|
||||
// certain cases.
|
||||
type relocExt struct {
|
||||
Xadd int64 // addend passed to external linker
|
||||
Xsym *Symbol // symbol passed to external linker
|
||||
Variant RelocVariant // variation on Type, currently used only on PPC64 and S390X
|
||||
}
|
||||
|
||||
func (r *Reloc) InitExt() {
|
||||
if r.relocExt == nil {
|
||||
r.relocExt = new(relocExt)
|
||||
}
|
||||
}
|
||||
|
||||
// RelocVariant is a linker-internal variation on a relocation.
|
||||
type RelocVariant uint8
|
||||
|
||||
const (
|
||||
RV_NONE RelocVariant = iota
|
||||
RV_POWER_LO
|
||||
RV_POWER_HI
|
||||
RV_POWER_HA
|
||||
RV_POWER_DS
|
||||
|
||||
// RV_390_DBL is a s390x-specific relocation variant that indicates that
|
||||
// the value to be placed into the relocatable field should first be
|
||||
// divided by 2.
|
||||
RV_390_DBL
|
||||
|
||||
RV_CHECK_OVERFLOW RelocVariant = 1 << 7
|
||||
RV_TYPE_MASK RelocVariant = RV_CHECK_OVERFLOW - 1
|
||||
)
|
||||
|
||||
func RelocName(arch *sys.Arch, r objabi.RelocType) string {
|
||||
// We didn't have some relocation types at Go1.4.
|
||||
// Uncomment code when we include those in bootstrap code.
|
||||
|
||||
switch {
|
||||
case r >= objabi.MachoRelocOffset: // Mach-O
|
||||
// nr := (r - objabi.MachoRelocOffset)>>1
|
||||
// switch ctxt.Arch.Family {
|
||||
// case sys.AMD64:
|
||||
// return macho.RelocTypeX86_64(nr).String()
|
||||
// case sys.ARM:
|
||||
// return macho.RelocTypeARM(nr).String()
|
||||
// case sys.ARM64:
|
||||
// return macho.RelocTypeARM64(nr).String()
|
||||
// case sys.I386:
|
||||
// return macho.RelocTypeGeneric(nr).String()
|
||||
// default:
|
||||
// panic("unreachable")
|
||||
// }
|
||||
case r >= objabi.ElfRelocOffset: // ELF
|
||||
nr := r - objabi.ElfRelocOffset
|
||||
switch arch.Family {
|
||||
case sys.AMD64:
|
||||
return elf.R_X86_64(nr).String()
|
||||
case sys.ARM:
|
||||
return elf.R_ARM(nr).String()
|
||||
case sys.ARM64:
|
||||
return elf.R_AARCH64(nr).String()
|
||||
case sys.I386:
|
||||
return elf.R_386(nr).String()
|
||||
case sys.MIPS, sys.MIPS64:
|
||||
return elf.R_MIPS(nr).String()
|
||||
case sys.PPC64:
|
||||
return elf.R_PPC64(nr).String()
|
||||
case sys.S390X:
|
||||
return elf.R_390(nr).String()
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
return r.String()
|
||||
}
|
||||
|
||||
// RelocByOff implements sort.Interface for sorting relocations by offset.
|
||||
type RelocByOff []Reloc
|
||||
|
||||
func (x RelocByOff) Len() int { return len(x) }
|
||||
|
||||
func (x RelocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x RelocByOff) Less(i, j int) bool {
|
||||
a := &x[i]
|
||||
b := &x[j]
|
||||
if a.Off < b.Off {
|
||||
return true
|
||||
}
|
||||
if a.Off > b.Off {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
// Inferno utils/8l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package sym
|
||||
|
||||
// Terrible but standard terminology.
|
||||
// A segment describes a block of file to load into memory.
|
||||
// A section further describes the pieces of that block for
|
||||
// use in debuggers and such.
|
||||
|
||||
type Segment struct {
|
||||
Rwx uint8 // permission as usual unix bits (5 = r-x etc)
|
||||
Vaddr uint64 // virtual address
|
||||
Length uint64 // length in memory
|
||||
Fileoff uint64 // file offset
|
||||
Filelen uint64 // length on disk
|
||||
Sections []*Section
|
||||
}
|
||||
|
||||
type Section struct {
|
||||
Rwx uint8
|
||||
Extnum int16
|
||||
Align int32
|
||||
Name string
|
||||
Vaddr uint64
|
||||
Length uint64
|
||||
Seg *Segment
|
||||
Elfsect interface{} // an *ld.ElfShdr
|
||||
Reloff uint64
|
||||
Rellen uint64
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright 2018 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 sym
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Assert that the size of important structures do not change unexpectedly.
|
||||
|
||||
func TestSizeof(t *testing.T) {
|
||||
const nbit = unsafe.Sizeof(uintptr(0)) * 8
|
||||
const _64bit = nbit == 64
|
||||
|
||||
var tests = []struct {
|
||||
val interface{} // type as a value
|
||||
_32bit uintptr // size on 32bit platforms
|
||||
_64bit uintptr // size on 64bit platforms
|
||||
}{
|
||||
{Symbol{}, 108, 176},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
want := tt._32bit
|
||||
if _64bit {
|
||||
want = tt._64bit
|
||||
}
|
||||
got := reflect.TypeOf(tt.val).Size()
|
||||
if want != got {
|
||||
t.Errorf("%d bit unsafe.Sizeof(%T) = %d, want %d", nbit, tt.val, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,543 +0,0 @@
|
|||
// Copyright 2017 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 sym
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Symbol is an entry in the symbol table.
|
||||
type Symbol struct {
|
||||
Name string
|
||||
Type SymKind
|
||||
Version int16
|
||||
Attr Attribute
|
||||
Dynid int32
|
||||
Align int32
|
||||
Elfsym int32
|
||||
LocalElfsym int32
|
||||
Value int64
|
||||
Size int64
|
||||
Sub *Symbol
|
||||
Outer *Symbol
|
||||
Gotype *Symbol
|
||||
File string // actually package!
|
||||
auxinfo *AuxSymbol
|
||||
Sect *Section
|
||||
FuncInfo *FuncInfo
|
||||
Unit *CompilationUnit
|
||||
// P contains the raw symbol data.
|
||||
P []byte
|
||||
R []Reloc
|
||||
}
|
||||
|
||||
// AuxSymbol contains less-frequently used sym.Symbol fields.
|
||||
type AuxSymbol struct {
|
||||
extname string
|
||||
dynimplib string
|
||||
dynimpvers string
|
||||
localentry uint8
|
||||
plt int32
|
||||
got int32
|
||||
// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
|
||||
// is not set for symbols defined by the packages being linked or by symbols
|
||||
// read by ldelf (and so is left as elf.STT_NOTYPE).
|
||||
elftype elf.SymType
|
||||
}
|
||||
|
||||
const (
|
||||
SymVerABI0 = 0
|
||||
SymVerABIInternal = 1
|
||||
SymVerStatic = 10 // Minimum version used by static (file-local) syms
|
||||
)
|
||||
|
||||
func ABIToVersion(abi obj.ABI) int {
|
||||
switch abi {
|
||||
case obj.ABI0:
|
||||
return SymVerABI0
|
||||
case obj.ABIInternal:
|
||||
return SymVerABIInternal
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func VersionToABI(v int) (obj.ABI, bool) {
|
||||
switch v {
|
||||
case SymVerABI0:
|
||||
return obj.ABI0, true
|
||||
case SymVerABIInternal:
|
||||
return obj.ABIInternal, true
|
||||
}
|
||||
return ^obj.ABI(0), false
|
||||
}
|
||||
|
||||
func (s *Symbol) String() string {
|
||||
if s.Version == 0 {
|
||||
return s.Name
|
||||
}
|
||||
return fmt.Sprintf("%s<%d>", s.Name, s.Version)
|
||||
}
|
||||
|
||||
func (s *Symbol) IsFileLocal() bool {
|
||||
return s.Version >= SymVerStatic
|
||||
}
|
||||
|
||||
func (s *Symbol) ElfsymForReloc() int32 {
|
||||
// If putelfsym created a local version of this symbol, use that in all
|
||||
// relocations.
|
||||
if s.LocalElfsym != 0 {
|
||||
return s.LocalElfsym
|
||||
} else {
|
||||
return s.Elfsym
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Symbol) Length(_ interface{}) int64 {
|
||||
return s.Size
|
||||
}
|
||||
|
||||
func (s *Symbol) Grow(siz int64) {
|
||||
if int64(int(siz)) != siz {
|
||||
log.Fatalf("symgrow size %d too long", siz)
|
||||
}
|
||||
if int64(len(s.P)) >= siz {
|
||||
return
|
||||
}
|
||||
if cap(s.P) < int(siz) {
|
||||
p := make([]byte, 2*(siz+1))
|
||||
s.P = append(p[:0], s.P...)
|
||||
}
|
||||
s.P = s.P[:siz]
|
||||
}
|
||||
|
||||
func (s *Symbol) AddBytes(bytes []byte) int64 {
|
||||
if s.Type == 0 {
|
||||
s.Type = SDATA
|
||||
}
|
||||
s.Attr |= AttrReachable
|
||||
s.P = append(s.P, bytes...)
|
||||
s.Size = int64(len(s.P))
|
||||
|
||||
return s.Size
|
||||
}
|
||||
|
||||
func (s *Symbol) AddUint8(v uint8) int64 {
|
||||
off := s.Size
|
||||
if s.Type == 0 {
|
||||
s.Type = SDATA
|
||||
}
|
||||
s.Attr |= AttrReachable
|
||||
s.Size++
|
||||
s.P = append(s.P, v)
|
||||
|
||||
return off
|
||||
}
|
||||
|
||||
func (s *Symbol) AddUint16(arch *sys.Arch, v uint16) int64 {
|
||||
return s.AddUintXX(arch, uint64(v), 2)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddUint32(arch *sys.Arch, v uint32) int64 {
|
||||
return s.AddUintXX(arch, uint64(v), 4)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddUint64(arch *sys.Arch, v uint64) int64 {
|
||||
return s.AddUintXX(arch, v, 8)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddUint(arch *sys.Arch, v uint64) int64 {
|
||||
return s.AddUintXX(arch, v, arch.PtrSize)
|
||||
}
|
||||
|
||||
func (s *Symbol) SetUint8(arch *sys.Arch, r int64, v uint8) int64 {
|
||||
return s.setUintXX(arch, r, uint64(v), 1)
|
||||
}
|
||||
|
||||
func (s *Symbol) SetUint16(arch *sys.Arch, r int64, v uint16) int64 {
|
||||
return s.setUintXX(arch, r, uint64(v), 2)
|
||||
}
|
||||
|
||||
func (s *Symbol) SetUint32(arch *sys.Arch, r int64, v uint32) int64 {
|
||||
return s.setUintXX(arch, r, uint64(v), 4)
|
||||
}
|
||||
|
||||
func (s *Symbol) SetUint(arch *sys.Arch, r int64, v uint64) int64 {
|
||||
return s.setUintXX(arch, r, v, int64(arch.PtrSize))
|
||||
}
|
||||
|
||||
func (s *Symbol) addAddrPlus(arch *sys.Arch, t *Symbol, add int64, typ objabi.RelocType) int64 {
|
||||
if s.Type == 0 {
|
||||
s.Type = SDATA
|
||||
}
|
||||
s.Attr |= AttrReachable
|
||||
i := s.Size
|
||||
s.Size += int64(arch.PtrSize)
|
||||
s.Grow(s.Size)
|
||||
r := s.AddRel()
|
||||
r.Sym = t
|
||||
r.Off = int32(i)
|
||||
r.Siz = uint8(arch.PtrSize)
|
||||
r.Type = typ
|
||||
r.Add = add
|
||||
return i + int64(r.Siz)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
|
||||
return s.addAddrPlus(arch, t, add, objabi.R_ADDR)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddCURelativeAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
|
||||
return s.addAddrPlus(arch, t, add, objabi.R_ADDRCUOFF)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddPCRelPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
|
||||
if s.Type == 0 {
|
||||
s.Type = SDATA
|
||||
}
|
||||
s.Attr |= AttrReachable
|
||||
i := s.Size
|
||||
s.Size += 4
|
||||
s.Grow(s.Size)
|
||||
r := s.AddRel()
|
||||
r.Sym = t
|
||||
r.Off = int32(i)
|
||||
r.Add = add
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Siz = 4
|
||||
if arch.Family == sys.S390X || arch.Family == sys.PPC64 {
|
||||
r.InitExt()
|
||||
}
|
||||
if arch.Family == sys.S390X {
|
||||
r.Variant = RV_390_DBL
|
||||
}
|
||||
return i + int64(r.Siz)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddAddr(arch *sys.Arch, t *Symbol) int64 {
|
||||
return s.AddAddrPlus(arch, t, 0)
|
||||
}
|
||||
|
||||
func (s *Symbol) SetAddrPlus(arch *sys.Arch, off int64, t *Symbol, add int64) int64 {
|
||||
if s.Type == 0 {
|
||||
s.Type = SDATA
|
||||
}
|
||||
s.Attr |= AttrReachable
|
||||
if off+int64(arch.PtrSize) > s.Size {
|
||||
s.Size = off + int64(arch.PtrSize)
|
||||
s.Grow(s.Size)
|
||||
}
|
||||
|
||||
r := s.AddRel()
|
||||
r.Sym = t
|
||||
r.Off = int32(off)
|
||||
r.Siz = uint8(arch.PtrSize)
|
||||
r.Type = objabi.R_ADDR
|
||||
r.Add = add
|
||||
return off + int64(r.Siz)
|
||||
}
|
||||
|
||||
func (s *Symbol) SetAddr(arch *sys.Arch, off int64, t *Symbol) int64 {
|
||||
return s.SetAddrPlus(arch, off, t, 0)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddSize(arch *sys.Arch, t *Symbol) int64 {
|
||||
if s.Type == 0 {
|
||||
s.Type = SDATA
|
||||
}
|
||||
s.Attr |= AttrReachable
|
||||
i := s.Size
|
||||
s.Size += int64(arch.PtrSize)
|
||||
s.Grow(s.Size)
|
||||
r := s.AddRel()
|
||||
r.Sym = t
|
||||
r.Off = int32(i)
|
||||
r.Siz = uint8(arch.PtrSize)
|
||||
r.Type = objabi.R_SIZE
|
||||
return i + int64(r.Siz)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddAddrPlus4(t *Symbol, add int64) int64 {
|
||||
if s.Type == 0 {
|
||||
s.Type = SDATA
|
||||
}
|
||||
s.Attr |= AttrReachable
|
||||
i := s.Size
|
||||
s.Size += 4
|
||||
s.Grow(s.Size)
|
||||
r := s.AddRel()
|
||||
r.Sym = t
|
||||
r.Off = int32(i)
|
||||
r.Siz = 4
|
||||
r.Type = objabi.R_ADDR
|
||||
r.Add = add
|
||||
return i + int64(r.Siz)
|
||||
}
|
||||
|
||||
func (s *Symbol) AddRel() *Reloc {
|
||||
s.R = append(s.R, Reloc{})
|
||||
return &s.R[len(s.R)-1]
|
||||
}
|
||||
|
||||
func (s *Symbol) AddUintXX(arch *sys.Arch, v uint64, wid int) int64 {
|
||||
off := s.Size
|
||||
s.setUintXX(arch, off, v, int64(wid))
|
||||
return off
|
||||
}
|
||||
|
||||
func (s *Symbol) setUintXX(arch *sys.Arch, off int64, v uint64, wid int64) int64 {
|
||||
if s.Type == 0 {
|
||||
s.Type = SDATA
|
||||
}
|
||||
s.Attr |= AttrReachable
|
||||
if s.Size < off+wid {
|
||||
s.Size = off + wid
|
||||
s.Grow(s.Size)
|
||||
}
|
||||
|
||||
switch wid {
|
||||
case 1:
|
||||
s.P[off] = uint8(v)
|
||||
case 2:
|
||||
arch.ByteOrder.PutUint16(s.P[off:], uint16(v))
|
||||
case 4:
|
||||
arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
|
||||
case 8:
|
||||
arch.ByteOrder.PutUint64(s.P[off:], v)
|
||||
}
|
||||
|
||||
return off + wid
|
||||
}
|
||||
|
||||
func (s *Symbol) makeAuxInfo() {
|
||||
if s.auxinfo == nil {
|
||||
s.auxinfo = &AuxSymbol{extname: s.Name, plt: -1, got: -1}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Symbol) Extname() string {
|
||||
if s.auxinfo == nil {
|
||||
return s.Name
|
||||
}
|
||||
return s.auxinfo.extname
|
||||
}
|
||||
|
||||
func (s *Symbol) SetExtname(n string) {
|
||||
if s.auxinfo == nil {
|
||||
if s.Name == n {
|
||||
return
|
||||
}
|
||||
s.makeAuxInfo()
|
||||
}
|
||||
s.auxinfo.extname = n
|
||||
}
|
||||
|
||||
func (s *Symbol) Dynimplib() string {
|
||||
if s.auxinfo == nil {
|
||||
return ""
|
||||
}
|
||||
return s.auxinfo.dynimplib
|
||||
}
|
||||
|
||||
func (s *Symbol) Dynimpvers() string {
|
||||
if s.auxinfo == nil {
|
||||
return ""
|
||||
}
|
||||
return s.auxinfo.dynimpvers
|
||||
}
|
||||
|
||||
func (s *Symbol) SetDynimplib(lib string) {
|
||||
if s.auxinfo == nil {
|
||||
s.makeAuxInfo()
|
||||
}
|
||||
s.auxinfo.dynimplib = lib
|
||||
}
|
||||
|
||||
func (s *Symbol) SetDynimpvers(vers string) {
|
||||
if s.auxinfo == nil {
|
||||
s.makeAuxInfo()
|
||||
}
|
||||
s.auxinfo.dynimpvers = vers
|
||||
}
|
||||
|
||||
func (s *Symbol) ResetDyninfo() {
|
||||
if s.auxinfo != nil {
|
||||
s.auxinfo.dynimplib = ""
|
||||
s.auxinfo.dynimpvers = ""
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Symbol) Localentry() uint8 {
|
||||
if s.auxinfo == nil {
|
||||
return 0
|
||||
}
|
||||
return s.auxinfo.localentry
|
||||
}
|
||||
|
||||
func (s *Symbol) SetLocalentry(val uint8) {
|
||||
if s.auxinfo == nil {
|
||||
if val != 0 {
|
||||
return
|
||||
}
|
||||
s.makeAuxInfo()
|
||||
}
|
||||
s.auxinfo.localentry = val
|
||||
}
|
||||
|
||||
func (s *Symbol) Plt() int32 {
|
||||
if s.auxinfo == nil {
|
||||
return -1
|
||||
}
|
||||
return s.auxinfo.plt
|
||||
}
|
||||
|
||||
func (s *Symbol) SetPlt(val int32) {
|
||||
if s.auxinfo == nil {
|
||||
if val == -1 {
|
||||
return
|
||||
}
|
||||
s.makeAuxInfo()
|
||||
}
|
||||
s.auxinfo.plt = val
|
||||
}
|
||||
|
||||
func (s *Symbol) Got() int32 {
|
||||
if s.auxinfo == nil {
|
||||
return -1
|
||||
}
|
||||
return s.auxinfo.got
|
||||
}
|
||||
|
||||
func (s *Symbol) SetGot(val int32) {
|
||||
if s.auxinfo == nil {
|
||||
if val == -1 {
|
||||
return
|
||||
}
|
||||
s.makeAuxInfo()
|
||||
}
|
||||
s.auxinfo.got = val
|
||||
}
|
||||
|
||||
func (s *Symbol) ElfType() elf.SymType {
|
||||
if s.auxinfo == nil {
|
||||
return elf.STT_NOTYPE
|
||||
}
|
||||
return s.auxinfo.elftype
|
||||
}
|
||||
|
||||
func (s *Symbol) SetElfType(val elf.SymType) {
|
||||
if s.auxinfo == nil {
|
||||
if val == elf.STT_NOTYPE {
|
||||
return
|
||||
}
|
||||
s.makeAuxInfo()
|
||||
}
|
||||
s.auxinfo.elftype = val
|
||||
}
|
||||
|
||||
// SortSub sorts a linked-list (by Sub) of *Symbol by Value.
|
||||
// Used for sub-symbols when loading host objects (see e.g. ldelf.go).
|
||||
func SortSub(l *Symbol) *Symbol {
|
||||
if l == nil || l.Sub == nil {
|
||||
return l
|
||||
}
|
||||
|
||||
l1 := l
|
||||
l2 := l
|
||||
for {
|
||||
l2 = l2.Sub
|
||||
if l2 == nil {
|
||||
break
|
||||
}
|
||||
l2 = l2.Sub
|
||||
if l2 == nil {
|
||||
break
|
||||
}
|
||||
l1 = l1.Sub
|
||||
}
|
||||
|
||||
l2 = l1.Sub
|
||||
l1.Sub = nil
|
||||
l1 = SortSub(l)
|
||||
l2 = SortSub(l2)
|
||||
|
||||
/* set up lead element */
|
||||
if l1.Value < l2.Value {
|
||||
l = l1
|
||||
l1 = l1.Sub
|
||||
} else {
|
||||
l = l2
|
||||
l2 = l2.Sub
|
||||
}
|
||||
|
||||
le := l
|
||||
|
||||
for {
|
||||
if l1 == nil {
|
||||
for l2 != nil {
|
||||
le.Sub = l2
|
||||
le = l2
|
||||
l2 = l2.Sub
|
||||
}
|
||||
|
||||
le.Sub = nil
|
||||
break
|
||||
}
|
||||
|
||||
if l2 == nil {
|
||||
for l1 != nil {
|
||||
le.Sub = l1
|
||||
le = l1
|
||||
l1 = l1.Sub
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if l1.Value < l2.Value {
|
||||
le.Sub = l1
|
||||
le = l1
|
||||
l1 = l1.Sub
|
||||
} else {
|
||||
le.Sub = l2
|
||||
le = l2
|
||||
l2 = l2.Sub
|
||||
}
|
||||
}
|
||||
|
||||
le.Sub = nil
|
||||
return l
|
||||
}
|
||||
|
||||
type FuncInfo struct {
|
||||
Args int32
|
||||
Locals int32
|
||||
Pcsp Pcdata
|
||||
Pcfile Pcdata
|
||||
Pcline Pcdata
|
||||
Pcinline Pcdata
|
||||
Pcdata []Pcdata
|
||||
Funcdata []*Symbol
|
||||
Funcdataoff []int64
|
||||
File []*Symbol
|
||||
InlTree []InlinedCall
|
||||
}
|
||||
|
||||
// InlinedCall is a node in a local inlining tree (FuncInfo.InlTree).
|
||||
type InlinedCall struct {
|
||||
Parent int32 // index of parent in InlTree
|
||||
File *Symbol // file of the inlined call
|
||||
Line int32 // line number of the inlined call
|
||||
Func string // name of the function that was inlined
|
||||
ParentPC int32 // PC of the instruction just before the inlined body (offset from function start)
|
||||
}
|
||||
|
||||
type Pcdata struct {
|
||||
P []byte
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
// Derived from Inferno utils/6l/l.h and related files.
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package sym
|
||||
|
||||
type Symbols struct {
|
||||
symbolBatch []Symbol
|
||||
|
||||
// Symbol lookup based on name and indexed by version.
|
||||
hash []map[string]*Symbol
|
||||
|
||||
Allsym []*Symbol
|
||||
}
|
||||
|
||||
func NewSymbols() *Symbols {
|
||||
hash := make([]map[string]*Symbol, SymVerStatic)
|
||||
// Preallocate about 2mb for hash of non static symbols
|
||||
hash[0] = make(map[string]*Symbol, 100000)
|
||||
// And another 1mb for internal ABI text symbols.
|
||||
hash[SymVerABIInternal] = make(map[string]*Symbol, 50000)
|
||||
return &Symbols{
|
||||
hash: hash,
|
||||
Allsym: make([]*Symbol, 0, 100000),
|
||||
}
|
||||
}
|
||||
|
||||
func (syms *Symbols) Newsym(name string, v int) *Symbol {
|
||||
batch := syms.symbolBatch
|
||||
if len(batch) == 0 {
|
||||
batch = make([]Symbol, 1000)
|
||||
}
|
||||
s := &batch[0]
|
||||
syms.symbolBatch = batch[1:]
|
||||
|
||||
s.Dynid = -1
|
||||
s.Name = name
|
||||
s.Version = int16(v)
|
||||
syms.Allsym = append(syms.Allsym, s)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Look up the symbol with the given name and version, creating the
|
||||
// symbol if it is not found.
|
||||
func (syms *Symbols) Lookup(name string, v int) *Symbol {
|
||||
m := syms.hash[v]
|
||||
s := m[name]
|
||||
if s != nil {
|
||||
return s
|
||||
}
|
||||
s = syms.Newsym(name, v)
|
||||
m[name] = s
|
||||
return s
|
||||
}
|
||||
|
||||
// Look up the symbol with the given name and version, returning nil
|
||||
// if it is not found.
|
||||
func (syms *Symbols) ROLookup(name string, v int) *Symbol {
|
||||
return syms.hash[v][name]
|
||||
}
|
||||
|
||||
// Add an existing symbol to the symbol table.
|
||||
func (syms *Symbols) Add(s *Symbol) {
|
||||
name := s.Name
|
||||
v := int(s.Version)
|
||||
m := syms.hash[v]
|
||||
if _, ok := m[name]; ok {
|
||||
panic(name + " already added")
|
||||
}
|
||||
m[name] = s
|
||||
}
|
||||
|
||||
// Allocate a new version (i.e. symbol namespace).
|
||||
func (syms *Symbols) IncVersion() int {
|
||||
syms.hash = append(syms.hash, make(map[string]*Symbol))
|
||||
return len(syms.hash) - 1
|
||||
}
|
||||
|
||||
// Rename renames a symbol.
|
||||
func (syms *Symbols) Rename(old, new string, v int, reachparent map[*Symbol]*Symbol) {
|
||||
s := syms.hash[v][old]
|
||||
oldExtName := s.Extname()
|
||||
s.Name = new
|
||||
if oldExtName == old {
|
||||
s.SetExtname(new)
|
||||
}
|
||||
delete(syms.hash[v], old)
|
||||
|
||||
dup := syms.hash[v][new]
|
||||
if dup == nil {
|
||||
syms.hash[v][new] = s
|
||||
} else {
|
||||
if s.Type == 0 {
|
||||
dup.Attr |= s.Attr
|
||||
if s.Attr.Reachable() && reachparent != nil {
|
||||
reachparent[dup] = reachparent[s]
|
||||
}
|
||||
*s = *dup
|
||||
} else if dup.Type == 0 {
|
||||
s.Attr |= dup.Attr
|
||||
if dup.Attr.Reachable() && reachparent != nil {
|
||||
reachparent[s] = reachparent[dup]
|
||||
}
|
||||
*dup = *s
|
||||
syms.hash[v][new] = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
// Derived from Inferno utils/6l/l.h and related files.
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package sym
|
||||
|
||||
// A SymKind describes the kind of memory represented by a symbol.
|
||||
type SymKind uint8
|
||||
|
||||
// Defined SymKind values.
|
||||
//
|
||||
// TODO(rsc): Give idiomatic Go names.
|
||||
//go:generate stringer -type=SymKind
|
||||
const (
|
||||
Sxxx SymKind = iota
|
||||
STEXT
|
||||
SELFRXSECT
|
||||
|
||||
// Read-only sections.
|
||||
STYPE
|
||||
SSTRING
|
||||
SGOSTRING
|
||||
SGOFUNC
|
||||
SGCBITS
|
||||
SRODATA
|
||||
SFUNCTAB
|
||||
|
||||
SELFROSECT
|
||||
SMACHOPLT
|
||||
|
||||
// Read-only sections with relocations.
|
||||
//
|
||||
// Types STYPE-SFUNCTAB above are written to the .rodata section by default.
|
||||
// When linking a shared object, some conceptually "read only" types need to
|
||||
// be written to by relocations and putting them in a section called
|
||||
// ".rodata" interacts poorly with the system linkers. The GNU linkers
|
||||
// support this situation by arranging for sections of the name
|
||||
// ".data.rel.ro.XXX" to be mprotected read only by the dynamic linker after
|
||||
// relocations have applied, so when the Go linker is creating a shared
|
||||
// object it checks all objects of the above types and bumps any object that
|
||||
// has a relocation to it to the corresponding type below, which are then
|
||||
// written to sections with appropriate magic names.
|
||||
STYPERELRO
|
||||
SSTRINGRELRO
|
||||
SGOSTRINGRELRO
|
||||
SGOFUNCRELRO
|
||||
SGCBITSRELRO
|
||||
SRODATARELRO
|
||||
SFUNCTABRELRO
|
||||
|
||||
// Part of .data.rel.ro if it exists, otherwise part of .rodata.
|
||||
STYPELINK
|
||||
SITABLINK
|
||||
SSYMTAB
|
||||
SPCLNTAB
|
||||
|
||||
// Writable sections.
|
||||
SFirstWritable
|
||||
SBUILDINFO
|
||||
SELFSECT
|
||||
SMACHO
|
||||
SMACHOGOT
|
||||
SWINDOWS
|
||||
SELFGOT
|
||||
SNOPTRDATA
|
||||
SINITARR
|
||||
SDATA
|
||||
SXCOFFTOC
|
||||
SBSS
|
||||
SNOPTRBSS
|
||||
SLIBFUZZER_EXTRA_COUNTER
|
||||
STLSBSS
|
||||
SXREF
|
||||
SMACHOSYMSTR
|
||||
SMACHOSYMTAB
|
||||
SMACHOINDIRECTPLT
|
||||
SMACHOINDIRECTGOT
|
||||
SFILEPATH
|
||||
SCONST
|
||||
SDYNIMPORT
|
||||
SHOSTOBJ
|
||||
SUNDEFEXT // Undefined symbol for resolution by external linker
|
||||
|
||||
// Sections for debugging information
|
||||
SDWARFSECT
|
||||
SDWARFINFO
|
||||
SDWARFRANGE
|
||||
SDWARFLOC
|
||||
SDWARFLINES
|
||||
|
||||
// ABI aliases (these never appear in the output)
|
||||
SABIALIAS
|
||||
)
|
||||
|
||||
// AbiSymKindToSymKind maps values read from object files (which are
|
||||
// of type cmd/internal/objabi.SymKind) to values of type SymKind.
|
||||
var AbiSymKindToSymKind = [...]SymKind{
|
||||
Sxxx,
|
||||
STEXT,
|
||||
SRODATA,
|
||||
SNOPTRDATA,
|
||||
SDATA,
|
||||
SBSS,
|
||||
SNOPTRBSS,
|
||||
STLSBSS,
|
||||
SDWARFINFO,
|
||||
SDWARFRANGE,
|
||||
SDWARFLOC,
|
||||
SDWARFLINES,
|
||||
SABIALIAS,
|
||||
SLIBFUZZER_EXTRA_COUNTER,
|
||||
}
|
||||
|
||||
// ReadOnly are the symbol kinds that form read-only sections. In some
|
||||
// cases, if they will require relocations, they are transformed into
|
||||
// rel-ro sections using relROMap.
|
||||
var ReadOnly = []SymKind{
|
||||
STYPE,
|
||||
SSTRING,
|
||||
SGOSTRING,
|
||||
SGOFUNC,
|
||||
SGCBITS,
|
||||
SRODATA,
|
||||
SFUNCTAB,
|
||||
}
|
||||
|
||||
// RelROMap describes the transformation of read-only symbols to rel-ro
|
||||
// symbols.
|
||||
var RelROMap = map[SymKind]SymKind{
|
||||
STYPE: STYPERELRO,
|
||||
SSTRING: SSTRINGRELRO,
|
||||
SGOSTRING: SGOSTRINGRELRO,
|
||||
SGOFUNC: SGOFUNCRELRO,
|
||||
SGCBITS: SGCBITSRELRO,
|
||||
SRODATA: SRODATARELRO,
|
||||
SFUNCTAB: SFUNCTABRELRO,
|
||||
}
|
||||
|
||||
// IsData returns true if the type is a data type.
|
||||
func (t SymKind) IsData() bool {
|
||||
return t == SDATA || t == SNOPTRDATA || t == SBSS || t == SNOPTRBSS
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
// Code generated by "stringer -type=SymKind symkind.go"; DO NOT EDIT.
|
||||
|
||||
package sym
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Sxxx-0]
|
||||
_ = x[STEXT-1]
|
||||
_ = x[SELFRXSECT-2]
|
||||
_ = x[STYPE-3]
|
||||
_ = x[SSTRING-4]
|
||||
_ = x[SGOSTRING-5]
|
||||
_ = x[SGOFUNC-6]
|
||||
_ = x[SGCBITS-7]
|
||||
_ = x[SRODATA-8]
|
||||
_ = x[SFUNCTAB-9]
|
||||
_ = x[SELFROSECT-10]
|
||||
_ = x[SMACHOPLT-11]
|
||||
_ = x[STYPERELRO-12]
|
||||
_ = x[SSTRINGRELRO-13]
|
||||
_ = x[SGOSTRINGRELRO-14]
|
||||
_ = x[SGOFUNCRELRO-15]
|
||||
_ = x[SGCBITSRELRO-16]
|
||||
_ = x[SRODATARELRO-17]
|
||||
_ = x[SFUNCTABRELRO-18]
|
||||
_ = x[STYPELINK-19]
|
||||
_ = x[SITABLINK-20]
|
||||
_ = x[SSYMTAB-21]
|
||||
_ = x[SPCLNTAB-22]
|
||||
_ = x[SFirstWritable-23]
|
||||
_ = x[SBUILDINFO-24]
|
||||
_ = x[SELFSECT-25]
|
||||
_ = x[SMACHO-26]
|
||||
_ = x[SMACHOGOT-27]
|
||||
_ = x[SWINDOWS-28]
|
||||
_ = x[SELFGOT-29]
|
||||
_ = x[SNOPTRDATA-30]
|
||||
_ = x[SINITARR-31]
|
||||
_ = x[SDATA-32]
|
||||
_ = x[SXCOFFTOC-33]
|
||||
_ = x[SBSS-34]
|
||||
_ = x[SNOPTRBSS-35]
|
||||
_ = x[SLIBFUZZER_EXTRA_COUNTER-36]
|
||||
_ = x[STLSBSS-37]
|
||||
_ = x[SXREF-38]
|
||||
_ = x[SMACHOSYMSTR-39]
|
||||
_ = x[SMACHOSYMTAB-40]
|
||||
_ = x[SMACHOINDIRECTPLT-41]
|
||||
_ = x[SMACHOINDIRECTGOT-42]
|
||||
_ = x[SFILEPATH-43]
|
||||
_ = x[SCONST-44]
|
||||
_ = x[SDYNIMPORT-45]
|
||||
_ = x[SHOSTOBJ-46]
|
||||
_ = x[SUNDEFEXT-47]
|
||||
_ = x[SDWARFSECT-48]
|
||||
_ = x[SDWARFINFO-49]
|
||||
_ = x[SDWARFRANGE-50]
|
||||
_ = x[SDWARFLOC-51]
|
||||
_ = x[SDWARFLINES-52]
|
||||
_ = x[SABIALIAS-53]
|
||||
}
|
||||
|
||||
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSFirstWritableSBUILDINFOSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASXCOFFTOCSBSSSNOPTRBSSSLIBFUZZER_EXTRA_COUNTERSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSCONSTSDYNIMPORTSHOSTOBJSUNDEFEXTSDWARFSECTSDWARFINFOSDWARFRANGESDWARFLOCSDWARFLINESSABIALIAS"
|
||||
|
||||
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 220, 230, 238, 244, 253, 261, 268, 278, 286, 291, 300, 304, 313, 337, 344, 349, 361, 373, 390, 407, 416, 422, 432, 440, 449, 459, 469, 480, 489, 500, 509}
|
||||
|
||||
func (i SymKind) String() string {
|
||||
if i >= SymKind(len(_SymKind_index)-1) {
|
||||
return "SymKind(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]]
|
||||
}
|
||||
|
|
@ -1,583 +0,0 @@
|
|||
// Copyright 2018 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 wasm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/oldlink/internal/ld"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"io"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
I32 = 0x7F
|
||||
I64 = 0x7E
|
||||
F32 = 0x7D
|
||||
F64 = 0x7C
|
||||
)
|
||||
|
||||
const (
|
||||
sectionCustom = 0
|
||||
sectionType = 1
|
||||
sectionImport = 2
|
||||
sectionFunction = 3
|
||||
sectionTable = 4
|
||||
sectionMemory = 5
|
||||
sectionGlobal = 6
|
||||
sectionExport = 7
|
||||
sectionStart = 8
|
||||
sectionElement = 9
|
||||
sectionCode = 10
|
||||
sectionData = 11
|
||||
)
|
||||
|
||||
// funcValueOffset is the offset between the PC_F value of a function and the index of the function in WebAssembly
|
||||
const funcValueOffset = 0x1000 // TODO(neelance): make function addresses play nice with heap addresses
|
||||
|
||||
func gentext(ctxt *ld.Link) {
|
||||
}
|
||||
|
||||
type wasmFunc struct {
|
||||
Name string
|
||||
Type uint32
|
||||
Code []byte
|
||||
}
|
||||
|
||||
type wasmFuncType struct {
|
||||
Params []byte
|
||||
Results []byte
|
||||
}
|
||||
|
||||
var wasmFuncTypes = map[string]*wasmFuncType{
|
||||
"_rt0_wasm_js": {Params: []byte{}}, //
|
||||
"wasm_export_run": {Params: []byte{I32, I32}}, // argc, argv
|
||||
"wasm_export_resume": {Params: []byte{}}, //
|
||||
"wasm_export_getsp": {Results: []byte{I32}}, // sp
|
||||
"wasm_pc_f_loop": {Params: []byte{}}, //
|
||||
"runtime.wasmMove": {Params: []byte{I32, I32, I32}}, // dst, src, len
|
||||
"runtime.wasmZero": {Params: []byte{I32, I32}}, // ptr, len
|
||||
"runtime.wasmDiv": {Params: []byte{I64, I64}, Results: []byte{I64}}, // x, y -> x/y
|
||||
"runtime.wasmTruncS": {Params: []byte{F64}, Results: []byte{I64}}, // x -> int(x)
|
||||
"runtime.wasmTruncU": {Params: []byte{F64}, Results: []byte{I64}}, // x -> uint(x)
|
||||
"runtime.gcWriteBarrier": {Params: []byte{I64, I64}}, // ptr, val
|
||||
"cmpbody": {Params: []byte{I64, I64, I64, I64}, Results: []byte{I64}}, // a, alen, b, blen -> -1/0/1
|
||||
"memeqbody": {Params: []byte{I64, I64, I64}, Results: []byte{I64}}, // a, b, len -> 0/1
|
||||
"memcmp": {Params: []byte{I32, I32, I32}, Results: []byte{I32}}, // a, b, len -> <0/0/>0
|
||||
"memchr": {Params: []byte{I32, I32, I32}, Results: []byte{I32}}, // s, c, len -> index
|
||||
}
|
||||
|
||||
func assignAddress(ctxt *ld.Link, sect *sym.Section, n int, s *sym.Symbol, va uint64, isTramp bool) (*sym.Section, int, uint64) {
|
||||
// WebAssembly functions do not live in the same address space as the linear memory.
|
||||
// Instead, WebAssembly automatically assigns indices. Imported functions (section "import")
|
||||
// have indices 0 to n. They are followed by native functions (sections "function" and "code")
|
||||
// with indices n+1 and following.
|
||||
//
|
||||
// The following rules describe how wasm handles function indices and addresses:
|
||||
// PC_F = funcValueOffset + WebAssembly function index (not including the imports)
|
||||
// s.Value = PC = PC_F<<16 + PC_B
|
||||
//
|
||||
// The funcValueOffset is necessary to avoid conflicts with expectations
|
||||
// that the Go runtime has about function addresses.
|
||||
// The field "s.Value" corresponds to the concept of PC at runtime.
|
||||
// However, there is no PC register, only PC_F and PC_B. PC_F denotes the function,
|
||||
// PC_B the resume point inside of that function. The entry of the function has PC_B = 0.
|
||||
s.Sect = sect
|
||||
s.Value = int64(funcValueOffset+va/ld.MINFUNC) << 16 // va starts at zero
|
||||
va += uint64(ld.MINFUNC)
|
||||
return sect, n, va
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {} // dummy
|
||||
|
||||
// asmb writes the final WebAssembly module binary.
|
||||
// Spec: https://webassembly.github.io/spec/core/binary/modules.html
|
||||
func asmb2(ctxt *ld.Link) {
|
||||
types := []*wasmFuncType{
|
||||
// For normal Go functions, the single parameter is PC_B,
|
||||
// the return value is
|
||||
// 0 if the function returned normally or
|
||||
// 1 if the stack needs to be unwound.
|
||||
{Params: []byte{I32}, Results: []byte{I32}},
|
||||
}
|
||||
|
||||
// collect host imports (functions that get imported from the WebAssembly host, usually JavaScript)
|
||||
hostImports := []*wasmFunc{
|
||||
{
|
||||
Name: "debug",
|
||||
Type: lookupType(&wasmFuncType{Params: []byte{I32}}, &types),
|
||||
},
|
||||
}
|
||||
hostImportMap := make(map[*sym.Symbol]int64)
|
||||
for _, fn := range ctxt.Textp {
|
||||
for _, r := range fn.R {
|
||||
if r.Type == objabi.R_WASMIMPORT {
|
||||
hostImportMap[r.Sym] = int64(len(hostImports))
|
||||
hostImports = append(hostImports, &wasmFunc{
|
||||
Name: r.Sym.Name,
|
||||
Type: lookupType(&wasmFuncType{Params: []byte{I32}}, &types),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// collect functions with WebAssembly body
|
||||
var buildid []byte
|
||||
fns := make([]*wasmFunc, len(ctxt.Textp))
|
||||
for i, fn := range ctxt.Textp {
|
||||
wfn := new(bytes.Buffer)
|
||||
if fn.Name == "go.buildid" {
|
||||
writeUleb128(wfn, 0) // number of sets of locals
|
||||
writeI32Const(wfn, 0)
|
||||
wfn.WriteByte(0x0b) // end
|
||||
buildid = fn.P
|
||||
} else {
|
||||
// Relocations have variable length, handle them here.
|
||||
off := int32(0)
|
||||
for _, r := range fn.R {
|
||||
wfn.Write(fn.P[off:r.Off])
|
||||
off = r.Off
|
||||
switch r.Type {
|
||||
case objabi.R_ADDR:
|
||||
writeSleb128(wfn, r.Sym.Value+r.Add)
|
||||
case objabi.R_CALL:
|
||||
writeSleb128(wfn, int64(len(hostImports))+r.Sym.Value>>16-funcValueOffset)
|
||||
case objabi.R_WASMIMPORT:
|
||||
writeSleb128(wfn, hostImportMap[r.Sym])
|
||||
default:
|
||||
ld.Errorf(fn, "bad reloc type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
|
||||
continue
|
||||
}
|
||||
}
|
||||
wfn.Write(fn.P[off:])
|
||||
}
|
||||
|
||||
typ := uint32(0)
|
||||
if sig, ok := wasmFuncTypes[fn.Name]; ok {
|
||||
typ = lookupType(sig, &types)
|
||||
}
|
||||
|
||||
name := nameRegexp.ReplaceAllString(fn.Name, "_")
|
||||
fns[i] = &wasmFunc{Name: name, Type: typ, Code: wfn.Bytes()}
|
||||
}
|
||||
|
||||
ctxt.Out.Write([]byte{0x00, 0x61, 0x73, 0x6d}) // magic
|
||||
ctxt.Out.Write([]byte{0x01, 0x00, 0x00, 0x00}) // version
|
||||
|
||||
// Add any buildid early in the binary:
|
||||
if len(buildid) != 0 {
|
||||
writeBuildID(ctxt, buildid)
|
||||
}
|
||||
|
||||
writeTypeSec(ctxt, types)
|
||||
writeImportSec(ctxt, hostImports)
|
||||
writeFunctionSec(ctxt, fns)
|
||||
writeTableSec(ctxt, fns)
|
||||
writeMemorySec(ctxt)
|
||||
writeGlobalSec(ctxt)
|
||||
writeExportSec(ctxt, len(hostImports))
|
||||
writeElementSec(ctxt, uint64(len(hostImports)), uint64(len(fns)))
|
||||
writeCodeSec(ctxt, fns)
|
||||
writeDataSec(ctxt)
|
||||
writeProducerSec(ctxt)
|
||||
if !*ld.FlagS {
|
||||
writeNameSec(ctxt, len(hostImports), fns)
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
||||
func lookupType(sig *wasmFuncType, types *[]*wasmFuncType) uint32 {
|
||||
for i, t := range *types {
|
||||
if bytes.Equal(sig.Params, t.Params) && bytes.Equal(sig.Results, t.Results) {
|
||||
return uint32(i)
|
||||
}
|
||||
}
|
||||
*types = append(*types, sig)
|
||||
return uint32(len(*types) - 1)
|
||||
}
|
||||
|
||||
func writeSecHeader(ctxt *ld.Link, id uint8) int64 {
|
||||
ctxt.Out.WriteByte(id)
|
||||
sizeOffset := ctxt.Out.Offset()
|
||||
ctxt.Out.Write(make([]byte, 5)) // placeholder for length
|
||||
return sizeOffset
|
||||
}
|
||||
|
||||
func writeSecSize(ctxt *ld.Link, sizeOffset int64) {
|
||||
endOffset := ctxt.Out.Offset()
|
||||
ctxt.Out.SeekSet(sizeOffset)
|
||||
writeUleb128FixedLength(ctxt.Out, uint64(endOffset-sizeOffset-5), 5)
|
||||
ctxt.Out.SeekSet(endOffset)
|
||||
}
|
||||
|
||||
func writeBuildID(ctxt *ld.Link, buildid []byte) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionCustom)
|
||||
writeName(ctxt.Out, "go.buildid")
|
||||
ctxt.Out.Write(buildid)
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeTypeSec writes the section that declares all function types
|
||||
// so they can be referenced by index.
|
||||
func writeTypeSec(ctxt *ld.Link, types []*wasmFuncType) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionType)
|
||||
|
||||
writeUleb128(ctxt.Out, uint64(len(types)))
|
||||
|
||||
for _, t := range types {
|
||||
ctxt.Out.WriteByte(0x60) // functype
|
||||
writeUleb128(ctxt.Out, uint64(len(t.Params)))
|
||||
for _, v := range t.Params {
|
||||
ctxt.Out.WriteByte(byte(v))
|
||||
}
|
||||
writeUleb128(ctxt.Out, uint64(len(t.Results)))
|
||||
for _, v := range t.Results {
|
||||
ctxt.Out.WriteByte(byte(v))
|
||||
}
|
||||
}
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeImportSec writes the section that lists the functions that get
|
||||
// imported from the WebAssembly host, usually JavaScript.
|
||||
func writeImportSec(ctxt *ld.Link, hostImports []*wasmFunc) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionImport)
|
||||
|
||||
writeUleb128(ctxt.Out, uint64(len(hostImports))) // number of imports
|
||||
for _, fn := range hostImports {
|
||||
writeName(ctxt.Out, "go") // provided by the import object in wasm_exec.js
|
||||
writeName(ctxt.Out, fn.Name)
|
||||
ctxt.Out.WriteByte(0x00) // func import
|
||||
writeUleb128(ctxt.Out, uint64(fn.Type))
|
||||
}
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeFunctionSec writes the section that declares the types of functions.
|
||||
// The bodies of these functions will later be provided in the "code" section.
|
||||
func writeFunctionSec(ctxt *ld.Link, fns []*wasmFunc) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionFunction)
|
||||
|
||||
writeUleb128(ctxt.Out, uint64(len(fns)))
|
||||
for _, fn := range fns {
|
||||
writeUleb128(ctxt.Out, uint64(fn.Type))
|
||||
}
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeTableSec writes the section that declares tables. Currently there is only a single table
|
||||
// that is used by the CallIndirect operation to dynamically call any function.
|
||||
// The contents of the table get initialized by the "element" section.
|
||||
func writeTableSec(ctxt *ld.Link, fns []*wasmFunc) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionTable)
|
||||
|
||||
numElements := uint64(funcValueOffset + len(fns))
|
||||
writeUleb128(ctxt.Out, 1) // number of tables
|
||||
ctxt.Out.WriteByte(0x70) // type: anyfunc
|
||||
ctxt.Out.WriteByte(0x00) // no max
|
||||
writeUleb128(ctxt.Out, numElements) // min
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeMemorySec writes the section that declares linear memories. Currently one linear memory is being used.
|
||||
// Linear memory always starts at address zero. More memory can be requested with the GrowMemory instruction.
|
||||
func writeMemorySec(ctxt *ld.Link) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionMemory)
|
||||
|
||||
dataSection := ctxt.Syms.Lookup("runtime.data", 0).Sect
|
||||
dataEnd := dataSection.Vaddr + dataSection.Length
|
||||
var initialSize = dataEnd + 16<<20 // 16MB, enough for runtime init without growing
|
||||
|
||||
const wasmPageSize = 64 << 10 // 64KB
|
||||
|
||||
writeUleb128(ctxt.Out, 1) // number of memories
|
||||
ctxt.Out.WriteByte(0x00) // no maximum memory size
|
||||
writeUleb128(ctxt.Out, initialSize/wasmPageSize) // minimum (initial) memory size
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeGlobalSec writes the section that declares global variables.
|
||||
func writeGlobalSec(ctxt *ld.Link) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionGlobal)
|
||||
|
||||
globalRegs := []byte{
|
||||
I32, // 0: SP
|
||||
I64, // 1: CTXT
|
||||
I64, // 2: g
|
||||
I64, // 3: RET0
|
||||
I64, // 4: RET1
|
||||
I64, // 5: RET2
|
||||
I64, // 6: RET3
|
||||
I32, // 7: PAUSE
|
||||
}
|
||||
|
||||
writeUleb128(ctxt.Out, uint64(len(globalRegs))) // number of globals
|
||||
|
||||
for _, typ := range globalRegs {
|
||||
ctxt.Out.WriteByte(typ)
|
||||
ctxt.Out.WriteByte(0x01) // var
|
||||
switch typ {
|
||||
case I32:
|
||||
writeI32Const(ctxt.Out, 0)
|
||||
case I64:
|
||||
writeI64Const(ctxt.Out, 0)
|
||||
}
|
||||
ctxt.Out.WriteByte(0x0b) // end
|
||||
}
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeExportSec writes the section that declares exports.
|
||||
// Exports can be accessed by the WebAssembly host, usually JavaScript.
|
||||
// The wasm_export_* functions and the linear memory get exported.
|
||||
func writeExportSec(ctxt *ld.Link, lenHostImports int) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionExport)
|
||||
|
||||
writeUleb128(ctxt.Out, 4) // number of exports
|
||||
|
||||
for _, name := range []string{"run", "resume", "getsp"} {
|
||||
idx := uint32(lenHostImports) + uint32(ctxt.Syms.ROLookup("wasm_export_"+name, 0).Value>>16) - funcValueOffset
|
||||
writeName(ctxt.Out, name) // inst.exports.run/resume/getsp in wasm_exec.js
|
||||
ctxt.Out.WriteByte(0x00) // func export
|
||||
writeUleb128(ctxt.Out, uint64(idx)) // funcidx
|
||||
}
|
||||
|
||||
writeName(ctxt.Out, "mem") // inst.exports.mem in wasm_exec.js
|
||||
ctxt.Out.WriteByte(0x02) // mem export
|
||||
writeUleb128(ctxt.Out, 0) // memidx
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeElementSec writes the section that initializes the tables declared by the "table" section.
|
||||
// The table for CallIndirect gets initialized in a very simple way so that each table index (PC_F value)
|
||||
// maps linearly to the function index (numImports + PC_F).
|
||||
func writeElementSec(ctxt *ld.Link, numImports, numFns uint64) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionElement)
|
||||
|
||||
writeUleb128(ctxt.Out, 1) // number of element segments
|
||||
|
||||
writeUleb128(ctxt.Out, 0) // tableidx
|
||||
writeI32Const(ctxt.Out, funcValueOffset)
|
||||
ctxt.Out.WriteByte(0x0b) // end
|
||||
|
||||
writeUleb128(ctxt.Out, numFns) // number of entries
|
||||
for i := uint64(0); i < numFns; i++ {
|
||||
writeUleb128(ctxt.Out, numImports+i)
|
||||
}
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeElementSec writes the section that provides the function bodies for the functions
|
||||
// declared by the "func" section.
|
||||
func writeCodeSec(ctxt *ld.Link, fns []*wasmFunc) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionCode)
|
||||
|
||||
writeUleb128(ctxt.Out, uint64(len(fns))) // number of code entries
|
||||
for _, fn := range fns {
|
||||
writeUleb128(ctxt.Out, uint64(len(fn.Code)))
|
||||
ctxt.Out.Write(fn.Code)
|
||||
}
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeDataSec writes the section that provides data that will be used to initialize the linear memory.
|
||||
func writeDataSec(ctxt *ld.Link) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionData)
|
||||
|
||||
sections := []*sym.Section{
|
||||
ctxt.Syms.Lookup("runtime.rodata", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.typelink", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.itablink", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.symtab", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.pclntab", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect,
|
||||
ctxt.Syms.Lookup("runtime.data", 0).Sect,
|
||||
}
|
||||
|
||||
type dataSegment struct {
|
||||
offset int32
|
||||
data []byte
|
||||
}
|
||||
|
||||
// Omit blocks of zeroes and instead emit data segments with offsets skipping the zeroes.
|
||||
// This reduces the size of the WebAssembly binary. We use 8 bytes as an estimate for the
|
||||
// overhead of adding a new segment (same as wasm-opt's memory-packing optimization uses).
|
||||
const segmentOverhead = 8
|
||||
|
||||
// Generate at most this many segments. A higher number of segments gets rejected by some WebAssembly runtimes.
|
||||
const maxNumSegments = 100000
|
||||
|
||||
var segments []*dataSegment
|
||||
for secIndex, sec := range sections {
|
||||
data := ld.DatblkBytes(ctxt, int64(sec.Vaddr), int64(sec.Length))
|
||||
offset := int32(sec.Vaddr)
|
||||
|
||||
// skip leading zeroes
|
||||
for len(data) > 0 && data[0] == 0 {
|
||||
data = data[1:]
|
||||
offset++
|
||||
}
|
||||
|
||||
for len(data) > 0 {
|
||||
dataLen := int32(len(data))
|
||||
var segmentEnd, zeroEnd int32
|
||||
if len(segments)+(len(sections)-secIndex) == maxNumSegments {
|
||||
segmentEnd = dataLen
|
||||
zeroEnd = dataLen
|
||||
} else {
|
||||
for {
|
||||
// look for beginning of zeroes
|
||||
for segmentEnd < dataLen && data[segmentEnd] != 0 {
|
||||
segmentEnd++
|
||||
}
|
||||
// look for end of zeroes
|
||||
zeroEnd = segmentEnd
|
||||
for zeroEnd < dataLen && data[zeroEnd] == 0 {
|
||||
zeroEnd++
|
||||
}
|
||||
// emit segment if omitting zeroes reduces the output size
|
||||
if zeroEnd-segmentEnd >= segmentOverhead || zeroEnd == dataLen {
|
||||
break
|
||||
}
|
||||
segmentEnd = zeroEnd
|
||||
}
|
||||
}
|
||||
|
||||
segments = append(segments, &dataSegment{
|
||||
offset: offset,
|
||||
data: data[:segmentEnd],
|
||||
})
|
||||
data = data[zeroEnd:]
|
||||
offset += zeroEnd
|
||||
}
|
||||
}
|
||||
|
||||
writeUleb128(ctxt.Out, uint64(len(segments))) // number of data entries
|
||||
for _, seg := range segments {
|
||||
writeUleb128(ctxt.Out, 0) // memidx
|
||||
writeI32Const(ctxt.Out, seg.offset)
|
||||
ctxt.Out.WriteByte(0x0b) // end
|
||||
writeUleb128(ctxt.Out, uint64(len(seg.data)))
|
||||
ctxt.Out.Write(seg.data)
|
||||
}
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
// writeProducerSec writes an optional section that reports the source language and compiler version.
|
||||
func writeProducerSec(ctxt *ld.Link) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionCustom)
|
||||
writeName(ctxt.Out, "producers")
|
||||
|
||||
writeUleb128(ctxt.Out, 2) // number of fields
|
||||
|
||||
writeName(ctxt.Out, "language") // field name
|
||||
writeUleb128(ctxt.Out, 1) // number of values
|
||||
writeName(ctxt.Out, "Go") // value: name
|
||||
writeName(ctxt.Out, objabi.Version) // value: version
|
||||
|
||||
writeName(ctxt.Out, "processed-by") // field name
|
||||
writeUleb128(ctxt.Out, 1) // number of values
|
||||
writeName(ctxt.Out, "Go cmd/compile") // value: name
|
||||
writeName(ctxt.Out, objabi.Version) // value: version
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
var nameRegexp = regexp.MustCompile(`[^\w\.]`)
|
||||
|
||||
// writeNameSec writes an optional section that assigns names to the functions declared by the "func" section.
|
||||
// The names are only used by WebAssembly stack traces, debuggers and decompilers.
|
||||
// TODO(neelance): add symbol table of DATA symbols
|
||||
func writeNameSec(ctxt *ld.Link, firstFnIndex int, fns []*wasmFunc) {
|
||||
sizeOffset := writeSecHeader(ctxt, sectionCustom)
|
||||
writeName(ctxt.Out, "name")
|
||||
|
||||
sizeOffset2 := writeSecHeader(ctxt, 0x01) // function names
|
||||
writeUleb128(ctxt.Out, uint64(len(fns)))
|
||||
for i, fn := range fns {
|
||||
writeUleb128(ctxt.Out, uint64(firstFnIndex+i))
|
||||
writeName(ctxt.Out, fn.Name)
|
||||
}
|
||||
writeSecSize(ctxt, sizeOffset2)
|
||||
|
||||
writeSecSize(ctxt, sizeOffset)
|
||||
}
|
||||
|
||||
type nameWriter interface {
|
||||
io.ByteWriter
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func writeI32Const(w io.ByteWriter, v int32) {
|
||||
w.WriteByte(0x41) // i32.const
|
||||
writeSleb128(w, int64(v))
|
||||
}
|
||||
|
||||
func writeI64Const(w io.ByteWriter, v int64) {
|
||||
w.WriteByte(0x42) // i64.const
|
||||
writeSleb128(w, v)
|
||||
}
|
||||
|
||||
func writeName(w nameWriter, name string) {
|
||||
writeUleb128(w, uint64(len(name)))
|
||||
w.Write([]byte(name))
|
||||
}
|
||||
|
||||
func writeUleb128(w io.ByteWriter, v uint64) {
|
||||
if v < 128 {
|
||||
w.WriteByte(uint8(v))
|
||||
return
|
||||
}
|
||||
more := true
|
||||
for more {
|
||||
c := uint8(v & 0x7f)
|
||||
v >>= 7
|
||||
more = v != 0
|
||||
if more {
|
||||
c |= 0x80
|
||||
}
|
||||
w.WriteByte(c)
|
||||
}
|
||||
}
|
||||
|
||||
func writeUleb128FixedLength(w io.ByteWriter, v uint64, length int) {
|
||||
for i := 0; i < length; i++ {
|
||||
c := uint8(v & 0x7f)
|
||||
v >>= 7
|
||||
if i < length-1 {
|
||||
c |= 0x80
|
||||
}
|
||||
w.WriteByte(c)
|
||||
}
|
||||
if v != 0 {
|
||||
panic("writeUleb128FixedLength: length too small")
|
||||
}
|
||||
}
|
||||
|
||||
func writeSleb128(w io.ByteWriter, v int64) {
|
||||
more := true
|
||||
for more {
|
||||
c := uint8(v & 0x7f)
|
||||
s := uint8(v & 0x40)
|
||||
v >>= 7
|
||||
more = !((v == 0 && s == 0) || (v == -1 && s != 0))
|
||||
if more {
|
||||
c |= 0x80
|
||||
}
|
||||
w.WriteByte(c)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright 2018 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 wasm
|
||||
|
||||
import (
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
)
|
||||
|
||||
func Init() (*sys.Arch, ld.Arch) {
|
||||
theArch := ld.Arch{
|
||||
Funcalign: 16,
|
||||
Maxalign: 32,
|
||||
Minalign: 1,
|
||||
|
||||
Archinit: archinit,
|
||||
AssignAddress: assignAddress,
|
||||
Asmb: asmb,
|
||||
Asmb2: asmb2,
|
||||
Gentext: gentext,
|
||||
}
|
||||
|
||||
return sys.ArchWasm, theArch
|
||||
}
|
||||
|
||||
func archinit(ctxt *ld.Link) {
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 4096
|
||||
}
|
||||
if *ld.FlagTextAddr == -1 {
|
||||
*ld.FlagTextAddr = 0
|
||||
}
|
||||
}
|
||||
|
|
@ -1,699 +0,0 @@
|
|||
// Inferno utils/8l/asm.c
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package x86
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/oldlink/internal/ld"
|
||||
"cmd/oldlink/internal/sym"
|
||||
"debug/elf"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Append 4 bytes to s and create a R_CALL relocation targeting t to fill them in.
|
||||
func addcall(ctxt *ld.Link, s *sym.Symbol, t *sym.Symbol) {
|
||||
s.Attr |= sym.AttrReachable
|
||||
i := s.Size
|
||||
s.Size += 4
|
||||
s.Grow(s.Size)
|
||||
r := s.AddRel()
|
||||
r.Sym = t
|
||||
r.Off = int32(i)
|
||||
r.Type = objabi.R_CALL
|
||||
r.Siz = 4
|
||||
}
|
||||
|
||||
func gentext(ctxt *ld.Link) {
|
||||
if ctxt.DynlinkingGo() {
|
||||
// We need get_pc_thunk.
|
||||
} else {
|
||||
switch ctxt.BuildMode {
|
||||
case ld.BuildModeCArchive:
|
||||
if !ctxt.IsELF {
|
||||
return
|
||||
}
|
||||
case ld.BuildModePIE, ld.BuildModeCShared, ld.BuildModePlugin:
|
||||
// We need get_pc_thunk.
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Generate little thunks that load the PC of the next instruction into a register.
|
||||
thunks := make([]*sym.Symbol, 0, 7+len(ctxt.Textp))
|
||||
for _, r := range [...]struct {
|
||||
name string
|
||||
num uint8
|
||||
}{
|
||||
{"ax", 0},
|
||||
{"cx", 1},
|
||||
{"dx", 2},
|
||||
{"bx", 3},
|
||||
// sp
|
||||
{"bp", 5},
|
||||
{"si", 6},
|
||||
{"di", 7},
|
||||
} {
|
||||
thunkfunc := ctxt.Syms.Lookup("__x86.get_pc_thunk."+r.name, 0)
|
||||
thunkfunc.Type = sym.STEXT
|
||||
thunkfunc.Attr |= sym.AttrLocal
|
||||
thunkfunc.Attr |= sym.AttrReachable //TODO: remove?
|
||||
o := func(op ...uint8) {
|
||||
for _, op1 := range op {
|
||||
thunkfunc.AddUint8(op1)
|
||||
}
|
||||
}
|
||||
// 8b 04 24 mov (%esp),%eax
|
||||
// Destination register is in bits 3-5 of the middle byte, so add that in.
|
||||
o(0x8b, 0x04+r.num<<3, 0x24)
|
||||
// c3 ret
|
||||
o(0xc3)
|
||||
|
||||
thunks = append(thunks, thunkfunc)
|
||||
}
|
||||
ctxt.Textp = append(thunks, ctxt.Textp...) // keep Textp in dependency order
|
||||
|
||||
addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
|
||||
if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
|
||||
// we're linking a module containing the runtime -> no need for
|
||||
// an init function
|
||||
return
|
||||
}
|
||||
|
||||
addmoduledata.Attr |= sym.AttrReachable
|
||||
|
||||
initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
|
||||
initfunc.Type = sym.STEXT
|
||||
initfunc.Attr |= sym.AttrLocal
|
||||
initfunc.Attr |= sym.AttrReachable
|
||||
o := func(op ...uint8) {
|
||||
for _, op1 := range op {
|
||||
initfunc.AddUint8(op1)
|
||||
}
|
||||
}
|
||||
|
||||
// go.link.addmoduledata:
|
||||
// 53 push %ebx
|
||||
// e8 00 00 00 00 call __x86.get_pc_thunk.cx + R_CALL __x86.get_pc_thunk.cx
|
||||
// 8d 81 00 00 00 00 lea 0x0(%ecx), %eax + R_PCREL ctxt.Moduledata
|
||||
// 8d 99 00 00 00 00 lea 0x0(%ecx), %ebx + R_GOTPC _GLOBAL_OFFSET_TABLE_
|
||||
// e8 00 00 00 00 call runtime.addmoduledata@plt + R_CALL runtime.addmoduledata
|
||||
// 5b pop %ebx
|
||||
// c3 ret
|
||||
|
||||
o(0x53)
|
||||
|
||||
o(0xe8)
|
||||
addcall(ctxt, initfunc, ctxt.Syms.Lookup("__x86.get_pc_thunk.cx", 0))
|
||||
|
||||
o(0x8d, 0x81)
|
||||
initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 6)
|
||||
|
||||
o(0x8d, 0x99)
|
||||
i := initfunc.Size
|
||||
initfunc.Size += 4
|
||||
initfunc.Grow(initfunc.Size)
|
||||
r := initfunc.AddRel()
|
||||
r.Sym = ctxt.Syms.Lookup("_GLOBAL_OFFSET_TABLE_", 0)
|
||||
r.Off = int32(i)
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add = 12
|
||||
r.Siz = 4
|
||||
|
||||
o(0xe8)
|
||||
addcall(ctxt, initfunc, addmoduledata)
|
||||
|
||||
o(0x5b)
|
||||
|
||||
o(0xc3)
|
||||
|
||||
if ctxt.BuildMode == ld.BuildModePlugin {
|
||||
ctxt.Textp = append(ctxt.Textp, addmoduledata)
|
||||
}
|
||||
ctxt.Textp = append(ctxt.Textp, initfunc)
|
||||
initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
|
||||
initarray_entry.Attr |= sym.AttrReachable
|
||||
initarray_entry.Attr |= sym.AttrLocal
|
||||
initarray_entry.Type = sym.SINITARR
|
||||
initarray_entry.AddAddr(ctxt.Arch, initfunc)
|
||||
}
|
||||
|
||||
func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
|
||||
targ := r.Sym
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= objabi.ElfRelocOffset {
|
||||
ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Add += 4
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add += int64(targ.Plt())
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
|
||||
s.P[r.Off-2] = 0x8d
|
||||
|
||||
r.Type = objabi.R_GOTOFF
|
||||
return true
|
||||
}
|
||||
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
|
||||
// turn PUSHL of GOT entry into PUSHL of symbol itself.
|
||||
// use unnecessary SS prefix to keep instruction same length.
|
||||
s.P[r.Off-2] = 0x36
|
||||
|
||||
s.P[r.Off-1] = 0x68
|
||||
r.Type = objabi.R_ADDR
|
||||
return true
|
||||
}
|
||||
|
||||
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
addgotsym(ctxt, targ)
|
||||
r.Type = objabi.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
r.Add += int64(targ.Got())
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF):
|
||||
r.Type = objabi.R_GOTOFF
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
|
||||
r.Type = objabi.R_PCREL
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += 4
|
||||
return true
|
||||
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = objabi.R_ADDR
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
|
||||
r.Type = objabi.R_ADDR
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
|
||||
if targ.Type == sym.SDYNIMPORT {
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add = int64(targ.Plt())
|
||||
r.Type = objabi.R_PCREL
|
||||
return true
|
||||
}
|
||||
|
||||
r.Type = objabi.R_PCREL
|
||||
return true
|
||||
|
||||
case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
// have symbol
|
||||
// turn MOVL of GOT entry into LEAL of symbol itself
|
||||
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||
ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
s.P[r.Off-2] = 0x8d
|
||||
r.Type = objabi.R_PCREL
|
||||
return true
|
||||
}
|
||||
|
||||
addgotsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".got", 0)
|
||||
r.Add += int64(targ.Got())
|
||||
r.Type = objabi.R_PCREL
|
||||
return true
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != sym.SDYNIMPORT {
|
||||
return true
|
||||
}
|
||||
switch r.Type {
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
// External linker will do this relocation.
|
||||
return true
|
||||
}
|
||||
addpltsym(ctxt, targ)
|
||||
r.Sym = ctxt.Syms.Lookup(".plt", 0)
|
||||
r.Add = int64(targ.Plt())
|
||||
return true
|
||||
|
||||
case objabi.R_ADDR:
|
||||
if s.Type != sym.SDATA {
|
||||
break
|
||||
}
|
||||
if ctxt.IsELF {
|
||||
ld.Adddynsym(ctxt, targ)
|
||||
rel := ctxt.Syms.Lookup(".rel", 0)
|
||||
rel.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
|
||||
rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32)))
|
||||
r.Type = objabi.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
return true
|
||||
}
|
||||
|
||||
if ctxt.HeadType == objabi.Hdarwin && s.Size == int64(ctxt.Arch.PtrSize) && r.Off == 0 {
|
||||
// Mach-O relocations are a royal pain to lay out.
|
||||
// They use a compact stateful bytecode representation
|
||||
// that is too much bother to deal with.
|
||||
// Instead, interpret the C declaration
|
||||
// void *_Cvar_stderr = &stderr;
|
||||
// as making _Cvar_stderr the name of a GOT entry
|
||||
// for stderr. This is separate from the usual GOT entry,
|
||||
// just in case the C code assigns to the variable,
|
||||
// and of course it only works for single pointers,
|
||||
// but we only need to support cgo and that's all it needs.
|
||||
ld.Adddynsym(ctxt, targ)
|
||||
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
s.Type = got.Type
|
||||
s.Attr |= sym.AttrSubSymbol
|
||||
s.Outer = got
|
||||
s.Sub = got.Sub
|
||||
got.Sub = s
|
||||
s.Value = got.Size
|
||||
got.AddUint32(ctxt.Arch, 0)
|
||||
ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(targ.Dynid))
|
||||
r.Type = objabi.ElfRelocOffset // ignore during relocsym
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
|
||||
ctxt.Out.Write32(uint32(sectoff))
|
||||
|
||||
elfsym := r.Xsym.ElfsymForReloc()
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
case objabi.R_ADDR:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_GOTPCREL:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write32(uint32(elf.R_386_GOTPC))
|
||||
if r.Xsym.Name != "_GLOBAL_OFFSET_TABLE_" {
|
||||
ctxt.Out.Write32(uint32(sectoff))
|
||||
ctxt.Out.Write32(uint32(elf.R_386_GOT32) | uint32(elfsym)<<8)
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_CALL:
|
||||
if r.Siz == 4 {
|
||||
if r.Xsym.Type == sym.SDYNIMPORT {
|
||||
ctxt.Out.Write32(uint32(elf.R_386_PLT32) | uint32(elfsym)<<8)
|
||||
} else {
|
||||
ctxt.Out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_PCREL:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_TLS_LE:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write32(uint32(elf.R_386_TLS_LE) | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case objabi.R_TLS_IE:
|
||||
if r.Siz == 4 {
|
||||
ctxt.Out.Write32(uint32(elf.R_386_GOTPC))
|
||||
ctxt.Out.Write32(uint32(sectoff))
|
||||
ctxt.Out.Write32(uint32(elf.R_386_TLS_GOTIE) | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
|
||||
var v uint32
|
||||
|
||||
rs := r.Xsym
|
||||
|
||||
if rs.Dynid < 0 {
|
||||
ld.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
|
||||
return false
|
||||
}
|
||||
|
||||
out.Write32(uint32(sectoff))
|
||||
out.Write32(uint32(rs.Dynid))
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
return false
|
||||
|
||||
case objabi.R_DWARFSECREF:
|
||||
v = ld.IMAGE_REL_I386_SECREL
|
||||
|
||||
case objabi.R_ADDR:
|
||||
v = ld.IMAGE_REL_I386_DIR32
|
||||
|
||||
case objabi.R_CALL,
|
||||
objabi.R_PCREL:
|
||||
v = ld.IMAGE_REL_I386_REL32
|
||||
}
|
||||
|
||||
out.Write16(uint16(v))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
return val, false
|
||||
}
|
||||
switch r.Type {
|
||||
case objabi.R_CONST:
|
||||
return r.Add, true
|
||||
case objabi.R_GOTOFF:
|
||||
return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
|
||||
}
|
||||
|
||||
return val, false
|
||||
}
|
||||
|
||||
func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
|
||||
log.Fatalf("unexpected relocation variant")
|
||||
return t
|
||||
}
|
||||
|
||||
func elfsetupplt(ctxt *ld.Link) {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
got := ctxt.Syms.Lookup(".got.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
// pushl got+4
|
||||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x35)
|
||||
plt.AddAddrPlus(ctxt.Arch, got, 4)
|
||||
|
||||
// jmp *got+8
|
||||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddAddrPlus(ctxt.Arch, got, 8)
|
||||
|
||||
// zero pad
|
||||
plt.AddUint32(ctxt.Arch, 0)
|
||||
|
||||
// assume got->size == 0 too
|
||||
got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
|
||||
|
||||
got.AddUint32(ctxt.Arch, 0)
|
||||
got.AddUint32(ctxt.Arch, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Plt() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
|
||||
if ctxt.IsELF {
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
got := ctxt.Syms.Lookup(".got.plt", 0)
|
||||
rel := ctxt.Syms.Lookup(".rel.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
elfsetupplt(ctxt)
|
||||
}
|
||||
|
||||
// jmpq *got+size
|
||||
plt.AddUint8(0xff)
|
||||
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddAddrPlus(ctxt.Arch, got, got.Size)
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
got.AddAddrPlus(ctxt.Arch, plt, plt.Size)
|
||||
|
||||
// pushl $x
|
||||
plt.AddUint8(0x68)
|
||||
|
||||
plt.AddUint32(ctxt.Arch, uint32(rel.Size))
|
||||
|
||||
// jmp .plt
|
||||
plt.AddUint8(0xe9)
|
||||
|
||||
plt.AddUint32(ctxt.Arch, uint32(-(plt.Size + 4)))
|
||||
|
||||
// rel
|
||||
rel.AddAddrPlus(ctxt.Arch, got, got.Size-4)
|
||||
|
||||
rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT)))
|
||||
|
||||
s.SetPlt(int32(plt.Size - 16))
|
||||
} else if ctxt.HeadType == objabi.Hdarwin {
|
||||
// Same laziness as in 6l.
|
||||
|
||||
plt := ctxt.Syms.Lookup(".plt", 0)
|
||||
|
||||
addgotsym(ctxt, s)
|
||||
|
||||
ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
s.SetPlt(int32(plt.Size))
|
||||
|
||||
plt.AddUint8(0xff)
|
||||
plt.AddUint8(0x25)
|
||||
plt.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got()))
|
||||
} else {
|
||||
ld.Errorf(s, "addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
|
||||
if s.Got() >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ld.Adddynsym(ctxt, s)
|
||||
got := ctxt.Syms.Lookup(".got", 0)
|
||||
s.SetGot(int32(got.Size))
|
||||
got.AddUint32(ctxt.Arch, 0)
|
||||
|
||||
if ctxt.IsELF {
|
||||
rel := ctxt.Syms.Lookup(".rel", 0)
|
||||
rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got()))
|
||||
rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT)))
|
||||
} else if ctxt.HeadType == objabi.Hdarwin {
|
||||
ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
|
||||
} else {
|
||||
ld.Errorf(s, "addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb(ctxt *ld.Link) {
|
||||
if ctxt.IsELF {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect := ld.Segtext.Sections[0]
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
// 0xCC is INT $3 - breakpoint instruction
|
||||
ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
|
||||
for _, sect = range ld.Segtext.Sections[1:] {
|
||||
ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
if ld.Segrelrodata.Filelen > 0 {
|
||||
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
|
||||
ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
|
||||
}
|
||||
|
||||
func asmb2(ctxt *ld.Link) {
|
||||
machlink := uint32(0)
|
||||
if ctxt.HeadType == objabi.Hdarwin {
|
||||
machlink = uint32(ld.Domacholink(ctxt))
|
||||
}
|
||||
|
||||
ld.Symsize = 0
|
||||
ld.Spsize = 0
|
||||
ld.Lcsize = 0
|
||||
symo := uint32(0)
|
||||
if !*ld.FlagS {
|
||||
// TODO: rationalize
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
if ctxt.IsELF {
|
||||
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
|
||||
}
|
||||
|
||||
case objabi.Hplan9:
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
|
||||
case objabi.Hdarwin:
|
||||
symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
|
||||
|
||||
case objabi.Hwindows:
|
||||
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(int64(symo))
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
if ctxt.IsELF {
|
||||
ld.Asmelfsym(ctxt)
|
||||
ctxt.Out.Flush()
|
||||
ctxt.Out.Write(ld.Elfstrdat)
|
||||
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Elfemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
// Do nothing
|
||||
|
||||
case objabi.Hdarwin:
|
||||
if ctxt.LinkMode == ld.LinkExternal {
|
||||
ld.Machoemitreloc(ctxt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Out.SeekSet(0)
|
||||
switch ctxt.HeadType {
|
||||
default:
|
||||
case objabi.Hplan9: /* plan9 */
|
||||
magic := int32(4*11*11 + 7)
|
||||
|
||||
ctxt.Out.Write32b(uint32(magic)) /* magic */
|
||||
ctxt.Out.Write32b(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||
ctxt.Out.Write32b(uint32(ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32b(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||
ctxt.Out.Write32b(uint32(ld.Symsize)) /* nsyms */
|
||||
ctxt.Out.Write32b(uint32(ld.Entryvalue(ctxt))) /* va of entry */
|
||||
ctxt.Out.Write32b(uint32(ld.Spsize)) /* sp offsets */
|
||||
ctxt.Out.Write32b(uint32(ld.Lcsize)) /* line offsets */
|
||||
|
||||
case objabi.Hdarwin:
|
||||
ld.Asmbmacho(ctxt)
|
||||
|
||||
case objabi.Hlinux,
|
||||
objabi.Hfreebsd,
|
||||
objabi.Hnetbsd,
|
||||
objabi.Hopenbsd:
|
||||
ld.Asmbelf(ctxt, int64(symo))
|
||||
|
||||
case objabi.Hwindows:
|
||||
ld.Asmbpe(ctxt)
|
||||
}
|
||||
|
||||
ctxt.Out.Flush()
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
// Inferno utils/8l/l.h
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package x86
|
||||
|
||||
const (
|
||||
maxAlign = 32 // max data alignment
|
||||
minAlign = 1 // min data alignment
|
||||
funcAlign = 16
|
||||
)
|
||||
|
||||
/* Used by ../internal/ld/dwarf.go */
|
||||
const (
|
||||
dwarfRegSP = 4
|
||||
dwarfRegLR = 8
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue