[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:
Cherry Zhang 2020-05-01 19:13:30 -04:00
parent a38bc324ee
commit c89251204e
102 changed files with 44 additions and 33389 deletions

View file

@ -25,8 +25,6 @@ var (
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
Importpath = flag.String("p", "", "set expected package import to path")
Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)")
Go115Newobj = flag.Bool("go115newobj", true, "use new object file format")
)
var (

View file

@ -40,7 +40,6 @@ func main() {
}
ctxt.Flag_dynlink = *flags.Dynlink
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
ctxt.Flag_go115newobj = *flags.Go115Newobj
ctxt.IsAsm = true
switch *flags.Spectre {
default:

View file

@ -997,7 +997,6 @@ func (w *exportWriter) linkname(s *types.Sym) {
}
func (w *exportWriter) symIdx(s *types.Sym) {
if Ctxt.Flag_go115newobj {
lsym := s.Linksym()
if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
// Don't export index for non-package symbols, linkname'd symbols,
@ -1010,7 +1009,6 @@ func (w *exportWriter) symIdx(s *types.Sym) {
w.int64(int64(lsym.SymIdx))
}
}
}
// Inline bodies.

View file

@ -696,7 +696,6 @@ func (r *importReader) linkname(s *types.Sym) {
}
func (r *importReader) symIdx(s *types.Sym) {
if Ctxt.Flag_go115newobj {
lsym := s.Linksym()
idx := int32(r.int64())
if idx != -1 {
@ -707,7 +706,6 @@ func (r *importReader) symIdx(s *types.Sym) {
lsym.Set(obj.AttrIndexed, true)
}
}
}
func (r *importReader) doInline(n *Node) {
if len(n.Func.Inl.Body) != 0 {

View file

@ -281,7 +281,6 @@ func Main(archInit func(*Arch)) {
flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
flag.BoolVar(&Ctxt.Flag_go115newobj, "go115newobj", true, "use new object file format")
flag.StringVar(&jsonLogOpt, "json", "", "version,destination for JSON compiler/optimizer logging")
objabi.Flagparse(usage)
@ -315,7 +314,7 @@ func Main(archInit func(*Arch)) {
// Record flags that affect the build result. (And don't
// record flags that don't, since that would cause spurious
// changes in the binary.)
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre", "go115newobj")
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
if smallFrames {
maxStackVarSize = 128 * 1024

View file

@ -18,21 +18,9 @@ import (
"strings"
)
// TODO(go115newobj): clean up. Some constant prefixes here are no longer
// needed in the new object files.
// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
const InfoPrefix = "go.info."
// RangePrefix is the prefix for all the symbols containing DWARF location lists.
const LocPrefix = "go.loc."
// RangePrefix is the prefix for all the symbols containing DWARF range lists.
const RangePrefix = "go.range."
// DebugLinesPrefix is the prefix for all the symbols containing DWARF debug_line information from the compiler.
const DebugLinesPrefix = "go.debuglines."
// ConstInfoPrefix is the prefix for all symbols containing DWARF info
// entries that contain constants.
const ConstInfoPrefix = "go.constinfo."

View file

@ -151,12 +151,9 @@ func buildGoobj() error {
return nil
}
// Check that a symbol has a given name, accepting both
// new and old objects.
// TODO(go115newobj): remove.
// Check that a symbol has a given name.
func matchSymName(symname, want string) bool {
return symname == want ||
strings.HasPrefix(symname, want+"#") // new style, with index
return strings.HasPrefix(symname, want+"#") // new style, with index
}
func TestParseGoobj(t *testing.T) {

View file

@ -656,7 +656,6 @@ type Link struct {
Flag_linkshared bool
Flag_optimize bool
Flag_locationlists bool
Flag_go115newobj bool // use new object file format
Retpoline bool // emit use of retpoline stubs for indirect jmp/call
Bso *bufio.Writer
Pathname string

View file

@ -2,234 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Writing of Go object files.
package obj
import (
"bufio"
"cmd/internal/bio"
"cmd/internal/dwarf"
"cmd/internal/objabi"
"cmd/internal/sys"
"fmt"
"io"
"log"
"path/filepath"
"sort"
"strings"
"sync"
)
// objWriter writes Go object files.
type objWriter struct {
wr *bufio.Writer
ctxt *Link
// Temporary buffer for zigzag int writing.
varintbuf [10]uint8
// Number of objects written of each type.
nRefs int
nData int
nReloc int
nPcdata int
nFuncdata int
nFile int
pkgpath string // the package import path (escaped), "" if unknown
}
func (w *objWriter) addLengths(s *LSym) {
w.nData += len(s.P)
w.nReloc += len(s.R)
if s.Type != objabi.STEXT {
return
}
pc := &s.Func.Pcln
data := 0
data += len(pc.Pcsp.P)
data += len(pc.Pcfile.P)
data += len(pc.Pcline.P)
data += len(pc.Pcinline.P)
for _, pcd := range pc.Pcdata {
data += len(pcd.P)
}
w.nData += data
w.nPcdata += len(pc.Pcdata)
w.nFuncdata += len(pc.Funcdataoff)
w.nFile += len(pc.File)
}
func (w *objWriter) writeLengths() {
w.writeInt(int64(w.nData))
w.writeInt(int64(w.nReloc))
w.writeInt(int64(w.nPcdata))
w.writeInt(int64(0)) // TODO: remove at next object file rev
w.writeInt(int64(w.nFuncdata))
w.writeInt(int64(w.nFile))
}
func newObjWriter(ctxt *Link, b *bufio.Writer, pkgpath string) *objWriter {
return &objWriter{
ctxt: ctxt,
wr: b,
pkgpath: objabi.PathToPrefix(pkgpath),
}
}
func WriteObjFile(ctxt *Link, bout *bio.Writer, pkgpath string) {
if ctxt.Flag_go115newobj {
WriteObjFile2(ctxt, bout, pkgpath)
return
}
b := bout.Writer
w := newObjWriter(ctxt, b, pkgpath)
// Magic header
w.wr.WriteString("\x00go114ld")
// Version
w.wr.WriteByte(1)
// Autolib
for _, p := range ctxt.Imports {
w.writeString(p.Pkg)
// This object format ignores p.Fingerprint.
}
w.writeString("")
// DWARF File Table
fileTable := ctxt.PosTable.DebugLinesFileTable()
w.writeInt(int64(len(fileTable)))
for _, str := range fileTable {
w.writeString(filepath.ToSlash(str))
}
// Symbol references
for _, s := range ctxt.Text {
w.writeRefs(s)
w.addLengths(s)
}
if ctxt.Headtype == objabi.Haix {
// Data must be sorted to keep a constant order in TOC symbols.
// As they are created during Progedit, two symbols can be switched between
// two different compilations. Therefore, BuildID will be different.
// TODO: find a better place and optimize to only sort TOC symbols
sort.Slice(ctxt.Data, func(i, j int) bool {
return ctxt.Data[i].Name < ctxt.Data[j].Name
})
}
for _, s := range ctxt.Data {
w.writeRefs(s)
w.addLengths(s)
}
for _, s := range ctxt.ABIAliases {
w.writeRefs(s)
w.addLengths(s)
}
// End symbol references
w.wr.WriteByte(0xff)
// Lengths
w.writeLengths()
// Data block
for _, s := range ctxt.Text {
w.wr.Write(s.P)
pc := &s.Func.Pcln
w.wr.Write(pc.Pcsp.P)
w.wr.Write(pc.Pcfile.P)
w.wr.Write(pc.Pcline.P)
w.wr.Write(pc.Pcinline.P)
for _, pcd := range pc.Pcdata {
w.wr.Write(pcd.P)
}
}
for _, s := range ctxt.Data {
if len(s.P) > 0 {
switch s.Type {
case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name)
}
}
w.wr.Write(s.P)
}
// Symbols
for _, s := range ctxt.Text {
w.writeSym(s)
}
for _, s := range ctxt.Data {
w.writeSym(s)
}
for _, s := range ctxt.ABIAliases {
w.writeSym(s)
}
// Magic footer
w.wr.WriteString("\xffgo114ld")
}
// Symbols are prefixed so their content doesn't get confused with the magic footer.
const symPrefix = 0xfe
func (w *objWriter) writeRef(s *LSym, isPath bool) {
if s == nil || s.RefIdx != 0 {
return
}
w.wr.WriteByte(symPrefix)
if isPath {
w.writeString(filepath.ToSlash(s.Name))
} else if w.pkgpath != "" {
// w.pkgpath is already escaped.
n := strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
w.writeString(n)
} else {
w.writeString(s.Name)
}
// Write ABI/static information.
abi := int64(s.ABI())
if s.Static() {
abi = -1
}
w.writeInt(abi)
w.nRefs++
s.RefIdx = w.nRefs
}
func (w *objWriter) writeRefs(s *LSym) {
w.writeRef(s, false)
w.writeRef(s.Gotype, false)
for _, r := range s.R {
w.writeRef(r.Sym, false)
}
if s.Type == objabi.STEXT {
pc := &s.Func.Pcln
for _, d := range pc.Funcdata {
w.writeRef(d, false)
}
for _, f := range pc.File {
fsym := w.ctxt.Lookup(f)
w.writeRef(fsym, true)
}
for _, call := range pc.InlTree.nodes {
w.writeRef(call.Func, false)
f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
fsym := w.ctxt.Lookup(f)
w.writeRef(fsym, true)
}
}
}
func (ctxt *Link) writeSymDebug(s *LSym) {
ctxt.writeSymDebugNamed(s, s.Name)
}
@ -311,138 +95,6 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
}
}
func (w *objWriter) writeSym(s *LSym) {
ctxt := w.ctxt
if ctxt.Debugasm > 0 {
w.ctxt.writeSymDebug(s)
}
w.wr.WriteByte(symPrefix)
w.wr.WriteByte(byte(s.Type))
w.writeRefIndex(s)
flags := int64(0)
if s.DuplicateOK() {
flags |= 1
}
if s.Local() {
flags |= 1 << 1
}
if s.MakeTypelink() {
flags |= 1 << 2
}
w.writeInt(flags)
w.writeInt(s.Size)
w.writeRefIndex(s.Gotype)
w.writeInt(int64(len(s.P)))
w.writeInt(int64(len(s.R)))
var r *Reloc
for i := range s.R {
r = &s.R[i]
w.writeInt(int64(r.Off))
w.writeInt(int64(r.Siz))
w.writeInt(int64(r.Type))
w.writeInt(r.Add)
w.writeRefIndex(r.Sym)
}
if s.Type != objabi.STEXT {
return
}
w.writeInt(int64(s.Func.Args))
w.writeInt(int64(s.Func.Locals))
w.writeInt(int64(s.Func.Align))
w.writeBool(s.NoSplit())
flags = int64(0)
if s.Leaf() {
flags |= 1
}
if s.CFunc() {
flags |= 1 << 1
}
if s.ReflectMethod() {
flags |= 1 << 2
}
if ctxt.Flag_shared {
flags |= 1 << 3
}
if s.TopFrame() {
flags |= 1 << 4
}
w.writeInt(flags)
w.writeInt(int64(0)) // TODO: remove at next object file rev
pc := &s.Func.Pcln
w.writeInt(int64(len(pc.Pcsp.P)))
w.writeInt(int64(len(pc.Pcfile.P)))
w.writeInt(int64(len(pc.Pcline.P)))
w.writeInt(int64(len(pc.Pcinline.P)))
w.writeInt(int64(len(pc.Pcdata)))
for _, pcd := range pc.Pcdata {
w.writeInt(int64(len(pcd.P)))
}
w.writeInt(int64(len(pc.Funcdataoff)))
for i := range pc.Funcdataoff {
w.writeRefIndex(pc.Funcdata[i])
}
for i := range pc.Funcdataoff {
w.writeInt(pc.Funcdataoff[i])
}
w.writeInt(int64(len(pc.File)))
for _, f := range pc.File {
fsym := ctxt.Lookup(f)
w.writeRefIndex(fsym)
}
w.writeInt(int64(len(pc.InlTree.nodes)))
for _, call := range pc.InlTree.nodes {
w.writeInt(int64(call.Parent))
f, l := linkgetlineFromPos(w.ctxt, call.Pos)
fsym := ctxt.Lookup(f)
w.writeRefIndex(fsym)
w.writeInt(int64(l))
w.writeRefIndex(call.Func)
w.writeInt(int64(call.ParentPC))
}
}
func (w *objWriter) writeBool(b bool) {
if b {
w.writeInt(1)
} else {
w.writeInt(0)
}
}
func (w *objWriter) writeInt(sval int64) {
var v uint64
uv := (uint64(sval) << 1) ^ uint64(sval>>63)
p := w.varintbuf[:]
for v = uv; v >= 0x80; v >>= 7 {
p[0] = uint8(v | 0x80)
p = p[1:]
}
p[0] = uint8(v)
p = p[1:]
w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
}
func (w *objWriter) writeString(s string) {
w.writeInt(int64(len(s)))
w.wr.WriteString(s)
}
func (w *objWriter) writeRefIndex(s *LSym) {
if s == nil {
w.writeInt(0)
return
}
if s.RefIdx == 0 {
log.Fatalln("writing an unreferenced symbol", s.Name)
}
w.writeInt(int64(s.RefIdx))
}
// relocByOff sorts relocations by their offsets.
type relocByOff []Reloc
@ -510,17 +162,11 @@ func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64)
func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
ls := s.(*LSym)
rsym := f.(*LSym)
if c.Link.Flag_go115newobj {
fidx := c.Link.PosTable.FileIndex(rsym.Name)
// Note the +1 here -- the value we're writing is going to be an
// index into the DWARF line table file section, whose entries
// are numbered starting at 1, not 0.
ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
} else {
ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0)
r := &ls.R[len(ls.R)-1]
r.Type = objabi.R_DWARFFILEREF
}
}
func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
@ -558,7 +204,6 @@ func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym,
ctxt.Diag("dwarfSym of non-TEXT %v", s)
}
if s.Func.dwarfInfoSym == nil {
if ctxt.Flag_go115newobj {
s.Func.dwarfInfoSym = &LSym{
Type: objabi.SDWARFINFO,
}
@ -573,14 +218,6 @@ func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym,
s.Func.dwarfDebugLinesSym = &LSym{
Type: objabi.SDWARFLINES,
}
} else {
s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
if ctxt.Flag_locationlists {
s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name)
}
s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
s.Func.dwarfDebugLinesSym = ctxt.LookupDerived(s, dwarf.DebugLinesPrefix+s.Name)
}
if s.WasInlined() {
s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
}

View file

@ -17,7 +17,7 @@ import (
)
// Entry point of writing new object file.
func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
func WriteObjFile(ctxt *Link, b *bio.Writer, pkgpath string) {
debugAsmEmit(ctxt)

View file

@ -139,26 +139,7 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
ctxt.Text = append(ctxt.Text, s)
// Set up DWARF entries for s
info, loc, ranges, _, lines := ctxt.dwarfSym(s)
// When using new object files, the DWARF symbols are unnamed aux
// symbols and don't need to be added to ctxt.Data.
// But the old object file still needs them.
if !ctxt.Flag_go115newobj {
info.Type = objabi.SDWARFINFO
info.Set(AttrDuplicateOK, s.DuplicateOK())
if loc != nil {
loc.Type = objabi.SDWARFLOC
loc.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, loc)
}
ranges.Type = objabi.SDWARFRANGE
ranges.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, info, ranges)
lines.Type = objabi.SDWARFLINES
lines.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, lines)
}
ctxt.dwarfSym(s)
}
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {

View file

@ -165,10 +165,6 @@ func (ctxt *Link) Int64Sym(i int64) *LSym {
// asm is set to true if this is called by the assembler (i.e. not the compiler),
// in which case all the symbols are non-package (for now).
func (ctxt *Link) NumberSyms(asm bool) {
if !ctxt.Flag_go115newobj {
return
}
if ctxt.Headtype == objabi.Haix {
// Data must be sorted to keep a constant order in TOC symbols.
// As they are created during Progedit, two symbols can be switched between

View file

@ -39,7 +39,6 @@ import (
"flag"
"log"
"os"
"os/exec"
"runtime"
"runtime/pprof"
"strings"
@ -99,8 +98,6 @@ var (
benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof")
flagGo115Newobj = flag.Bool("go115newobj", true, "use new object file format")
)
// Main is the main entry point for the linker code.
@ -140,10 +137,6 @@ func Main(arch *sys.Arch, theArch Arch) {
objabi.Flagparse(usage)
if !*flagGo115Newobj {
oldlink()
}
switch *flagHeadType {
case "":
case "windowsgui":
@ -415,48 +408,3 @@ func startProfile() {
})
}
}
// Invoke the old linker and exit.
func oldlink() {
linker := os.Args[0]
if strings.HasSuffix(linker, "link") {
linker = linker[:len(linker)-4] + "oldlink"
} else if strings.HasSuffix(linker, "link.exe") {
linker = linker[:len(linker)-8] + "oldlink.exe"
} else {
log.Fatal("cannot find oldlink. arg0=", linker)
}
// Copy args, filter out -go115newobj flag
args := make([]string, 0, len(os.Args)-1)
skipNext := false
for i, a := range os.Args {
if i == 0 {
continue // skip arg0
}
if skipNext {
skipNext = false
continue
}
if a == "-go115newobj" {
skipNext = true
continue
}
if strings.HasPrefix(a, "-go115newobj=") {
continue
}
args = append(args, a)
}
cmd := exec.Command(linker, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err == nil {
os.Exit(0)
}
if _, ok := err.(*exec.ExitError); ok {
os.Exit(2) // would be nice to use ExitError.ExitCode(), but that is too new
}
log.Fatal("invoke oldlink failed:", err)
}

View file

@ -1914,7 +1914,7 @@ func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, uni
r := goobj2.NewReaderFromBytes(roObject, readonly)
if r == nil {
if len(roObject) >= 8 && bytes.Equal(roObject[:8], []byte("\x00go114ld")) {
log.Fatalf("found object file %s in old format, but -go115newobj is true\nset -go115newobj consistently in all -gcflags, -asmflags, and -ldflags", f.File().Name())
log.Fatalf("found object file %s in old format", f.File().Name())
}
panic("cannot read object file")
}

View file

@ -535,30 +535,6 @@ func TestStrictDup(t *testing.T) {
}
}
func TestOldLink(t *testing.T) {
// Test that old object file format still works.
// TODO(go115newobj): delete.
testenv.MustHaveGoBuild(t)
tmpdir, err := ioutil.TempDir("", "TestOldLink")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "main.go")
err = ioutil.WriteFile(src, []byte("package main; func main(){}\n"), 0666)
if err != nil {
t.Fatal(err)
}
cmd := exec.Command(testenv.GoToolPath(t), "run", "-gcflags=all=-go115newobj=false", "-asmflags=all=-go115newobj=false", "-ldflags=-go115newobj=false", src)
if out, err := cmd.CombinedOutput(); err != nil {
t.Errorf("%v: %v:\n%s", cmd.Args, err, out)
}
}
const testFuncAlignSrc = `
package main
import (

View file

@ -335,11 +335,11 @@ func TestGoLib(t *testing.T) {
}
// Check that a symbol has a given name, accepting both
// new and old objects.
// TODO(go115newobj): remove.
// with (for packaged symbols) and without index (for
// non-package symbols).
func matchSymName(symname, want string) bool {
return symname == want ||
strings.HasPrefix(symname, want+"#") // new style, with index
strings.HasPrefix(symname, want+"#")
}
const testexec = `

View file

@ -286,9 +286,8 @@ func TestDisasmGoobj(t *testing.T) {
t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out)
}
// TODO(go115newobj): drop old object file support.
need := []string{
`main(#\d+)?\(SB\)`, // either new or old object file
`main#\d+\(SB\)`,
`fmthello\.go:6`,
}

View file

@ -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

View file

@ -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)
}
}

View file

@ -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
)

View file

@ -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
}
}

View file

@ -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))
}
}

View file

@ -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
)

View file

@ -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
}
}

View file

@ -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))
}
}

View file

@ -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
)

View file

@ -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
}
}
}

View file

@ -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
}

View file

@ -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

View file

@ -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)
}
}

View file

@ -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)
}

View file

@ -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

View file

@ -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)
}
}

View file

@ -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")
}

View file

@ -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()
}
}

View file

@ -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

View file

@ -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

View file

@ -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)
}

View file

@ -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)
}
})
}
}

View file

@ -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)
}
}

View file

@ -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
}

View file

@ -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") }

View file

@ -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)
}

View file

@ -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

View file

@ -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
}
}
}

View file

@ -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_")
}

View file

@ -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()
}

View file

@ -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.

View file

@ -1 +0,0 @@
// This file is needed to make "go build" work for package with external functions.

View file

@ -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 }()
}

View file

@ -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()
}

View file

@ -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)
}

View file

@ -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")
}
}

View file

@ -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;
}

View file

@ -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")
}

View file

@ -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()
}

View file

@ -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
}
}

View file

@ -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

View file

@ -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)
}
}

View file

@ -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 := &sect.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)
}

View file

@ -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
}

View file

@ -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)
}
}
}

View file

@ -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))
}
}

View file

@ -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
)

View file

@ -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
}
}
}

View file

@ -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))
}
}

View file

@ -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
)

View file

@ -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
}
}
}

View file

@ -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

View file

@ -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
)

View file

@ -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)
}
}

View file

@ -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))
}
}

View file

@ -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
)

View file

@ -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)
}
}

View file

@ -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))
}
}

View file

@ -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
)

View file

@ -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
}
}
}

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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)
}
}
}

View file

@ -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
}

View file

@ -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
}
}
}

View file

@ -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
}

View file

@ -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]]
}

View file

@ -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)
}
}

View file

@ -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
}
}

View file

@ -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()
}

View file

@ -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