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")
|
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")
|
Importpath = flag.String("p", "", "set expected package import to path")
|
||||||
Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)")
|
Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)")
|
||||||
|
|
||||||
Go115Newobj = flag.Bool("go115newobj", true, "use new object file format")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ func main() {
|
||||||
}
|
}
|
||||||
ctxt.Flag_dynlink = *flags.Dynlink
|
ctxt.Flag_dynlink = *flags.Dynlink
|
||||||
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
|
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
|
||||||
ctxt.Flag_go115newobj = *flags.Go115Newobj
|
|
||||||
ctxt.IsAsm = true
|
ctxt.IsAsm = true
|
||||||
switch *flags.Spectre {
|
switch *flags.Spectre {
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -997,7 +997,6 @@ func (w *exportWriter) linkname(s *types.Sym) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *exportWriter) symIdx(s *types.Sym) {
|
func (w *exportWriter) symIdx(s *types.Sym) {
|
||||||
if Ctxt.Flag_go115newobj {
|
|
||||||
lsym := s.Linksym()
|
lsym := s.Linksym()
|
||||||
if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
|
if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
|
||||||
// Don't export index for non-package symbols, linkname'd symbols,
|
// 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))
|
w.int64(int64(lsym.SymIdx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Inline bodies.
|
// Inline bodies.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -696,7 +696,6 @@ func (r *importReader) linkname(s *types.Sym) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *importReader) symIdx(s *types.Sym) {
|
func (r *importReader) symIdx(s *types.Sym) {
|
||||||
if Ctxt.Flag_go115newobj {
|
|
||||||
lsym := s.Linksym()
|
lsym := s.Linksym()
|
||||||
idx := int32(r.int64())
|
idx := int32(r.int64())
|
||||||
if idx != -1 {
|
if idx != -1 {
|
||||||
|
|
@ -707,7 +706,6 @@ func (r *importReader) symIdx(s *types.Sym) {
|
||||||
lsym.Set(obj.AttrIndexed, true)
|
lsym.Set(obj.AttrIndexed, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (r *importReader) doInline(n *Node) {
|
func (r *importReader) doInline(n *Node) {
|
||||||
if len(n.Func.Inl.Body) != 0 {
|
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.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
|
||||||
flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
|
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.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")
|
flag.StringVar(&jsonLogOpt, "json", "", "version,destination for JSON compiler/optimizer logging")
|
||||||
|
|
||||||
objabi.Flagparse(usage)
|
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 affect the build result. (And don't
|
||||||
// record flags that don't, since that would cause spurious
|
// record flags that don't, since that would cause spurious
|
||||||
// changes in the binary.)
|
// 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 {
|
if smallFrames {
|
||||||
maxStackVarSize = 128 * 1024
|
maxStackVarSize = 128 * 1024
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,9 @@ import (
|
||||||
"strings"
|
"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.
|
// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
|
||||||
const InfoPrefix = "go.info."
|
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
|
// ConstInfoPrefix is the prefix for all symbols containing DWARF info
|
||||||
// entries that contain constants.
|
// entries that contain constants.
|
||||||
const ConstInfoPrefix = "go.constinfo."
|
const ConstInfoPrefix = "go.constinfo."
|
||||||
|
|
|
||||||
|
|
@ -151,12 +151,9 @@ func buildGoobj() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that a symbol has a given name, accepting both
|
// Check that a symbol has a given name.
|
||||||
// new and old objects.
|
|
||||||
// TODO(go115newobj): remove.
|
|
||||||
func matchSymName(symname, want string) bool {
|
func matchSymName(symname, want string) bool {
|
||||||
return symname == want ||
|
return strings.HasPrefix(symname, want+"#") // new style, with index
|
||||||
strings.HasPrefix(symname, want+"#") // new style, with index
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseGoobj(t *testing.T) {
|
func TestParseGoobj(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -656,7 +656,6 @@ type Link struct {
|
||||||
Flag_linkshared bool
|
Flag_linkshared bool
|
||||||
Flag_optimize bool
|
Flag_optimize bool
|
||||||
Flag_locationlists bool
|
Flag_locationlists bool
|
||||||
Flag_go115newobj bool // use new object file format
|
|
||||||
Retpoline bool // emit use of retpoline stubs for indirect jmp/call
|
Retpoline bool // emit use of retpoline stubs for indirect jmp/call
|
||||||
Bso *bufio.Writer
|
Bso *bufio.Writer
|
||||||
Pathname string
|
Pathname string
|
||||||
|
|
|
||||||
|
|
@ -2,234 +2,18 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Writing of Go object files.
|
|
||||||
|
|
||||||
package obj
|
package obj
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"cmd/internal/bio"
|
|
||||||
"cmd/internal/dwarf"
|
"cmd/internal/dwarf"
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
"sync"
|
"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) {
|
func (ctxt *Link) writeSymDebug(s *LSym) {
|
||||||
ctxt.writeSymDebugNamed(s, s.Name)
|
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.
|
// relocByOff sorts relocations by their offsets.
|
||||||
type relocByOff []Reloc
|
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{}) {
|
func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
|
||||||
ls := s.(*LSym)
|
ls := s.(*LSym)
|
||||||
rsym := f.(*LSym)
|
rsym := f.(*LSym)
|
||||||
if c.Link.Flag_go115newobj {
|
|
||||||
fidx := c.Link.PosTable.FileIndex(rsym.Name)
|
fidx := c.Link.PosTable.FileIndex(rsym.Name)
|
||||||
// Note the +1 here -- the value we're writing is going to be an
|
// Note the +1 here -- the value we're writing is going to be an
|
||||||
// index into the DWARF line table file section, whose entries
|
// index into the DWARF line table file section, whose entries
|
||||||
// are numbered starting at 1, not 0.
|
// are numbered starting at 1, not 0.
|
||||||
ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
|
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 {
|
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)
|
ctxt.Diag("dwarfSym of non-TEXT %v", s)
|
||||||
}
|
}
|
||||||
if s.Func.dwarfInfoSym == nil {
|
if s.Func.dwarfInfoSym == nil {
|
||||||
if ctxt.Flag_go115newobj {
|
|
||||||
s.Func.dwarfInfoSym = &LSym{
|
s.Func.dwarfInfoSym = &LSym{
|
||||||
Type: objabi.SDWARFINFO,
|
Type: objabi.SDWARFINFO,
|
||||||
}
|
}
|
||||||
|
|
@ -573,14 +218,6 @@ func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym,
|
||||||
s.Func.dwarfDebugLinesSym = &LSym{
|
s.Func.dwarfDebugLinesSym = &LSym{
|
||||||
Type: objabi.SDWARFLINES,
|
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() {
|
if s.WasInlined() {
|
||||||
s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
|
s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Entry point of writing new object file.
|
// 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)
|
debugAsmEmit(ctxt)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,26 +139,7 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
|
||||||
ctxt.Text = append(ctxt.Text, s)
|
ctxt.Text = append(ctxt.Text, s)
|
||||||
|
|
||||||
// Set up DWARF entries for s
|
// Set up DWARF entries for s
|
||||||
info, loc, ranges, _, lines := ctxt.dwarfSym(s)
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
|
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),
|
// 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).
|
// in which case all the symbols are non-package (for now).
|
||||||
func (ctxt *Link) NumberSyms(asm bool) {
|
func (ctxt *Link) NumberSyms(asm bool) {
|
||||||
if !ctxt.Flag_go115newobj {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctxt.Headtype == objabi.Haix {
|
if ctxt.Headtype == objabi.Haix {
|
||||||
// Data must be sorted to keep a constant order in TOC symbols.
|
// Data must be sorted to keep a constant order in TOC symbols.
|
||||||
// As they are created during Progedit, two symbols can be switched between
|
// As they are created during Progedit, two symbols can be switched between
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -99,8 +98,6 @@ var (
|
||||||
|
|
||||||
benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
|
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")
|
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.
|
// Main is the main entry point for the linker code.
|
||||||
|
|
@ -140,10 +137,6 @@ func Main(arch *sys.Arch, theArch Arch) {
|
||||||
|
|
||||||
objabi.Flagparse(usage)
|
objabi.Flagparse(usage)
|
||||||
|
|
||||||
if !*flagGo115Newobj {
|
|
||||||
oldlink()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch *flagHeadType {
|
switch *flagHeadType {
|
||||||
case "":
|
case "":
|
||||||
case "windowsgui":
|
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)
|
r := goobj2.NewReaderFromBytes(roObject, readonly)
|
||||||
if r == nil {
|
if r == nil {
|
||||||
if len(roObject) >= 8 && bytes.Equal(roObject[:8], []byte("\x00go114ld")) {
|
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")
|
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 = `
|
const testFuncAlignSrc = `
|
||||||
package main
|
package main
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -335,11 +335,11 @@ func TestGoLib(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that a symbol has a given name, accepting both
|
// Check that a symbol has a given name, accepting both
|
||||||
// new and old objects.
|
// with (for packaged symbols) and without index (for
|
||||||
// TODO(go115newobj): remove.
|
// non-package symbols).
|
||||||
func matchSymName(symname, want string) bool {
|
func matchSymName(symname, want string) bool {
|
||||||
return symname == want ||
|
return symname == want ||
|
||||||
strings.HasPrefix(symname, want+"#") // new style, with index
|
strings.HasPrefix(symname, want+"#")
|
||||||
}
|
}
|
||||||
|
|
||||||
const testexec = `
|
const testexec = `
|
||||||
|
|
|
||||||
|
|
@ -286,9 +286,8 @@ func TestDisasmGoobj(t *testing.T) {
|
||||||
t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out)
|
t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(go115newobj): drop old object file support.
|
|
||||||
need := []string{
|
need := []string{
|
||||||
`main(#\d+)?\(SB\)`, // either new or old object file
|
`main#\d+\(SB\)`,
|
||||||
`fmthello\.go:6`,
|
`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