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 (
}
ctxt.Flag_dynlink = *flags.Dynlink
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
- ctxt.Flag_go115newobj = *flags.Go115Newobj
ctxt.IsAsm = true
switch *flags.Spectre {
default:
}
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,
- // and symbols without an index. They can only be referenced by
- // name.
- w.int64(-1)
- } else {
- // For a defined symbol, export its index.
- // For re-exporting an imported symbol, pass its index through.
- w.int64(int64(lsym.SymIdx))
- }
+ 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,
+ // and symbols without an index. They can only be referenced by
+ // name.
+ w.int64(-1)
+ } else {
+ // For a defined symbol, export its index.
+ // For re-exporting an imported symbol, pass its index through.
+ w.int64(int64(lsym.SymIdx))
}
}
}
func (r *importReader) symIdx(s *types.Sym) {
- if Ctxt.Flag_go115newobj {
- lsym := s.Linksym()
- idx := int32(r.int64())
- if idx != -1 {
- if s.Linkname != "" {
- Fatalf("bad index for linknamed symbol: %v %d\n", lsym, idx)
- }
- lsym.SymIdx = idx
- lsym.Set(obj.AttrIndexed, true)
+ lsym := s.Linksym()
+ idx := int32(r.int64())
+ if idx != -1 {
+ if s.Linkname != "" {
+ Fatalf("bad index for linknamed symbol: %v %d\n", lsym, idx)
}
+ lsym.SymIdx = idx
+ lsym.Set(obj.AttrIndexed, true)
}
}
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)
// 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
"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."
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) {
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
// 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)
}
}
}
-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
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
- }
+ 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))
}
func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
ctxt.Diag("dwarfSym of non-TEXT %v", s)
}
if s.Func.dwarfInfoSym == nil {
- if ctxt.Flag_go115newobj {
- s.Func.dwarfInfoSym = &LSym{
- Type: objabi.SDWARFINFO,
- }
- if ctxt.Flag_locationlists {
- s.Func.dwarfLocSym = &LSym{
- Type: objabi.SDWARFLOC,
- }
- }
- s.Func.dwarfRangesSym = &LSym{
- Type: objabi.SDWARFRANGE,
- }
- 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.dwarfInfoSym = &LSym{
+ Type: objabi.SDWARFINFO,
+ }
+ if ctxt.Flag_locationlists {
+ s.Func.dwarfLocSym = &LSym{
+ Type: objabi.SDWARFLOC,
}
- s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
- s.Func.dwarfDebugLinesSym = ctxt.LookupDerived(s, dwarf.DebugLinesPrefix+s.Name)
+ }
+ s.Func.dwarfRangesSym = &LSym{
+ Type: objabi.SDWARFRANGE,
+ }
+ s.Func.dwarfDebugLinesSym = &LSym{
+ Type: objabi.SDWARFLINES,
}
if s.WasInlined() {
s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
)
// 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)
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) {
// 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
"flag"
"log"
"os"
- "os/exec"
"runtime"
"runtime/pprof"
"strings"
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.
objabi.Flagparse(usage)
- if !*flagGo115Newobj {
- oldlink()
- }
-
switch *flagHeadType {
case "":
case "windowsgui":
})
}
}
-
-// 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)
-}
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")
}
}
}
-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 (
}
// 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 = `
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`,
}
+++ /dev/null
-// 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
+++ /dev/null
-// 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)
- }
-}
+++ /dev/null
-// 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
-)
+++ /dev/null
-// 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
- }
-}
+++ /dev/null
-// 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))
- }
-}
+++ /dev/null
-// 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
-)
+++ /dev/null
-// 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
- }
-}
+++ /dev/null
-// 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))
- }
-}
+++ /dev/null
-// 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
-)
+++ /dev/null
-// 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
- }
- }
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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)
- }
- }
-}
+++ /dev/null
-// 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 (
- "bufio"
- "bytes"
- "cmd/internal/gcprog"
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/sym"
- "compress/zlib"
- "encoding/binary"
- "fmt"
- "log"
- "os"
- "sort"
- "strconv"
- "strings"
- "sync"
-)
-
-// isRuntimeDepPkg reports whether pkg is the runtime package or its dependency
-func isRuntimeDepPkg(pkg string) bool {
- switch pkg {
- case "runtime",
- "sync/atomic", // runtime may call to sync/atomic, due to go:linkname
- "internal/bytealg", // for IndexByte
- "internal/cpu": // for cpu features
- return true
- }
- return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test")
-}
-
-// Estimate the max size needed to hold any new trampolines created for this function. This
-// is used to determine when the section can be split if it becomes too large, to ensure that
-// the trampolines are in the same section as the function that uses them.
-func maxSizeTrampolinesPPC64(s *sym.Symbol, isTramp bool) uint64 {
- // If thearch.Trampoline is nil, then trampoline support is not available on this arch.
- // A trampoline does not need any dependent trampolines.
- if thearch.Trampoline == nil || isTramp {
- return 0
- }
-
- n := uint64(0)
- for ri := range s.R {
- r := &s.R[ri]
- if r.Type.IsDirectCallOrJump() {
- n++
- }
- }
- // Trampolines in ppc64 are 4 instructions.
- return n * 16
-}
-
-// detect too-far jumps in function s, and add trampolines if necessary
-// ARM, PPC64 & PPC64LE support trampoline insertion for internal and external linking
-// On PPC64 & PPC64LE the text sections might be split but will still insert trampolines
-// where necessary.
-func trampoline(ctxt *Link, s *sym.Symbol) {
- if thearch.Trampoline == nil {
- return // no need or no support of trampolines on this arch
- }
-
- for ri := range s.R {
- r := &s.R[ri]
- if !r.Type.IsDirectCallOrJump() {
- continue
- }
- if Symaddr(r.Sym) == 0 && (r.Sym.Type != sym.SDYNIMPORT && r.Sym.Type != sym.SUNDEFEXT) {
- if r.Sym.File != s.File {
- if !isRuntimeDepPkg(s.File) || !isRuntimeDepPkg(r.Sym.File) {
- ctxt.ErrorUnresolved(s, r)
- }
- // runtime and its dependent packages may call to each other.
- // they are fine, as they will be laid down together.
- }
- continue
- }
-
- thearch.Trampoline(ctxt, r, s)
- }
-
-}
-
-// relocsym resolve relocations in "s". The main loop walks through
-// the list of relocations attached to "s" and resolves them where
-// applicable. Relocations are often architecture-specific, requiring
-// calls into the 'archreloc' and/or 'archrelocvariant' functions for
-// the architecture. When external linking is in effect, it may not be
-// possible to completely resolve the address/offset for a symbol, in
-// which case the goal is to lay the groundwork for turning a given
-// relocation into an external reloc (to be applied by the external
-// linker). For more on how relocations work in general, see
-//
-// "Linkers and Loaders", by John R. Levine (Morgan Kaufmann, 1999), ch. 7
-//
-// This is a performance-critical function for the linker; be careful
-// to avoid introducing unnecessary allocations in the main loop.
-func relocsym(ctxt *Link, s *sym.Symbol) {
- if len(s.R) == 0 {
- return
- }
- if s.Attr.ReadOnly() {
- // The symbol's content is backed by read-only memory.
- // Copy it to writable memory to apply relocations.
- s.P = append([]byte(nil), s.P...)
- s.Attr.Set(sym.AttrReadOnly, false)
- }
- for ri := int32(0); ri < int32(len(s.R)); ri++ {
- r := &s.R[ri]
- if r.Done {
- // Relocation already processed by an earlier phase.
- continue
- }
- r.Done = true
- off := r.Off
- siz := int32(r.Siz)
- if off < 0 || off+siz > int32(len(s.P)) {
- rname := ""
- if r.Sym != nil {
- rname = r.Sym.Name
- }
- Errorf(s, "invalid relocation %s: %d+%d not in [%d,%d)", rname, off, siz, 0, len(s.P))
- continue
- }
-
- if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) {
- // When putting the runtime but not main into a shared library
- // these symbols are undefined and that's OK.
- if ctxt.BuildMode == BuildModeShared || ctxt.BuildMode == BuildModePlugin {
- if r.Sym.Name == "main.main" || (ctxt.BuildMode != BuildModePlugin && r.Sym.Name == "main..inittask") {
- r.Sym.Type = sym.SDYNIMPORT
- } else if strings.HasPrefix(r.Sym.Name, "go.info.") {
- // Skip go.info symbols. They are only needed to communicate
- // DWARF info between the compiler and linker.
- continue
- }
- } else {
- ctxt.ErrorUnresolved(s, r)
- continue
- }
- }
-
- if r.Type >= objabi.ElfRelocOffset {
- continue
- }
- if r.Siz == 0 { // informational relocation - no work to do
- continue
- }
-
- // We need to be able to reference dynimport symbols when linking against
- // shared libraries, and Solaris, Darwin and AIX need it always
- if ctxt.HeadType != objabi.Hsolaris && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Haix && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !ctxt.DynlinkingGo() && !r.Sym.Attr.SubSymbol() {
- if !(ctxt.Arch.Family == sys.PPC64 && ctxt.LinkMode == LinkExternal && r.Sym.Name == ".TOC.") {
- Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(ctxt.Arch, r.Type))
- }
- }
- if r.Sym != nil && r.Sym.Type != sym.STLSBSS && r.Type != objabi.R_WEAKADDROFF && !r.Sym.Attr.Reachable() {
- Errorf(s, "unreachable sym in relocation: %s", r.Sym.Name)
- }
-
- if ctxt.LinkMode == LinkExternal {
- r.InitExt()
- }
-
- // TODO(mundaym): remove this special case - see issue 14218.
- if ctxt.Arch.Family == sys.S390X {
- switch r.Type {
- case objabi.R_PCRELDBL:
- r.InitExt()
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- case objabi.R_CALL:
- r.InitExt()
- r.Variant = sym.RV_390_DBL
- }
- }
-
- var o int64
- switch r.Type {
- default:
- switch siz {
- default:
- Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
- case 1:
- o = int64(s.P[off])
- case 2:
- o = int64(ctxt.Arch.ByteOrder.Uint16(s.P[off:]))
- case 4:
- o = int64(ctxt.Arch.ByteOrder.Uint32(s.P[off:]))
- case 8:
- o = int64(ctxt.Arch.ByteOrder.Uint64(s.P[off:]))
- }
- if offset, ok := thearch.Archreloc(ctxt, r, s, o); ok {
- o = offset
- } else {
- Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type))
- }
- case objabi.R_TLS_LE:
- if ctxt.LinkMode == LinkExternal && ctxt.IsELF {
- r.Done = false
- if r.Sym == nil {
- r.Sym = ctxt.Tlsg
- }
- r.Xsym = r.Sym
- r.Xadd = r.Add
- o = 0
- if ctxt.Arch.Family != sys.AMD64 {
- o = r.Add
- }
- break
- }
-
- if ctxt.IsELF && ctxt.Arch.Family == sys.ARM {
- // On ELF ARM, the thread pointer is 8 bytes before
- // the start of the thread-local data block, so add 8
- // to the actual TLS offset (r->sym->value).
- // This 8 seems to be a fundamental constant of
- // ELF on ARM (or maybe Glibc on ARM); it is not
- // related to the fact that our own TLS storage happens
- // to take up 8 bytes.
- o = 8 + r.Sym.Value
- } else if ctxt.IsELF || ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hdarwin {
- o = int64(ctxt.Tlsoffset) + r.Add
- } else if ctxt.HeadType == objabi.Hwindows {
- o = r.Add
- } else {
- log.Fatalf("unexpected R_TLS_LE relocation for %v", ctxt.HeadType)
- }
- case objabi.R_TLS_IE:
- if ctxt.LinkMode == LinkExternal && ctxt.IsELF {
- r.Done = false
- if r.Sym == nil {
- r.Sym = ctxt.Tlsg
- }
- r.Xsym = r.Sym
- r.Xadd = r.Add
- o = 0
- if ctxt.Arch.Family != sys.AMD64 {
- o = r.Add
- }
- break
- }
- if ctxt.BuildMode == BuildModePIE && ctxt.IsELF {
- // We are linking the final executable, so we
- // can optimize any TLS IE relocation to LE.
- if thearch.TLSIEtoLE == nil {
- log.Fatalf("internal linking of TLS IE not supported on %v", ctxt.Arch.Family)
- }
- thearch.TLSIEtoLE(s, int(off), int(r.Siz))
- o = int64(ctxt.Tlsoffset)
- // TODO: o += r.Add when ctxt.Arch.Family != sys.AMD64?
- // Why do we treat r.Add differently on AMD64?
- // Is the external linker using Xadd at all?
- } else {
- log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", s.Name)
- }
- case objabi.R_ADDR:
- if ctxt.LinkMode == LinkExternal && r.Sym.Type != sym.SCONST {
- r.Done = false
-
- // set up addend for eventual relocation via outer symbol.
- rs := r.Sym
-
- r.Xadd = r.Add
- for rs.Outer != nil {
- r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
- rs = rs.Outer
- }
-
- if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
- Errorf(s, "missing section for relocation target %s", rs.Name)
- }
- r.Xsym = rs
-
- o = r.Xadd
- if ctxt.IsELF {
- if ctxt.Arch.Family == sys.AMD64 {
- o = 0
- }
- } else if ctxt.HeadType == objabi.Hdarwin {
- if rs.Type != sym.SHOSTOBJ {
- o += Symaddr(rs)
- }
- } else if ctxt.HeadType == objabi.Hwindows {
- // nothing to do
- } else if ctxt.HeadType == objabi.Haix {
- o = Symaddr(r.Sym) + r.Add
- } else {
- Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, ctxt.HeadType)
- }
-
- break
- }
-
- // On AIX, a second relocation must be done by the loader,
- // as section addresses can change once loaded.
- // The "default" symbol address is still needed by the loader so
- // the current relocation can't be skipped.
- if ctxt.HeadType == objabi.Haix && r.Sym.Type != sym.SDYNIMPORT {
- // It's not possible to make a loader relocation in a
- // symbol which is not inside .data section.
- // FIXME: It should be forbidden to have R_ADDR from a
- // symbol which isn't in .data. However, as .text has the
- // same address once loaded, this is possible.
- if s.Sect.Seg == &Segdata {
- Xcoffadddynrel(ctxt, s, r)
- }
- }
-
- o = Symaddr(r.Sym) + r.Add
-
- // On amd64, 4-byte offsets will be sign-extended, so it is impossible to
- // access more than 2GB of static data; fail at link time is better than
- // fail at runtime. See https://golang.org/issue/7980.
- // Instead of special casing only amd64, we treat this as an error on all
- // 64-bit architectures so as to be future-proof.
- if int32(o) < 0 && ctxt.Arch.PtrSize > 4 && siz == 4 {
- Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", r.Sym.Name, uint64(o), Symaddr(r.Sym), r.Add)
- errorexit()
- }
- case objabi.R_DWARFSECREF:
- if r.Sym.Sect == nil {
- Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
- }
-
- if ctxt.LinkMode == LinkExternal {
- r.Done = false
-
- // On most platforms, the external linker needs to adjust DWARF references
- // as it combines DWARF sections. However, on Darwin, dsymutil does the
- // DWARF linking, and it understands how to follow section offsets.
- // Leaving in the relocation records confuses it (see
- // https://golang.org/issue/22068) so drop them for Darwin.
- if ctxt.HeadType == objabi.Hdarwin {
- r.Done = true
- }
-
- // PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
- // for R_DWARFSECREF relocations, while R_ADDR is replaced with
- // IMAGE_REL_I386_DIR32, IMAGE_REL_AMD64_ADDR64 and IMAGE_REL_AMD64_ADDR32.
- // Do not replace R_DWARFSECREF with R_ADDR for windows -
- // let PE code emit correct relocations.
- if ctxt.HeadType != objabi.Hwindows {
- r.Type = objabi.R_ADDR
- }
-
- r.Xsym = ctxt.Syms.ROLookup(r.Sym.Sect.Name, 0)
- r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
-
- o = r.Xadd
- if ctxt.IsELF && ctxt.Arch.Family == sys.AMD64 {
- o = 0
- }
- break
- }
- o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
- case objabi.R_WEAKADDROFF:
- if !r.Sym.Attr.Reachable() {
- continue
- }
- fallthrough
- case objabi.R_ADDROFF:
- // The method offset tables using this relocation expect the offset to be relative
- // to the start of the first text section, even if there are multiple.
- if r.Sym.Sect.Name == ".text" {
- o = Symaddr(r.Sym) - int64(Segtext.Sections[0].Vaddr) + r.Add
- } else {
- o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
- }
-
- case objabi.R_ADDRCUOFF:
- // debug_range and debug_loc elements use this relocation type to get an
- // offset from the start of the compile unit.
- o = Symaddr(r.Sym) + r.Add - Symaddr(r.Sym.Unit.Textp[0])
-
- // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
- case objabi.R_GOTPCREL:
- if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin && r.Sym != nil && r.Sym.Type != sym.SCONST {
- r.Done = false
- r.Xadd = r.Add
- r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
- r.Xsym = r.Sym
-
- o = r.Xadd
- o += int64(r.Siz)
- break
- }
- fallthrough
- case objabi.R_CALL, objabi.R_PCREL:
- if ctxt.LinkMode == LinkExternal && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
- // pass through to the external linker.
- r.Done = false
- r.Xadd = 0
- if ctxt.IsELF {
- r.Xadd -= int64(r.Siz)
- }
- r.Xsym = r.Sym
- o = 0
- break
- }
- if ctxt.LinkMode == LinkExternal && r.Sym != nil && r.Sym.Type != sym.SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) {
- r.Done = false
-
- // set up addend for eventual relocation via outer symbol.
- rs := r.Sym
-
- r.Xadd = r.Add
- for rs.Outer != nil {
- r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
- rs = rs.Outer
- }
-
- r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
- if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
- Errorf(s, "missing section for relocation target %s", rs.Name)
- }
- r.Xsym = rs
-
- o = r.Xadd
- if ctxt.IsELF {
- if ctxt.Arch.Family == sys.AMD64 {
- o = 0
- }
- } else if ctxt.HeadType == objabi.Hdarwin {
- if r.Type == objabi.R_CALL {
- if ctxt.LinkMode == LinkExternal && rs.Type == sym.SDYNIMPORT {
- if ctxt.Arch.Family == sys.AMD64 {
- // AMD64 dynamic relocations are relative to the end of the relocation.
- o += int64(r.Siz)
- }
- } else {
- if rs.Type != sym.SHOSTOBJ {
- o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr)
- }
- o -= int64(r.Off) // relative to section offset, not symbol
- }
- } else {
- o += int64(r.Siz)
- }
- } else if ctxt.HeadType == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 { // only amd64 needs PCREL
- // PE/COFF's PC32 relocation uses the address after the relocated
- // bytes as the base. Compensate by skewing the addend.
- o += int64(r.Siz)
- } else {
- Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, ctxt.HeadType)
- }
-
- break
- }
-
- o = 0
- if r.Sym != nil {
- o += Symaddr(r.Sym)
- }
-
- o += r.Add - (s.Value + int64(r.Off) + int64(r.Siz))
- case objabi.R_SIZE:
- o = r.Sym.Size + r.Add
-
- case objabi.R_XCOFFREF:
- if ctxt.HeadType != objabi.Haix {
- Errorf(s, "find XCOFF R_REF on non-XCOFF files")
- }
- if ctxt.LinkMode != LinkExternal {
- Errorf(s, "find XCOFF R_REF with internal linking")
- }
- r.Xsym = r.Sym
- r.Xadd = r.Add
- r.Done = false
-
- // This isn't a real relocation so it must not update
- // its offset value.
- continue
-
- case objabi.R_DWARFFILEREF:
- // The final file index is saved in r.Add in dwarf.go:writelines.
- o = r.Add
- }
-
- if ctxt.Arch.Family == sys.PPC64 || ctxt.Arch.Family == sys.S390X {
- r.InitExt()
- if r.Variant != sym.RV_NONE {
- o = thearch.Archrelocvariant(ctxt, r, s, o)
- }
- }
-
- if false {
- nam := "<nil>"
- var addr int64
- if r.Sym != nil {
- nam = r.Sym.Name
- addr = Symaddr(r.Sym)
- }
- xnam := "<nil>"
- if r.Xsym != nil {
- xnam = r.Xsym.Name
- }
- fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x (xsym: %s +%#x) [type %d (%s)/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, addr, r.Add, xnam, r.Xadd, r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Variant, o)
- }
- switch siz {
- default:
- Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
- fallthrough
-
- // TODO(rsc): Remove.
- case 1:
- s.P[off] = byte(int8(o))
- case 2:
- if o != int64(int16(o)) {
- Errorf(s, "relocation address for %s is too big: %#x", r.Sym.Name, o)
- }
- i16 := int16(o)
- ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
- case 4:
- if r.Type == objabi.R_PCREL || r.Type == objabi.R_CALL {
- if o != int64(int32(o)) {
- Errorf(s, "pc-relative relocation address for %s is too big: %#x", r.Sym.Name, o)
- }
- } else {
- if o != int64(int32(o)) && o != int64(uint32(o)) {
- Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", r.Sym.Name, uint64(o))
- }
- }
-
- fl := int32(o)
- ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
- case 8:
- ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
- }
- }
-}
-
-func (ctxt *Link) reloc() {
- for _, s := range ctxt.Textp {
- relocsym(ctxt, s)
- }
- for _, s := range datap {
- relocsym(ctxt, s)
- }
- for _, s := range dwarfp {
- relocsym(ctxt, s)
- }
-}
-
-func windynrelocsym(ctxt *Link, rel, s *sym.Symbol) {
- for ri := range s.R {
- r := &s.R[ri]
- targ := r.Sym
- if targ == nil {
- continue
- }
- if !targ.Attr.Reachable() {
- if r.Type == objabi.R_WEAKADDROFF {
- continue
- }
- Errorf(s, "dynamic relocation to unreachable symbol %s", targ.Name)
- }
- if r.Sym.Plt() == -2 && r.Sym.Got() != -2 { // make dynimport JMP table for PE object files.
- targ.SetPlt(int32(rel.Size))
- r.Sym = rel
- r.Add = int64(targ.Plt())
-
- // jmp *addr
- switch ctxt.Arch.Family {
- default:
- Errorf(s, "unsupported arch %v", ctxt.Arch.Family)
- return
- case sys.I386:
- rel.AddUint8(0xff)
- rel.AddUint8(0x25)
- rel.AddAddr(ctxt.Arch, targ)
- rel.AddUint8(0x90)
- rel.AddUint8(0x90)
- case sys.AMD64:
- rel.AddUint8(0xff)
- rel.AddUint8(0x24)
- rel.AddUint8(0x25)
- rel.AddAddrPlus4(targ, 0)
- rel.AddUint8(0x90)
- }
- } else if r.Sym.Plt() >= 0 {
- r.Sym = rel
- r.Add = int64(targ.Plt())
- }
- }
-}
-
-// windynrelocsyms generates jump table to C library functions that will be
-// added later. windynrelocsyms writes the table into .rel symbol.
-func (ctxt *Link) windynrelocsyms() {
- if !(ctxt.HeadType == objabi.Hwindows && iscgo && ctxt.LinkMode == LinkInternal) {
- return
- }
-
- /* relocation table */
- rel := ctxt.Syms.Lookup(".rel", 0)
- rel.Attr |= sym.AttrReachable
- rel.Type = sym.STEXT
- ctxt.Textp = append(ctxt.Textp, rel)
-
- for _, s := range ctxt.Textp {
- if s == rel {
- continue
- }
- windynrelocsym(ctxt, rel, s)
- }
-}
-
-func dynrelocsym(ctxt *Link, s *sym.Symbol) {
- for ri := range s.R {
- r := &s.R[ri]
- if ctxt.BuildMode == BuildModePIE && ctxt.LinkMode == LinkInternal {
- // It's expected that some relocations will be done
- // later by relocsym (R_TLS_LE, R_ADDROFF), so
- // don't worry if Adddynrel returns false.
- thearch.Adddynrel(ctxt, s, r)
- continue
- }
-
- if r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT || r.Type >= objabi.ElfRelocOffset {
- if r.Sym != nil && !r.Sym.Attr.Reachable() {
- Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name)
- }
- if !thearch.Adddynrel(ctxt, s, r) {
- Errorf(s, "unsupported dynamic relocation for symbol %s (type=%d (%s) stype=%d (%s))", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Type, r.Sym.Type)
- }
- }
- }
-}
-
-func dynreloc(ctxt *Link, data *[sym.SXREF][]*sym.Symbol) {
- if ctxt.HeadType == objabi.Hwindows {
- return
- }
- // -d suppresses dynamic loader format, so we may as well not
- // compute these sections or mark their symbols as reachable.
- if *FlagD {
- return
- }
-
- for _, s := range ctxt.Textp {
- dynrelocsym(ctxt, s)
- }
- for _, syms := range data {
- for _, s := range syms {
- dynrelocsym(ctxt, s)
- }
- }
- if ctxt.IsELF {
- elfdynhash(ctxt)
- }
-}
-
-func Codeblk(ctxt *Link, addr int64, size int64) {
- CodeblkPad(ctxt, addr, size, zeros[:])
-}
-func CodeblkPad(ctxt *Link, addr int64, size int64, pad []byte) {
- if *flagA {
- ctxt.Logf("codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, ctxt.Out.Offset())
- }
-
- blk(ctxt.Out, ctxt.Textp, addr, size, pad)
-
- /* again for printing */
- if !*flagA {
- return
- }
-
- syms := ctxt.Textp
- for i, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if s.Value >= addr {
- syms = syms[i:]
- break
- }
- }
-
- eaddr := addr + size
- for _, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if s.Value >= eaddr {
- break
- }
-
- if addr < s.Value {
- ctxt.Logf("%-20s %.8x|", "_", uint64(addr))
- for ; addr < s.Value; addr++ {
- ctxt.Logf(" %.2x", 0)
- }
- ctxt.Logf("\n")
- }
-
- ctxt.Logf("%.6x\t%-20s\n", uint64(addr), s.Name)
- q := s.P
-
- for len(q) >= 16 {
- ctxt.Logf("%.6x\t% x\n", uint64(addr), q[:16])
- addr += 16
- q = q[16:]
- }
-
- if len(q) > 0 {
- ctxt.Logf("%.6x\t% x\n", uint64(addr), q)
- addr += int64(len(q))
- }
- }
-
- if addr < eaddr {
- ctxt.Logf("%-20s %.8x|", "_", uint64(addr))
- for ; addr < eaddr; addr++ {
- ctxt.Logf(" %.2x", 0)
- }
- }
-}
-
-func blk(out *OutBuf, syms []*sym.Symbol, addr, size int64, pad []byte) {
- for i, s := range syms {
- if !s.Attr.SubSymbol() && s.Value >= addr {
- syms = syms[i:]
- break
- }
- }
-
- // This doesn't distinguish the memory size from the file
- // size, and it lays out the file based on Symbol.Value, which
- // is the virtual address. DWARF compression changes file sizes,
- // so dwarfcompress will fix this up later if necessary.
- eaddr := addr + size
- for _, s := range syms {
- if s.Attr.SubSymbol() {
- continue
- }
- if s.Value >= eaddr {
- break
- }
- if s.Value < addr {
- Errorf(s, "phase error: addr=%#x but sym=%#x type=%d", addr, s.Value, s.Type)
- errorexit()
- }
- if addr < s.Value {
- out.WriteStringPad("", int(s.Value-addr), pad)
- addr = s.Value
- }
- out.WriteSym(s)
- addr += int64(len(s.P))
- if addr < s.Value+s.Size {
- out.WriteStringPad("", int(s.Value+s.Size-addr), pad)
- addr = s.Value + s.Size
- }
- if addr != s.Value+s.Size {
- Errorf(s, "phase error: addr=%#x value+size=%#x", addr, s.Value+s.Size)
- errorexit()
- }
- if s.Value+s.Size >= eaddr {
- break
- }
- }
-
- if addr < eaddr {
- out.WriteStringPad("", int(eaddr-addr), pad)
- }
- out.Flush()
-}
-
-func Datblk(ctxt *Link, addr int64, size int64) {
- writeDatblkToOutBuf(ctxt, ctxt.Out, addr, size)
-}
-
-// Used only on Wasm for now.
-func DatblkBytes(ctxt *Link, addr int64, size int64) []byte {
- buf := bytes.NewBuffer(make([]byte, 0, size))
- out := &OutBuf{w: bufio.NewWriter(buf)}
- writeDatblkToOutBuf(ctxt, out, addr, size)
- out.Flush()
- return buf.Bytes()
-}
-
-func writeDatblkToOutBuf(ctxt *Link, out *OutBuf, addr int64, size int64) {
- if *flagA {
- ctxt.Logf("datblk [%#x,%#x) at offset %#x\n", addr, addr+size, ctxt.Out.Offset())
- }
-
- blk(out, datap, addr, size, zeros[:])
-
- /* again for printing */
- if !*flagA {
- return
- }
-
- syms := datap
- for i, sym := range syms {
- if sym.Value >= addr {
- syms = syms[i:]
- break
- }
- }
-
- eaddr := addr + size
- for _, sym := range syms {
- if sym.Value >= eaddr {
- break
- }
- if addr < sym.Value {
- ctxt.Logf("\t%.8x| 00 ...\n", uint64(addr))
- addr = sym.Value
- }
-
- ctxt.Logf("%s\n\t%.8x|", sym.Name, uint64(addr))
- for i, b := range sym.P {
- if i > 0 && i%16 == 0 {
- ctxt.Logf("\n\t%.8x|", uint64(addr)+uint64(i))
- }
- ctxt.Logf(" %.2x", b)
- }
-
- addr += int64(len(sym.P))
- for ; addr < sym.Value+sym.Size; addr++ {
- ctxt.Logf(" %.2x", 0)
- }
- ctxt.Logf("\n")
-
- if ctxt.LinkMode != LinkExternal {
- continue
- }
- for i := range sym.R {
- r := &sym.R[i] // Copying sym.Reloc has measurable impact on performance
- rsname := ""
- rsval := int64(0)
- if r.Sym != nil {
- rsname = r.Sym.Name
- rsval = r.Sym.Value
- }
- typ := "?"
- switch r.Type {
- case objabi.R_ADDR:
- typ = "addr"
- case objabi.R_PCREL:
- typ = "pcrel"
- case objabi.R_CALL:
- typ = "call"
- }
- ctxt.Logf("\treloc %.8x/%d %s %s+%#x [%#x]\n", uint(sym.Value+int64(r.Off)), r.Siz, typ, rsname, r.Add, rsval+r.Add)
- }
- }
-
- if addr < eaddr {
- ctxt.Logf("\t%.8x| 00 ...\n", uint(addr))
- }
- ctxt.Logf("\t%.8x|\n", uint(eaddr))
-}
-
-func Dwarfblk(ctxt *Link, addr int64, size int64) {
- if *flagA {
- ctxt.Logf("dwarfblk [%#x,%#x) at offset %#x\n", addr, addr+size, ctxt.Out.Offset())
- }
-
- blk(ctxt.Out, dwarfp, addr, size, zeros[:])
-}
-
-var zeros [512]byte
-
-var (
- strdata = make(map[string]string)
- strnames []string
-)
-
-func addstrdata1(ctxt *Link, arg string) {
- eq := strings.Index(arg, "=")
- dot := strings.LastIndex(arg[:eq+1], ".")
- if eq < 0 || dot < 0 {
- Exitf("-X flag requires argument of the form importpath.name=value")
- }
- pkg := arg[:dot]
- if ctxt.BuildMode == BuildModePlugin && pkg == "main" {
- pkg = *flagPluginPath
- }
- pkg = objabi.PathToPrefix(pkg)
- name := pkg + arg[dot:eq]
- value := arg[eq+1:]
- if _, ok := strdata[name]; !ok {
- strnames = append(strnames, name)
- }
- strdata[name] = value
-}
-
-// addstrdata sets the initial value of the string variable name to value.
-func addstrdata(ctxt *Link, name, value string) {
- s := ctxt.Syms.ROLookup(name, 0)
- if s == nil || s.Gotype == nil {
- // Not defined in the loaded packages.
- return
- }
- if s.Gotype.Name != "type.string" {
- Errorf(s, "cannot set with -X: not a var of type string (%s)", s.Gotype.Name)
- return
- }
- if s.Type == sym.SBSS {
- s.Type = sym.SDATA
- }
-
- p := fmt.Sprintf("%s.str", s.Name)
- sp := ctxt.Syms.Lookup(p, 0)
-
- Addstring(sp, value)
- sp.Type = sym.SRODATA
-
- s.Size = 0
- s.P = s.P[:0]
- if s.Attr.ReadOnly() {
- s.P = make([]byte, 0, ctxt.Arch.PtrSize*2)
- s.Attr.Set(sym.AttrReadOnly, false)
- }
- s.R = s.R[:0]
- reachable := s.Attr.Reachable()
- s.AddAddr(ctxt.Arch, sp)
- s.AddUint(ctxt.Arch, uint64(len(value)))
-
- // addstring, addaddr, etc., mark the symbols as reachable.
- // In this case that is not necessarily true, so stick to what
- // we know before entering this function.
- s.Attr.Set(sym.AttrReachable, reachable)
-
- sp.Attr.Set(sym.AttrReachable, reachable)
-}
-
-func (ctxt *Link) dostrdata() {
- for _, name := range strnames {
- addstrdata(ctxt, name, strdata[name])
- }
-}
-
-func Addstring(s *sym.Symbol, str string) int64 {
- if s.Type == 0 {
- s.Type = sym.SNOPTRDATA
- }
- s.Attr |= sym.AttrReachable
- r := s.Size
- if s.Name == ".shstrtab" {
- elfsetstring(s, str, int(r))
- }
- s.P = append(s.P, str...)
- s.P = append(s.P, 0)
- s.Size = int64(len(s.P))
- return r
-}
-
-// addgostring adds str, as a Go string value, to s. symname is the name of the
-// symbol used to define the string data and must be unique per linked object.
-func addgostring(ctxt *Link, s *sym.Symbol, symname, str string) {
- sdata := ctxt.Syms.Lookup(symname, 0)
- if sdata.Type != sym.Sxxx {
- Errorf(s, "duplicate symname in addgostring: %s", symname)
- }
- sdata.Attr |= sym.AttrReachable
- sdata.Attr |= sym.AttrLocal
- sdata.Type = sym.SRODATA
- sdata.Size = int64(len(str))
- sdata.P = []byte(str)
- s.AddAddr(ctxt.Arch, sdata)
- s.AddUint(ctxt.Arch, uint64(len(str)))
-}
-
-func addinitarrdata(ctxt *Link, s *sym.Symbol) {
- p := s.Name + ".ptr"
- sp := ctxt.Syms.Lookup(p, 0)
- sp.Type = sym.SINITARR
- sp.Size = 0
- sp.Attr |= sym.AttrDuplicateOK
- sp.AddAddr(ctxt.Arch, s)
-}
-
-// symalign returns the required alignment for the given symbol s.
-func symalign(s *sym.Symbol) int32 {
- min := int32(thearch.Minalign)
- if s.Align >= min {
- return s.Align
- } else if s.Align != 0 {
- return min
- }
- if strings.HasPrefix(s.Name, "go.string.") || strings.HasPrefix(s.Name, "type..namedata.") {
- // String data is just bytes.
- // If we align it, we waste a lot of space to padding.
- return min
- }
- align := int32(thearch.Maxalign)
- for int64(align) > s.Size && align > min {
- align >>= 1
- }
- s.Align = align
- return align
-}
-
-func aligndatsize(datsize int64, s *sym.Symbol) int64 {
- return Rnd(datsize, int64(symalign(s)))
-}
-
-const debugGCProg = false
-
-type GCProg struct {
- ctxt *Link
- sym *sym.Symbol
- w gcprog.Writer
-}
-
-func (p *GCProg) Init(ctxt *Link, name string) {
- p.ctxt = ctxt
- p.sym = ctxt.Syms.Lookup(name, 0)
- p.w.Init(p.writeByte(ctxt))
- if debugGCProg {
- fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name)
- p.w.Debug(os.Stderr)
- }
-}
-
-func (p *GCProg) writeByte(ctxt *Link) func(x byte) {
- return func(x byte) {
- p.sym.AddUint8(x)
- }
-}
-
-func (p *GCProg) End(size int64) {
- p.w.ZeroUntil(size / int64(p.ctxt.Arch.PtrSize))
- p.w.End()
- if debugGCProg {
- fmt.Fprintf(os.Stderr, "ld: end GCProg\n")
- }
-}
-
-func (p *GCProg) AddSym(s *sym.Symbol) {
- typ := s.Gotype
- // Things without pointers should be in sym.SNOPTRDATA or sym.SNOPTRBSS;
- // everything we see should have pointers and should therefore have a type.
- if typ == nil {
- switch s.Name {
- case "runtime.data", "runtime.edata", "runtime.bss", "runtime.ebss":
- // Ignore special symbols that are sometimes laid out
- // as real symbols. See comment about dyld on darwin in
- // the address function.
- return
- }
- Errorf(s, "missing Go type information for global symbol: size %d", s.Size)
- return
- }
-
- ptrsize := int64(p.ctxt.Arch.PtrSize)
- nptr := decodetypePtrdata(p.ctxt.Arch, typ.P) / ptrsize
-
- if debugGCProg {
- fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr)
- }
-
- if decodetypeUsegcprog(p.ctxt.Arch, typ.P) == 0 {
- // Copy pointers from mask into program.
- mask := decodetypeGcmask(p.ctxt, typ)
- for i := int64(0); i < nptr; i++ {
- if (mask[i/8]>>uint(i%8))&1 != 0 {
- p.w.Ptr(s.Value/ptrsize + i)
- }
- }
- return
- }
-
- // Copy program.
- prog := decodetypeGcprog(p.ctxt, typ)
- p.w.ZeroUntil(s.Value / ptrsize)
- p.w.Append(prog[4:], nptr)
-}
-
-// dataSortKey is used to sort a slice of data symbol *sym.Symbol pointers.
-// The sort keys are kept inline to improve cache behavior while sorting.
-type dataSortKey struct {
- size int64
- name string
- sym *sym.Symbol
-}
-
-type bySizeAndName []dataSortKey
-
-func (d bySizeAndName) Len() int { return len(d) }
-func (d bySizeAndName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
-func (d bySizeAndName) Less(i, j int) bool {
- s1, s2 := d[i], d[j]
- if s1.size != s2.size {
- return s1.size < s2.size
- }
- return s1.name < s2.name
-}
-
-// cutoff is the maximum data section size permitted by the linker
-// (see issue #9862).
-const cutoff = 2e9 // 2 GB (or so; looks better in errors than 2^31)
-
-func checkdatsize(ctxt *Link, datsize int64, symn sym.SymKind) {
- if datsize > cutoff {
- Errorf(nil, "too much data in section %v (over %v bytes)", symn, cutoff)
- }
-}
-
-// datap is a collection of reachable data symbols in address order.
-// Generated by dodata.
-var datap []*sym.Symbol
-
-func (ctxt *Link) dodata() {
- if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- // The values in moduledata are filled out by relocations
- // pointing to the addresses of these special symbols.
- // Typically these symbols have no size and are not laid
- // out with their matching section.
- //
- // However on darwin, dyld will find the special symbol
- // in the first loaded module, even though it is local.
- //
- // (An hypothesis, formed without looking in the dyld sources:
- // these special symbols have no size, so their address
- // matches a real symbol. The dynamic linker assumes we
- // want the normal symbol with the same address and finds
- // it in the other module.)
- //
- // To work around this we lay out the symbls whose
- // addresses are vital for multi-module programs to work
- // as normal symbols, and give them a little size.
- //
- // On AIX, as all DATA sections are merged together, ld might not put
- // these symbols at the beginning of their respective section if there
- // aren't real symbols, their alignment might not match the
- // first symbol alignment. Therefore, there are explicitly put at the
- // beginning of their section with the same alignment.
- bss := ctxt.Syms.Lookup("runtime.bss", 0)
- bss.Size = 8
- bss.Attr.Set(sym.AttrSpecial, false)
-
- ctxt.Syms.Lookup("runtime.ebss", 0).Attr.Set(sym.AttrSpecial, false)
-
- data := ctxt.Syms.Lookup("runtime.data", 0)
- data.Size = 8
- data.Attr.Set(sym.AttrSpecial, false)
-
- edata := ctxt.Syms.Lookup("runtime.edata", 0)
- edata.Attr.Set(sym.AttrSpecial, false)
- if ctxt.HeadType == objabi.Haix {
- // XCOFFTOC symbols are part of .data section.
- edata.Type = sym.SXCOFFTOC
- }
-
- types := ctxt.Syms.Lookup("runtime.types", 0)
- types.Type = sym.STYPE
- types.Size = 8
- types.Attr.Set(sym.AttrSpecial, false)
-
- etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
- etypes.Type = sym.SFUNCTAB
- etypes.Attr.Set(sym.AttrSpecial, false)
-
- if ctxt.HeadType == objabi.Haix {
- rodata := ctxt.Syms.Lookup("runtime.rodata", 0)
- rodata.Type = sym.SSTRING
- rodata.Size = 8
- rodata.Attr.Set(sym.AttrSpecial, false)
-
- ctxt.Syms.Lookup("runtime.erodata", 0).Attr.Set(sym.AttrSpecial, false)
-
- }
- }
-
- // Collect data symbols by type into data.
- var data [sym.SXREF][]*sym.Symbol
- for _, s := range ctxt.Syms.Allsym {
- if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() {
- continue
- }
- if s.Type <= sym.STEXT || s.Type >= sym.SXREF {
- continue
- }
- data[s.Type] = append(data[s.Type], s)
- }
-
- // Now that we have the data symbols, but before we start
- // to assign addresses, record all the necessary
- // dynamic relocations. These will grow the relocation
- // symbol, which is itself data.
- //
- // On darwin, we need the symbol table numbers for dynreloc.
- if ctxt.HeadType == objabi.Hdarwin {
- machosymorder(ctxt)
- }
- dynreloc(ctxt, &data)
-
- if ctxt.UseRelro() {
- // "read only" data with relocations needs to go in its own section
- // when building a shared library. We do this by boosting objects of
- // type SXXX with relocations to type SXXXRELRO.
- for _, symnro := range sym.ReadOnly {
- symnrelro := sym.RelROMap[symnro]
-
- ro := []*sym.Symbol{}
- relro := data[symnrelro]
-
- for _, s := range data[symnro] {
- isRelro := len(s.R) > 0
- switch s.Type {
- case sym.STYPE, sym.STYPERELRO, sym.SGOFUNCRELRO:
- // Symbols are not sorted yet, so it is possible
- // that an Outer symbol has been changed to a
- // relro Type before it reaches here.
- isRelro = true
- case sym.SFUNCTAB:
- if ctxt.HeadType == objabi.Haix && s.Name == "runtime.etypes" {
- // runtime.etypes must be at the end of
- // the relro datas.
- isRelro = true
- }
- }
- if isRelro {
- s.Type = symnrelro
- if s.Outer != nil {
- s.Outer.Type = s.Type
- }
- relro = append(relro, s)
- } else {
- ro = append(ro, s)
- }
- }
-
- // Check that we haven't made two symbols with the same .Outer into
- // different types (because references two symbols with non-nil Outer
- // become references to the outer symbol + offset it's vital that the
- // symbol and the outer end up in the same section).
- for _, s := range relro {
- if s.Outer != nil && s.Outer.Type != s.Type {
- Errorf(s, "inconsistent types for symbol and its Outer %s (%v != %v)",
- s.Outer.Name, s.Type, s.Outer.Type)
- }
- }
-
- data[symnro] = ro
- data[symnrelro] = relro
- }
- }
-
- // Sort symbols.
- var dataMaxAlign [sym.SXREF]int32
- var wg sync.WaitGroup
- for symn := range data {
- symn := sym.SymKind(symn)
- wg.Add(1)
- go func() {
- data[symn], dataMaxAlign[symn] = dodataSect(ctxt, symn, data[symn])
- wg.Done()
- }()
- }
- wg.Wait()
-
- if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
- // These symbols must have the same alignment as their section.
- // Otherwize, ld might change the layout of Go sections.
- ctxt.Syms.ROLookup("runtime.data", 0).Align = dataMaxAlign[sym.SDATA]
- ctxt.Syms.ROLookup("runtime.bss", 0).Align = dataMaxAlign[sym.SBSS]
- }
-
- // Allocate sections.
- // Data is processed before segtext, because we need
- // to see all symbols in the .data and .bss sections in order
- // to generate garbage collection information.
- datsize := int64(0)
-
- // Writable data sections that do not need any specialized handling.
- writable := []sym.SymKind{
- sym.SBUILDINFO,
- sym.SELFSECT,
- sym.SMACHO,
- sym.SMACHOGOT,
- sym.SWINDOWS,
- }
- for _, symn := range writable {
- for _, s := range data[symn] {
- sect := addsection(ctxt.Arch, &Segdata, s.Name, 06)
- sect.Align = symalign(s)
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- s.Sect = sect
- s.Type = sym.SDATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- sect.Length = uint64(datsize) - sect.Vaddr
- }
- checkdatsize(ctxt, datsize, symn)
- }
-
- // .got (and .toc on ppc64)
- if len(data[sym.SELFGOT]) > 0 {
- sect := addsection(ctxt.Arch, &Segdata, ".got", 06)
- sect.Align = dataMaxAlign[sym.SELFGOT]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- for _, s := range data[sym.SELFGOT] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Type = sym.SDATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
-
- // Resolve .TOC. symbol for this object file (ppc64)
- toc := ctxt.Syms.ROLookup(".TOC.", int(s.Version))
- if toc != nil {
- toc.Sect = sect
- toc.Outer = s
- toc.Sub = s.Sub
- s.Sub = toc
-
- toc.Value = 0x8000
- }
-
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, sym.SELFGOT)
- sect.Length = uint64(datsize) - sect.Vaddr
- }
-
- /* pointer-free data */
- sect := addsection(ctxt.Arch, &Segdata, ".noptrdata", 06)
- sect.Align = dataMaxAlign[sym.SNOPTRDATA]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.enoptrdata", 0).Sect = sect
- for _, s := range data[sym.SNOPTRDATA] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Type = sym.SDATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, sym.SNOPTRDATA)
- sect.Length = uint64(datsize) - sect.Vaddr
-
- hasinitarr := ctxt.linkShared
-
- /* shared library initializer */
- switch ctxt.BuildMode {
- case BuildModeCArchive, BuildModeCShared, BuildModeShared, BuildModePlugin:
- hasinitarr = true
- }
-
- if ctxt.HeadType == objabi.Haix {
- if len(data[sym.SINITARR]) > 0 {
- Errorf(nil, "XCOFF format doesn't allow .init_array section")
- }
- }
-
- if hasinitarr && len(data[sym.SINITARR]) > 0 {
- sect := addsection(ctxt.Arch, &Segdata, ".init_array", 06)
- sect.Align = dataMaxAlign[sym.SINITARR]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- for _, s := range data[sym.SINITARR] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- sect.Length = uint64(datsize) - sect.Vaddr
- checkdatsize(ctxt, datsize, sym.SINITARR)
- }
-
- /* data */
- sect = addsection(ctxt.Arch, &Segdata, ".data", 06)
- sect.Align = dataMaxAlign[sym.SDATA]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- ctxt.Syms.Lookup("runtime.data", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.edata", 0).Sect = sect
- var gc GCProg
- gc.Init(ctxt, "runtime.gcdata")
- for _, s := range data[sym.SDATA] {
- s.Sect = sect
- s.Type = sym.SDATA
- datsize = aligndatsize(datsize, s)
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- gc.AddSym(s)
- datsize += s.Size
- }
- gc.End(datsize - int64(sect.Vaddr))
- // On AIX, TOC entries must be the last of .data
- // These aren't part of gc as they won't change during the runtime.
- for _, s := range data[sym.SXCOFFTOC] {
- s.Sect = sect
- s.Type = sym.SDATA
- datsize = aligndatsize(datsize, s)
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, sym.SDATA)
- sect.Length = uint64(datsize) - sect.Vaddr
-
- /* bss */
- sect = addsection(ctxt.Arch, &Segdata, ".bss", 06)
- sect.Align = dataMaxAlign[sym.SBSS]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- ctxt.Syms.Lookup("runtime.bss", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.ebss", 0).Sect = sect
- gc = GCProg{}
- gc.Init(ctxt, "runtime.gcbss")
- for _, s := range data[sym.SBSS] {
- s.Sect = sect
- datsize = aligndatsize(datsize, s)
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- gc.AddSym(s)
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, sym.SBSS)
- sect.Length = uint64(datsize) - sect.Vaddr
- gc.End(int64(sect.Length))
-
- /* pointer-free bss */
- sect = addsection(ctxt.Arch, &Segdata, ".noptrbss", 06)
- sect.Align = dataMaxAlign[sym.SNOPTRBSS]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- ctxt.Syms.Lookup("runtime.noptrbss", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.enoptrbss", 0).Sect = sect
- for _, s := range data[sym.SNOPTRBSS] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- sect.Length = uint64(datsize) - sect.Vaddr
- ctxt.Syms.Lookup("runtime.end", 0).Sect = sect
- checkdatsize(ctxt, datsize, sym.SNOPTRBSS)
-
- // Coverage instrumentation counters for libfuzzer.
- if len(data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
- sect := addsection(ctxt.Arch, &Segdata, "__libfuzzer_extra_counters", 06)
- sect.Align = dataMaxAlign[sym.SLIBFUZZER_EXTRA_COUNTER]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- for _, s := range data[sym.SLIBFUZZER_EXTRA_COUNTER] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- sect.Length = uint64(datsize) - sect.Vaddr
- checkdatsize(ctxt, datsize, sym.SLIBFUZZER_EXTRA_COUNTER)
- }
-
- if len(data[sym.STLSBSS]) > 0 {
- var sect *sym.Section
- if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && (ctxt.LinkMode == LinkExternal || !*FlagD) {
- sect = addsection(ctxt.Arch, &Segdata, ".tbss", 06)
- sect.Align = int32(ctxt.Arch.PtrSize)
- sect.Vaddr = 0
- }
- datsize = 0
-
- for _, s := range data[sym.STLSBSS] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Value = datsize
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, sym.STLSBSS)
-
- if sect != nil {
- sect.Length = uint64(datsize)
- }
- }
-
- /*
- * We finished data, begin read-only data.
- * Not all systems support a separate read-only non-executable data section.
- * ELF and Windows PE systems do.
- * OS X and Plan 9 do not.
- * And if we're using external linking mode, the point is moot,
- * since it's not our decision; that code expects the sections in
- * segtext.
- */
- var segro *sym.Segment
- if ctxt.IsELF && ctxt.LinkMode == LinkInternal {
- segro = &Segrodata
- } else if ctxt.HeadType == objabi.Hwindows {
- segro = &Segrodata
- } else {
- segro = &Segtext
- }
-
- datsize = 0
-
- /* read-only executable ELF, Mach-O sections */
- if len(data[sym.STEXT]) != 0 {
- Errorf(nil, "dodata found an sym.STEXT symbol: %s", data[sym.STEXT][0].Name)
- }
- for _, s := range data[sym.SELFRXSECT] {
- sect := addsection(ctxt.Arch, &Segtext, s.Name, 04)
- sect.Align = symalign(s)
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- sect.Length = uint64(datsize) - sect.Vaddr
- checkdatsize(ctxt, datsize, sym.SELFRXSECT)
- }
-
- /* read-only data */
- sect = addsection(ctxt.Arch, segro, ".rodata", 04)
-
- sect.Vaddr = 0
- ctxt.Syms.Lookup("runtime.rodata", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.erodata", 0).Sect = sect
- if !ctxt.UseRelro() {
- ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
- }
- for _, symn := range sym.ReadOnly {
- align := dataMaxAlign[symn]
- if sect.Align < align {
- sect.Align = align
- }
- }
- datsize = Rnd(datsize, int64(sect.Align))
- for _, symn := range sym.ReadOnly {
- symnStartValue := datsize
- for _, s := range data[symn] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, symn)
- if ctxt.HeadType == objabi.Haix {
- // Read-only symbols might be wrapped inside their outer
- // symbol.
- // XCOFF symbol table needs to know the size of
- // these outer symbols.
- xcoffUpdateOuterSize(ctxt, datsize-symnStartValue, symn)
- }
- }
- sect.Length = uint64(datsize) - sect.Vaddr
-
- /* read-only ELF, Mach-O sections */
- for _, s := range data[sym.SELFROSECT] {
- sect = addsection(ctxt.Arch, segro, s.Name, 04)
- sect.Align = symalign(s)
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- sect.Length = uint64(datsize) - sect.Vaddr
- }
- checkdatsize(ctxt, datsize, sym.SELFROSECT)
-
- for _, s := range data[sym.SMACHOPLT] {
- sect = addsection(ctxt.Arch, segro, s.Name, 04)
- sect.Align = symalign(s)
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- sect.Length = uint64(datsize) - sect.Vaddr
- }
- checkdatsize(ctxt, datsize, sym.SMACHOPLT)
-
- // There is some data that are conceptually read-only but are written to by
- // relocations. On GNU systems, we can arrange for the dynamic linker to
- // mprotect sections after relocations are applied by giving them write
- // permissions in the object file and calling them ".data.rel.ro.FOO". We
- // divide the .rodata section between actual .rodata and .data.rel.ro.rodata,
- // but for the other sections that this applies to, we just write a read-only
- // .FOO section or a read-write .data.rel.ro.FOO section depending on the
- // situation.
- // TODO(mwhudson): It would make sense to do this more widely, but it makes
- // the system linker segfault on darwin.
- addrelrosection := func(suffix string) *sym.Section {
- return addsection(ctxt.Arch, segro, suffix, 04)
- }
-
- if ctxt.UseRelro() {
- segrelro := &Segrelrodata
- if ctxt.LinkMode == LinkExternal && ctxt.HeadType != objabi.Haix {
- // Using a separate segment with an external
- // linker results in some programs moving
- // their data sections unexpectedly, which
- // corrupts the moduledata. So we use the
- // rodata segment and let the external linker
- // sort out a rel.ro segment.
- segrelro = segro
- } else {
- // Reset datsize for new segment.
- datsize = 0
- }
-
- addrelrosection = func(suffix string) *sym.Section {
- return addsection(ctxt.Arch, segrelro, ".data.rel.ro"+suffix, 06)
- }
-
- /* data only written by relocations */
- sect = addrelrosection("")
-
- ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
-
- for _, symnro := range sym.ReadOnly {
- symn := sym.RelROMap[symnro]
- align := dataMaxAlign[symn]
- if sect.Align < align {
- sect.Align = align
- }
- }
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
-
- for i, symnro := range sym.ReadOnly {
- if i == 0 && symnro == sym.STYPE && ctxt.HeadType != objabi.Haix {
- // Skip forward so that no type
- // reference uses a zero offset.
- // This is unlikely but possible in small
- // programs with no other read-only data.
- datsize++
- }
-
- symn := sym.RelROMap[symnro]
- symnStartValue := datsize
- for _, s := range data[symn] {
- datsize = aligndatsize(datsize, s)
- if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
- Errorf(s, "s.Outer (%s) in different section from s, %s != %s", s.Outer.Name, s.Outer.Sect.Name, sect.Name)
- }
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, symn)
- if ctxt.HeadType == objabi.Haix {
- // Read-only symbols might be wrapped inside their outer
- // symbol.
- // XCOFF symbol table needs to know the size of
- // these outer symbols.
- xcoffUpdateOuterSize(ctxt, datsize-symnStartValue, symn)
- }
- }
-
- sect.Length = uint64(datsize) - sect.Vaddr
- }
-
- /* typelink */
- sect = addrelrosection(".typelink")
- sect.Align = dataMaxAlign[sym.STYPELINK]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
- typelink.Sect = sect
- typelink.Type = sym.SRODATA
- datsize += typelink.Size
- checkdatsize(ctxt, datsize, sym.STYPELINK)
- sect.Length = uint64(datsize) - sect.Vaddr
-
- /* itablink */
- sect = addrelrosection(".itablink")
- sect.Align = dataMaxAlign[sym.SITABLINK]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- ctxt.Syms.Lookup("runtime.itablink", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.eitablink", 0).Sect = sect
- for _, s := range data[sym.SITABLINK] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, sym.SITABLINK)
- sect.Length = uint64(datsize) - sect.Vaddr
- if ctxt.HeadType == objabi.Haix {
- // Store .itablink size because its symbols are wrapped
- // under an outer symbol: runtime.itablink.
- xcoffUpdateOuterSize(ctxt, int64(sect.Length), sym.SITABLINK)
- }
-
- /* gosymtab */
- sect = addrelrosection(".gosymtab")
- sect.Align = dataMaxAlign[sym.SSYMTAB]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- ctxt.Syms.Lookup("runtime.symtab", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.esymtab", 0).Sect = sect
- for _, s := range data[sym.SSYMTAB] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, sym.SSYMTAB)
- sect.Length = uint64(datsize) - sect.Vaddr
-
- /* gopclntab */
- sect = addrelrosection(".gopclntab")
- sect.Align = dataMaxAlign[sym.SPCLNTAB]
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- ctxt.Syms.Lookup("runtime.pclntab", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.epclntab", 0).Sect = sect
- for _, s := range data[sym.SPCLNTAB] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- checkdatsize(ctxt, datsize, sym.SRODATA)
- sect.Length = uint64(datsize) - sect.Vaddr
-
- // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
- if datsize != int64(uint32(datsize)) {
- Errorf(nil, "read-only data segment too large: %d", datsize)
- }
-
- for symn := sym.SELFRXSECT; symn < sym.SXREF; symn++ {
- datap = append(datap, data[symn]...)
- }
-
- dwarfGenerateDebugSyms(ctxt)
-
- var i int
- for ; i < len(dwarfp); i++ {
- s := dwarfp[i]
- if s.Type != sym.SDWARFSECT {
- break
- }
-
- sect = addsection(ctxt.Arch, &Segdwarf, s.Name, 04)
- sect.Align = 1
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- sect.Length = uint64(datsize) - sect.Vaddr
- }
- checkdatsize(ctxt, datsize, sym.SDWARFSECT)
-
- for i < len(dwarfp) {
- curType := dwarfp[i].Type
- var sect *sym.Section
- switch curType {
- case sym.SDWARFINFO:
- sect = addsection(ctxt.Arch, &Segdwarf, ".debug_info", 04)
- case sym.SDWARFRANGE:
- sect = addsection(ctxt.Arch, &Segdwarf, ".debug_ranges", 04)
- case sym.SDWARFLOC:
- sect = addsection(ctxt.Arch, &Segdwarf, ".debug_loc", 04)
- default:
- // Error is unrecoverable, so panic.
- panic(fmt.Sprintf("unknown DWARF section %v", curType))
- }
-
- sect.Align = 1
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- for ; i < len(dwarfp); i++ {
- s := dwarfp[i]
- if s.Type != curType {
- break
- }
- s.Sect = sect
- s.Type = sym.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- s.Attr |= sym.AttrLocal
- datsize += s.Size
-
- if ctxt.HeadType == objabi.Haix && curType == sym.SDWARFLOC {
- // Update the size of .debug_loc for this symbol's
- // package.
- addDwsectCUSize(".debug_loc", s.File, uint64(s.Size))
- }
- }
- sect.Length = uint64(datsize) - sect.Vaddr
- checkdatsize(ctxt, datsize, curType)
- }
-
- /* number the sections */
- n := int32(1)
-
- for _, sect := range Segtext.Sections {
- sect.Extnum = int16(n)
- n++
- }
- for _, sect := range Segrodata.Sections {
- sect.Extnum = int16(n)
- n++
- }
- for _, sect := range Segrelrodata.Sections {
- sect.Extnum = int16(n)
- n++
- }
- for _, sect := range Segdata.Sections {
- sect.Extnum = int16(n)
- n++
- }
- for _, sect := range Segdwarf.Sections {
- sect.Extnum = int16(n)
- n++
- }
-}
-
-func dodataSect(ctxt *Link, symn sym.SymKind, syms []*sym.Symbol) (result []*sym.Symbol, maxAlign int32) {
- if ctxt.HeadType == objabi.Hdarwin {
- // Some symbols may no longer belong in syms
- // due to movement in machosymorder.
- newSyms := make([]*sym.Symbol, 0, len(syms))
- for _, s := range syms {
- if s.Type == symn {
- newSyms = append(newSyms, s)
- }
- }
- syms = newSyms
- }
-
- var head, tail *sym.Symbol
- symsSort := make([]dataSortKey, 0, len(syms))
- for _, s := range syms {
- if s.Attr.OnList() {
- log.Fatalf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
- switch {
- case s.Size < int64(len(s.P)):
- Errorf(s, "initialize bounds (%d < %d)", s.Size, len(s.P))
- case s.Size < 0:
- Errorf(s, "negative size (%d bytes)", s.Size)
- case s.Size > cutoff:
- Errorf(s, "symbol too large (%d bytes)", s.Size)
- }
-
- // If the usually-special section-marker symbols are being laid
- // out as regular symbols, put them either at the beginning or
- // end of their section.
- if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- switch s.Name {
- case "runtime.text", "runtime.bss", "runtime.data", "runtime.types", "runtime.rodata":
- head = s
- continue
- case "runtime.etext", "runtime.ebss", "runtime.edata", "runtime.etypes", "runtime.erodata":
- tail = s
- continue
- }
- }
-
- key := dataSortKey{
- size: s.Size,
- name: s.Name,
- sym: s,
- }
-
- switch s.Type {
- case sym.SELFGOT:
- // For ppc64, we want to interleave the .got and .toc sections
- // from input files. Both are type sym.SELFGOT, so in that case
- // we skip size comparison and fall through to the name
- // comparison (conveniently, .got sorts before .toc).
- key.size = 0
- }
-
- symsSort = append(symsSort, key)
- }
-
- sort.Sort(bySizeAndName(symsSort))
-
- off := 0
- if head != nil {
- syms[0] = head
- off++
- }
- for i, symSort := range symsSort {
- syms[i+off] = symSort.sym
- align := symalign(symSort.sym)
- if maxAlign < align {
- maxAlign = align
- }
- }
- if tail != nil {
- syms[len(syms)-1] = tail
- }
-
- if ctxt.IsELF && symn == sym.SELFROSECT {
- // Make .rela and .rela.plt contiguous, the ELF ABI requires this
- // and Solaris actually cares.
- reli, plti := -1, -1
- for i, s := range syms {
- switch s.Name {
- case ".rel.plt", ".rela.plt":
- plti = i
- case ".rel", ".rela":
- reli = i
- }
- }
- if reli >= 0 && plti >= 0 && plti != reli+1 {
- var first, second int
- if plti > reli {
- first, second = reli, plti
- } else {
- first, second = plti, reli
- }
- rel, plt := syms[reli], syms[plti]
- copy(syms[first+2:], syms[first+1:second])
- syms[first+0] = rel
- syms[first+1] = plt
-
- // Make sure alignment doesn't introduce a gap.
- // Setting the alignment explicitly prevents
- // symalign from basing it on the size and
- // getting it wrong.
- rel.Align = int32(ctxt.Arch.RegSize)
- plt.Align = int32(ctxt.Arch.RegSize)
- }
- }
-
- return syms, maxAlign
-}
-
-// Add buildid to beginning of text segment, on non-ELF systems.
-// Non-ELF binary formats are not always flexible enough to
-// give us a place to put the Go build ID. On those systems, we put it
-// at the very beginning of the text segment.
-// This ``header'' is read by cmd/go.
-func (ctxt *Link) textbuildid() {
- if ctxt.IsELF || ctxt.BuildMode == BuildModePlugin || *flagBuildid == "" {
- return
- }
-
- s := ctxt.Syms.Lookup("go.buildid", 0)
- s.Attr |= sym.AttrReachable
- // The \xff is invalid UTF-8, meant to make it less likely
- // to find one of these accidentally.
- data := "\xff Go build ID: " + strconv.Quote(*flagBuildid) + "\n \xff"
- s.Type = sym.STEXT
- s.P = []byte(data)
- s.Size = int64(len(s.P))
-
- ctxt.Textp = append(ctxt.Textp, nil)
- copy(ctxt.Textp[1:], ctxt.Textp)
- ctxt.Textp[0] = s
-}
-
-func (ctxt *Link) buildinfo() {
- if ctxt.linkShared || ctxt.BuildMode == BuildModePlugin {
- // -linkshared and -buildmode=plugin get confused
- // about the relocations in go.buildinfo
- // pointing at the other data sections.
- // The version information is only available in executables.
- return
- }
-
- s := ctxt.Syms.Lookup(".go.buildinfo", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SBUILDINFO
- s.Align = 16
- // The \xff is invalid UTF-8, meant to make it less likely
- // to find one of these accidentally.
- const prefix = "\xff Go buildinf:" // 14 bytes, plus 2 data bytes filled in below
- data := make([]byte, 32)
- copy(data, prefix)
- data[len(prefix)] = byte(ctxt.Arch.PtrSize)
- data[len(prefix)+1] = 0
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- data[len(prefix)+1] = 1
- }
- s.P = data
- s.Size = int64(len(s.P))
- s1 := ctxt.Syms.Lookup("runtime.buildVersion", 0)
- s2 := ctxt.Syms.Lookup("runtime.modinfo", 0)
- s.R = []sym.Reloc{
- {Off: 16, Siz: uint8(ctxt.Arch.PtrSize), Type: objabi.R_ADDR, Sym: s1},
- {Off: 16 + int32(ctxt.Arch.PtrSize), Siz: uint8(ctxt.Arch.PtrSize), Type: objabi.R_ADDR, Sym: s2},
- }
-}
-
-// assign addresses to text
-func (ctxt *Link) textaddress() {
- addsection(ctxt.Arch, &Segtext, ".text", 05)
-
- // Assign PCs in text segment.
- // Could parallelize, by assigning to text
- // and then letting threads copy down, but probably not worth it.
- sect := Segtext.Sections[0]
-
- sect.Align = int32(Funcalign)
-
- text := ctxt.Syms.Lookup("runtime.text", 0)
- text.Sect = sect
- if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
- // Setting runtime.text has a real symbol prevents ld to
- // change its base address resulting in wrong offsets for
- // reflect methods.
- text.Align = sect.Align
- text.Size = 0x8
- }
-
- if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- etext := ctxt.Syms.Lookup("runtime.etext", 0)
- etext.Sect = sect
-
- ctxt.Textp = append(ctxt.Textp, etext, nil)
- copy(ctxt.Textp[1:], ctxt.Textp)
- ctxt.Textp[0] = text
- }
-
- va := uint64(*FlagTextAddr)
- n := 1
- sect.Vaddr = va
- ntramps := 0
- for _, s := range ctxt.Textp {
- sect, n, va = assignAddress(ctxt, sect, n, s, va, false)
-
- trampoline(ctxt, s) // resolve jumps, may add trampolines if jump too far
-
- // lay down trampolines after each function
- for ; ntramps < len(ctxt.tramps); ntramps++ {
- tramp := ctxt.tramps[ntramps]
- if ctxt.HeadType == objabi.Haix && strings.HasPrefix(tramp.Name, "runtime.text.") {
- // Already set in assignAddress
- continue
- }
- sect, n, va = assignAddress(ctxt, sect, n, tramp, va, true)
- }
- }
-
- sect.Length = va - sect.Vaddr
- ctxt.Syms.Lookup("runtime.etext", 0).Sect = sect
-
- // merge tramps into Textp, keeping Textp in address order
- if ntramps != 0 {
- newtextp := make([]*sym.Symbol, 0, len(ctxt.Textp)+ntramps)
- i := 0
- for _, s := range ctxt.Textp {
- for ; i < ntramps && ctxt.tramps[i].Value < s.Value; i++ {
- newtextp = append(newtextp, ctxt.tramps[i])
- }
- newtextp = append(newtextp, s)
- }
- newtextp = append(newtextp, ctxt.tramps[i:ntramps]...)
-
- ctxt.Textp = newtextp
- }
-}
-
-// assigns address for a text symbol, returns (possibly new) section, its number, and the address
-// Note: once we have trampoline insertion support for external linking, this function
-// will not need to create new text sections, and so no need to return sect and n.
-func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint64, isTramp bool) (*sym.Section, int, uint64) {
- if thearch.AssignAddress != nil {
- return thearch.AssignAddress(ctxt, sect, n, s, va, isTramp)
- }
-
- s.Sect = sect
- if s.Attr.SubSymbol() {
- return sect, n, va
- }
- if s.Align != 0 {
- va = uint64(Rnd(int64(va), int64(s.Align)))
- } else {
- va = uint64(Rnd(int64(va), int64(Funcalign)))
- }
-
- funcsize := uint64(MINFUNC) // spacing required for findfunctab
- if s.Size > MINFUNC {
- funcsize = uint64(s.Size)
- }
-
- if sect.Align < s.Align {
- sect.Align = s.Align
- }
-
- // On ppc64x a text section should not be larger than 2^26 bytes due to the size of
- // call target offset field in the bl instruction. Splitting into smaller text
- // sections smaller than this limit allows the GNU linker to modify the long calls
- // appropriately. The limit allows for the space needed for tables inserted by the linker.
-
- // If this function doesn't fit in the current text section, then create a new one.
-
- // Only break at outermost syms.
-
- if ctxt.Arch.InFamily(sys.PPC64) && s.Outer == nil && ctxt.LinkMode == LinkExternal && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(s, isTramp) > 0x1c00000 {
- // Set the length for the previous text section
- sect.Length = va - sect.Vaddr
-
- // Create new section, set the starting Vaddr
- sect = addsection(ctxt.Arch, &Segtext, ".text", 05)
- sect.Vaddr = va
- s.Sect = sect
-
- // Create a symbol for the start of the secondary text sections
- ntext := ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
- ntext.Sect = sect
- if ctxt.HeadType == objabi.Haix {
- // runtime.text.X must be a real symbol on AIX.
- // Assign its address directly in order to be the
- // first symbol of this new section.
- ntext.Type = sym.STEXT
- ntext.Size = int64(MINFUNC)
- ntext.Attr |= sym.AttrReachable
- ntext.Attr |= sym.AttrOnList
- ctxt.tramps = append(ctxt.tramps, ntext)
-
- ntext.Value = int64(va)
- va += uint64(ntext.Size)
-
- if s.Align != 0 {
- va = uint64(Rnd(int64(va), int64(s.Align)))
- } else {
- va = uint64(Rnd(int64(va), int64(Funcalign)))
- }
- }
- n++
- }
-
- s.Value = 0
- for sub := s; sub != nil; sub = sub.Sub {
- sub.Value += int64(va)
- }
-
- va += funcsize
-
- return sect, n, va
-}
-
-// address assigns virtual addresses to all segments and sections and
-// returns all segments in file order.
-func (ctxt *Link) address() []*sym.Segment {
- var order []*sym.Segment // Layout order
-
- va := uint64(*FlagTextAddr)
- order = append(order, &Segtext)
- Segtext.Rwx = 05
- Segtext.Vaddr = va
- for _, s := range Segtext.Sections {
- va = uint64(Rnd(int64(va), int64(s.Align)))
- s.Vaddr = va
- va += s.Length
- }
-
- Segtext.Length = va - uint64(*FlagTextAddr)
-
- if len(Segrodata.Sections) > 0 {
- // align to page boundary so as not to mix
- // rodata and executable text.
- //
- // Note: gold or GNU ld will reduce the size of the executable
- // file by arranging for the relro segment to end at a page
- // boundary, and overlap the end of the text segment with the
- // start of the relro segment in the file. The PT_LOAD segments
- // will be such that the last page of the text segment will be
- // mapped twice, once r-x and once starting out rw- and, after
- // relocation processing, changed to r--.
- //
- // Ideally the last page of the text segment would not be
- // writable even for this short period.
- va = uint64(Rnd(int64(va), int64(*FlagRound)))
-
- order = append(order, &Segrodata)
- Segrodata.Rwx = 04
- Segrodata.Vaddr = va
- for _, s := range Segrodata.Sections {
- va = uint64(Rnd(int64(va), int64(s.Align)))
- s.Vaddr = va
- va += s.Length
- }
-
- Segrodata.Length = va - Segrodata.Vaddr
- }
- if len(Segrelrodata.Sections) > 0 {
- // align to page boundary so as not to mix
- // rodata, rel-ro data, and executable text.
- va = uint64(Rnd(int64(va), int64(*FlagRound)))
- if ctxt.HeadType == objabi.Haix {
- // Relro data are inside data segment on AIX.
- va += uint64(XCOFFDATABASE) - uint64(XCOFFTEXTBASE)
- }
-
- order = append(order, &Segrelrodata)
- Segrelrodata.Rwx = 06
- Segrelrodata.Vaddr = va
- for _, s := range Segrelrodata.Sections {
- va = uint64(Rnd(int64(va), int64(s.Align)))
- s.Vaddr = va
- va += s.Length
- }
-
- Segrelrodata.Length = va - Segrelrodata.Vaddr
- }
-
- va = uint64(Rnd(int64(va), int64(*FlagRound)))
- if ctxt.HeadType == objabi.Haix && len(Segrelrodata.Sections) == 0 {
- // Data sections are moved to an unreachable segment
- // to ensure that they are position-independent.
- // Already done if relro sections exist.
- va += uint64(XCOFFDATABASE) - uint64(XCOFFTEXTBASE)
- }
- order = append(order, &Segdata)
- Segdata.Rwx = 06
- Segdata.Vaddr = va
- var data *sym.Section
- var noptr *sym.Section
- var bss *sym.Section
- var noptrbss *sym.Section
- for i, s := range Segdata.Sections {
- if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && s.Name == ".tbss" {
- continue
- }
- vlen := int64(s.Length)
- if i+1 < len(Segdata.Sections) && !((ctxt.IsELF || ctxt.HeadType == objabi.Haix) && Segdata.Sections[i+1].Name == ".tbss") {
- vlen = int64(Segdata.Sections[i+1].Vaddr - s.Vaddr)
- }
- s.Vaddr = va
- va += uint64(vlen)
- Segdata.Length = va - Segdata.Vaddr
- if s.Name == ".data" {
- data = s
- }
- if s.Name == ".noptrdata" {
- noptr = s
- }
- if s.Name == ".bss" {
- bss = s
- }
- if s.Name == ".noptrbss" {
- noptrbss = s
- }
- }
-
- // Assign Segdata's Filelen omitting the BSS. We do this here
- // simply because right now we know where the BSS starts.
- Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
-
- va = uint64(Rnd(int64(va), int64(*FlagRound)))
- order = append(order, &Segdwarf)
- Segdwarf.Rwx = 06
- Segdwarf.Vaddr = va
- for i, s := range Segdwarf.Sections {
- vlen := int64(s.Length)
- if i+1 < len(Segdwarf.Sections) {
- vlen = int64(Segdwarf.Sections[i+1].Vaddr - s.Vaddr)
- }
- s.Vaddr = va
- va += uint64(vlen)
- if ctxt.HeadType == objabi.Hwindows {
- va = uint64(Rnd(int64(va), PEFILEALIGN))
- }
- Segdwarf.Length = va - Segdwarf.Vaddr
- }
-
- var (
- text = Segtext.Sections[0]
- rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect
- itablink = ctxt.Syms.Lookup("runtime.itablink", 0).Sect
- symtab = ctxt.Syms.Lookup("runtime.symtab", 0).Sect
- pclntab = ctxt.Syms.Lookup("runtime.pclntab", 0).Sect
- types = ctxt.Syms.Lookup("runtime.types", 0).Sect
- )
- lasttext := text
- // Could be multiple .text sections
- for _, sect := range Segtext.Sections {
- if sect.Name == ".text" {
- lasttext = sect
- }
- }
-
- for _, s := range datap {
- if s.Sect != nil {
- s.Value += int64(s.Sect.Vaddr)
- }
- for sub := s.Sub; sub != nil; sub = sub.Sub {
- sub.Value += s.Value
- }
- }
-
- for _, s := range dwarfp {
- if s.Sect != nil {
- s.Value += int64(s.Sect.Vaddr)
- }
- for sub := s.Sub; sub != nil; sub = sub.Sub {
- sub.Value += s.Value
- }
- }
-
- if ctxt.BuildMode == BuildModeShared {
- s := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
- sectSym := ctxt.Syms.Lookup(".note.go.abihash", 0)
- s.Sect = sectSym.Sect
- s.Value = int64(sectSym.Sect.Vaddr + 16)
- }
-
- ctxt.xdefine("runtime.text", sym.STEXT, int64(text.Vaddr))
- ctxt.xdefine("runtime.etext", sym.STEXT, int64(lasttext.Vaddr+lasttext.Length))
-
- // If there are multiple text sections, create runtime.text.n for
- // their section Vaddr, using n for index
- n := 1
- for _, sect := range Segtext.Sections[1:] {
- if sect.Name != ".text" {
- break
- }
- symname := fmt.Sprintf("runtime.text.%d", n)
- if ctxt.HeadType != objabi.Haix || ctxt.LinkMode != LinkExternal {
- // Addresses are already set on AIX with external linker
- // because these symbols are part of their sections.
- ctxt.xdefine(symname, sym.STEXT, int64(sect.Vaddr))
- }
- n++
- }
-
- ctxt.xdefine("runtime.rodata", sym.SRODATA, int64(rodata.Vaddr))
- ctxt.xdefine("runtime.erodata", sym.SRODATA, int64(rodata.Vaddr+rodata.Length))
- ctxt.xdefine("runtime.types", sym.SRODATA, int64(types.Vaddr))
- ctxt.xdefine("runtime.etypes", sym.SRODATA, int64(types.Vaddr+types.Length))
- ctxt.xdefine("runtime.itablink", sym.SRODATA, int64(itablink.Vaddr))
- ctxt.xdefine("runtime.eitablink", sym.SRODATA, int64(itablink.Vaddr+itablink.Length))
-
- s := ctxt.Syms.Lookup("runtime.gcdata", 0)
- s.Attr |= sym.AttrLocal
- ctxt.xdefine("runtime.egcdata", sym.SRODATA, Symaddr(s)+s.Size)
- ctxt.Syms.Lookup("runtime.egcdata", 0).Sect = s.Sect
-
- s = ctxt.Syms.Lookup("runtime.gcbss", 0)
- s.Attr |= sym.AttrLocal
- ctxt.xdefine("runtime.egcbss", sym.SRODATA, Symaddr(s)+s.Size)
- ctxt.Syms.Lookup("runtime.egcbss", 0).Sect = s.Sect
-
- ctxt.xdefine("runtime.symtab", sym.SRODATA, int64(symtab.Vaddr))
- ctxt.xdefine("runtime.esymtab", sym.SRODATA, int64(symtab.Vaddr+symtab.Length))
- ctxt.xdefine("runtime.pclntab", sym.SRODATA, int64(pclntab.Vaddr))
- ctxt.xdefine("runtime.epclntab", sym.SRODATA, int64(pclntab.Vaddr+pclntab.Length))
- ctxt.xdefine("runtime.noptrdata", sym.SNOPTRDATA, int64(noptr.Vaddr))
- ctxt.xdefine("runtime.enoptrdata", sym.SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
- ctxt.xdefine("runtime.bss", sym.SBSS, int64(bss.Vaddr))
- ctxt.xdefine("runtime.ebss", sym.SBSS, int64(bss.Vaddr+bss.Length))
- ctxt.xdefine("runtime.data", sym.SDATA, int64(data.Vaddr))
- ctxt.xdefine("runtime.edata", sym.SDATA, int64(data.Vaddr+data.Length))
- ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr))
- ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
- ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
-
- return order
-}
-
-// layout assigns file offsets and lengths to the segments in order.
-// Returns the file size containing all the segments.
-func (ctxt *Link) layout(order []*sym.Segment) uint64 {
- var prev *sym.Segment
- for _, seg := range order {
- if prev == nil {
- seg.Fileoff = uint64(HEADR)
- } else {
- switch ctxt.HeadType {
- default:
- // Assuming the previous segment was
- // aligned, the following rounding
- // should ensure that this segment's
- // VA ≡ Fileoff mod FlagRound.
- seg.Fileoff = uint64(Rnd(int64(prev.Fileoff+prev.Filelen), int64(*FlagRound)))
- if seg.Vaddr%uint64(*FlagRound) != seg.Fileoff%uint64(*FlagRound) {
- Exitf("bad segment rounding (Vaddr=%#x Fileoff=%#x FlagRound=%#x)", seg.Vaddr, seg.Fileoff, *FlagRound)
- }
- case objabi.Hwindows:
- seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), PEFILEALIGN))
- case objabi.Hplan9:
- seg.Fileoff = prev.Fileoff + prev.Filelen
- }
- }
- if seg != &Segdata {
- // Link.address already set Segdata.Filelen to
- // account for BSS.
- seg.Filelen = seg.Length
- }
- prev = seg
- }
- return prev.Fileoff + prev.Filelen
-}
-
-// add a trampoline with symbol s (to be laid down after the current function)
-func (ctxt *Link) AddTramp(s *sym.Symbol) {
- s.Type = sym.STEXT
- s.Attr |= sym.AttrReachable
- s.Attr |= sym.AttrOnList
- ctxt.tramps = append(ctxt.tramps, s)
- if *FlagDebugTramp > 0 && ctxt.Debugvlog > 0 {
- ctxt.Logf("trampoline %s inserted\n", s)
- }
-}
-
-// compressSyms compresses syms and returns the contents of the
-// compressed section. If the section would get larger, it returns nil.
-func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte {
- var total int64
- for _, sym := range syms {
- total += sym.Size
- }
-
- var buf bytes.Buffer
- buf.Write([]byte("ZLIB"))
- var sizeBytes [8]byte
- binary.BigEndian.PutUint64(sizeBytes[:], uint64(total))
- buf.Write(sizeBytes[:])
-
- // Using zlib.BestSpeed achieves very nearly the same
- // compression levels of zlib.DefaultCompression, but takes
- // substantially less time. This is important because DWARF
- // compression can be a significant fraction of link time.
- z, err := zlib.NewWriterLevel(&buf, zlib.BestSpeed)
- if err != nil {
- log.Fatalf("NewWriterLevel failed: %s", err)
- }
- for _, s := range syms {
- // s.P may be read-only. Apply relocations in a
- // temporary buffer, and immediately write it out.
- oldP := s.P
- wasReadOnly := s.Attr.ReadOnly()
- if len(s.R) != 0 && wasReadOnly {
- ctxt.relocbuf = append(ctxt.relocbuf[:0], s.P...)
- s.P = ctxt.relocbuf
- s.Attr.Set(sym.AttrReadOnly, false)
- }
- relocsym(ctxt, s)
- if _, err := z.Write(s.P); err != nil {
- log.Fatalf("compression failed: %s", err)
- }
- for i := s.Size - int64(len(s.P)); i > 0; {
- b := zeros[:]
- if i < int64(len(b)) {
- b = b[:i]
- }
- n, err := z.Write(b)
- if err != nil {
- log.Fatalf("compression failed: %s", err)
- }
- i -= int64(n)
- }
- // Restore s.P if a temporary buffer was used. If compression
- // is not beneficial, we'll go back to use the uncompressed
- // contents, in which case we still need s.P.
- if len(s.R) != 0 && wasReadOnly {
- s.P = oldP
- s.Attr.Set(sym.AttrReadOnly, wasReadOnly)
- for i := range s.R {
- s.R[i].Done = false
- }
- }
- }
- if err := z.Close(); err != nil {
- log.Fatalf("compression failed: %s", err)
- }
- if int64(buf.Len()) >= total {
- // Compression didn't save any space.
- return nil
- }
- return buf.Bytes()
-}
+++ /dev/null
-// 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)
- }
-}
+++ /dev/null
-// 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)
-}
+++ /dev/null
-// 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)
-}
+++ /dev/null
-// 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.
-
-// TODO/NICETOHAVE:
-// - eliminate DW_CLS_ if not used
-// - package info in compilation units
-// - assign types to their packages
-// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
-// ptype struct '[]uint8' and qualifiers need to be quoted away
-// - file:line info for variables
-// - make strings a typedef so prettyprinters can see the underlying string type
-
-package ld
-
-import (
- "cmd/internal/dwarf"
- "cmd/internal/obj"
- "cmd/internal/objabi"
- "cmd/internal/src"
- "cmd/internal/sys"
- "cmd/oldlink/internal/sym"
- "fmt"
- "log"
- "sort"
- "strings"
-)
-
-type dwctxt struct {
- linkctxt *Link
-}
-
-func (c dwctxt) PtrSize() int {
- return c.linkctxt.Arch.PtrSize
-}
-func (c dwctxt) AddInt(s dwarf.Sym, size int, i int64) {
- ls := s.(*sym.Symbol)
- ls.AddUintXX(c.linkctxt.Arch, uint64(i), size)
-}
-func (c dwctxt) AddBytes(s dwarf.Sym, b []byte) {
- ls := s.(*sym.Symbol)
- ls.AddBytes(b)
-}
-func (c dwctxt) AddString(s dwarf.Sym, v string) {
- Addstring(s.(*sym.Symbol), v)
-}
-
-func (c dwctxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
- if value != 0 {
- value -= (data.(*sym.Symbol)).Value
- }
- s.(*sym.Symbol).AddAddrPlus(c.linkctxt.Arch, data.(*sym.Symbol), value)
-}
-
-func (c dwctxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
- if value != 0 {
- value -= (data.(*sym.Symbol)).Value
- }
- s.(*sym.Symbol).AddCURelativeAddrPlus(c.linkctxt.Arch, data.(*sym.Symbol), value)
-}
-
-func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
- ls := s.(*sym.Symbol)
- switch size {
- default:
- Errorf(ls, "invalid size %d in adddwarfref\n", size)
- fallthrough
- case c.linkctxt.Arch.PtrSize:
- ls.AddAddr(c.linkctxt.Arch, t.(*sym.Symbol))
- case 4:
- ls.AddAddrPlus4(t.(*sym.Symbol), 0)
- }
- r := &ls.R[len(ls.R)-1]
- r.Type = objabi.R_ADDROFF
- r.Add = ofs
-}
-
-func (c dwctxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
- size := 4
- if isDwarf64(c.linkctxt) {
- size = 8
- }
-
- c.AddSectionOffset(s, size, t, ofs)
- ls := s.(*sym.Symbol)
- ls.R[len(ls.R)-1].Type = objabi.R_DWARFSECREF
-}
-
-func (c dwctxt) Logf(format string, args ...interface{}) {
- c.linkctxt.Logf(format, args...)
-}
-
-// At the moment these interfaces are only used in the compiler.
-
-func (c dwctxt) AddFileRef(s dwarf.Sym, f interface{}) {
- panic("should be used only in the compiler")
-}
-
-func (c dwctxt) CurrentOffset(s dwarf.Sym) int64 {
- panic("should be used only in the compiler")
-}
-
-func (c dwctxt) RecordDclReference(s dwarf.Sym, t dwarf.Sym, dclIdx int, inlIndex int) {
- panic("should be used only in the compiler")
-}
-
-func (c dwctxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
- panic("should be used only in the compiler")
-}
-
-func isDwarf64(ctxt *Link) bool {
- return ctxt.HeadType == objabi.Haix
-}
-
-var gdbscript string
-
-var dwarfp []*sym.Symbol
-
-func writeabbrev(ctxt *Link) *sym.Symbol {
- s := ctxt.Syms.Lookup(".debug_abbrev", 0)
- s.Type = sym.SDWARFSECT
- s.AddBytes(dwarf.GetAbbrev())
- return s
-}
-
-var dwtypes dwarf.DWDie
-
-func newattr(die *dwarf.DWDie, attr uint16, cls int, value int64, data interface{}) *dwarf.DWAttr {
- a := new(dwarf.DWAttr)
- a.Link = die.Attr
- die.Attr = a
- a.Atr = attr
- a.Cls = uint8(cls)
- a.Value = value
- a.Data = data
- return a
-}
-
-// Each DIE (except the root ones) has at least 1 attribute: its
-// name. getattr moves the desired one to the front so
-// frequently searched ones are found faster.
-func getattr(die *dwarf.DWDie, attr uint16) *dwarf.DWAttr {
- if die.Attr.Atr == attr {
- return die.Attr
- }
-
- a := die.Attr
- b := a.Link
- for b != nil {
- if b.Atr == attr {
- a.Link = b.Link
- b.Link = die.Attr
- die.Attr = b
- return b
- }
-
- a = b
- b = b.Link
- }
-
- return nil
-}
-
-// Every DIE manufactured by the linker has at least an AT_name
-// attribute (but it will only be written out if it is listed in the abbrev).
-// The compiler does create nameless DWARF DIEs (ex: concrete subprogram
-// instance).
-func newdie(ctxt *Link, parent *dwarf.DWDie, abbrev int, name string, version int) *dwarf.DWDie {
- die := new(dwarf.DWDie)
- die.Abbrev = abbrev
- die.Link = parent.Child
- parent.Child = die
-
- newattr(die, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len(name)), name)
-
- if name != "" && (abbrev <= dwarf.DW_ABRV_VARIABLE || abbrev >= dwarf.DW_ABRV_NULLTYPE) {
- if abbrev != dwarf.DW_ABRV_VARIABLE || version == 0 {
- if abbrev == dwarf.DW_ABRV_COMPUNIT {
- // Avoid collisions with "real" symbol names.
- name = fmt.Sprintf(".pkg.%s.%d", name, len(ctxt.compUnits))
- }
- s := ctxt.Syms.Lookup(dwarf.InfoPrefix+name, version)
- s.Attr |= sym.AttrNotInSymbolTable
- s.Type = sym.SDWARFINFO
- die.Sym = s
- }
- }
-
- return die
-}
-
-func walktypedef(die *dwarf.DWDie) *dwarf.DWDie {
- if die == nil {
- return nil
- }
- // Resolve typedef if present.
- if die.Abbrev == dwarf.DW_ABRV_TYPEDECL {
- for attr := die.Attr; attr != nil; attr = attr.Link {
- if attr.Atr == dwarf.DW_AT_type && attr.Cls == dwarf.DW_CLS_REFERENCE && attr.Data != nil {
- return attr.Data.(*dwarf.DWDie)
- }
- }
- }
-
- return die
-}
-
-func walksymtypedef(ctxt *Link, s *sym.Symbol) *sym.Symbol {
- if t := ctxt.Syms.ROLookup(s.Name+"..def", int(s.Version)); t != nil {
- return t
- }
- return s
-}
-
-// Find child by AT_name using hashtable if available or linear scan
-// if not.
-func findchild(die *dwarf.DWDie, name string) *dwarf.DWDie {
- var prev *dwarf.DWDie
- for ; die != prev; prev, die = die, walktypedef(die) {
- for a := die.Child; a != nil; a = a.Link {
- if name == getattr(a, dwarf.DW_AT_name).Data {
- return a
- }
- }
- continue
- }
- return nil
-}
-
-// Used to avoid string allocation when looking up dwarf symbols
-var prefixBuf = []byte(dwarf.InfoPrefix)
-
-func find(ctxt *Link, name string) *sym.Symbol {
- n := append(prefixBuf, name...)
- // The string allocation below is optimized away because it is only used in a map lookup.
- s := ctxt.Syms.ROLookup(string(n), 0)
- prefixBuf = n[:len(dwarf.InfoPrefix)]
- if s != nil && s.Type == sym.SDWARFINFO {
- return s
- }
- return nil
-}
-
-func mustFind(ctxt *Link, name string) *sym.Symbol {
- r := find(ctxt, name)
- if r == nil {
- Exitf("dwarf find: cannot find %s", name)
- }
- return r
-}
-
-func adddwarfref(ctxt *Link, s *sym.Symbol, t *sym.Symbol, size int) int64 {
- var result int64
- switch size {
- default:
- Errorf(s, "invalid size %d in adddwarfref\n", size)
- fallthrough
- case ctxt.Arch.PtrSize:
- result = s.AddAddr(ctxt.Arch, t)
- case 4:
- result = s.AddAddrPlus4(t, 0)
- }
- r := &s.R[len(s.R)-1]
- r.Type = objabi.R_DWARFSECREF
- return result
-}
-
-func newrefattr(die *dwarf.DWDie, attr uint16, ref *sym.Symbol) *dwarf.DWAttr {
- if ref == nil {
- return nil
- }
- return newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, ref)
-}
-
-func dtolsym(s dwarf.Sym) *sym.Symbol {
- if s == nil {
- return nil
- }
- return s.(*sym.Symbol)
-}
-
-func putdie(linkctxt *Link, ctxt dwarf.Context, syms []*sym.Symbol, die *dwarf.DWDie) []*sym.Symbol {
- s := dtolsym(die.Sym)
- if s == nil {
- s = syms[len(syms)-1]
- } else {
- if s.Attr.OnList() {
- log.Fatalf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
- syms = append(syms, s)
- }
- dwarf.Uleb128put(ctxt, s, int64(die.Abbrev))
- dwarf.PutAttrs(ctxt, s, die.Abbrev, die.Attr)
- if dwarf.HasChildren(die) {
- for die := die.Child; die != nil; die = die.Link {
- syms = putdie(linkctxt, ctxt, syms, die)
- }
- syms[len(syms)-1].AddUint8(0)
- }
- return syms
-}
-
-func reverselist(list **dwarf.DWDie) {
- curr := *list
- var prev *dwarf.DWDie
- for curr != nil {
- next := curr.Link
- curr.Link = prev
- prev = curr
- curr = next
- }
-
- *list = prev
-}
-
-func reversetree(list **dwarf.DWDie) {
- reverselist(list)
- for die := *list; die != nil; die = die.Link {
- if dwarf.HasChildren(die) {
- reversetree(&die.Child)
- }
- }
-}
-
-func newmemberoffsetattr(die *dwarf.DWDie, offs int32) {
- newattr(die, dwarf.DW_AT_data_member_location, dwarf.DW_CLS_CONSTANT, int64(offs), nil)
-}
-
-// GDB doesn't like FORM_addr for AT_location, so emit a
-// location expression that evals to a const.
-func newabslocexprattr(die *dwarf.DWDie, addr int64, sym *sym.Symbol) {
- newattr(die, dwarf.DW_AT_location, dwarf.DW_CLS_ADDRESS, addr, sym)
- // below
-}
-
-// Lookup predefined types
-func lookupOrDiag(ctxt *Link, n string) *sym.Symbol {
- s := ctxt.Syms.ROLookup(n, 0)
- if s == nil || s.Size == 0 {
- Exitf("dwarf: missing type: %s", n)
- }
-
- return s
-}
-
-// dwarfFuncSym looks up a DWARF metadata symbol for function symbol s.
-// If the symbol does not exist, it creates it if create is true,
-// or returns nil otherwise.
-func dwarfFuncSym(ctxt *Link, s *sym.Symbol, meta string, create bool) *sym.Symbol {
- // All function ABIs use symbol version 0 for the DWARF data.
- //
- // TODO(austin): It may be useful to have DWARF info for ABI
- // wrappers, in which case we may want these versions to
- // align. Better yet, replace these name lookups with a
- // general way to attach metadata to a symbol.
- ver := 0
- if s.IsFileLocal() {
- ver = int(s.Version)
- }
- if create {
- return ctxt.Syms.Lookup(meta+s.Name, ver)
- }
- return ctxt.Syms.ROLookup(meta+s.Name, ver)
-}
-
-func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) *dwarf.DWDie {
- // Only emit typedefs for real names.
- if strings.HasPrefix(name, "map[") {
- return nil
- }
- if strings.HasPrefix(name, "struct {") {
- return nil
- }
- if strings.HasPrefix(name, "chan ") {
- return nil
- }
- if name[0] == '[' || name[0] == '*' {
- return nil
- }
- if def == nil {
- Errorf(nil, "dwarf: bad def in dotypedef")
- }
-
- s := ctxt.Syms.Lookup(dtolsym(def.Sym).Name+"..def", 0)
- s.Attr |= sym.AttrNotInSymbolTable
- s.Type = sym.SDWARFINFO
- def.Sym = s
-
- // The typedef entry must be created after the def,
- // so that future lookups will find the typedef instead
- // of the real definition. This hooks the typedef into any
- // circular definition loops, so that gdb can understand them.
- die := newdie(ctxt, parent, dwarf.DW_ABRV_TYPEDECL, name, 0)
-
- newrefattr(die, dwarf.DW_AT_type, s)
-
- return die
-}
-
-// Define gotype, for composite ones recurse into constituents.
-func defgotype(ctxt *Link, gotype *sym.Symbol) *sym.Symbol {
- if gotype == nil {
- return mustFind(ctxt, "<unspecified>")
- }
-
- if !strings.HasPrefix(gotype.Name, "type.") {
- Errorf(gotype, "dwarf: type name doesn't start with \"type.\"")
- return mustFind(ctxt, "<unspecified>")
- }
-
- name := gotype.Name[5:] // could also decode from Type.string
-
- sdie := find(ctxt, name)
-
- if sdie != nil {
- return sdie
- }
-
- return newtype(ctxt, gotype).Sym.(*sym.Symbol)
-}
-
-func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
- name := gotype.Name[5:] // could also decode from Type.string
- kind := decodetypeKind(ctxt.Arch, gotype.P)
- bytesize := decodetypeSize(ctxt.Arch, gotype.P)
-
- var die, typedefdie *dwarf.DWDie
- switch kind {
- case objabi.KindBool:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
- newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_boolean, 0)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
-
- case objabi.KindInt,
- objabi.KindInt8,
- objabi.KindInt16,
- objabi.KindInt32,
- objabi.KindInt64:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
- newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_signed, 0)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
-
- case objabi.KindUint,
- objabi.KindUint8,
- objabi.KindUint16,
- objabi.KindUint32,
- objabi.KindUint64,
- objabi.KindUintptr:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
- newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
-
- case objabi.KindFloat32,
- objabi.KindFloat64:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
- newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_float, 0)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
-
- case objabi.KindComplex64,
- objabi.KindComplex128:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
- newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_complex_float, 0)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
-
- case objabi.KindArray:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_ARRAYTYPE, name, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
- s := decodetypeArrayElem(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
- fld := newdie(ctxt, die, dwarf.DW_ABRV_ARRAYRANGE, "range", 0)
-
- // use actual length not upper bound; correct for 0-length arrays.
- newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, decodetypeArrayLen(ctxt.Arch, gotype), 0)
-
- newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
-
- case objabi.KindChan:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_CHANTYPE, name, 0)
- s := decodetypeChanElem(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_go_elem, defgotype(ctxt, s))
- // Save elem type for synthesizechantypes. We could synthesize here
- // but that would change the order of DIEs we output.
- newrefattr(die, dwarf.DW_AT_type, s)
-
- case objabi.KindFunc:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
- nfields := decodetypeFuncInCount(ctxt.Arch, gotype.P)
- for i := 0; i < nfields; i++ {
- s := decodetypeFuncInType(ctxt.Arch, gotype, i)
- fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
- newrefattr(fld, dwarf.DW_AT_type, defgotype(ctxt, s))
- }
-
- if decodetypeFuncDotdotdot(ctxt.Arch, gotype.P) {
- newdie(ctxt, die, dwarf.DW_ABRV_DOTDOTDOT, "...", 0)
- }
- nfields = decodetypeFuncOutCount(ctxt.Arch, gotype.P)
- for i := 0; i < nfields; i++ {
- s := decodetypeFuncOutType(ctxt.Arch, gotype, i)
- fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
- newrefattr(fld, dwarf.DW_AT_type, defptrto(ctxt, defgotype(ctxt, s)))
- }
-
- case objabi.KindInterface:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
- nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype.P))
- var s *sym.Symbol
- if nfields == 0 {
- s = lookupOrDiag(ctxt, "type.runtime.eface")
- } else {
- s = lookupOrDiag(ctxt, "type.runtime.iface")
- }
- newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
-
- case objabi.KindMap:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_MAPTYPE, name, 0)
- s := decodetypeMapKey(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_go_key, defgotype(ctxt, s))
- s = decodetypeMapValue(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_go_elem, defgotype(ctxt, s))
- // Save gotype for use in synthesizemaptypes. We could synthesize here,
- // but that would change the order of the DIEs.
- newrefattr(die, dwarf.DW_AT_type, gotype)
-
- case objabi.KindPtr:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_PTRTYPE, name, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
- s := decodetypePtrElem(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
-
- case objabi.KindSlice:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_SLICETYPE, name, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
- s := decodetypeArrayElem(ctxt.Arch, gotype)
- elem := defgotype(ctxt, s)
- newrefattr(die, dwarf.DW_AT_go_elem, elem)
-
- case objabi.KindString:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_STRINGTYPE, name, 0)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
-
- case objabi.KindStruct:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_STRUCTTYPE, name, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
- nfields := decodetypeStructFieldCount(ctxt.Arch, gotype)
- for i := 0; i < nfields; i++ {
- f := decodetypeStructFieldName(ctxt.Arch, gotype, i)
- s := decodetypeStructFieldType(ctxt.Arch, gotype, i)
- if f == "" {
- f = s.Name[5:] // skip "type."
- }
- fld := newdie(ctxt, die, dwarf.DW_ABRV_STRUCTFIELD, f, 0)
- newrefattr(fld, dwarf.DW_AT_type, defgotype(ctxt, s))
- offsetAnon := decodetypeStructFieldOffsAnon(ctxt.Arch, gotype, i)
- newmemberoffsetattr(fld, int32(offsetAnon>>1))
- if offsetAnon&1 != 0 { // is embedded field
- newattr(fld, dwarf.DW_AT_go_embedded_field, dwarf.DW_CLS_FLAG, 1, 0)
- }
- }
-
- case objabi.KindUnsafePointer:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, name, 0)
-
- default:
- Errorf(gotype, "dwarf: definition of unknown kind %d", kind)
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_TYPEDECL, name, 0)
- newrefattr(die, dwarf.DW_AT_type, mustFind(ctxt, "<unspecified>"))
- }
-
- newattr(die, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(kind), 0)
- if gotype.Attr.Reachable() {
- newattr(die, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, gotype)
- }
-
- if _, ok := prototypedies[gotype.Name]; ok {
- prototypedies[gotype.Name] = die
- }
-
- if typedefdie != nil {
- return typedefdie
- }
- return die
-}
-
-func nameFromDIESym(dwtype *sym.Symbol) string {
- return strings.TrimSuffix(dwtype.Name[len(dwarf.InfoPrefix):], "..def")
-}
-
-// Find or construct *T given T.
-func defptrto(ctxt *Link, dwtype *sym.Symbol) *sym.Symbol {
- ptrname := "*" + nameFromDIESym(dwtype)
- if die := find(ctxt, ptrname); die != nil {
- return die
- }
-
- pdie := newdie(ctxt, &dwtypes, dwarf.DW_ABRV_PTRTYPE, ptrname, 0)
- newrefattr(pdie, dwarf.DW_AT_type, dwtype)
-
- // The DWARF info synthesizes pointer types that don't exist at the
- // language level, like *hash<...> and *bucket<...>, and the data
- // pointers of slices. Link to the ones we can find.
- gotype := ctxt.Syms.ROLookup("type."+ptrname, 0)
- if gotype != nil && gotype.Attr.Reachable() {
- newattr(pdie, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, gotype)
- }
- return dtolsym(pdie.Sym)
-}
-
-// Copies src's children into dst. Copies attributes by value.
-// DWAttr.data is copied as pointer only. If except is one of
-// the top-level children, it will not be copied.
-func copychildrenexcept(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie, except *dwarf.DWDie) {
- for src = src.Child; src != nil; src = src.Link {
- if src == except {
- continue
- }
- c := newdie(ctxt, dst, src.Abbrev, getattr(src, dwarf.DW_AT_name).Data.(string), 0)
- for a := src.Attr; a != nil; a = a.Link {
- newattr(c, a.Atr, int(a.Cls), a.Value, a.Data)
- }
- copychildrenexcept(ctxt, c, src, nil)
- }
-
- reverselist(&dst.Child)
-}
-
-func copychildren(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie) {
- copychildrenexcept(ctxt, dst, src, nil)
-}
-
-// Search children (assumed to have TAG_member) for the one named
-// field and set its AT_type to dwtype
-func substitutetype(structdie *dwarf.DWDie, field string, dwtype *sym.Symbol) {
- child := findchild(structdie, field)
- if child == nil {
- Exitf("dwarf substitutetype: %s does not have member %s",
- getattr(structdie, dwarf.DW_AT_name).Data, field)
- return
- }
-
- a := getattr(child, dwarf.DW_AT_type)
- if a != nil {
- a.Data = dwtype
- } else {
- newrefattr(child, dwarf.DW_AT_type, dwtype)
- }
-}
-
-func findprotodie(ctxt *Link, name string) *dwarf.DWDie {
- die, ok := prototypedies[name]
- if ok && die == nil {
- defgotype(ctxt, lookupOrDiag(ctxt, name))
- die = prototypedies[name]
- }
- return die
-}
-
-func synthesizestringtypes(ctxt *Link, die *dwarf.DWDie) {
- prototype := walktypedef(findprotodie(ctxt, "type.runtime.stringStructDWARF"))
- if prototype == nil {
- return
- }
-
- for ; die != nil; die = die.Link {
- if die.Abbrev != dwarf.DW_ABRV_STRINGTYPE {
- continue
- }
- copychildren(ctxt, die, prototype)
- }
-}
-
-func synthesizeslicetypes(ctxt *Link, die *dwarf.DWDie) {
- prototype := walktypedef(findprotodie(ctxt, "type.runtime.slice"))
- if prototype == nil {
- return
- }
-
- for ; die != nil; die = die.Link {
- if die.Abbrev != dwarf.DW_ABRV_SLICETYPE {
- continue
- }
- copychildren(ctxt, die, prototype)
- elem := getattr(die, dwarf.DW_AT_go_elem).Data.(*sym.Symbol)
- substitutetype(die, "array", defptrto(ctxt, elem))
- }
-}
-
-func mkinternaltypename(base string, arg1 string, arg2 string) string {
- if arg2 == "" {
- return fmt.Sprintf("%s<%s>", base, arg1)
- }
- return fmt.Sprintf("%s<%s,%s>", base, arg1, arg2)
-}
-
-// synthesizemaptypes is way too closely married to runtime/hashmap.c
-const (
- MaxKeySize = 128
- MaxValSize = 128
- BucketSize = 8
-)
-
-func mkinternaltype(ctxt *Link, abbrev int, typename, keyname, valname string, f func(*dwarf.DWDie)) *sym.Symbol {
- name := mkinternaltypename(typename, keyname, valname)
- symname := dwarf.InfoPrefix + name
- s := ctxt.Syms.ROLookup(symname, 0)
- if s != nil && s.Type == sym.SDWARFINFO {
- return s
- }
- die := newdie(ctxt, &dwtypes, abbrev, name, 0)
- f(die)
- return dtolsym(die.Sym)
-}
-
-func synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
- hash := walktypedef(findprotodie(ctxt, "type.runtime.hmap"))
- bucket := walktypedef(findprotodie(ctxt, "type.runtime.bmap"))
-
- if hash == nil {
- return
- }
-
- for ; die != nil; die = die.Link {
- if die.Abbrev != dwarf.DW_ABRV_MAPTYPE {
- continue
- }
- gotype := getattr(die, dwarf.DW_AT_type).Data.(*sym.Symbol)
- keytype := decodetypeMapKey(ctxt.Arch, gotype)
- valtype := decodetypeMapValue(ctxt.Arch, gotype)
- keysize, valsize := decodetypeSize(ctxt.Arch, keytype.P), decodetypeSize(ctxt.Arch, valtype.P)
- keytype, valtype = walksymtypedef(ctxt, defgotype(ctxt, keytype)), walksymtypedef(ctxt, defgotype(ctxt, valtype))
-
- // compute size info like hashmap.c does.
- indirectKey, indirectVal := false, false
- if keysize > MaxKeySize {
- keysize = int64(ctxt.Arch.PtrSize)
- indirectKey = true
- }
- if valsize > MaxValSize {
- valsize = int64(ctxt.Arch.PtrSize)
- indirectVal = true
- }
-
- // Construct type to represent an array of BucketSize keys
- keyname := nameFromDIESym(keytype)
- dwhks := mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *dwarf.DWDie) {
- newattr(dwhk, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize*keysize, 0)
- t := keytype
- if indirectKey {
- t = defptrto(ctxt, keytype)
- }
- newrefattr(dwhk, dwarf.DW_AT_type, t)
- fld := newdie(ctxt, dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
- newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 0)
- newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
- })
-
- // Construct type to represent an array of BucketSize values
- valname := nameFromDIESym(valtype)
- dwhvs := mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *dwarf.DWDie) {
- newattr(dwhv, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize*valsize, 0)
- t := valtype
- if indirectVal {
- t = defptrto(ctxt, valtype)
- }
- newrefattr(dwhv, dwarf.DW_AT_type, t)
- fld := newdie(ctxt, dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
- newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 0)
- newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
- })
-
- // Construct bucket<K,V>
- dwhbs := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *dwarf.DWDie) {
- // Copy over all fields except the field "data" from the generic
- // bucket. "data" will be replaced with keys/values below.
- copychildrenexcept(ctxt, dwhb, bucket, findchild(bucket, "data"))
-
- fld := newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys", 0)
- newrefattr(fld, dwarf.DW_AT_type, dwhks)
- newmemberoffsetattr(fld, BucketSize)
- fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values", 0)
- newrefattr(fld, dwarf.DW_AT_type, dwhvs)
- newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
- fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow", 0)
- newrefattr(fld, dwarf.DW_AT_type, defptrto(ctxt, dtolsym(dwhb.Sym)))
- newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
- if ctxt.Arch.RegSize > ctxt.Arch.PtrSize {
- fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad", 0)
- newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
- newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(ctxt.Arch.PtrSize))
- }
-
- newattr(dwhb, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*valsize+int64(ctxt.Arch.RegSize), 0)
- })
-
- // Construct hash<K,V>
- dwhs := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *dwarf.DWDie) {
- copychildren(ctxt, dwh, hash)
- substitutetype(dwh, "buckets", defptrto(ctxt, dwhbs))
- substitutetype(dwh, "oldbuckets", defptrto(ctxt, dwhbs))
- newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hash, dwarf.DW_AT_byte_size).Value, nil)
- })
-
- // make map type a pointer to hash<K,V>
- newrefattr(die, dwarf.DW_AT_type, defptrto(ctxt, dwhs))
- }
-}
-
-func synthesizechantypes(ctxt *Link, die *dwarf.DWDie) {
- sudog := walktypedef(findprotodie(ctxt, "type.runtime.sudog"))
- waitq := walktypedef(findprotodie(ctxt, "type.runtime.waitq"))
- hchan := walktypedef(findprotodie(ctxt, "type.runtime.hchan"))
- if sudog == nil || waitq == nil || hchan == nil {
- return
- }
-
- sudogsize := int(getattr(sudog, dwarf.DW_AT_byte_size).Value)
-
- for ; die != nil; die = die.Link {
- if die.Abbrev != dwarf.DW_ABRV_CHANTYPE {
- continue
- }
- elemgotype := getattr(die, dwarf.DW_AT_type).Data.(*sym.Symbol)
- elemname := elemgotype.Name[5:]
- elemtype := walksymtypedef(ctxt, defgotype(ctxt, elemgotype))
-
- // sudog<T>
- dwss := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "sudog", elemname, "", func(dws *dwarf.DWDie) {
- copychildren(ctxt, dws, sudog)
- substitutetype(dws, "elem", defptrto(ctxt, elemtype))
- newattr(dws, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(sudogsize), nil)
- })
-
- // waitq<T>
- dwws := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "waitq", elemname, "", func(dww *dwarf.DWDie) {
-
- copychildren(ctxt, dww, waitq)
- substitutetype(dww, "first", defptrto(ctxt, dwss))
- substitutetype(dww, "last", defptrto(ctxt, dwss))
- newattr(dww, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(waitq, dwarf.DW_AT_byte_size).Value, nil)
- })
-
- // hchan<T>
- dwhs := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hchan", elemname, "", func(dwh *dwarf.DWDie) {
- copychildren(ctxt, dwh, hchan)
- substitutetype(dwh, "recvq", dwws)
- substitutetype(dwh, "sendq", dwws)
- newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hchan, dwarf.DW_AT_byte_size).Value, nil)
- })
-
- newrefattr(die, dwarf.DW_AT_type, defptrto(ctxt, dwhs))
- }
-}
-
-func dwarfDefineGlobal(ctxt *Link, s *sym.Symbol, str string, v int64, gotype *sym.Symbol) {
- // Find a suitable CU DIE to include the global.
- // One would think it's as simple as just looking at the unit, but that might
- // not have any reachable code. So, we go to the runtime's CU if our unit
- // isn't otherwise reachable.
- var unit *sym.CompilationUnit
- if s.Unit != nil {
- unit = s.Unit
- } else {
- unit = ctxt.runtimeCU
- }
- dv := newdie(ctxt, unit.DWInfo, dwarf.DW_ABRV_VARIABLE, str, int(s.Version))
- newabslocexprattr(dv, v, s)
- if !s.IsFileLocal() {
- newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0)
- }
- dt := defgotype(ctxt, gotype)
- newrefattr(dv, dwarf.DW_AT_type, dt)
-}
-
-// For use with pass.c::genasmsym
-func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, gotype *sym.Symbol) {
- if strings.HasPrefix(str, "go.string.") {
- return
- }
- if strings.HasPrefix(str, "runtime.gcbits.") {
- return
- }
-
- switch t {
- case DataSym, BSSSym:
- switch s.Type {
- case sym.SDATA, sym.SNOPTRDATA, sym.STYPE, sym.SBSS, sym.SNOPTRBSS, sym.STLSBSS:
- // ok
- case sym.SRODATA:
- if gotype != nil {
- defgotype(ctxt, gotype)
- }
- return
- default:
- return
- }
- if ctxt.LinkMode != LinkExternal && isStaticTemp(s.Name) {
- return
- }
- dwarfDefineGlobal(ctxt, s, str, v, gotype)
-
- case AutoSym, ParamSym, DeletedAutoSym:
- defgotype(ctxt, gotype)
- }
-}
-
-// createUnitLength creates the initial length field with value v and update
-// offset of unit_length if needed.
-func createUnitLength(ctxt *Link, s *sym.Symbol, v uint64) {
- if isDwarf64(ctxt) {
- s.AddUint32(ctxt.Arch, 0xFFFFFFFF)
- }
- addDwarfAddrField(ctxt, s, v)
-}
-
-// addDwarfAddrField adds a DWARF field in DWARF 64bits or 32bits.
-func addDwarfAddrField(ctxt *Link, s *sym.Symbol, v uint64) {
- if isDwarf64(ctxt) {
- s.AddUint(ctxt.Arch, v)
- } else {
- s.AddUint32(ctxt.Arch, uint32(v))
- }
-}
-
-// addDwarfAddrRef adds a DWARF pointer in DWARF 64bits or 32bits.
-func addDwarfAddrRef(ctxt *Link, s *sym.Symbol, t *sym.Symbol) {
- if isDwarf64(ctxt) {
- adddwarfref(ctxt, s, t, 8)
- } else {
- adddwarfref(ctxt, s, t, 4)
- }
-}
-
-// calcCompUnitRanges calculates the PC ranges of the compilation units.
-func calcCompUnitRanges(ctxt *Link) {
- var prevUnit *sym.CompilationUnit
- for _, s := range ctxt.Textp {
- if s.FuncInfo == nil {
- continue
- }
- // Skip linker-created functions (ex: runtime.addmoduledata), since they
- // don't have DWARF to begin with.
- if s.Unit == nil {
- continue
- }
- unit := s.Unit
- // Update PC ranges.
- //
- // We don't simply compare the end of the previous
- // symbol with the start of the next because there's
- // often a little padding between them. Instead, we
- // only create boundaries between symbols from
- // different units.
- if prevUnit != unit {
- unit.PCs = append(unit.PCs, dwarf.Range{Start: s.Value - unit.Textp[0].Value})
- prevUnit = unit
- }
- unit.PCs[len(unit.PCs)-1].End = s.Value - unit.Textp[0].Value + s.Size
- }
-}
-
-func movetomodule(ctxt *Link, parent *dwarf.DWDie) {
- die := ctxt.runtimeCU.DWInfo.Child
- if die == nil {
- ctxt.runtimeCU.DWInfo.Child = parent.Child
- return
- }
- for die.Link != nil {
- die = die.Link
- }
- die.Link = parent.Child
-}
-
-// If the pcln table contains runtime/proc.go, use that to set gdbscript path.
-func finddebugruntimepath(s *sym.Symbol) {
- if gdbscript != "" {
- return
- }
-
- for i := range s.FuncInfo.File {
- f := s.FuncInfo.File[i]
- // We can't use something that may be dead-code
- // eliminated from a binary here. proc.go contains
- // main and the scheduler, so it's not going anywhere.
- if i := strings.Index(f.Name, "runtime/proc.go"); i >= 0 {
- gdbscript = f.Name[:i] + "runtime/runtime-gdb.py"
- break
- }
- }
-}
-
-/*
- * Generate a sequence of opcodes that is as short as possible.
- * See section 6.2.5
- */
-const (
- LINE_BASE = -4
- LINE_RANGE = 10
- PC_RANGE = (255 - OPCODE_BASE) / LINE_RANGE
- OPCODE_BASE = 11
-)
-
-/*
- * Walk prog table, emit line program and build DIE tree.
- */
-
-func getCompilationDir() string {
- // OSX requires this be set to something, but it's not easy to choose
- // a value. Linking takes place in a temporary directory, so there's
- // no point including it here. Paths in the file table are usually
- // absolute, in which case debuggers will ignore this value. -trimpath
- // produces relative paths, but we don't know where they start, so
- // all we can do here is try not to make things worse.
- return "."
-}
-
-func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) {
- dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable
- dsym.Type = sym.SDWARFINFO
- for i := range dsym.R {
- r := &dsym.R[i] // Copying sym.Reloc has measurable impact on performance
- if r.Type == objabi.R_DWARFSECREF && r.Sym.Size == 0 {
- n := nameFromDIESym(r.Sym)
- defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0))
- }
- }
-}
-
-func writelines(ctxt *Link, unit *sym.CompilationUnit, ls *sym.Symbol) {
-
- var dwarfctxt dwarf.Context = dwctxt{ctxt}
- is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles.
-
- unitstart := int64(-1)
- headerstart := int64(-1)
- headerend := int64(-1)
-
- newattr(unit.DWInfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, ls.Size, ls)
-
- // Write .debug_line Line Number Program Header (sec 6.2.4)
- // Fields marked with (*) must be changed for 64-bit dwarf
- unitLengthOffset := ls.Size
- createUnitLength(ctxt, ls, 0) // unit_length (*), filled in at end
- unitstart = ls.Size
- ls.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05
- headerLengthOffset := ls.Size
- addDwarfAddrField(ctxt, ls, 0) // header_length (*), filled in at end
- headerstart = ls.Size
-
- // cpos == unitstart + 4 + 2 + 4
- ls.AddUint8(1) // minimum_instruction_length
- ls.AddUint8(is_stmt) // default_is_stmt
- ls.AddUint8(LINE_BASE & 0xFF) // line_base
- ls.AddUint8(LINE_RANGE) // line_range
- ls.AddUint8(OPCODE_BASE) // opcode_base
- ls.AddUint8(0) // standard_opcode_lengths[1]
- ls.AddUint8(1) // standard_opcode_lengths[2]
- ls.AddUint8(1) // standard_opcode_lengths[3]
- ls.AddUint8(1) // standard_opcode_lengths[4]
- ls.AddUint8(1) // standard_opcode_lengths[5]
- ls.AddUint8(0) // standard_opcode_lengths[6]
- ls.AddUint8(0) // standard_opcode_lengths[7]
- ls.AddUint8(0) // standard_opcode_lengths[8]
- ls.AddUint8(1) // standard_opcode_lengths[9]
- ls.AddUint8(0) // standard_opcode_lengths[10]
- ls.AddUint8(0) // include_directories (empty)
-
- // Copy over the file table.
- fileNums := make(map[string]int)
- for i, name := range unit.DWARFFileTable {
- if len(name) != 0 {
- if strings.HasPrefix(name, src.FileSymPrefix) {
- name = name[len(src.FileSymPrefix):]
- }
- name = expandGoroot(name)
- } else {
- // Can't have empty filenames, and having a unique filename is quite useful
- // for debugging.
- name = fmt.Sprintf("<missing>_%d", i)
- }
- fileNums[name] = i + 1
- dwarfctxt.AddString(ls, name)
- ls.AddUint8(0)
- ls.AddUint8(0)
- ls.AddUint8(0)
- }
- // Grab files for inlined functions.
- // TODO: With difficulty, this could be moved into the compiler.
- for _, s := range unit.Textp {
- dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, true)
- for ri := 0; ri < len(dsym.R); ri++ {
- r := &dsym.R[ri]
- if r.Type != objabi.R_DWARFFILEREF {
- continue
- }
- name := r.Sym.Name
- if _, ok := fileNums[name]; ok {
- continue
- }
- fileNums[name] = len(fileNums) + 1
- dwarfctxt.AddString(ls, name)
- ls.AddUint8(0)
- ls.AddUint8(0)
- ls.AddUint8(0)
- }
- }
-
- // 4 zeros: the string termination + 3 fields.
- ls.AddUint8(0)
- // terminate file_names.
- headerend = ls.Size
-
- // Output the state machine for each function remaining.
- var lastAddr int64
- for _, s := range unit.Textp {
- finddebugruntimepath(s)
-
- // Set the PC.
- ls.AddUint8(0)
- dwarf.Uleb128put(dwarfctxt, ls, 1+int64(ctxt.Arch.PtrSize))
- ls.AddUint8(dwarf.DW_LNE_set_address)
- addr := ls.AddAddr(ctxt.Arch, s)
- // Make sure the units are sorted.
- if addr < lastAddr {
- Errorf(s, "address wasn't increasing %x < %x", addr, lastAddr)
- }
- lastAddr = addr
-
- // Output the line table.
- // TODO: Now that we have all the debug information in separate
- // symbols, it would make sense to use a rope, and concatenate them all
- // together rather then the append() below. This would allow us to have
- // the compiler emit the DW_LNE_set_address and a rope data structure
- // to concat them all together in the output.
- lines := dwarfFuncSym(ctxt, s, dwarf.DebugLinesPrefix, false)
- if lines != nil {
- ls.P = append(ls.P, lines.P...)
- }
- }
-
- ls.AddUint8(0) // start extended opcode
- dwarf.Uleb128put(dwarfctxt, ls, 1)
- ls.AddUint8(dwarf.DW_LNE_end_sequence)
-
- if ctxt.HeadType == objabi.Haix {
- saveDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(ls.Size-unitLengthOffset))
- }
- if isDwarf64(ctxt) {
- ls.SetUint(ctxt.Arch, unitLengthOffset+4, uint64(ls.Size-unitstart)) // +4 because of 0xFFFFFFFF
- ls.SetUint(ctxt.Arch, headerLengthOffset, uint64(headerend-headerstart))
- } else {
- ls.SetUint32(ctxt.Arch, unitLengthOffset, uint32(ls.Size-unitstart))
- ls.SetUint32(ctxt.Arch, headerLengthOffset, uint32(headerend-headerstart))
- }
-
- // Process any R_DWARFFILEREF relocations, since we now know the
- // line table file indices for this compilation unit. Note that
- // this loop visits only subprogram DIEs: if the compiler is
- // changed to generate DW_AT_decl_file attributes for other
- // DIE flavors (ex: variables) then those DIEs would need to
- // be included below.
- missing := make(map[int]interface{})
- s := unit.Textp[0]
- for _, f := range unit.FuncDIEs {
- for ri := range f.R {
- r := &f.R[ri]
- if r.Type != objabi.R_DWARFFILEREF {
- continue
- }
- idx, ok := fileNums[r.Sym.Name]
- if ok {
- if int(int32(idx)) != idx {
- Errorf(f, "bad R_DWARFFILEREF relocation: file index overflow")
- }
- if r.Siz != 4 {
- Errorf(f, "bad R_DWARFFILEREF relocation: has size %d, expected 4", r.Siz)
- }
- if r.Off < 0 || r.Off+4 > int32(len(f.P)) {
- Errorf(f, "bad R_DWARFFILEREF relocation offset %d + 4 would write past length %d", r.Off, len(s.P))
- continue
- }
- if r.Add != 0 {
- Errorf(f, "bad R_DWARFFILEREF relocation: addend not zero")
- }
- r.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
- r.Add = int64(idx) // record the index in r.Add, we'll apply it in the reloc phase.
- } else {
- _, found := missing[int(r.Sym.Value)]
- if !found {
- Errorf(f, "R_DWARFFILEREF relocation file missing: %v idx %d", r.Sym, r.Sym.Value)
- missing[int(r.Sym.Value)] = nil
- }
- }
- }
- }
-}
-
-// writepcranges generates the DW_AT_ranges table for compilation unit cu.
-func writepcranges(ctxt *Link, unit *sym.CompilationUnit, base *sym.Symbol, pcs []dwarf.Range, ranges *sym.Symbol) {
- var dwarfctxt dwarf.Context = dwctxt{ctxt}
-
- unitLengthOffset := ranges.Size
-
- // Create PC ranges for this CU.
- newattr(unit.DWInfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, ranges.Size, ranges)
- newattr(unit.DWInfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, base.Value, base)
- dwarf.PutBasedRanges(dwarfctxt, ranges, pcs)
-
- if ctxt.HeadType == objabi.Haix {
- addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(ranges.Size-unitLengthOffset))
- }
-
-}
-
-/*
- * Emit .debug_frame
- */
-const (
- dataAlignmentFactor = -4
-)
-
-// appendPCDeltaCFA appends per-PC CFA deltas to b and returns the final slice.
-func appendPCDeltaCFA(arch *sys.Arch, b []byte, deltapc, cfa int64) []byte {
- b = append(b, dwarf.DW_CFA_def_cfa_offset_sf)
- b = dwarf.AppendSleb128(b, cfa/dataAlignmentFactor)
-
- switch {
- case deltapc < 0x40:
- b = append(b, uint8(dwarf.DW_CFA_advance_loc+deltapc))
- case deltapc < 0x100:
- b = append(b, dwarf.DW_CFA_advance_loc1)
- b = append(b, uint8(deltapc))
- case deltapc < 0x10000:
- b = append(b, dwarf.DW_CFA_advance_loc2, 0, 0)
- arch.ByteOrder.PutUint16(b[len(b)-2:], uint16(deltapc))
- default:
- b = append(b, dwarf.DW_CFA_advance_loc4, 0, 0, 0, 0)
- arch.ByteOrder.PutUint32(b[len(b)-4:], uint32(deltapc))
- }
- return b
-}
-
-func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
- var dwarfctxt dwarf.Context = dwctxt{ctxt}
- fs := ctxt.Syms.Lookup(".debug_frame", 0)
- fs.Type = sym.SDWARFSECT
- syms = append(syms, fs)
-
- // Length field is 4 bytes on Dwarf32 and 12 bytes on Dwarf64
- lengthFieldSize := int64(4)
- if isDwarf64(ctxt) {
- lengthFieldSize += 8
- }
-
- // Emit the CIE, Section 6.4.1
- cieReserve := uint32(16)
- if haslinkregister(ctxt) {
- cieReserve = 32
- }
- if isDwarf64(ctxt) {
- cieReserve += 4 // 4 bytes added for cid
- }
- createUnitLength(ctxt, fs, uint64(cieReserve)) // initial length, must be multiple of thearch.ptrsize
- addDwarfAddrField(ctxt, fs, ^uint64(0)) // cid
- fs.AddUint8(3) // dwarf version (appendix F)
- fs.AddUint8(0) // augmentation ""
- dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor
- dwarf.Sleb128put(dwarfctxt, fs, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfreglr)) // return_address_register
-
- fs.AddUint8(dwarf.DW_CFA_def_cfa) // Set the current frame address..
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)...
- if haslinkregister(ctxt) {
- dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...plus a 0 offset.
-
- fs.AddUint8(dwarf.DW_CFA_same_value) // The platform's link register is unchanged during the prologue.
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfreglr))
-
- fs.AddUint8(dwarf.DW_CFA_val_offset) // The previous value...
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfregsp)) // ...of the platform's SP register...
- dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...is CFA+0.
- } else {
- dwarf.Uleb128put(dwarfctxt, fs, int64(ctxt.Arch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame).
-
- fs.AddUint8(dwarf.DW_CFA_offset_extended) // The previous value...
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfreglr)) // ...of the return address...
- dwarf.Uleb128put(dwarfctxt, fs, int64(-ctxt.Arch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)].
- }
-
- pad := int64(cieReserve) + lengthFieldSize - fs.Size
-
- if pad < 0 {
- Exitf("dwarf: cieReserve too small by %d bytes.", -pad)
- }
-
- fs.AddBytes(zeros[:pad])
-
- var deltaBuf []byte
- pcsp := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
- for _, s := range ctxt.Textp {
- if s.FuncInfo == nil {
- continue
- }
-
- // Emit a FDE, Section 6.4.1.
- // First build the section contents into a byte buffer.
- deltaBuf = deltaBuf[:0]
- if haslinkregister(ctxt) && s.Attr.TopFrame() {
- // Mark the link register as having an undefined value.
- // This stops call stack unwinders progressing any further.
- // TODO: similar mark on non-LR architectures.
- deltaBuf = append(deltaBuf, dwarf.DW_CFA_undefined)
- deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr))
- }
- for pcsp.Init(s.FuncInfo.Pcsp.P); !pcsp.Done; pcsp.Next() {
- nextpc := pcsp.NextPC
-
- // pciterinit goes up to the end of the function,
- // but DWARF expects us to stop just before the end.
- if int64(nextpc) == s.Size {
- nextpc--
- if nextpc < pcsp.PC {
- continue
- }
- }
-
- spdelta := int64(pcsp.Value)
- if !haslinkregister(ctxt) {
- // Return address has been pushed onto stack.
- spdelta += int64(ctxt.Arch.PtrSize)
- }
-
- if haslinkregister(ctxt) && !s.Attr.TopFrame() {
- // TODO(bryanpkc): This is imprecise. In general, the instruction
- // that stores the return address to the stack frame is not the
- // same one that allocates the frame.
- if pcsp.Value > 0 {
- // The return address is preserved at (CFA-frame_size)
- // after a stack frame has been allocated.
- deltaBuf = append(deltaBuf, dwarf.DW_CFA_offset_extended_sf)
- deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr))
- deltaBuf = dwarf.AppendSleb128(deltaBuf, -spdelta/dataAlignmentFactor)
- } else {
- // The return address is restored into the link register
- // when a stack frame has been de-allocated.
- deltaBuf = append(deltaBuf, dwarf.DW_CFA_same_value)
- deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr))
- }
- }
-
- deltaBuf = appendPCDeltaCFA(ctxt.Arch, deltaBuf, int64(nextpc)-int64(pcsp.PC), spdelta)
- }
- pad := int(Rnd(int64(len(deltaBuf)), int64(ctxt.Arch.PtrSize))) - len(deltaBuf)
- deltaBuf = append(deltaBuf, zeros[:pad]...)
-
- // Emit the FDE header, Section 6.4.1.
- // 4 bytes: length, must be multiple of thearch.ptrsize
- // 4/8 bytes: Pointer to the CIE above, at offset 0
- // ptrsize: initial location
- // ptrsize: address range
-
- fdeLength := uint64(4 + 2*ctxt.Arch.PtrSize + len(deltaBuf))
- if isDwarf64(ctxt) {
- fdeLength += 4 // 4 bytes added for CIE pointer
- }
- createUnitLength(ctxt, fs, fdeLength)
-
- if ctxt.LinkMode == LinkExternal {
- addDwarfAddrRef(ctxt, fs, fs)
- } else {
- addDwarfAddrField(ctxt, fs, 0) // CIE offset
- }
- fs.AddAddr(ctxt.Arch, s)
- fs.AddUintXX(ctxt.Arch, uint64(s.Size), ctxt.Arch.PtrSize) // address range
- fs.AddBytes(deltaBuf)
-
- if ctxt.HeadType == objabi.Haix {
- addDwsectCUSize(".debug_frame", s.File, fdeLength+uint64(lengthFieldSize))
- }
- }
- return syms
-}
-
-/*
- * Walk DWarfDebugInfoEntries, and emit .debug_info
- */
-const (
- COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
-)
-
-func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*sym.CompilationUnit, abbrevsym *sym.Symbol, pubNames, pubTypes *pubWriter) []*sym.Symbol {
- infosec := ctxt.Syms.Lookup(".debug_info", 0)
- infosec.Type = sym.SDWARFINFO
- infosec.Attr |= sym.AttrReachable
- syms = append(syms, infosec)
-
- var dwarfctxt dwarf.Context = dwctxt{ctxt}
-
- for _, u := range units {
- compunit := u.DWInfo
- s := dtolsym(compunit.Sym)
-
- if len(u.Textp) == 0 && u.DWInfo.Child == nil {
- continue
- }
-
- pubNames.beginCompUnit(compunit)
- pubTypes.beginCompUnit(compunit)
-
- // Write .debug_info Compilation Unit Header (sec 7.5.1)
- // Fields marked with (*) must be changed for 64-bit dwarf
- // This must match COMPUNITHEADERSIZE above.
- createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later.
- s.AddUint16(ctxt.Arch, 4) // dwarf version (appendix F)
-
- // debug_abbrev_offset (*)
- addDwarfAddrRef(ctxt, s, abbrevsym)
-
- s.AddUint8(uint8(ctxt.Arch.PtrSize)) // address_size
-
- dwarf.Uleb128put(dwarfctxt, s, int64(compunit.Abbrev))
- dwarf.PutAttrs(dwarfctxt, s, compunit.Abbrev, compunit.Attr)
-
- cu := []*sym.Symbol{s}
- cu = append(cu, u.AbsFnDIEs...)
- cu = append(cu, u.FuncDIEs...)
- if u.Consts != nil {
- cu = append(cu, u.Consts)
- }
- var cusize int64
- for _, child := range cu {
- cusize += child.Size
- }
-
- for die := compunit.Child; die != nil; die = die.Link {
- l := len(cu)
- lastSymSz := cu[l-1].Size
- cu = putdie(ctxt, dwarfctxt, cu, die)
- if ispubname(die) {
- pubNames.add(die, cusize)
- }
- if ispubtype(die) {
- pubTypes.add(die, cusize)
- }
- if lastSymSz != cu[l-1].Size {
- // putdie will sometimes append directly to the last symbol of the list
- cusize = cusize - lastSymSz + cu[l-1].Size
- }
- for _, child := range cu[l:] {
- cusize += child.Size
- }
- }
- cu[len(cu)-1].AddUint8(0) // closes compilation unit DIE
- cusize++
-
- // Save size for AIX symbol table.
- if ctxt.HeadType == objabi.Haix {
- saveDwsectCUSize(".debug_info", getPkgFromCUSym(s), uint64(cusize))
- }
- if isDwarf64(ctxt) {
- cusize -= 12 // exclude the length field.
- s.SetUint(ctxt.Arch, 4, uint64(cusize)) // 4 because of 0XFFFFFFFF
- } else {
- cusize -= 4 // exclude the length field.
- s.SetUint32(ctxt.Arch, 0, uint32(cusize))
- }
- pubNames.endCompUnit(compunit, uint32(cusize)+4)
- pubTypes.endCompUnit(compunit, uint32(cusize)+4)
- syms = append(syms, cu...)
- }
- return syms
-}
-
-/*
- * Emit .debug_pubnames/_types. _info must have been written before,
- * because we need die->offs and infoo/infosize;
- */
-func ispubname(die *dwarf.DWDie) bool {
- switch die.Abbrev {
- case dwarf.DW_ABRV_FUNCTION, dwarf.DW_ABRV_VARIABLE:
- a := getattr(die, dwarf.DW_AT_external)
- return a != nil && a.Value != 0
- }
-
- return false
-}
-
-func ispubtype(die *dwarf.DWDie) bool {
- return die.Abbrev >= dwarf.DW_ABRV_NULLTYPE
-}
-
-type pubWriter struct {
- ctxt *Link
- s *sym.Symbol
- sname string
-
- sectionstart int64
- culengthOff int64
-}
-
-func newPubWriter(ctxt *Link, sname string) *pubWriter {
- s := ctxt.Syms.Lookup(sname, 0)
- s.Type = sym.SDWARFSECT
- return &pubWriter{ctxt: ctxt, s: s, sname: sname}
-}
-
-func (pw *pubWriter) beginCompUnit(compunit *dwarf.DWDie) {
- pw.sectionstart = pw.s.Size
-
- // Write .debug_pubnames/types Header (sec 6.1.1)
- createUnitLength(pw.ctxt, pw.s, 0) // unit_length (*), will be filled in later.
- pw.s.AddUint16(pw.ctxt.Arch, 2) // dwarf version (appendix F)
- addDwarfAddrRef(pw.ctxt, pw.s, dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header)
- pw.culengthOff = pw.s.Size
- addDwarfAddrField(pw.ctxt, pw.s, uint64(0)) // debug_info_length, will be filled in later.
-
-}
-
-func (pw *pubWriter) add(die *dwarf.DWDie, offset int64) {
- dwa := getattr(die, dwarf.DW_AT_name)
- name := dwa.Data.(string)
- if die.Sym == nil {
- fmt.Println("Missing sym for ", name)
- }
- addDwarfAddrField(pw.ctxt, pw.s, uint64(offset))
- Addstring(pw.s, name)
-}
-
-func (pw *pubWriter) endCompUnit(compunit *dwarf.DWDie, culength uint32) {
- addDwarfAddrField(pw.ctxt, pw.s, 0) // Null offset
-
- // On AIX, save the current size of this compilation unit.
- if pw.ctxt.HeadType == objabi.Haix {
- saveDwsectCUSize(pw.sname, getPkgFromCUSym(dtolsym(compunit.Sym)), uint64(pw.s.Size-pw.sectionstart))
- }
- if isDwarf64(pw.ctxt) {
- pw.s.SetUint(pw.ctxt.Arch, pw.sectionstart+4, uint64(pw.s.Size-pw.sectionstart)-12) // exclude the length field.
- pw.s.SetUint(pw.ctxt.Arch, pw.culengthOff, uint64(culength))
- } else {
- pw.s.SetUint32(pw.ctxt.Arch, pw.sectionstart, uint32(pw.s.Size-pw.sectionstart)-4) // exclude the length field.
- pw.s.SetUint32(pw.ctxt.Arch, pw.culengthOff, culength)
- }
-}
-
-func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
- // TODO (aix): make it available
- if ctxt.HeadType == objabi.Haix {
- return syms
- }
- if ctxt.LinkMode == LinkExternal && ctxt.HeadType == objabi.Hwindows && ctxt.BuildMode == BuildModeCArchive {
- // gcc on Windows places .debug_gdb_scripts in the wrong location, which
- // causes the program not to run. See https://golang.org/issue/20183
- // Non c-archives can avoid this issue via a linker script
- // (see fix near writeGDBLinkerScript).
- // c-archive users would need to specify the linker script manually.
- // For UX it's better not to deal with this.
- return syms
- }
-
- if gdbscript != "" {
- s := ctxt.Syms.Lookup(".debug_gdb_scripts", 0)
- s.Type = sym.SDWARFSECT
- syms = append(syms, s)
- s.AddUint8(1) // magic 1 byte?
- Addstring(s, gdbscript)
- }
-
- return syms
-}
-
-var prototypedies map[string]*dwarf.DWDie
-
-func dwarfEnabled(ctxt *Link) bool {
- if *FlagW { // disable dwarf
- return false
- }
- if *FlagS && ctxt.HeadType != objabi.Hdarwin {
- return false
- }
- if ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hjs {
- return false
- }
-
- if ctxt.LinkMode == LinkExternal {
- switch {
- case ctxt.IsELF:
- case ctxt.HeadType == objabi.Hdarwin:
- case ctxt.HeadType == objabi.Hwindows:
- case ctxt.HeadType == objabi.Haix:
- res, err := dwarf.IsDWARFEnabledOnAIXLd(ctxt.extld())
- if err != nil {
- Exitf("%v", err)
- }
- return res
- default:
- return false
- }
- }
-
- return true
-}
-
-// dwarfGenerateDebugInfo generated debug info entries for all types,
-// variables and functions in the program.
-// Along with dwarfGenerateDebugSyms they are the two main entry points into
-// dwarf generation: dwarfGenerateDebugInfo does all the work that should be
-// done before symbol names are mangled while dwarfgeneratedebugsyms does
-// all the work that can only be done after addresses have been assigned to
-// text symbols.
-func dwarfGenerateDebugInfo(ctxt *Link) {
- if !dwarfEnabled(ctxt) {
- return
- }
-
- if ctxt.HeadType == objabi.Haix {
- // Initial map used to store package size for each DWARF section.
- dwsectCUSize = make(map[string]uint64)
- }
-
- // Forctxt.Diagnostic messages.
- newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
-
- // Some types that must exist to define other ones.
- newdie(ctxt, &dwtypes, dwarf.DW_ABRV_NULLTYPE, "<unspecified>", 0)
-
- newdie(ctxt, &dwtypes, dwarf.DW_ABRV_NULLTYPE, "void", 0)
- newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer", 0)
-
- die := newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, "uintptr", 0) // needed for array size
- newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(ctxt.Arch.PtrSize), 0)
- newattr(die, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, objabi.KindUintptr, 0)
- newattr(die, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_ADDRESS, 0, lookupOrDiag(ctxt, "type.uintptr"))
-
- // Prototypes needed for type synthesis.
- prototypedies = map[string]*dwarf.DWDie{
- "type.runtime.stringStructDWARF": nil,
- "type.runtime.slice": nil,
- "type.runtime.hmap": nil,
- "type.runtime.bmap": nil,
- "type.runtime.sudog": nil,
- "type.runtime.waitq": nil,
- "type.runtime.hchan": nil,
- }
-
- // Needed by the prettyprinter code for interface inspection.
- for _, typ := range []string{
- "type.runtime._type",
- "type.runtime.arraytype",
- "type.runtime.chantype",
- "type.runtime.functype",
- "type.runtime.maptype",
- "type.runtime.ptrtype",
- "type.runtime.slicetype",
- "type.runtime.structtype",
- "type.runtime.interfacetype",
- "type.runtime.itab",
- "type.runtime.imethod"} {
- defgotype(ctxt, lookupOrDiag(ctxt, typ))
- }
-
- // fake root DIE for compile unit DIEs
- var dwroot dwarf.DWDie
- flagVariants := make(map[string]bool)
-
- for _, lib := range ctxt.Library {
- consts := ctxt.Syms.ROLookup(dwarf.ConstInfoPrefix+lib.Pkg, 0)
- for _, unit := range lib.Units {
- // We drop the constants into the first CU.
- if consts != nil {
- importInfoSymbol(ctxt, consts)
- unit.Consts = consts
- consts = nil
- }
-
- ctxt.compUnits = append(ctxt.compUnits, unit)
-
- // We need at least one runtime unit.
- if unit.Lib.Pkg == "runtime" {
- ctxt.runtimeCU = unit
- }
-
- unit.DWInfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, unit.Lib.Pkg, 0)
- newattr(unit.DWInfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(dwarf.DW_LANG_Go), 0)
- // OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
- compDir := getCompilationDir()
- // TODO: Make this be the actual compilation directory, not
- // the linker directory. If we move CU construction into the
- // compiler, this should happen naturally.
- newattr(unit.DWInfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir)
- producerExtra := ctxt.Syms.Lookup(dwarf.CUInfoPrefix+"producer."+unit.Lib.Pkg, 0)
- producer := "Go cmd/compile " + objabi.Version
- if len(producerExtra.P) > 0 {
- // We put a semicolon before the flags to clearly
- // separate them from the version, which can be long
- // and have lots of weird things in it in development
- // versions. We promise not to put a semicolon in the
- // version, so it should be safe for readers to scan
- // forward to the semicolon.
- producer += "; " + string(producerExtra.P)
- flagVariants[string(producerExtra.P)] = true
- } else {
- flagVariants[""] = true
- }
-
- newattr(unit.DWInfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer)
-
- var pkgname string
- if s := ctxt.Syms.ROLookup(dwarf.CUInfoPrefix+"packagename."+unit.Lib.Pkg, 0); s != nil {
- pkgname = string(s.P)
- }
- newattr(unit.DWInfo, dwarf.DW_AT_go_package_name, dwarf.DW_CLS_STRING, int64(len(pkgname)), pkgname)
-
- if len(unit.Textp) == 0 {
- unit.DWInfo.Abbrev = dwarf.DW_ABRV_COMPUNIT_TEXTLESS
- }
-
- // Scan all functions in this compilation unit, create DIEs for all
- // referenced types, create the file table for debug_line, find all
- // referenced abstract functions.
- // Collect all debug_range symbols in unit.rangeSyms
- for _, s := range unit.Textp { // textp has been dead-code-eliminated already.
- dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, false)
- dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable
- dsym.Type = sym.SDWARFINFO
- unit.FuncDIEs = append(unit.FuncDIEs, dsym)
-
- rangeSym := dwarfFuncSym(ctxt, s, dwarf.RangePrefix, false)
- if rangeSym != nil && rangeSym.Size > 0 {
- rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
- rangeSym.Type = sym.SDWARFRANGE
- if ctxt.HeadType == objabi.Haix {
- addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(rangeSym.Size))
- }
- unit.RangeSyms = append(unit.RangeSyms, rangeSym)
- }
-
- for ri := 0; ri < len(dsym.R); ri++ {
- r := &dsym.R[ri]
- if r.Type == objabi.R_DWARFSECREF {
- rsym := r.Sym
- if strings.HasPrefix(rsym.Name, dwarf.InfoPrefix) && strings.HasSuffix(rsym.Name, dwarf.AbstractFuncSuffix) && !rsym.Attr.OnList() {
- // abstract function
- rsym.Attr |= sym.AttrOnList
- unit.AbsFnDIEs = append(unit.AbsFnDIEs, rsym)
- importInfoSymbol(ctxt, rsym)
- } else if rsym.Size == 0 {
- // a type we do not have a DIE for
- n := nameFromDIESym(rsym)
- defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0))
- }
- }
- }
- }
- }
- }
-
- // Fix for 31034: if the objects feeding into this link were compiled
- // with different sets of flags, then don't issue an error if
- // the -strictdups checks fail.
- if checkStrictDups > 1 && len(flagVariants) > 1 {
- checkStrictDups = 1
- }
-
- // Create DIEs for global variables and the types they use.
- genasmsym(ctxt, defdwsymb)
-
- // Create DIEs for variable types indirectly referenced by function
- // autos (which may not appear directly as param/var DIEs).
- for _, lib := range ctxt.Library {
- for _, unit := range lib.Units {
- lists := [][]*sym.Symbol{unit.AbsFnDIEs, unit.FuncDIEs}
- for _, list := range lists {
- for _, s := range list {
- for i := 0; i < len(s.R); i++ {
- r := &s.R[i]
- if r.Type == objabi.R_USETYPE {
- defgotype(ctxt, r.Sym)
- }
- }
- }
- }
- }
- }
-
- synthesizestringtypes(ctxt, dwtypes.Child)
- synthesizeslicetypes(ctxt, dwtypes.Child)
- synthesizemaptypes(ctxt, dwtypes.Child)
- synthesizechantypes(ctxt, dwtypes.Child)
-}
-
-// dwarfGenerateDebugSyms constructs debug_line, debug_frame, debug_loc,
-// debug_pubnames and debug_pubtypes. It also writes out the debug_info
-// section using symbols generated in dwarfGenerateDebugInfo.
-func dwarfGenerateDebugSyms(ctxt *Link) {
- if !dwarfEnabled(ctxt) {
- return
- }
-
- abbrev := writeabbrev(ctxt)
- syms := []*sym.Symbol{abbrev}
-
- calcCompUnitRanges(ctxt)
- sort.Sort(compilationUnitByStartPC(ctxt.compUnits))
-
- // Write per-package line and range tables and start their CU DIEs.
- debugLine := ctxt.Syms.Lookup(".debug_line", 0)
- debugLine.Type = sym.SDWARFSECT
- debugRanges := ctxt.Syms.Lookup(".debug_ranges", 0)
- debugRanges.Type = sym.SDWARFRANGE
- debugRanges.Attr |= sym.AttrReachable
- syms = append(syms, debugLine)
- for _, u := range ctxt.compUnits {
- reversetree(&u.DWInfo.Child)
- if u.DWInfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS {
- continue
- }
- writelines(ctxt, u, debugLine)
- writepcranges(ctxt, u, u.Textp[0], u.PCs, debugRanges)
- }
-
- // newdie adds DIEs to the *beginning* of the parent's DIE list.
- // Now that we're done creating DIEs, reverse the trees so DIEs
- // appear in the order they were created.
- reversetree(&dwtypes.Child)
- movetomodule(ctxt, &dwtypes)
-
- pubNames := newPubWriter(ctxt, ".debug_pubnames")
- pubTypes := newPubWriter(ctxt, ".debug_pubtypes")
-
- // Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT
- infosyms := writeinfo(ctxt, nil, ctxt.compUnits, abbrev, pubNames, pubTypes)
-
- syms = writeframes(ctxt, syms)
- syms = append(syms, pubNames.s, pubTypes.s)
- syms = writegdbscript(ctxt, syms)
- // Now we're done writing SDWARFSECT symbols, so we can write
- // other SDWARF* symbols.
- syms = append(syms, infosyms...)
- syms = collectlocs(ctxt, syms, ctxt.compUnits)
- syms = append(syms, debugRanges)
- for _, unit := range ctxt.compUnits {
- syms = append(syms, unit.RangeSyms...)
- }
- dwarfp = syms
-}
-
-func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*sym.CompilationUnit) []*sym.Symbol {
- empty := true
- for _, u := range units {
- for _, fn := range u.FuncDIEs {
- for i := range fn.R {
- reloc := &fn.R[i] // Copying sym.Reloc has measurable impact on performance
- if reloc.Type == objabi.R_DWARFSECREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) {
- reloc.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
- syms = append(syms, reloc.Sym)
- empty = false
- // One location list entry per function, but many relocations to it. Don't duplicate.
- break
- }
- }
- }
- }
- // Don't emit .debug_loc if it's empty -- it makes the ARM linker mad.
- if !empty {
- locsym := ctxt.Syms.Lookup(".debug_loc", 0)
- locsym.Type = sym.SDWARFLOC
- locsym.Attr |= sym.AttrReachable
- syms = append(syms, locsym)
- }
- return syms
-}
-
-// Read a pointer-sized uint from the beginning of buf.
-func readPtr(ctxt *Link, buf []byte) uint64 {
- switch ctxt.Arch.PtrSize {
- case 4:
- return uint64(ctxt.Arch.ByteOrder.Uint32(buf))
- case 8:
- return ctxt.Arch.ByteOrder.Uint64(buf)
- default:
- panic("unexpected pointer size")
- }
-}
-
-/*
- * Elf.
- */
-func dwarfaddshstrings(ctxt *Link, shstrtab *sym.Symbol) {
- if *FlagW { // disable dwarf
- return
- }
-
- secs := []string{"abbrev", "frame", "info", "loc", "line", "pubnames", "pubtypes", "gdb_scripts", "ranges"}
- for _, sec := range secs {
- Addstring(shstrtab, ".debug_"+sec)
- if ctxt.LinkMode == LinkExternal {
- Addstring(shstrtab, elfRelType+".debug_"+sec)
- } else {
- Addstring(shstrtab, ".zdebug_"+sec)
- }
- }
-}
-
-// Add section symbols for DWARF debug info. This is called before
-// dwarfaddelfheaders.
-func dwarfaddelfsectionsyms(ctxt *Link) {
- if *FlagW { // disable dwarf
- return
- }
- if ctxt.LinkMode != LinkExternal {
- return
- }
-
- s := ctxt.Syms.Lookup(".debug_info", 0)
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- s = ctxt.Syms.Lookup(".debug_abbrev", 0)
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- s = ctxt.Syms.Lookup(".debug_line", 0)
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- s = ctxt.Syms.Lookup(".debug_frame", 0)
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- s = ctxt.Syms.Lookup(".debug_loc", 0)
- if s.Sect != nil {
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- }
- s = ctxt.Syms.Lookup(".debug_ranges", 0)
- if s.Sect != nil {
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- }
-}
-
-// dwarfcompress compresses the DWARF sections. Relocations are applied
-// on the fly. After this, dwarfp will contain a different (new) set of
-// symbols, and sections may have been replaced.
-func dwarfcompress(ctxt *Link) {
- supported := ctxt.IsELF || ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Hdarwin
- if !ctxt.compressDWARF || !supported || ctxt.LinkMode != LinkInternal {
- return
- }
-
- var start int
- var newDwarfp []*sym.Symbol
- Segdwarf.Sections = Segdwarf.Sections[:0]
- for i, s := range dwarfp {
- // Find the boundaries between sections and compress
- // the whole section once we've found the last of its
- // symbols.
- if i+1 >= len(dwarfp) || s.Sect != dwarfp[i+1].Sect {
- s1 := compressSyms(ctxt, dwarfp[start:i+1])
- if s1 == nil {
- // Compression didn't help.
- newDwarfp = append(newDwarfp, dwarfp[start:i+1]...)
- Segdwarf.Sections = append(Segdwarf.Sections, s.Sect)
- } else {
- compressedSegName := ".zdebug_" + s.Sect.Name[len(".debug_"):]
- sect := addsection(ctxt.Arch, &Segdwarf, compressedSegName, 04)
- sect.Length = uint64(len(s1))
- newSym := ctxt.Syms.Lookup(compressedSegName, 0)
- newSym.P = s1
- newSym.Size = int64(len(s1))
- newSym.Sect = sect
- newDwarfp = append(newDwarfp, newSym)
- }
- start = i + 1
- }
- }
- dwarfp = newDwarfp
- ctxt.relocbuf = nil // no longer needed, don't hold it live
-
- // Re-compute the locations of the compressed DWARF symbols
- // and sections, since the layout of these within the file is
- // based on Section.Vaddr and Symbol.Value.
- pos := Segdwarf.Vaddr
- var prevSect *sym.Section
- for _, s := range dwarfp {
- s.Value = int64(pos)
- if s.Sect != prevSect {
- s.Sect.Vaddr = uint64(s.Value)
- prevSect = s.Sect
- }
- if s.Sub != nil {
- log.Fatalf("%s: unexpected sub-symbols", s)
- }
- pos += uint64(s.Size)
- if ctxt.HeadType == objabi.Hwindows {
- pos = uint64(Rnd(int64(pos), PEFILEALIGN))
- }
-
- }
- Segdwarf.Length = pos - Segdwarf.Vaddr
-}
-
-type compilationUnitByStartPC []*sym.CompilationUnit
-
-func (v compilationUnitByStartPC) Len() int { return len(v) }
-func (v compilationUnitByStartPC) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
-
-func (v compilationUnitByStartPC) Less(i, j int) bool {
- switch {
- case len(v[i].Textp) == 0 && len(v[j].Textp) == 0:
- return v[i].Lib.Pkg < v[j].Lib.Pkg
- case len(v[i].Textp) != 0 && len(v[j].Textp) == 0:
- return true
- case len(v[i].Textp) == 0 && len(v[j].Textp) != 0:
- return false
- default:
- return v[i].Textp[0].Value < v[j].Textp[0].Value
- }
-}
-
-// On AIX, the symbol table needs to know where are the compilation units parts
-// for a specific package in each .dw section.
-// dwsectCUSize map will save the size of a compilation unit for
-// the corresponding .dw section.
-// This size can later be retrieved with the index "sectionName.pkgName".
-var dwsectCUSize map[string]uint64
-
-// getDwsectCUSize retrieves the corresponding package size inside the current section.
-func getDwsectCUSize(sname string, pkgname string) uint64 {
- return dwsectCUSize[sname+"."+pkgname]
-}
-
-func saveDwsectCUSize(sname string, pkgname string, size uint64) {
- dwsectCUSize[sname+"."+pkgname] = size
-}
-
-func addDwsectCUSize(sname string, pkgname string, size uint64) {
- dwsectCUSize[sname+"."+pkgname] += size
-}
-
-// getPkgFromCUSym returns the package name for the compilation unit
-// represented by s.
-// The prefix dwarf.InfoPrefix+".pkg." needs to be removed in order to get
-// the package name.
-func getPkgFromCUSym(s *sym.Symbol) string {
- return strings.TrimPrefix(s.Name, dwarf.InfoPrefix+".pkg.")
-}
+++ /dev/null
-// 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.
-
-package ld
-
-import (
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/sym"
- "crypto/sha1"
- "encoding/binary"
- "encoding/hex"
- "io"
- "path/filepath"
- "sort"
- "strings"
-)
-
-/*
- * Derived from:
- * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
- * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
- * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
- * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
- * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
- * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
- *
- * Copyright (c) 1996-1998 John D. Polstra. All rights reserved.
- * Copyright (c) 2001 David E. O'Brien
- * Portions Copyright 2009 The Go Authors. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-/*
- * ELF definitions that are independent of architecture or word size.
- */
-
-/*
- * Note header. The ".note" section contains an array of notes. Each
- * begins with this header, aligned to a word boundary. Immediately
- * following the note header is n_namesz bytes of name, padded to the
- * next word boundary. Then comes n_descsz bytes of descriptor, again
- * padded to a word boundary. The values of n_namesz and n_descsz do
- * not include the padding.
- */
-type elfNote struct {
- nNamesz uint32
- nDescsz uint32
- nType uint32
-}
-
-const (
- EI_MAG0 = 0
- EI_MAG1 = 1
- EI_MAG2 = 2
- EI_MAG3 = 3
- EI_CLASS = 4
- EI_DATA = 5
- EI_VERSION = 6
- EI_OSABI = 7
- EI_ABIVERSION = 8
- OLD_EI_BRAND = 8
- EI_PAD = 9
- EI_NIDENT = 16
- ELFMAG0 = 0x7f
- ELFMAG1 = 'E'
- ELFMAG2 = 'L'
- ELFMAG3 = 'F'
- SELFMAG = 4
- EV_NONE = 0
- EV_CURRENT = 1
- ELFCLASSNONE = 0
- ELFCLASS32 = 1
- ELFCLASS64 = 2
- ELFDATANONE = 0
- ELFDATA2LSB = 1
- ELFDATA2MSB = 2
- ELFOSABI_NONE = 0
- ELFOSABI_HPUX = 1
- ELFOSABI_NETBSD = 2
- ELFOSABI_LINUX = 3
- ELFOSABI_HURD = 4
- ELFOSABI_86OPEN = 5
- ELFOSABI_SOLARIS = 6
- ELFOSABI_AIX = 7
- ELFOSABI_IRIX = 8
- ELFOSABI_FREEBSD = 9
- ELFOSABI_TRU64 = 10
- ELFOSABI_MODESTO = 11
- ELFOSABI_OPENBSD = 12
- ELFOSABI_OPENVMS = 13
- ELFOSABI_NSK = 14
- ELFOSABI_ARM = 97
- ELFOSABI_STANDALONE = 255
- ELFOSABI_SYSV = ELFOSABI_NONE
- ELFOSABI_MONTEREY = ELFOSABI_AIX
- ET_NONE = 0
- ET_REL = 1
- ET_EXEC = 2
- ET_DYN = 3
- ET_CORE = 4
- ET_LOOS = 0xfe00
- ET_HIOS = 0xfeff
- ET_LOPROC = 0xff00
- ET_HIPROC = 0xffff
- EM_NONE = 0
- EM_M32 = 1
- EM_SPARC = 2
- EM_386 = 3
- EM_68K = 4
- EM_88K = 5
- EM_860 = 7
- EM_MIPS = 8
- EM_S370 = 9
- EM_MIPS_RS3_LE = 10
- EM_PARISC = 15
- EM_VPP500 = 17
- EM_SPARC32PLUS = 18
- EM_960 = 19
- EM_PPC = 20
- EM_PPC64 = 21
- EM_S390 = 22
- EM_V800 = 36
- EM_FR20 = 37
- EM_RH32 = 38
- EM_RCE = 39
- EM_ARM = 40
- EM_SH = 42
- EM_SPARCV9 = 43
- EM_TRICORE = 44
- EM_ARC = 45
- EM_H8_300 = 46
- EM_H8_300H = 47
- EM_H8S = 48
- EM_H8_500 = 49
- EM_IA_64 = 50
- EM_MIPS_X = 51
- EM_COLDFIRE = 52
- EM_68HC12 = 53
- EM_MMA = 54
- EM_PCP = 55
- EM_NCPU = 56
- EM_NDR1 = 57
- EM_STARCORE = 58
- EM_ME16 = 59
- EM_ST100 = 60
- EM_TINYJ = 61
- EM_X86_64 = 62
- EM_AARCH64 = 183
- EM_486 = 6
- EM_MIPS_RS4_BE = 10
- EM_ALPHA_STD = 41
- EM_ALPHA = 0x9026
- EM_RISCV = 243
- SHN_UNDEF = 0
- SHN_LORESERVE = 0xff00
- SHN_LOPROC = 0xff00
- SHN_HIPROC = 0xff1f
- SHN_LOOS = 0xff20
- SHN_HIOS = 0xff3f
- SHN_ABS = 0xfff1
- SHN_COMMON = 0xfff2
- SHN_XINDEX = 0xffff
- SHN_HIRESERVE = 0xffff
- SHT_NULL = 0
- SHT_PROGBITS = 1
- SHT_SYMTAB = 2
- SHT_STRTAB = 3
- SHT_RELA = 4
- SHT_HASH = 5
- SHT_DYNAMIC = 6
- SHT_NOTE = 7
- SHT_NOBITS = 8
- SHT_REL = 9
- SHT_SHLIB = 10
- SHT_DYNSYM = 11
- SHT_INIT_ARRAY = 14
- SHT_FINI_ARRAY = 15
- SHT_PREINIT_ARRAY = 16
- SHT_GROUP = 17
- SHT_SYMTAB_SHNDX = 18
- SHT_LOOS = 0x60000000
- SHT_HIOS = 0x6fffffff
- SHT_GNU_VERDEF = 0x6ffffffd
- SHT_GNU_VERNEED = 0x6ffffffe
- SHT_GNU_VERSYM = 0x6fffffff
- SHT_LOPROC = 0x70000000
- SHT_ARM_ATTRIBUTES = 0x70000003
- SHT_HIPROC = 0x7fffffff
- SHT_LOUSER = 0x80000000
- SHT_HIUSER = 0xffffffff
- SHF_WRITE = 0x1
- SHF_ALLOC = 0x2
- SHF_EXECINSTR = 0x4
- SHF_MERGE = 0x10
- SHF_STRINGS = 0x20
- SHF_INFO_LINK = 0x40
- SHF_LINK_ORDER = 0x80
- SHF_OS_NONCONFORMING = 0x100
- SHF_GROUP = 0x200
- SHF_TLS = 0x400
- SHF_MASKOS = 0x0ff00000
- SHF_MASKPROC = 0xf0000000
- PT_NULL = 0
- PT_LOAD = 1
- PT_DYNAMIC = 2
- PT_INTERP = 3
- PT_NOTE = 4
- PT_SHLIB = 5
- PT_PHDR = 6
- PT_TLS = 7
- PT_LOOS = 0x60000000
- PT_HIOS = 0x6fffffff
- PT_LOPROC = 0x70000000
- PT_HIPROC = 0x7fffffff
- PT_GNU_STACK = 0x6474e551
- PT_GNU_RELRO = 0x6474e552
- PT_PAX_FLAGS = 0x65041580
- PT_SUNWSTACK = 0x6ffffffb
- PF_X = 0x1
- PF_W = 0x2
- PF_R = 0x4
- PF_MASKOS = 0x0ff00000
- PF_MASKPROC = 0xf0000000
- DT_NULL = 0
- DT_NEEDED = 1
- DT_PLTRELSZ = 2
- DT_PLTGOT = 3
- DT_HASH = 4
- DT_STRTAB = 5
- DT_SYMTAB = 6
- DT_RELA = 7
- DT_RELASZ = 8
- DT_RELAENT = 9
- DT_STRSZ = 10
- DT_SYMENT = 11
- DT_INIT = 12
- DT_FINI = 13
- DT_SONAME = 14
- DT_RPATH = 15
- DT_SYMBOLIC = 16
- DT_REL = 17
- DT_RELSZ = 18
- DT_RELENT = 19
- DT_PLTREL = 20
- DT_DEBUG = 21
- DT_TEXTREL = 22
- DT_JMPREL = 23
- DT_BIND_NOW = 24
- DT_INIT_ARRAY = 25
- DT_FINI_ARRAY = 26
- DT_INIT_ARRAYSZ = 27
- DT_FINI_ARRAYSZ = 28
- DT_RUNPATH = 29
- DT_FLAGS = 30
- DT_ENCODING = 32
- DT_PREINIT_ARRAY = 32
- DT_PREINIT_ARRAYSZ = 33
- DT_LOOS = 0x6000000d
- DT_HIOS = 0x6ffff000
- DT_LOPROC = 0x70000000
- DT_HIPROC = 0x7fffffff
- DT_VERNEED = 0x6ffffffe
- DT_VERNEEDNUM = 0x6fffffff
- DT_VERSYM = 0x6ffffff0
- DT_PPC64_GLINK = DT_LOPROC + 0
- DT_PPC64_OPT = DT_LOPROC + 3
- DF_ORIGIN = 0x0001
- DF_SYMBOLIC = 0x0002
- DF_TEXTREL = 0x0004
- DF_BIND_NOW = 0x0008
- DF_STATIC_TLS = 0x0010
- NT_PRSTATUS = 1
- NT_FPREGSET = 2
- NT_PRPSINFO = 3
- STB_LOCAL = 0
- STB_GLOBAL = 1
- STB_WEAK = 2
- STB_LOOS = 10
- STB_HIOS = 12
- STB_LOPROC = 13
- STB_HIPROC = 15
- STT_NOTYPE = 0
- STT_OBJECT = 1
- STT_FUNC = 2
- STT_SECTION = 3
- STT_FILE = 4
- STT_COMMON = 5
- STT_TLS = 6
- STT_LOOS = 10
- STT_HIOS = 12
- STT_LOPROC = 13
- STT_HIPROC = 15
- STV_DEFAULT = 0x0
- STV_INTERNAL = 0x1
- STV_HIDDEN = 0x2
- STV_PROTECTED = 0x3
- STN_UNDEF = 0
-)
-
-/* For accessing the fields of r_info. */
-
-/* For constructing r_info from field values. */
-
-/*
- * Relocation types.
- */
-const (
- ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
-)
-
-/*
- * Symbol table entries.
- */
-
-/* For accessing the fields of st_info. */
-
-/* For constructing st_info from field values. */
-
-/* For accessing the fields of st_other. */
-
-/*
- * ELF header.
- */
-type ElfEhdr struct {
- ident [EI_NIDENT]uint8
- type_ uint16
- machine uint16
- version uint32
- entry uint64
- phoff uint64
- shoff uint64
- flags uint32
- ehsize uint16
- phentsize uint16
- phnum uint16
- shentsize uint16
- shnum uint16
- shstrndx uint16
-}
-
-/*
- * Section header.
- */
-type ElfShdr struct {
- name uint32
- type_ uint32
- flags uint64
- addr uint64
- off uint64
- size uint64
- link uint32
- info uint32
- addralign uint64
- entsize uint64
- shnum int
-}
-
-/*
- * Program header.
- */
-type ElfPhdr struct {
- type_ uint32
- flags uint32
- off uint64
- vaddr uint64
- paddr uint64
- filesz uint64
- memsz uint64
- align uint64
-}
-
-/* For accessing the fields of r_info. */
-
-/* For constructing r_info from field values. */
-
-/*
- * Symbol table entries.
- */
-
-/* For accessing the fields of st_info. */
-
-/* For constructing st_info from field values. */
-
-/* For accessing the fields of st_other. */
-
-/*
- * Go linker interface
- */
-const (
- ELF64HDRSIZE = 64
- ELF64PHDRSIZE = 56
- ELF64SHDRSIZE = 64
- ELF64RELSIZE = 16
- ELF64RELASIZE = 24
- ELF64SYMSIZE = 24
- ELF32HDRSIZE = 52
- ELF32PHDRSIZE = 32
- ELF32SHDRSIZE = 40
- ELF32SYMSIZE = 16
- ELF32RELSIZE = 8
-)
-
-/*
- * The interface uses the 64-bit structures always,
- * to avoid code duplication. The writers know how to
- * marshal a 32-bit representation from the 64-bit structure.
- */
-
-var Elfstrdat []byte
-
-/*
- * Total amount of space to reserve at the start of the file
- * for Header, PHeaders, SHeaders, and interp.
- * May waste some.
- * On FreeBSD, cannot be larger than a page.
- */
-const (
- ELFRESERVE = 4096
-)
-
-/*
- * We use the 64-bit data structures on both 32- and 64-bit machines
- * in order to write the code just once. The 64-bit data structure is
- * written in the 32-bit format on the 32-bit machines.
- */
-const (
- NSECT = 400
-)
-
-var (
- Nelfsym = 1
-
- elf64 bool
- // Either ".rel" or ".rela" depending on which type of relocation the
- // target platform uses.
- elfRelType string
-
- ehdr ElfEhdr
- phdr [NSECT]*ElfPhdr
- shdr [NSECT]*ElfShdr
-
- interp string
-)
-
-type Elfstring struct {
- s string
- off int
-}
-
-var elfstr [100]Elfstring
-
-var nelfstr int
-
-var buildinfo []byte
-
-/*
- Initialize the global variable that describes the ELF header. It will be updated as
- we write section and prog headers.
-*/
-func Elfinit(ctxt *Link) {
- ctxt.IsELF = true
-
- if ctxt.Arch.InFamily(sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X) {
- elfRelType = ".rela"
- } else {
- elfRelType = ".rel"
- }
-
- switch ctxt.Arch.Family {
- // 64-bit architectures
- case sys.PPC64, sys.S390X:
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- ehdr.flags = 1 /* Version 1 ABI */
- } else {
- ehdr.flags = 2 /* Version 2 ABI */
- }
- fallthrough
- case sys.AMD64, sys.ARM64, sys.MIPS64, sys.RISCV64:
- if ctxt.Arch.Family == sys.MIPS64 {
- ehdr.flags = 0x20000004 /* MIPS 3 CPIC */
- }
- elf64 = true
-
- ehdr.phoff = ELF64HDRSIZE /* Must be ELF64HDRSIZE: first PHdr must follow ELF header */
- ehdr.shoff = ELF64HDRSIZE /* Will move as we add PHeaders */
- ehdr.ehsize = ELF64HDRSIZE /* Must be ELF64HDRSIZE */
- ehdr.phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
- ehdr.shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */
-
- // 32-bit architectures
- case sys.ARM, sys.MIPS:
- if ctxt.Arch.Family == sys.ARM {
- // we use EABI on linux/arm, freebsd/arm, netbsd/arm.
- if ctxt.HeadType == objabi.Hlinux || ctxt.HeadType == objabi.Hfreebsd || ctxt.HeadType == objabi.Hnetbsd {
- // We set a value here that makes no indication of which
- // float ABI the object uses, because this is information
- // used by the dynamic linker to compare executables and
- // shared libraries -- so it only matters for cgo calls, and
- // the information properly comes from the object files
- // produced by the host C compiler. parseArmAttributes in
- // ldelf.go reads that information and updates this field as
- // appropriate.
- ehdr.flags = 0x5000002 // has entry point, Version5 EABI
- }
- } else if ctxt.Arch.Family == sys.MIPS {
- ehdr.flags = 0x50001004 /* MIPS 32 CPIC O32*/
- }
- fallthrough
- default:
- ehdr.phoff = ELF32HDRSIZE
- /* Must be ELF32HDRSIZE: first PHdr must follow ELF header */
- ehdr.shoff = ELF32HDRSIZE /* Will move as we add PHeaders */
- ehdr.ehsize = ELF32HDRSIZE /* Must be ELF32HDRSIZE */
- ehdr.phentsize = ELF32PHDRSIZE /* Must be ELF32PHDRSIZE */
- ehdr.shentsize = ELF32SHDRSIZE /* Must be ELF32SHDRSIZE */
- }
-}
-
-// Make sure PT_LOAD is aligned properly and
-// that there is no gap,
-// correct ELF loaders will do this implicitly,
-// but buggy ELF loaders like the one in some
-// versions of QEMU and UPX won't.
-func fixElfPhdr(e *ElfPhdr) {
- frag := int(e.vaddr & (e.align - 1))
-
- e.off -= uint64(frag)
- e.vaddr -= uint64(frag)
- e.paddr -= uint64(frag)
- e.filesz += uint64(frag)
- e.memsz += uint64(frag)
-}
-
-func elf64phdr(out *OutBuf, e *ElfPhdr) {
- if e.type_ == PT_LOAD {
- fixElfPhdr(e)
- }
-
- out.Write32(e.type_)
- out.Write32(e.flags)
- out.Write64(e.off)
- out.Write64(e.vaddr)
- out.Write64(e.paddr)
- out.Write64(e.filesz)
- out.Write64(e.memsz)
- out.Write64(e.align)
-}
-
-func elf32phdr(out *OutBuf, e *ElfPhdr) {
- if e.type_ == PT_LOAD {
- fixElfPhdr(e)
- }
-
- out.Write32(e.type_)
- out.Write32(uint32(e.off))
- out.Write32(uint32(e.vaddr))
- out.Write32(uint32(e.paddr))
- out.Write32(uint32(e.filesz))
- out.Write32(uint32(e.memsz))
- out.Write32(e.flags)
- out.Write32(uint32(e.align))
-}
-
-func elf64shdr(out *OutBuf, e *ElfShdr) {
- out.Write32(e.name)
- out.Write32(e.type_)
- out.Write64(e.flags)
- out.Write64(e.addr)
- out.Write64(e.off)
- out.Write64(e.size)
- out.Write32(e.link)
- out.Write32(e.info)
- out.Write64(e.addralign)
- out.Write64(e.entsize)
-}
-
-func elf32shdr(out *OutBuf, e *ElfShdr) {
- out.Write32(e.name)
- out.Write32(e.type_)
- out.Write32(uint32(e.flags))
- out.Write32(uint32(e.addr))
- out.Write32(uint32(e.off))
- out.Write32(uint32(e.size))
- out.Write32(e.link)
- out.Write32(e.info)
- out.Write32(uint32(e.addralign))
- out.Write32(uint32(e.entsize))
-}
-
-func elfwriteshdrs(out *OutBuf) uint32 {
- if elf64 {
- for i := 0; i < int(ehdr.shnum); i++ {
- elf64shdr(out, shdr[i])
- }
- return uint32(ehdr.shnum) * ELF64SHDRSIZE
- }
-
- for i := 0; i < int(ehdr.shnum); i++ {
- elf32shdr(out, shdr[i])
- }
- return uint32(ehdr.shnum) * ELF32SHDRSIZE
-}
-
-func elfsetstring(s *sym.Symbol, str string, off int) {
- if nelfstr >= len(elfstr) {
- Errorf(s, "too many elf strings")
- errorexit()
- }
-
- elfstr[nelfstr].s = str
- elfstr[nelfstr].off = off
- nelfstr++
-}
-
-func elfwritephdrs(out *OutBuf) uint32 {
- if elf64 {
- for i := 0; i < int(ehdr.phnum); i++ {
- elf64phdr(out, phdr[i])
- }
- return uint32(ehdr.phnum) * ELF64PHDRSIZE
- }
-
- for i := 0; i < int(ehdr.phnum); i++ {
- elf32phdr(out, phdr[i])
- }
- return uint32(ehdr.phnum) * ELF32PHDRSIZE
-}
-
-func newElfPhdr() *ElfPhdr {
- e := new(ElfPhdr)
- if ehdr.phnum >= NSECT {
- Errorf(nil, "too many phdrs")
- } else {
- phdr[ehdr.phnum] = e
- ehdr.phnum++
- }
- if elf64 {
- ehdr.shoff += ELF64PHDRSIZE
- } else {
- ehdr.shoff += ELF32PHDRSIZE
- }
- return e
-}
-
-func newElfShdr(name int64) *ElfShdr {
- e := new(ElfShdr)
- e.name = uint32(name)
- e.shnum = int(ehdr.shnum)
- if ehdr.shnum >= NSECT {
- Errorf(nil, "too many shdrs")
- } else {
- shdr[ehdr.shnum] = e
- ehdr.shnum++
- }
-
- return e
-}
-
-func getElfEhdr() *ElfEhdr {
- return &ehdr
-}
-
-func elf64writehdr(out *OutBuf) uint32 {
- out.Write(ehdr.ident[:])
- out.Write16(ehdr.type_)
- out.Write16(ehdr.machine)
- out.Write32(ehdr.version)
- out.Write64(ehdr.entry)
- out.Write64(ehdr.phoff)
- out.Write64(ehdr.shoff)
- out.Write32(ehdr.flags)
- out.Write16(ehdr.ehsize)
- out.Write16(ehdr.phentsize)
- out.Write16(ehdr.phnum)
- out.Write16(ehdr.shentsize)
- out.Write16(ehdr.shnum)
- out.Write16(ehdr.shstrndx)
- return ELF64HDRSIZE
-}
-
-func elf32writehdr(out *OutBuf) uint32 {
- out.Write(ehdr.ident[:])
- out.Write16(ehdr.type_)
- out.Write16(ehdr.machine)
- out.Write32(ehdr.version)
- out.Write32(uint32(ehdr.entry))
- out.Write32(uint32(ehdr.phoff))
- out.Write32(uint32(ehdr.shoff))
- out.Write32(ehdr.flags)
- out.Write16(ehdr.ehsize)
- out.Write16(ehdr.phentsize)
- out.Write16(ehdr.phnum)
- out.Write16(ehdr.shentsize)
- out.Write16(ehdr.shnum)
- out.Write16(ehdr.shstrndx)
- return ELF32HDRSIZE
-}
-
-func elfwritehdr(out *OutBuf) uint32 {
- if elf64 {
- return elf64writehdr(out)
- }
- return elf32writehdr(out)
-}
-
-/* Taken directly from the definition document for ELF64 */
-func elfhash(name string) uint32 {
- var h uint32
- for i := 0; i < len(name); i++ {
- h = (h << 4) + uint32(name[i])
- if g := h & 0xf0000000; g != 0 {
- h ^= g >> 24
- }
- h &= 0x0fffffff
- }
- return h
-}
-
-func Elfwritedynent(ctxt *Link, s *sym.Symbol, tag int, val uint64) {
- if elf64 {
- s.AddUint64(ctxt.Arch, uint64(tag))
- s.AddUint64(ctxt.Arch, val)
- } else {
- s.AddUint32(ctxt.Arch, uint32(tag))
- s.AddUint32(ctxt.Arch, uint32(val))
- }
-}
-
-func elfwritedynentsym(ctxt *Link, s *sym.Symbol, tag int, t *sym.Symbol) {
- Elfwritedynentsymplus(ctxt, s, tag, t, 0)
-}
-
-func Elfwritedynentsymplus(ctxt *Link, s *sym.Symbol, tag int, t *sym.Symbol, add int64) {
- if elf64 {
- s.AddUint64(ctxt.Arch, uint64(tag))
- } else {
- s.AddUint32(ctxt.Arch, uint32(tag))
- }
- s.AddAddrPlus(ctxt.Arch, t, add)
-}
-
-func elfwritedynentsymsize(ctxt *Link, s *sym.Symbol, tag int, t *sym.Symbol) {
- if elf64 {
- s.AddUint64(ctxt.Arch, uint64(tag))
- } else {
- s.AddUint32(ctxt.Arch, uint32(tag))
- }
- s.AddSize(ctxt.Arch, t)
-}
-
-func elfinterp(sh *ElfShdr, startva uint64, resoff uint64, p string) int {
- interp = p
- n := len(interp) + 1
- sh.addr = startva + resoff - uint64(n)
- sh.off = resoff - uint64(n)
- sh.size = uint64(n)
-
- return n
-}
-
-func elfwriteinterp(out *OutBuf) int {
- sh := elfshname(".interp")
- out.SeekSet(int64(sh.off))
- out.WriteString(interp)
- out.Write8(0)
- return int(sh.size)
-}
-
-func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int {
- n := 3*4 + uint64(sz) + resoff%4
-
- sh.type_ = SHT_NOTE
- sh.flags = SHF_ALLOC
- sh.addralign = 4
- sh.addr = startva + resoff - n
- sh.off = resoff - n
- sh.size = n - resoff%4
-
- return int(n)
-}
-
-func elfwritenotehdr(out *OutBuf, str string, namesz uint32, descsz uint32, tag uint32) *ElfShdr {
- sh := elfshname(str)
-
- // Write Elf_Note header.
- out.SeekSet(int64(sh.off))
-
- out.Write32(namesz)
- out.Write32(descsz)
- out.Write32(tag)
-
- return sh
-}
-
-// NetBSD Signature (as per sys/exec_elf.h)
-const (
- ELF_NOTE_NETBSD_NAMESZ = 7
- ELF_NOTE_NETBSD_DESCSZ = 4
- ELF_NOTE_NETBSD_TAG = 1
- ELF_NOTE_NETBSD_VERSION = 700000000 /* NetBSD 7.0 */
-)
-
-var ELF_NOTE_NETBSD_NAME = []byte("NetBSD\x00")
-
-func elfnetbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
- n := int(Rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + Rnd(ELF_NOTE_NETBSD_DESCSZ, 4))
- return elfnote(sh, startva, resoff, n)
-}
-
-func elfwritenetbsdsig(out *OutBuf) int {
- // Write Elf_Note header.
- sh := elfwritenotehdr(out, ".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG)
-
- if sh == nil {
- return 0
- }
-
- // Followed by NetBSD string and version.
- out.Write(ELF_NOTE_NETBSD_NAME)
- out.Write8(0)
- out.Write32(ELF_NOTE_NETBSD_VERSION)
-
- return int(sh.size)
-}
-
-// The race detector can't handle ASLR (address space layout randomization).
-// ASLR is on by default for NetBSD, so we turn the ASLR off eplicitly
-// using a magic elf Note when building race binaries.
-
-func elfnetbsdpax(sh *ElfShdr, startva uint64, resoff uint64) int {
- n := int(Rnd(4, 4) + Rnd(4, 4))
- return elfnote(sh, startva, resoff, n)
-}
-
-func elfwritenetbsdpax(out *OutBuf) int {
- sh := elfwritenotehdr(out, ".note.netbsd.pax", 4 /* length of PaX\x00 */, 4 /* length of flags */, 0x03 /* PaX type */)
- if sh == nil {
- return 0
- }
- out.Write([]byte("PaX\x00"))
- out.Write32(0x20) // 0x20 = Force disable ASLR
- return int(sh.size)
-}
-
-// OpenBSD Signature
-const (
- ELF_NOTE_OPENBSD_NAMESZ = 8
- ELF_NOTE_OPENBSD_DESCSZ = 4
- ELF_NOTE_OPENBSD_TAG = 1
- ELF_NOTE_OPENBSD_VERSION = 0
-)
-
-var ELF_NOTE_OPENBSD_NAME = []byte("OpenBSD\x00")
-
-func elfopenbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
- n := ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ
- return elfnote(sh, startva, resoff, n)
-}
-
-func elfwriteopenbsdsig(out *OutBuf) int {
- // Write Elf_Note header.
- sh := elfwritenotehdr(out, ".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG)
-
- if sh == nil {
- return 0
- }
-
- // Followed by OpenBSD string and version.
- out.Write(ELF_NOTE_OPENBSD_NAME)
-
- out.Write32(ELF_NOTE_OPENBSD_VERSION)
-
- return int(sh.size)
-}
-
-func addbuildinfo(val string) {
- if !strings.HasPrefix(val, "0x") {
- Exitf("-B argument must start with 0x: %s", val)
- }
-
- ov := val
- val = val[2:]
-
- const maxLen = 32
- if hex.DecodedLen(len(val)) > maxLen {
- Exitf("-B option too long (max %d digits): %s", maxLen, ov)
- }
-
- b, err := hex.DecodeString(val)
- if err != nil {
- if err == hex.ErrLength {
- Exitf("-B argument must have even number of digits: %s", ov)
- }
- if inv, ok := err.(hex.InvalidByteError); ok {
- Exitf("-B argument contains invalid hex digit %c: %s", byte(inv), ov)
- }
- Exitf("-B argument contains invalid hex: %s", ov)
- }
-
- buildinfo = b
-}
-
-// Build info note
-const (
- ELF_NOTE_BUILDINFO_NAMESZ = 4
- ELF_NOTE_BUILDINFO_TAG = 3
-)
-
-var ELF_NOTE_BUILDINFO_NAME = []byte("GNU\x00")
-
-func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int {
- n := int(ELF_NOTE_BUILDINFO_NAMESZ + Rnd(int64(len(buildinfo)), 4))
- return elfnote(sh, startva, resoff, n)
-}
-
-func elfgobuildid(sh *ElfShdr, startva uint64, resoff uint64) int {
- n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(*flagBuildid)), 4))
- return elfnote(sh, startva, resoff, n)
-}
-
-func elfwritebuildinfo(out *OutBuf) int {
- sh := elfwritenotehdr(out, ".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG)
- if sh == nil {
- return 0
- }
-
- out.Write(ELF_NOTE_BUILDINFO_NAME)
- out.Write(buildinfo)
- var zero = make([]byte, 4)
- out.Write(zero[:int(Rnd(int64(len(buildinfo)), 4)-int64(len(buildinfo)))])
-
- return int(sh.size)
-}
-
-func elfwritegobuildid(out *OutBuf) int {
- sh := elfwritenotehdr(out, ".note.go.buildid", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(*flagBuildid)), ELF_NOTE_GOBUILDID_TAG)
- if sh == nil {
- return 0
- }
-
- out.Write(ELF_NOTE_GO_NAME)
- out.Write([]byte(*flagBuildid))
- var zero = make([]byte, 4)
- out.Write(zero[:int(Rnd(int64(len(*flagBuildid)), 4)-int64(len(*flagBuildid)))])
-
- return int(sh.size)
-}
-
-// Go specific notes
-const (
- ELF_NOTE_GOPKGLIST_TAG = 1
- ELF_NOTE_GOABIHASH_TAG = 2
- ELF_NOTE_GODEPS_TAG = 3
- ELF_NOTE_GOBUILDID_TAG = 4
-)
-
-var ELF_NOTE_GO_NAME = []byte("Go\x00\x00")
-
-var elfverneed int
-
-type Elfaux struct {
- next *Elfaux
- num int
- vers string
-}
-
-type Elflib struct {
- next *Elflib
- aux *Elfaux
- file string
-}
-
-func addelflib(list **Elflib, file string, vers string) *Elfaux {
- var lib *Elflib
-
- for lib = *list; lib != nil; lib = lib.next {
- if lib.file == file {
- goto havelib
- }
- }
- lib = new(Elflib)
- lib.next = *list
- lib.file = file
- *list = lib
-
-havelib:
- for aux := lib.aux; aux != nil; aux = aux.next {
- if aux.vers == vers {
- return aux
- }
- }
- aux := new(Elfaux)
- aux.next = lib.aux
- aux.vers = vers
- lib.aux = aux
-
- return aux
-}
-
-func elfdynhash(ctxt *Link) {
- if !ctxt.IsELF {
- return
- }
-
- nsym := Nelfsym
- s := ctxt.Syms.Lookup(".hash", 0)
- s.Type = sym.SELFROSECT
- s.Attr |= sym.AttrReachable
-
- i := nsym
- nbucket := 1
- for i > 0 {
- nbucket++
- i >>= 1
- }
-
- var needlib *Elflib
- need := make([]*Elfaux, nsym)
- chain := make([]uint32, nsym)
- buckets := make([]uint32, nbucket)
-
- for _, sy := range ctxt.Syms.Allsym {
- if sy.Dynid <= 0 {
- continue
- }
-
- if sy.Dynimpvers() != "" {
- need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib(), sy.Dynimpvers())
- }
-
- name := sy.Extname()
- hc := elfhash(name)
-
- b := hc % uint32(nbucket)
- chain[sy.Dynid] = buckets[b]
- buckets[b] = uint32(sy.Dynid)
- }
-
- // s390x (ELF64) hash table entries are 8 bytes
- if ctxt.Arch.Family == sys.S390X {
- s.AddUint64(ctxt.Arch, uint64(nbucket))
- s.AddUint64(ctxt.Arch, uint64(nsym))
- for i := 0; i < nbucket; i++ {
- s.AddUint64(ctxt.Arch, uint64(buckets[i]))
- }
- for i := 0; i < nsym; i++ {
- s.AddUint64(ctxt.Arch, uint64(chain[i]))
- }
- } else {
- s.AddUint32(ctxt.Arch, uint32(nbucket))
- s.AddUint32(ctxt.Arch, uint32(nsym))
- for i := 0; i < nbucket; i++ {
- s.AddUint32(ctxt.Arch, buckets[i])
- }
- for i := 0; i < nsym; i++ {
- s.AddUint32(ctxt.Arch, chain[i])
- }
- }
-
- // version symbols
- dynstr := ctxt.Syms.Lookup(".dynstr", 0)
-
- s = ctxt.Syms.Lookup(".gnu.version_r", 0)
- i = 2
- nfile := 0
- for l := needlib; l != nil; l = l.next {
- nfile++
-
- // header
- s.AddUint16(ctxt.Arch, 1) // table version
- j := 0
- for x := l.aux; x != nil; x = x.next {
- j++
- }
- s.AddUint16(ctxt.Arch, uint16(j)) // aux count
- s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, l.file))) // file string offset
- s.AddUint32(ctxt.Arch, 16) // offset from header to first aux
- if l.next != nil {
- s.AddUint32(ctxt.Arch, 16+uint32(j)*16) // offset from this header to next
- } else {
- s.AddUint32(ctxt.Arch, 0)
- }
-
- for x := l.aux; x != nil; x = x.next {
- x.num = i
- i++
-
- // aux struct
- s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash
- s.AddUint16(ctxt.Arch, 0) // flags
- s.AddUint16(ctxt.Arch, uint16(x.num)) // other - index we refer to this by
- s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, x.vers))) // version string offset
- if x.next != nil {
- s.AddUint32(ctxt.Arch, 16) // offset from this aux to next
- } else {
- s.AddUint32(ctxt.Arch, 0)
- }
- }
- }
-
- // version references
- s = ctxt.Syms.Lookup(".gnu.version", 0)
-
- for i := 0; i < nsym; i++ {
- if i == 0 {
- s.AddUint16(ctxt.Arch, 0) // first entry - no symbol
- } else if need[i] == nil {
- s.AddUint16(ctxt.Arch, 1) // global
- } else {
- s.AddUint16(ctxt.Arch, uint16(need[i].num))
- }
- }
-
- s = ctxt.Syms.Lookup(".dynamic", 0)
- elfverneed = nfile
- if elfverneed != 0 {
- elfwritedynentsym(ctxt, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
- Elfwritedynent(ctxt, s, DT_VERNEEDNUM, uint64(nfile))
- elfwritedynentsym(ctxt, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
- }
-
- sy := ctxt.Syms.Lookup(elfRelType+".plt", 0)
- if sy.Size > 0 {
- if elfRelType == ".rela" {
- Elfwritedynent(ctxt, s, DT_PLTREL, DT_RELA)
- } else {
- Elfwritedynent(ctxt, s, DT_PLTREL, DT_REL)
- }
- elfwritedynentsymsize(ctxt, s, DT_PLTRELSZ, sy)
- elfwritedynentsym(ctxt, s, DT_JMPREL, sy)
- }
-
- Elfwritedynent(ctxt, s, DT_NULL, 0)
-}
-
-func elfphload(seg *sym.Segment) *ElfPhdr {
- ph := newElfPhdr()
- ph.type_ = PT_LOAD
- if seg.Rwx&4 != 0 {
- ph.flags |= PF_R
- }
- if seg.Rwx&2 != 0 {
- ph.flags |= PF_W
- }
- if seg.Rwx&1 != 0 {
- ph.flags |= PF_X
- }
- ph.vaddr = seg.Vaddr
- ph.paddr = seg.Vaddr
- ph.memsz = seg.Length
- ph.off = seg.Fileoff
- ph.filesz = seg.Filelen
- ph.align = uint64(*FlagRound)
-
- return ph
-}
-
-func elfphrelro(seg *sym.Segment) {
- ph := newElfPhdr()
- ph.type_ = PT_GNU_RELRO
- ph.vaddr = seg.Vaddr
- ph.paddr = seg.Vaddr
- ph.memsz = seg.Length
- ph.off = seg.Fileoff
- ph.filesz = seg.Filelen
- ph.align = uint64(*FlagRound)
-}
-
-func elfshname(name string) *ElfShdr {
- for i := 0; i < nelfstr; i++ {
- if name != elfstr[i].s {
- continue
- }
- off := elfstr[i].off
- for i = 0; i < int(ehdr.shnum); i++ {
- sh := shdr[i]
- if sh.name == uint32(off) {
- return sh
- }
- }
- return newElfShdr(int64(off))
- }
- Exitf("cannot find elf name %s", name)
- return nil
-}
-
-// Create an ElfShdr for the section with name.
-// Create a duplicate if one already exists with that name
-func elfshnamedup(name string) *ElfShdr {
- for i := 0; i < nelfstr; i++ {
- if name == elfstr[i].s {
- off := elfstr[i].off
- return newElfShdr(int64(off))
- }
- }
-
- Errorf(nil, "cannot find elf name %s", name)
- errorexit()
- return nil
-}
-
-func elfshalloc(sect *sym.Section) *ElfShdr {
- sh := elfshname(sect.Name)
- sect.Elfsect = sh
- return sh
-}
-
-func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
- var sh *ElfShdr
-
- if sect.Name == ".text" {
- if sect.Elfsect == nil {
- sect.Elfsect = elfshnamedup(sect.Name)
- }
- sh = sect.Elfsect.(*ElfShdr)
- } else {
- sh = elfshalloc(sect)
- }
-
- // If this section has already been set up as a note, we assume type_ and
- // flags are already correct, but the other fields still need filling in.
- if sh.type_ == SHT_NOTE {
- if linkmode != LinkExternal {
- // TODO(mwhudson): the approach here will work OK when
- // linking internally for notes that we want to be included
- // in a loadable segment (e.g. the abihash note) but not for
- // notes that we do not want to be mapped (e.g. the package
- // list note). The real fix is probably to define new values
- // for Symbol.Type corresponding to mapped and unmapped notes
- // and handle them in dodata().
- Errorf(nil, "sh.type_ == SHT_NOTE in elfshbits when linking internally")
- }
- sh.addralign = uint64(sect.Align)
- sh.size = sect.Length
- sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
- return sh
- }
- if sh.type_ > 0 {
- return sh
- }
-
- if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
- sh.type_ = SHT_PROGBITS
- } else {
- sh.type_ = SHT_NOBITS
- }
- sh.flags = SHF_ALLOC
- if sect.Rwx&1 != 0 {
- sh.flags |= SHF_EXECINSTR
- }
- if sect.Rwx&2 != 0 {
- sh.flags |= SHF_WRITE
- }
- if sect.Name == ".tbss" {
- sh.flags |= SHF_TLS
- sh.type_ = SHT_NOBITS
- }
- if strings.HasPrefix(sect.Name, ".debug") || strings.HasPrefix(sect.Name, ".zdebug") {
- sh.flags = 0
- }
-
- if linkmode != LinkExternal {
- sh.addr = sect.Vaddr
- }
- sh.addralign = uint64(sect.Align)
- sh.size = sect.Length
- if sect.Name != ".tbss" {
- sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
- }
-
- return sh
-}
-
-func elfshreloc(arch *sys.Arch, sect *sym.Section) *ElfShdr {
- // If main section is SHT_NOBITS, nothing to relocate.
- // Also nothing to relocate in .shstrtab or notes.
- if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
- return nil
- }
- if sect.Name == ".shstrtab" || sect.Name == ".tbss" {
- return nil
- }
- if sect.Elfsect.(*ElfShdr).type_ == SHT_NOTE {
- return nil
- }
-
- typ := SHT_REL
- if elfRelType == ".rela" {
- typ = SHT_RELA
- }
-
- sh := elfshname(elfRelType + sect.Name)
- // There could be multiple text sections but each needs
- // its own .rela.text.
-
- if sect.Name == ".text" {
- if sh.info != 0 && sh.info != uint32(sect.Elfsect.(*ElfShdr).shnum) {
- sh = elfshnamedup(elfRelType + sect.Name)
- }
- }
-
- sh.type_ = uint32(typ)
- sh.entsize = uint64(arch.RegSize) * 2
- if typ == SHT_RELA {
- sh.entsize += uint64(arch.RegSize)
- }
- sh.link = uint32(elfshname(".symtab").shnum)
- sh.info = uint32(sect.Elfsect.(*ElfShdr).shnum)
- sh.off = sect.Reloff
- sh.size = sect.Rellen
- sh.addralign = uint64(arch.RegSize)
- return sh
-}
-
-func elfrelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
- // If main section is SHT_NOBITS, nothing to relocate.
- // Also nothing to relocate in .shstrtab.
- if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
- return
- }
- if sect.Name == ".shstrtab" {
- return
- }
-
- sect.Reloff = uint64(ctxt.Out.Offset())
- for i, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if uint64(s.Value) >= sect.Vaddr {
- syms = syms[i:]
- break
- }
- }
-
- eaddr := int32(sect.Vaddr + sect.Length)
- for _, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if s.Value >= int64(eaddr) {
- break
- }
- for ri := range s.R {
- r := &s.R[ri]
- if r.Done {
- continue
- }
- if r.Xsym == nil {
- Errorf(s, "missing xsym in relocation %#v %#v", r.Sym.Name, s)
- continue
- }
- if r.Xsym.ElfsymForReloc() == 0 {
- Errorf(s, "reloc %d (%s) to non-elf symbol %s (outer=%s) %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Name, r.Xsym.Name, r.Sym.Type, r.Sym.Type)
- }
- if !r.Xsym.Attr.Reachable() {
- Errorf(s, "unreachable reloc %d (%s) target %v", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Xsym.Name)
- }
- if !thearch.Elfreloc1(ctxt, r, int64(uint64(s.Value+int64(r.Off))-sect.Vaddr)) {
- Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Siz, r.Sym.Name)
- }
- }
- }
-
- sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
-}
-
-func Elfemitreloc(ctxt *Link) {
- for ctxt.Out.Offset()&7 != 0 {
- ctxt.Out.Write8(0)
- }
-
- for _, sect := range Segtext.Sections {
- if sect.Name == ".text" {
- elfrelocsect(ctxt, sect, ctxt.Textp)
- } else {
- elfrelocsect(ctxt, sect, datap)
- }
- }
-
- for _, sect := range Segrodata.Sections {
- elfrelocsect(ctxt, sect, datap)
- }
- for _, sect := range Segrelrodata.Sections {
- elfrelocsect(ctxt, sect, datap)
- }
- for _, sect := range Segdata.Sections {
- elfrelocsect(ctxt, sect, datap)
- }
- for _, sect := range Segdwarf.Sections {
- elfrelocsect(ctxt, sect, dwarfp)
- }
-}
-
-func addgonote(ctxt *Link, sectionName string, tag uint32, desc []byte) {
- s := ctxt.Syms.Lookup(sectionName, 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
- // namesz
- s.AddUint32(ctxt.Arch, uint32(len(ELF_NOTE_GO_NAME)))
- // descsz
- s.AddUint32(ctxt.Arch, uint32(len(desc)))
- // tag
- s.AddUint32(ctxt.Arch, tag)
- // name + padding
- s.P = append(s.P, ELF_NOTE_GO_NAME...)
- for len(s.P)%4 != 0 {
- s.P = append(s.P, 0)
- }
- // desc + padding
- s.P = append(s.P, desc...)
- for len(s.P)%4 != 0 {
- s.P = append(s.P, 0)
- }
- s.Size = int64(len(s.P))
- s.Align = 4
-}
-
-func (ctxt *Link) doelf() {
- if !ctxt.IsELF {
- return
- }
-
- /* predefine strings we need for section headers */
- shstrtab := ctxt.Syms.Lookup(".shstrtab", 0)
-
- shstrtab.Type = sym.SELFROSECT
- shstrtab.Attr |= sym.AttrReachable
-
- Addstring(shstrtab, "")
- Addstring(shstrtab, ".text")
- Addstring(shstrtab, ".noptrdata")
- Addstring(shstrtab, ".data")
- Addstring(shstrtab, ".bss")
- Addstring(shstrtab, ".noptrbss")
- Addstring(shstrtab, "__libfuzzer_extra_counters")
- Addstring(shstrtab, ".go.buildinfo")
-
- // generate .tbss section for dynamic internal linker or external
- // linking, so that various binutils could correctly calculate
- // PT_TLS size. See https://golang.org/issue/5200.
- if !*FlagD || ctxt.LinkMode == LinkExternal {
- Addstring(shstrtab, ".tbss")
- }
- if ctxt.HeadType == objabi.Hnetbsd {
- Addstring(shstrtab, ".note.netbsd.ident")
- if *flagRace {
- Addstring(shstrtab, ".note.netbsd.pax")
- }
- }
- if ctxt.HeadType == objabi.Hopenbsd {
- Addstring(shstrtab, ".note.openbsd.ident")
- }
- if len(buildinfo) > 0 {
- Addstring(shstrtab, ".note.gnu.build-id")
- }
- if *flagBuildid != "" {
- Addstring(shstrtab, ".note.go.buildid")
- }
- Addstring(shstrtab, ".elfdata")
- Addstring(shstrtab, ".rodata")
- // See the comment about data.rel.ro.FOO section names in data.go.
- relro_prefix := ""
- if ctxt.UseRelro() {
- Addstring(shstrtab, ".data.rel.ro")
- relro_prefix = ".data.rel.ro"
- }
- Addstring(shstrtab, relro_prefix+".typelink")
- Addstring(shstrtab, relro_prefix+".itablink")
- Addstring(shstrtab, relro_prefix+".gosymtab")
- Addstring(shstrtab, relro_prefix+".gopclntab")
-
- if ctxt.LinkMode == LinkExternal {
- *FlagD = true
-
- Addstring(shstrtab, elfRelType+".text")
- Addstring(shstrtab, elfRelType+".rodata")
- Addstring(shstrtab, elfRelType+relro_prefix+".typelink")
- Addstring(shstrtab, elfRelType+relro_prefix+".itablink")
- Addstring(shstrtab, elfRelType+relro_prefix+".gosymtab")
- Addstring(shstrtab, elfRelType+relro_prefix+".gopclntab")
- Addstring(shstrtab, elfRelType+".noptrdata")
- Addstring(shstrtab, elfRelType+".data")
- if ctxt.UseRelro() {
- Addstring(shstrtab, elfRelType+".data.rel.ro")
- }
- Addstring(shstrtab, elfRelType+".go.buildinfo")
-
- // add a .note.GNU-stack section to mark the stack as non-executable
- Addstring(shstrtab, ".note.GNU-stack")
-
- if ctxt.BuildMode == BuildModeShared {
- Addstring(shstrtab, ".note.go.abihash")
- Addstring(shstrtab, ".note.go.pkg-list")
- Addstring(shstrtab, ".note.go.deps")
- }
- }
-
- hasinitarr := ctxt.linkShared
-
- /* shared library initializer */
- switch ctxt.BuildMode {
- case BuildModeCArchive, BuildModeCShared, BuildModeShared, BuildModePlugin:
- hasinitarr = true
- }
-
- if hasinitarr {
- Addstring(shstrtab, ".init_array")
- Addstring(shstrtab, elfRelType+".init_array")
- }
-
- if !*FlagS {
- Addstring(shstrtab, ".symtab")
- Addstring(shstrtab, ".strtab")
- dwarfaddshstrings(ctxt, shstrtab)
- }
-
- Addstring(shstrtab, ".shstrtab")
-
- if !*FlagD { /* -d suppresses dynamic loader format */
- Addstring(shstrtab, ".interp")
- Addstring(shstrtab, ".hash")
- Addstring(shstrtab, ".got")
- if ctxt.Arch.Family == sys.PPC64 {
- Addstring(shstrtab, ".glink")
- }
- Addstring(shstrtab, ".got.plt")
- Addstring(shstrtab, ".dynamic")
- Addstring(shstrtab, ".dynsym")
- Addstring(shstrtab, ".dynstr")
- Addstring(shstrtab, elfRelType)
- Addstring(shstrtab, elfRelType+".plt")
-
- Addstring(shstrtab, ".plt")
- Addstring(shstrtab, ".gnu.version")
- Addstring(shstrtab, ".gnu.version_r")
-
- /* dynamic symbol table - first entry all zeros */
- s := ctxt.Syms.Lookup(".dynsym", 0)
-
- s.Type = sym.SELFROSECT
- s.Attr |= sym.AttrReachable
- if elf64 {
- s.Size += ELF64SYMSIZE
- } else {
- s.Size += ELF32SYMSIZE
- }
-
- /* dynamic string table */
- s = ctxt.Syms.Lookup(".dynstr", 0)
-
- s.Type = sym.SELFROSECT
- s.Attr |= sym.AttrReachable
- if s.Size == 0 {
- Addstring(s, "")
- }
- dynstr := s
-
- /* relocation table */
- s = ctxt.Syms.Lookup(elfRelType, 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
-
- /* global offset table */
- s = ctxt.Syms.Lookup(".got", 0)
-
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFGOT // writable
-
- /* ppc64 glink resolver */
- if ctxt.Arch.Family == sys.PPC64 {
- s := ctxt.Syms.Lookup(".glink", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFRXSECT
- }
-
- /* hash */
- s = ctxt.Syms.Lookup(".hash", 0)
-
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
-
- s = ctxt.Syms.Lookup(".got.plt", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFSECT // writable
-
- s = ctxt.Syms.Lookup(".plt", 0)
-
- s.Attr |= sym.AttrReachable
- if ctxt.Arch.Family == sys.PPC64 {
- // In the ppc64 ABI, .plt is a data section
- // written by the dynamic linker.
- s.Type = sym.SELFSECT
- } else {
- s.Type = sym.SELFRXSECT
- }
-
- thearch.Elfsetupplt(ctxt)
-
- s = ctxt.Syms.Lookup(elfRelType+".plt", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
-
- s = ctxt.Syms.Lookup(".gnu.version", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
-
- s = ctxt.Syms.Lookup(".gnu.version_r", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
-
- /* define dynamic elf table */
- s = ctxt.Syms.Lookup(".dynamic", 0)
-
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFSECT // writable
-
- /*
- * .dynamic table
- */
- elfwritedynentsym(ctxt, s, DT_HASH, ctxt.Syms.Lookup(".hash", 0))
-
- elfwritedynentsym(ctxt, s, DT_SYMTAB, ctxt.Syms.Lookup(".dynsym", 0))
- if elf64 {
- Elfwritedynent(ctxt, s, DT_SYMENT, ELF64SYMSIZE)
- } else {
- Elfwritedynent(ctxt, s, DT_SYMENT, ELF32SYMSIZE)
- }
- elfwritedynentsym(ctxt, s, DT_STRTAB, ctxt.Syms.Lookup(".dynstr", 0))
- elfwritedynentsymsize(ctxt, s, DT_STRSZ, ctxt.Syms.Lookup(".dynstr", 0))
- if elfRelType == ".rela" {
- elfwritedynentsym(ctxt, s, DT_RELA, ctxt.Syms.Lookup(".rela", 0))
- elfwritedynentsymsize(ctxt, s, DT_RELASZ, ctxt.Syms.Lookup(".rela", 0))
- Elfwritedynent(ctxt, s, DT_RELAENT, ELF64RELASIZE)
- } else {
- elfwritedynentsym(ctxt, s, DT_REL, ctxt.Syms.Lookup(".rel", 0))
- elfwritedynentsymsize(ctxt, s, DT_RELSZ, ctxt.Syms.Lookup(".rel", 0))
- Elfwritedynent(ctxt, s, DT_RELENT, ELF32RELSIZE)
- }
-
- if rpath.val != "" {
- Elfwritedynent(ctxt, s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
- }
-
- if ctxt.Arch.Family == sys.PPC64 {
- elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".plt", 0))
- } else if ctxt.Arch.Family == sys.S390X {
- elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".got", 0))
- } else {
- elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".got.plt", 0))
- }
-
- if ctxt.Arch.Family == sys.PPC64 {
- Elfwritedynent(ctxt, s, DT_PPC64_OPT, 0)
- }
-
- // Solaris dynamic linker can't handle an empty .rela.plt if
- // DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
- // DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
- // size of .rel(a).plt section.
- Elfwritedynent(ctxt, s, DT_DEBUG, 0)
- }
-
- if ctxt.BuildMode == BuildModeShared {
- // The go.link.abihashbytes symbol will be pointed at the appropriate
- // part of the .note.go.abihash section in data.go:func address().
- s := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
- s.Attr |= sym.AttrLocal
- s.Type = sym.SRODATA
- s.Attr |= sym.AttrSpecial
- s.Attr |= sym.AttrReachable
- s.Size = int64(sha1.Size)
-
- sort.Sort(byPkg(ctxt.Library))
- h := sha1.New()
- for _, l := range ctxt.Library {
- io.WriteString(h, l.Hash)
- }
- addgonote(ctxt, ".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{}))
- addgonote(ctxt, ".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, pkglistfornote)
- var deplist []string
- for _, shlib := range ctxt.Shlibs {
- deplist = append(deplist, filepath.Base(shlib.Path))
- }
- addgonote(ctxt, ".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n")))
- }
-
- if ctxt.LinkMode == LinkExternal && *flagBuildid != "" {
- addgonote(ctxt, ".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(*flagBuildid))
- }
-}
-
-// Do not write DT_NULL. elfdynhash will finish it.
-func shsym(sh *ElfShdr, s *sym.Symbol) {
- addr := Symaddr(s)
- if sh.flags&SHF_ALLOC != 0 {
- sh.addr = uint64(addr)
- }
- sh.off = uint64(datoff(s, addr))
- sh.size = uint64(s.Size)
-}
-
-func phsh(ph *ElfPhdr, sh *ElfShdr) {
- ph.vaddr = sh.addr
- ph.paddr = ph.vaddr
- ph.off = sh.off
- ph.filesz = sh.size
- ph.memsz = sh.size
- ph.align = sh.addralign
-}
-
-func Asmbelfsetup() {
- /* This null SHdr must appear before all others */
- elfshname("")
-
- for _, sect := range Segtext.Sections {
- // There could be multiple .text sections. Instead check the Elfsect
- // field to determine if already has an ElfShdr and if not, create one.
- if sect.Name == ".text" {
- if sect.Elfsect == nil {
- sect.Elfsect = elfshnamedup(sect.Name)
- }
- } else {
- elfshalloc(sect)
- }
- }
- for _, sect := range Segrodata.Sections {
- elfshalloc(sect)
- }
- for _, sect := range Segrelrodata.Sections {
- elfshalloc(sect)
- }
- for _, sect := range Segdata.Sections {
- elfshalloc(sect)
- }
- for _, sect := range Segdwarf.Sections {
- elfshalloc(sect)
- }
-}
-
-func Asmbelf(ctxt *Link, symo int64) {
- eh := getElfEhdr()
- switch ctxt.Arch.Family {
- default:
- Exitf("unknown architecture in asmbelf: %v", ctxt.Arch.Family)
- case sys.MIPS, sys.MIPS64:
- eh.machine = EM_MIPS
- case sys.ARM:
- eh.machine = EM_ARM
- case sys.AMD64:
- eh.machine = EM_X86_64
- case sys.ARM64:
- eh.machine = EM_AARCH64
- case sys.I386:
- eh.machine = EM_386
- case sys.PPC64:
- eh.machine = EM_PPC64
- case sys.RISCV64:
- eh.machine = EM_RISCV
- case sys.S390X:
- eh.machine = EM_S390
- }
-
- elfreserve := int64(ELFRESERVE)
-
- numtext := int64(0)
- for _, sect := range Segtext.Sections {
- if sect.Name == ".text" {
- numtext++
- }
- }
-
- // If there are multiple text sections, extra space is needed
- // in the elfreserve for the additional .text and .rela.text
- // section headers. It can handle 4 extra now. Headers are
- // 64 bytes.
-
- if numtext > 4 {
- elfreserve += elfreserve + numtext*64*2
- }
-
- startva := *FlagTextAddr - int64(HEADR)
- resoff := elfreserve
-
- var pph *ElfPhdr
- var pnote *ElfPhdr
- if *flagRace && ctxt.HeadType == objabi.Hnetbsd {
- sh := elfshname(".note.netbsd.pax")
- resoff -= int64(elfnetbsdpax(sh, uint64(startva), uint64(resoff)))
- pnote = newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
- phsh(pnote, sh)
- }
- if ctxt.LinkMode == LinkExternal {
- /* skip program headers */
- eh.phoff = 0
-
- eh.phentsize = 0
-
- if ctxt.BuildMode == BuildModeShared {
- sh := elfshname(".note.go.pkg-list")
- sh.type_ = SHT_NOTE
- sh = elfshname(".note.go.abihash")
- sh.type_ = SHT_NOTE
- sh.flags = SHF_ALLOC
- sh = elfshname(".note.go.deps")
- sh.type_ = SHT_NOTE
- }
-
- if *flagBuildid != "" {
- sh := elfshname(".note.go.buildid")
- sh.type_ = SHT_NOTE
- sh.flags = SHF_ALLOC
- }
-
- goto elfobj
- }
-
- /* program header info */
- pph = newElfPhdr()
-
- pph.type_ = PT_PHDR
- pph.flags = PF_R
- pph.off = uint64(eh.ehsize)
- pph.vaddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
- pph.paddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
- pph.align = uint64(*FlagRound)
-
- /*
- * PHDR must be in a loaded segment. Adjust the text
- * segment boundaries downwards to include it.
- */
- {
- o := int64(Segtext.Vaddr - pph.vaddr)
- Segtext.Vaddr -= uint64(o)
- Segtext.Length += uint64(o)
- o = int64(Segtext.Fileoff - pph.off)
- Segtext.Fileoff -= uint64(o)
- Segtext.Filelen += uint64(o)
- }
-
- if !*FlagD { /* -d suppresses dynamic loader format */
- /* interpreter */
- sh := elfshname(".interp")
-
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC
- sh.addralign = 1
-
- if interpreter == "" && objabi.GO_LDSO != "" {
- interpreter = objabi.GO_LDSO
- }
-
- if interpreter == "" {
- switch ctxt.HeadType {
- case objabi.Hlinux:
- if objabi.GOOS == "android" {
- interpreter = thearch.Androiddynld
- if interpreter == "" {
- Exitf("ELF interpreter not set")
- }
- } else {
- interpreter = thearch.Linuxdynld
- }
-
- case objabi.Hfreebsd:
- interpreter = thearch.Freebsddynld
-
- case objabi.Hnetbsd:
- interpreter = thearch.Netbsddynld
-
- case objabi.Hopenbsd:
- interpreter = thearch.Openbsddynld
-
- case objabi.Hdragonfly:
- interpreter = thearch.Dragonflydynld
-
- case objabi.Hsolaris:
- interpreter = thearch.Solarisdynld
- }
- }
-
- resoff -= int64(elfinterp(sh, uint64(startva), uint64(resoff), interpreter))
-
- ph := newElfPhdr()
- ph.type_ = PT_INTERP
- ph.flags = PF_R
- phsh(ph, sh)
- }
-
- pnote = nil
- if ctxt.HeadType == objabi.Hnetbsd || ctxt.HeadType == objabi.Hopenbsd {
- var sh *ElfShdr
- switch ctxt.HeadType {
- case objabi.Hnetbsd:
- sh = elfshname(".note.netbsd.ident")
- resoff -= int64(elfnetbsdsig(sh, uint64(startva), uint64(resoff)))
-
- case objabi.Hopenbsd:
- sh = elfshname(".note.openbsd.ident")
- resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
- }
-
- pnote = newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
- phsh(pnote, sh)
- }
-
- if len(buildinfo) > 0 {
- sh := elfshname(".note.gnu.build-id")
- resoff -= int64(elfbuildinfo(sh, uint64(startva), uint64(resoff)))
-
- if pnote == nil {
- pnote = newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
- }
-
- phsh(pnote, sh)
- }
-
- if *flagBuildid != "" {
- sh := elfshname(".note.go.buildid")
- resoff -= int64(elfgobuildid(sh, uint64(startva), uint64(resoff)))
-
- pnote := newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
- phsh(pnote, sh)
- }
-
- // Additions to the reserved area must be above this line.
-
- elfphload(&Segtext)
- if len(Segrodata.Sections) > 0 {
- elfphload(&Segrodata)
- }
- if len(Segrelrodata.Sections) > 0 {
- elfphload(&Segrelrodata)
- elfphrelro(&Segrelrodata)
- }
- elfphload(&Segdata)
-
- /* Dynamic linking sections */
- if !*FlagD {
- sh := elfshname(".dynsym")
- sh.type_ = SHT_DYNSYM
- sh.flags = SHF_ALLOC
- if elf64 {
- sh.entsize = ELF64SYMSIZE
- } else {
- sh.entsize = ELF32SYMSIZE
- }
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynstr").shnum)
-
- // sh.info is the index of first non-local symbol (number of local symbols)
- s := ctxt.Syms.Lookup(".dynsym", 0)
- i := uint32(0)
- for sub := s; sub != nil; sub = sub.Sub {
- i++
- if !sub.Attr.Local() {
- break
- }
- }
- sh.info = i
- shsym(sh, s)
-
- sh = elfshname(".dynstr")
- sh.type_ = SHT_STRTAB
- sh.flags = SHF_ALLOC
- sh.addralign = 1
- shsym(sh, ctxt.Syms.Lookup(".dynstr", 0))
-
- if elfverneed != 0 {
- sh := elfshname(".gnu.version")
- sh.type_ = SHT_GNU_VERSYM
- sh.flags = SHF_ALLOC
- sh.addralign = 2
- sh.link = uint32(elfshname(".dynsym").shnum)
- sh.entsize = 2
- shsym(sh, ctxt.Syms.Lookup(".gnu.version", 0))
-
- sh = elfshname(".gnu.version_r")
- sh.type_ = SHT_GNU_VERNEED
- sh.flags = SHF_ALLOC
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.info = uint32(elfverneed)
- sh.link = uint32(elfshname(".dynstr").shnum)
- shsym(sh, ctxt.Syms.Lookup(".gnu.version_r", 0))
- }
-
- if elfRelType == ".rela" {
- sh := elfshname(".rela.plt")
- sh.type_ = SHT_RELA
- sh.flags = SHF_ALLOC
- sh.entsize = ELF64RELASIZE
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynsym").shnum)
- sh.info = uint32(elfshname(".plt").shnum)
- shsym(sh, ctxt.Syms.Lookup(".rela.plt", 0))
-
- sh = elfshname(".rela")
- sh.type_ = SHT_RELA
- sh.flags = SHF_ALLOC
- sh.entsize = ELF64RELASIZE
- sh.addralign = 8
- sh.link = uint32(elfshname(".dynsym").shnum)
- shsym(sh, ctxt.Syms.Lookup(".rela", 0))
- } else {
- sh := elfshname(".rel.plt")
- sh.type_ = SHT_REL
- sh.flags = SHF_ALLOC
- sh.entsize = ELF32RELSIZE
- sh.addralign = 4
- sh.link = uint32(elfshname(".dynsym").shnum)
- shsym(sh, ctxt.Syms.Lookup(".rel.plt", 0))
-
- sh = elfshname(".rel")
- sh.type_ = SHT_REL
- sh.flags = SHF_ALLOC
- sh.entsize = ELF32RELSIZE
- sh.addralign = 4
- sh.link = uint32(elfshname(".dynsym").shnum)
- shsym(sh, ctxt.Syms.Lookup(".rel", 0))
- }
-
- if eh.machine == EM_PPC64 {
- sh := elfshname(".glink")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_EXECINSTR
- sh.addralign = 4
- shsym(sh, ctxt.Syms.Lookup(".glink", 0))
- }
-
- sh = elfshname(".plt")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_EXECINSTR
- if eh.machine == EM_X86_64 {
- sh.entsize = 16
- } else if eh.machine == EM_S390 {
- sh.entsize = 32
- } else if eh.machine == EM_PPC64 {
- // On ppc64, this is just a table of addresses
- // filled by the dynamic linker
- sh.type_ = SHT_NOBITS
-
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = 8
- } else {
- sh.entsize = 4
- }
- sh.addralign = sh.entsize
- shsym(sh, ctxt.Syms.Lookup(".plt", 0))
-
- // On ppc64, .got comes from the input files, so don't
- // create it here, and .got.plt is not used.
- if eh.machine != EM_PPC64 {
- sh := elfshname(".got")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = uint64(ctxt.Arch.RegSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
- shsym(sh, ctxt.Syms.Lookup(".got", 0))
-
- sh = elfshname(".got.plt")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = uint64(ctxt.Arch.RegSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
- shsym(sh, ctxt.Syms.Lookup(".got.plt", 0))
- }
-
- sh = elfshname(".hash")
- sh.type_ = SHT_HASH
- sh.flags = SHF_ALLOC
- sh.entsize = 4
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynsym").shnum)
- shsym(sh, ctxt.Syms.Lookup(".hash", 0))
-
- /* sh and PT_DYNAMIC for .dynamic section */
- sh = elfshname(".dynamic")
-
- sh.type_ = SHT_DYNAMIC
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = 2 * uint64(ctxt.Arch.RegSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynstr").shnum)
- shsym(sh, ctxt.Syms.Lookup(".dynamic", 0))
- ph := newElfPhdr()
- ph.type_ = PT_DYNAMIC
- ph.flags = PF_R + PF_W
- phsh(ph, sh)
-
- /*
- * Thread-local storage segment (really just size).
- */
- tlssize := uint64(0)
- for _, sect := range Segdata.Sections {
- if sect.Name == ".tbss" {
- tlssize = sect.Length
- }
- }
- if tlssize != 0 {
- ph := newElfPhdr()
- ph.type_ = PT_TLS
- ph.flags = PF_R
- ph.memsz = tlssize
- ph.align = uint64(ctxt.Arch.RegSize)
- }
- }
-
- if ctxt.HeadType == objabi.Hlinux {
- ph := newElfPhdr()
- ph.type_ = PT_GNU_STACK
- ph.flags = PF_W + PF_R
- ph.align = uint64(ctxt.Arch.RegSize)
-
- ph = newElfPhdr()
- ph.type_ = PT_PAX_FLAGS
- ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
- ph.align = uint64(ctxt.Arch.RegSize)
- } else if ctxt.HeadType == objabi.Hsolaris {
- ph := newElfPhdr()
- ph.type_ = PT_SUNWSTACK
- ph.flags = PF_W + PF_R
- }
-
-elfobj:
- sh := elfshname(".shstrtab")
- sh.type_ = SHT_STRTAB
- sh.addralign = 1
- shsym(sh, ctxt.Syms.Lookup(".shstrtab", 0))
- eh.shstrndx = uint16(sh.shnum)
-
- // put these sections early in the list
- if !*FlagS {
- elfshname(".symtab")
- elfshname(".strtab")
- }
-
- for _, sect := range Segtext.Sections {
- elfshbits(ctxt.LinkMode, sect)
- }
- for _, sect := range Segrodata.Sections {
- elfshbits(ctxt.LinkMode, sect)
- }
- for _, sect := range Segrelrodata.Sections {
- elfshbits(ctxt.LinkMode, sect)
- }
- for _, sect := range Segdata.Sections {
- elfshbits(ctxt.LinkMode, sect)
- }
- for _, sect := range Segdwarf.Sections {
- elfshbits(ctxt.LinkMode, sect)
- }
-
- if ctxt.LinkMode == LinkExternal {
- for _, sect := range Segtext.Sections {
- elfshreloc(ctxt.Arch, sect)
- }
- for _, sect := range Segrodata.Sections {
- elfshreloc(ctxt.Arch, sect)
- }
- for _, sect := range Segrelrodata.Sections {
- elfshreloc(ctxt.Arch, sect)
- }
- for _, sect := range Segdata.Sections {
- elfshreloc(ctxt.Arch, sect)
- }
- for _, s := range dwarfp {
- if len(s.R) > 0 || s.Type == sym.SDWARFINFO || s.Type == sym.SDWARFLOC {
- elfshreloc(ctxt.Arch, s.Sect)
- }
- }
- // add a .note.GNU-stack section to mark the stack as non-executable
- sh := elfshname(".note.GNU-stack")
-
- sh.type_ = SHT_PROGBITS
- sh.addralign = 1
- sh.flags = 0
- }
-
- if !*FlagS {
- sh := elfshname(".symtab")
- sh.type_ = SHT_SYMTAB
- sh.off = uint64(symo)
- sh.size = uint64(Symsize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.entsize = 8 + 2*uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".strtab").shnum)
- sh.info = uint32(elfglobalsymndx)
-
- sh = elfshname(".strtab")
- sh.type_ = SHT_STRTAB
- sh.off = uint64(symo) + uint64(Symsize)
- sh.size = uint64(len(Elfstrdat))
- sh.addralign = 1
- }
-
- /* Main header */
- eh.ident[EI_MAG0] = '\177'
-
- eh.ident[EI_MAG1] = 'E'
- eh.ident[EI_MAG2] = 'L'
- eh.ident[EI_MAG3] = 'F'
- if ctxt.HeadType == objabi.Hfreebsd {
- eh.ident[EI_OSABI] = ELFOSABI_FREEBSD
- } else if ctxt.HeadType == objabi.Hnetbsd {
- eh.ident[EI_OSABI] = ELFOSABI_NETBSD
- } else if ctxt.HeadType == objabi.Hopenbsd {
- eh.ident[EI_OSABI] = ELFOSABI_OPENBSD
- } else if ctxt.HeadType == objabi.Hdragonfly {
- eh.ident[EI_OSABI] = ELFOSABI_NONE
- }
- if elf64 {
- eh.ident[EI_CLASS] = ELFCLASS64
- } else {
- eh.ident[EI_CLASS] = ELFCLASS32
- }
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- eh.ident[EI_DATA] = ELFDATA2MSB
- } else {
- eh.ident[EI_DATA] = ELFDATA2LSB
- }
- eh.ident[EI_VERSION] = EV_CURRENT
-
- if ctxt.LinkMode == LinkExternal {
- eh.type_ = ET_REL
- } else if ctxt.BuildMode == BuildModePIE {
- eh.type_ = ET_DYN
- } else {
- eh.type_ = ET_EXEC
- }
-
- if ctxt.LinkMode != LinkExternal {
- eh.entry = uint64(Entryvalue(ctxt))
- }
-
- eh.version = EV_CURRENT
-
- if pph != nil {
- pph.filesz = uint64(eh.phnum) * uint64(eh.phentsize)
- pph.memsz = pph.filesz
- }
-
- ctxt.Out.SeekSet(0)
- a := int64(0)
- a += int64(elfwritehdr(ctxt.Out))
- a += int64(elfwritephdrs(ctxt.Out))
- a += int64(elfwriteshdrs(ctxt.Out))
- if !*FlagD {
- a += int64(elfwriteinterp(ctxt.Out))
- }
- if ctxt.LinkMode != LinkExternal {
- if ctxt.HeadType == objabi.Hnetbsd {
- a += int64(elfwritenetbsdsig(ctxt.Out))
- }
- if ctxt.HeadType == objabi.Hopenbsd {
- a += int64(elfwriteopenbsdsig(ctxt.Out))
- }
- if len(buildinfo) > 0 {
- a += int64(elfwritebuildinfo(ctxt.Out))
- }
- if *flagBuildid != "" {
- a += int64(elfwritegobuildid(ctxt.Out))
- }
- }
- if *flagRace && ctxt.HeadType == objabi.Hnetbsd {
- a += int64(elfwritenetbsdpax(ctxt.Out))
- }
-
- if a > elfreserve {
- Errorf(nil, "ELFRESERVE too small: %d > %d with %d text sections", a, elfreserve, numtext)
- }
-}
-
-func elfadddynsym(ctxt *Link, s *sym.Symbol) {
- if elf64 {
- s.Dynid = int32(Nelfsym)
- Nelfsym++
-
- d := ctxt.Syms.Lookup(".dynsym", 0)
-
- name := s.Extname()
- d.AddUint32(ctxt.Arch, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name)))
-
- /* type */
- t := STB_GLOBAL << 4
-
- if s.Attr.CgoExport() && s.Type == sym.STEXT {
- t |= STT_FUNC
- } else {
- t |= STT_OBJECT
- }
- d.AddUint8(uint8(t))
-
- /* reserved */
- d.AddUint8(0)
-
- /* section where symbol is defined */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint16(ctxt.Arch, SHN_UNDEF)
- } else {
- d.AddUint16(ctxt.Arch, 1)
- }
-
- /* value */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint64(ctxt.Arch, 0)
- } else {
- d.AddAddr(ctxt.Arch, s)
- }
-
- /* size of object */
- d.AddUint64(ctxt.Arch, uint64(s.Size))
-
- if ctxt.Arch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib() != "" && !seenlib[s.Dynimplib()] {
- Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(ctxt.Syms.Lookup(".dynstr", 0), s.Dynimplib())))
- }
- } else {
- s.Dynid = int32(Nelfsym)
- Nelfsym++
-
- d := ctxt.Syms.Lookup(".dynsym", 0)
-
- /* name */
- name := s.Extname()
-
- d.AddUint32(ctxt.Arch, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name)))
-
- /* value */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint32(ctxt.Arch, 0)
- } else {
- d.AddAddr(ctxt.Arch, s)
- }
-
- /* size of object */
- d.AddUint32(ctxt.Arch, uint32(s.Size))
-
- /* type */
- t := STB_GLOBAL << 4
-
- // TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
- if ctxt.Arch.Family == sys.I386 && s.Attr.CgoExport() && s.Type == sym.STEXT {
- t |= STT_FUNC
- } else if ctxt.Arch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type == sym.STEXT {
- t |= STT_FUNC
- } else {
- t |= STT_OBJECT
- }
- d.AddUint8(uint8(t))
- d.AddUint8(0)
-
- /* shndx */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint16(ctxt.Arch, SHN_UNDEF)
- } else {
- d.AddUint16(ctxt.Arch, 1)
- }
- }
-}
-
-func ELF32_R_SYM(info uint32) uint32 {
- return info >> 8
-}
-
-func ELF32_R_TYPE(info uint32) uint32 {
- return uint32(uint8(info))
-}
-
-func ELF32_R_INFO(sym uint32, type_ uint32) uint32 {
- return sym<<8 | type_
-}
-
-func ELF32_ST_BIND(info uint8) uint8 {
- return info >> 4
-}
-
-func ELF32_ST_TYPE(info uint8) uint8 {
- return info & 0xf
-}
-
-func ELF32_ST_INFO(bind uint8, type_ uint8) uint8 {
- return bind<<4 | type_&0xf
-}
-
-func ELF32_ST_VISIBILITY(oth uint8) uint8 {
- return oth & 3
-}
-
-func ELF64_R_SYM(info uint64) uint32 {
- return uint32(info >> 32)
-}
-
-func ELF64_R_TYPE(info uint64) uint32 {
- return uint32(info)
-}
-
-func ELF64_R_INFO(sym uint32, type_ uint32) uint64 {
- return uint64(sym)<<32 | uint64(type_)
-}
-
-func ELF64_ST_BIND(info uint8) uint8 {
- return info >> 4
-}
-
-func ELF64_ST_TYPE(info uint8) uint8 {
- return info & 0xf
-}
-
-func ELF64_ST_INFO(bind uint8, type_ uint8) uint8 {
- return bind<<4 | type_&0xf
-}
-
-func ELF64_ST_VISIBILITY(oth uint8) uint8 {
- return oth & 3
-}
+++ /dev/null
-// 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)
- }
-}
+++ /dev/null
-// 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")
-}
+++ /dev/null
-// 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()
- }
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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 ld
-
-import (
- "bufio"
- "bytes"
- "cmd/internal/bio"
- "cmd/internal/obj"
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/loadelf"
- "cmd/oldlink/internal/loader"
- "cmd/oldlink/internal/loadmacho"
- "cmd/oldlink/internal/loadpe"
- "cmd/oldlink/internal/loadxcoff"
- "cmd/oldlink/internal/objfile"
- "cmd/oldlink/internal/sym"
- "crypto/sha1"
- "debug/elf"
- "debug/macho"
- "encoding/base64"
- "encoding/binary"
- "encoding/hex"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "sort"
- "strings"
- "sync"
-)
-
-// Data layout and relocation.
-
-// Derived from 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.
-
-type Arch struct {
- Funcalign int
- Maxalign int
- Minalign int
- Dwarfregsp int
- Dwarfreglr int
- Androiddynld string
- Linuxdynld string
- Freebsddynld string
- Netbsddynld string
- Openbsddynld string
- Dragonflydynld string
- Solarisdynld string
- Adddynrel func(*Link, *sym.Symbol, *sym.Reloc) bool
- Archinit func(*Link)
- // Archreloc is an arch-specific hook that assists in
- // relocation processing (invoked by 'relocsym'); it handles
- // target-specific relocation tasks. Here "rel" is the current
- // relocation being examined, "sym" is the symbol containing the
- // chunk of data to which the relocation applies, and "off" is the
- // contents of the to-be-relocated data item (from sym.P). Return
- // value is the appropriately relocated value (to be written back
- // to the same spot in sym.P) and a boolean indicating
- // success/failure (a failing value indicates a fatal error).
- Archreloc func(link *Link, rel *sym.Reloc, sym *sym.Symbol,
- offset int64) (relocatedOffset int64, success bool)
- // Archrelocvariant is a second arch-specific hook used for
- // relocation processing; it handles relocations where r.Type is
- // insufficient to describe the relocation (r.Variant !=
- // sym.RV_NONE). Here "rel" is the relocation being applied, "sym"
- // is the symbol containing the chunk of data to which the
- // relocation applies, and "off" is the contents of the
- // to-be-relocated data item (from sym.P). Return is an updated
- // offset value.
- Archrelocvariant func(link *Link, rel *sym.Reloc, sym *sym.Symbol,
- offset int64) (relocatedOffset int64)
- Trampoline func(*Link, *sym.Reloc, *sym.Symbol)
-
- // Asmb and Asmb2 are arch-specific routines that write the output
- // file. Typically, Asmb writes most of the content (sections and
- // segments), for which we have computed the size and offset. Asmb2
- // writes the rest.
- Asmb func(*Link)
- Asmb2 func(*Link)
-
- Elfreloc1 func(*Link, *sym.Reloc, int64) bool
- Elfsetupplt func(*Link)
- Gentext func(*Link)
- Machoreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
- PEreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
- Xcoffreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
-
- // TLSIEtoLE converts a TLS Initial Executable relocation to
- // a TLS Local Executable relocation.
- //
- // This is possible when a TLS IE relocation refers to a local
- // symbol in an executable, which is typical when internally
- // linking PIE binaries.
- TLSIEtoLE func(s *sym.Symbol, off, size int)
-
- // optional override for assignAddress
- AssignAddress func(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint64, isTramp bool) (*sym.Section, int, uint64)
-}
-
-var (
- thearch Arch
- Lcsize int32
- rpath Rpath
- Spsize int32
- Symsize int32
-)
-
-const (
- MINFUNC = 16 // minimum size for a function
-)
-
-// DynlinkingGo reports whether we are producing Go code that can live
-// in separate shared libraries linked together at runtime.
-func (ctxt *Link) DynlinkingGo() bool {
- if !ctxt.Loaded {
- panic("DynlinkingGo called before all symbols loaded")
- }
- return ctxt.BuildMode == BuildModeShared || ctxt.linkShared || ctxt.BuildMode == BuildModePlugin || ctxt.canUsePlugins
-}
-
-// CanUsePlugins reports whether a plugins can be used
-func (ctxt *Link) CanUsePlugins() bool {
- if !ctxt.Loaded {
- panic("CanUsePlugins called before all symbols loaded")
- }
- return ctxt.canUsePlugins
-}
-
-// UseRelro reports whether to make use of "read only relocations" aka
-// relro.
-func (ctxt *Link) UseRelro() bool {
- switch ctxt.BuildMode {
- case BuildModeCArchive, BuildModeCShared, BuildModeShared, BuildModePIE, BuildModePlugin:
- return ctxt.IsELF || ctxt.HeadType == objabi.Haix
- default:
- return ctxt.linkShared || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal)
- }
-}
-
-var (
- dynexp []*sym.Symbol
- dynlib []string
- ldflag []string
- havedynamic int
- Funcalign int
- iscgo bool
- elfglobalsymndx int
- interpreter string
-
- debug_s bool // backup old value of debug['s']
- HEADR int32
-
- nerrors int
- liveness int64
-
- // See -strictdups command line flag.
- checkStrictDups int // 0=off 1=warning 2=error
- strictDupMsgCount int
-)
-
-var (
- Segtext sym.Segment
- Segrodata sym.Segment
- Segrelrodata sym.Segment
- Segdata sym.Segment
- Segdwarf sym.Segment
-)
-
-const pkgdef = "__.PKGDEF"
-
-var (
- // Set if we see an object compiled by the host compiler that is not
- // from a package that is known to support internal linking mode.
- externalobj = false
- theline string
-)
-
-func Lflag(ctxt *Link, arg string) {
- ctxt.Libdir = append(ctxt.Libdir, arg)
-}
-
-/*
- * Unix doesn't like it when we write to a running (or, sometimes,
- * recently run) binary, so remove the output file before writing it.
- * On Windows 7, remove() can force a subsequent create() to fail.
- * S_ISREG() does not exist on Plan 9.
- */
-func mayberemoveoutfile() {
- if fi, err := os.Lstat(*flagOutfile); err == nil && !fi.Mode().IsRegular() {
- return
- }
- os.Remove(*flagOutfile)
-}
-
-func libinit(ctxt *Link) {
- Funcalign = thearch.Funcalign
-
- // add goroot to the end of the libdir list.
- suffix := ""
-
- suffixsep := ""
- if *flagInstallSuffix != "" {
- suffixsep = "_"
- suffix = *flagInstallSuffix
- } else if *flagRace {
- suffixsep = "_"
- suffix = "race"
- } else if *flagMsan {
- suffixsep = "_"
- suffix = "msan"
- }
-
- Lflag(ctxt, filepath.Join(objabi.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", objabi.GOOS, objabi.GOARCH, suffixsep, suffix)))
-
- mayberemoveoutfile()
- f, err := os.OpenFile(*flagOutfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
- if err != nil {
- Exitf("cannot create %s: %v", *flagOutfile, err)
- }
-
- ctxt.Out.w = bufio.NewWriter(f)
- ctxt.Out.f = f
-
- if *flagEntrySymbol == "" {
- switch ctxt.BuildMode {
- case BuildModeCShared, BuildModeCArchive:
- *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", objabi.GOARCH, objabi.GOOS)
- case BuildModeExe, BuildModePIE:
- *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", objabi.GOARCH, objabi.GOOS)
- case BuildModeShared, BuildModePlugin:
- // No *flagEntrySymbol for -buildmode=shared and plugin
- default:
- Errorf(nil, "unknown *flagEntrySymbol for buildmode %v", ctxt.BuildMode)
- }
- }
-}
-
-func exitIfErrors() {
- if nerrors != 0 || checkStrictDups > 1 && strictDupMsgCount > 0 {
- mayberemoveoutfile()
- Exit(2)
- }
-
-}
-
-func errorexit() {
- exitIfErrors()
- Exit(0)
-}
-
-func loadinternal(ctxt *Link, name string) *sym.Library {
- if ctxt.linkShared && ctxt.PackageShlib != nil {
- if shlib := ctxt.PackageShlib[name]; shlib != "" {
- return addlibpath(ctxt, "internal", "internal", "", name, shlib)
- }
- }
- if ctxt.PackageFile != nil {
- if pname := ctxt.PackageFile[name]; pname != "" {
- return addlibpath(ctxt, "internal", "internal", pname, name, "")
- }
- ctxt.Logf("loadinternal: cannot find %s\n", name)
- return nil
- }
-
- for _, libdir := range ctxt.Libdir {
- if ctxt.linkShared {
- shlibname := filepath.Join(libdir, name+".shlibname")
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
- }
- if _, err := os.Stat(shlibname); err == nil {
- return addlibpath(ctxt, "internal", "internal", "", name, shlibname)
- }
- }
- pname := filepath.Join(libdir, name+".a")
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("searching for %s.a in %s\n", name, pname)
- }
- if _, err := os.Stat(pname); err == nil {
- return addlibpath(ctxt, "internal", "internal", pname, name, "")
- }
- }
-
- ctxt.Logf("warning: unable to find %s.a\n", name)
- return nil
-}
-
-// extld returns the current external linker.
-func (ctxt *Link) extld() string {
- if *flagExtld == "" {
- *flagExtld = "gcc"
- }
- return *flagExtld
-}
-
-// findLibPathCmd uses cmd command to find gcc library libname.
-// It returns library full path if found, or "none" if not found.
-func (ctxt *Link) findLibPathCmd(cmd, libname string) string {
- extld := ctxt.extld()
- args := hostlinkArchArgs(ctxt.Arch)
- args = append(args, cmd)
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%s %v\n", extld, args)
- }
- out, err := exec.Command(extld, args...).Output()
- if err != nil {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("not using a %s file because compiler failed\n%v\n%s\n", libname, err, out)
- }
- return "none"
- }
- return strings.TrimSpace(string(out))
-}
-
-// findLibPath searches for library libname.
-// It returns library full path if found, or "none" if not found.
-func (ctxt *Link) findLibPath(libname string) string {
- return ctxt.findLibPathCmd("--print-file-name="+libname, libname)
-}
-
-func (ctxt *Link) loadlib() {
- if *flagNewobj {
- var flags uint32
- switch *FlagStrictDups {
- case 0:
- // nothing to do
- case 1, 2:
- flags = loader.FlagStrictDups
- default:
- log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
- }
- ctxt.loader = loader.NewLoader(flags)
- }
-
- ctxt.cgo_export_static = make(map[string]bool)
- ctxt.cgo_export_dynamic = make(map[string]bool)
-
- // ctxt.Library grows during the loop, so not a range loop.
- i := 0
- for ; i < len(ctxt.Library); i++ {
- lib := ctxt.Library[i]
- if lib.Shlib == "" {
- if ctxt.Debugvlog > 1 {
- ctxt.Logf("autolib: %s (from %s)\n", lib.File, lib.Objref)
- }
- loadobjfile(ctxt, lib)
- }
- }
-
- // load internal packages, if not already
- if *flagRace {
- loadinternal(ctxt, "runtime/race")
- }
- if *flagMsan {
- loadinternal(ctxt, "runtime/msan")
- }
- loadinternal(ctxt, "runtime")
- for ; i < len(ctxt.Library); i++ {
- lib := ctxt.Library[i]
- if lib.Shlib == "" {
- loadobjfile(ctxt, lib)
- }
- }
-
- if *flagNewobj {
- iscgo = ctxt.loader.Lookup("x_cgo_init", 0) != 0
- ctxt.canUsePlugins = ctxt.loader.Lookup("plugin.Open", sym.SymVerABIInternal) != 0
- } else {
- iscgo = ctxt.Syms.ROLookup("x_cgo_init", 0) != nil
- ctxt.canUsePlugins = ctxt.Syms.ROLookup("plugin.Open", sym.SymVerABIInternal) != nil
- }
-
- // We now have enough information to determine the link mode.
- determineLinkMode(ctxt)
-
- if ctxt.LinkMode == LinkExternal && !iscgo && ctxt.LibraryByPkg["runtime/cgo"] == nil && !(objabi.GOOS == "darwin" && ctxt.BuildMode != BuildModePlugin && ctxt.Arch.Family == sys.AMD64) {
- // This indicates a user requested -linkmode=external.
- // The startup code uses an import of runtime/cgo to decide
- // whether to initialize the TLS. So give it one. This could
- // be handled differently but it's an unusual case.
- if lib := loadinternal(ctxt, "runtime/cgo"); lib != nil {
- if lib.Shlib != "" {
- ldshlibsyms(ctxt, lib.Shlib)
- } else {
- if ctxt.BuildMode == BuildModeShared || ctxt.linkShared {
- Exitf("cannot implicitly include runtime/cgo in a shared library")
- }
- loadobjfile(ctxt, lib)
- }
- }
- }
-
- for _, lib := range ctxt.Library {
- if lib.Shlib != "" {
- if ctxt.Debugvlog > 1 {
- ctxt.Logf("autolib: %s (from %s)\n", lib.Shlib, lib.Objref)
- }
- ldshlibsyms(ctxt, lib.Shlib)
- }
- }
-
- if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
- if *flagNewobj {
- // In newobj mode, we typically create sym.Symbols later therefore
- // also set cgo attributes later. However, for internal cgo linking,
- // the host object loaders still work with sym.Symbols (for now),
- // and they need cgo attributes set to work properly. So process
- // them now.
- lookup := func(name string, ver int) *sym.Symbol { return ctxt.loader.LookupOrCreate(name, ver, ctxt.Syms) }
- for _, d := range ctxt.cgodata {
- setCgoAttr(ctxt, lookup, d.file, d.pkg, d.directives)
- }
- ctxt.cgodata = nil
- }
-
- // Drop all the cgo_import_static declarations.
- // Turns out we won't be needing them.
- for _, s := range ctxt.Syms.Allsym {
- if s.Type == sym.SHOSTOBJ {
- // If a symbol was marked both
- // cgo_import_static and cgo_import_dynamic,
- // then we want to make it cgo_import_dynamic
- // now.
- if s.Extname() != "" && s.Dynimplib() != "" && !s.Attr.CgoExport() {
- s.Type = sym.SDYNIMPORT
- } else {
- s.Type = 0
- }
- }
- }
- }
-
- // Conditionally load host objects, or setup for external linking.
- hostobjs(ctxt)
- hostlinksetup(ctxt)
-
- if *flagNewobj {
- // Add references of externally defined symbols.
- ctxt.loader.LoadRefs(ctxt.Arch, ctxt.Syms)
- }
-
- // Now that we know the link mode, set the dynexp list.
- if !*flagNewobj { // set this later in newobj mode
- setupdynexp(ctxt)
- }
-
- if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
- // If we have any undefined symbols in external
- // objects, try to read them from the libgcc file.
- any := false
- 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 && r.Sym.Name != ".got" {
- any = true
- break
- }
- }
- }
- if any {
- if *flagLibGCC == "" {
- *flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
- }
- if runtime.GOOS == "openbsd" && *flagLibGCC == "libgcc.a" {
- // On OpenBSD `clang --print-libgcc-file-name` returns "libgcc.a".
- // In this case we fail to load libgcc.a and can encounter link
- // errors - see if we can find libcompiler_rt.a instead.
- *flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
- }
- if *flagLibGCC != "none" {
- hostArchive(ctxt, *flagLibGCC)
- }
- if ctxt.HeadType == objabi.Hwindows {
- if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
- hostArchive(ctxt, p)
- }
- if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
- hostArchive(ctxt, p)
- }
- // Link libmsvcrt.a to resolve '__acrt_iob_func' symbol
- // (see https://golang.org/issue/23649 for details).
- if p := ctxt.findLibPath("libmsvcrt.a"); p != "none" {
- hostArchive(ctxt, p)
- }
- // TODO: maybe do something similar to peimporteddlls to collect all lib names
- // and try link them all to final exe just like libmingwex.a and libmingw32.a:
- /*
- for:
- #cgo windows LDFLAGS: -lmsvcrt -lm
- import:
- libmsvcrt.a libm.a
- */
- }
- }
- }
-
- // We've loaded all the code now.
- ctxt.Loaded = true
-
- importcycles()
-
- if *flagNewobj {
- strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
- }
-}
-
-// Set up dynexp list.
-func setupdynexp(ctxt *Link) {
- dynexpMap := ctxt.cgo_export_dynamic
- if ctxt.LinkMode == LinkExternal {
- dynexpMap = ctxt.cgo_export_static
- }
- dynexp = make([]*sym.Symbol, 0, len(dynexpMap))
- for exp := range dynexpMap {
- s := ctxt.Syms.Lookup(exp, 0)
- dynexp = append(dynexp, s)
- }
- sort.Sort(byName(dynexp))
-
- // Resolve ABI aliases in the list of cgo-exported functions.
- // This is necessary because we load the ABI0 symbol for all
- // cgo exports.
- for i, s := range dynexp {
- if s.Type != sym.SABIALIAS {
- continue
- }
- t := resolveABIAlias(s)
- t.Attr |= s.Attr
- t.SetExtname(s.Extname())
- dynexp[i] = t
- }
-
- ctxt.cgo_export_static = nil
- ctxt.cgo_export_dynamic = nil
-}
-
-// Set up flags and special symbols depending on the platform build mode.
-func (ctxt *Link) linksetup() {
- switch ctxt.BuildMode {
- case BuildModeCShared, BuildModePlugin:
- s := ctxt.Syms.Lookup("runtime.islibrary", 0)
- s.Type = sym.SNOPTRDATA
- s.Attr |= sym.AttrDuplicateOK
- s.AddUint8(1)
- case BuildModeCArchive:
- s := ctxt.Syms.Lookup("runtime.isarchive", 0)
- s.Type = sym.SNOPTRDATA
- s.Attr |= sym.AttrDuplicateOK
- s.AddUint8(1)
- }
-
- // Recalculate pe parameters now that we have ctxt.LinkMode set.
- if ctxt.HeadType == objabi.Hwindows {
- Peinit(ctxt)
- }
-
- if ctxt.HeadType == objabi.Hdarwin && ctxt.LinkMode == LinkExternal {
- *FlagTextAddr = 0
- }
-
- // If there are no dynamic libraries needed, gcc disables dynamic linking.
- // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
- // assumes that a dynamic binary always refers to at least one dynamic library.
- // Rather than be a source of test cases for glibc, disable dynamic linking
- // the same way that gcc would.
- //
- // Exception: on OS X, programs such as Shark only work with dynamic
- // binaries, so leave it enabled on OS X (Mach-O) binaries.
- // Also leave it enabled on Solaris which doesn't support
- // statically linked binaries.
- if ctxt.BuildMode == BuildModeExe {
- if havedynamic == 0 && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hsolaris {
- *FlagD = true
- }
- }
-
- if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && objabi.GOOS != "aix" {
- toc := ctxt.Syms.Lookup(".TOC.", 0)
- toc.Type = sym.SDYNIMPORT
- }
-
- // The Android Q linker started to complain about underalignment of the our TLS
- // section. We don't actually use the section on android, so dont't
- // generate it.
- if objabi.GOOS != "android" {
- tlsg := ctxt.Syms.Lookup("runtime.tlsg", 0)
-
- // runtime.tlsg is used for external linking on platforms that do not define
- // a variable to hold g in assembly (currently only intel).
- if tlsg.Type == 0 {
- tlsg.Type = sym.STLSBSS
- tlsg.Size = int64(ctxt.Arch.PtrSize)
- } else if tlsg.Type != sym.SDYNIMPORT {
- Errorf(nil, "runtime declared tlsg variable %v", tlsg.Type)
- }
- tlsg.Attr |= sym.AttrReachable
- ctxt.Tlsg = tlsg
- }
-
- var moduledata *sym.Symbol
- if ctxt.BuildMode == BuildModePlugin {
- moduledata = ctxt.Syms.Lookup("local.pluginmoduledata", 0)
- moduledata.Attr |= sym.AttrLocal
- } else {
- moduledata = ctxt.Syms.Lookup("runtime.firstmoduledata", 0)
- }
- if moduledata.Type != 0 && moduledata.Type != sym.SDYNIMPORT {
- // If the module (toolchain-speak for "executable or shared
- // library") we are linking contains the runtime package, it
- // will define the runtime.firstmoduledata symbol and we
- // truncate it back to 0 bytes so we can define its entire
- // contents in symtab.go:symtab().
- moduledata.Size = 0
-
- // In addition, on ARM, the runtime depends on the linker
- // recording the value of GOARM.
- if ctxt.Arch.Family == sys.ARM {
- s := ctxt.Syms.Lookup("runtime.goarm", 0)
- s.Type = sym.SDATA
- s.Size = 0
- s.AddUint8(uint8(objabi.GOARM))
- }
-
- if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
- s := ctxt.Syms.Lookup("runtime.framepointer_enabled", 0)
- s.Type = sym.SDATA
- s.Size = 0
- s.AddUint8(1)
- }
- } else {
- // If OTOH the module does not contain the runtime package,
- // create a local symbol for the moduledata.
- moduledata = ctxt.Syms.Lookup("local.moduledata", 0)
- moduledata.Attr |= sym.AttrLocal
- }
- // In all cases way we mark the moduledata as noptrdata to hide it from
- // the GC.
- moduledata.Type = sym.SNOPTRDATA
- moduledata.Attr |= sym.AttrReachable
- ctxt.Moduledata = moduledata
-
- // If package versioning is required, generate a hash of the
- // packages used in the link.
- if ctxt.BuildMode == BuildModeShared || ctxt.BuildMode == BuildModePlugin || ctxt.CanUsePlugins() {
- for _, lib := range ctxt.Library {
- if lib.Shlib == "" {
- genhash(ctxt, lib)
- }
- }
- }
-
- if ctxt.Arch == sys.Arch386 && ctxt.HeadType != objabi.Hwindows {
- if (ctxt.BuildMode == BuildModeCArchive && ctxt.IsELF) || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE || ctxt.DynlinkingGo() {
- got := ctxt.Syms.Lookup("_GLOBAL_OFFSET_TABLE_", 0)
- got.Type = sym.SDYNIMPORT
- got.Attr |= sym.AttrReachable
- }
- }
-}
-
-// mangleTypeSym shortens the names of symbols that represent Go types
-// if they are visible in the symbol table.
-//
-// As the names of these symbols are derived from the string of
-// the type, they can run to many kilobytes long. So we shorten
-// them using a SHA-1 when the name appears in the final binary.
-// This also removes characters that upset external linkers.
-//
-// These are the symbols that begin with the prefix 'type.' and
-// contain run-time type information used by the runtime and reflect
-// packages. All Go binaries contain these symbols, but only
-// those programs loaded dynamically in multiple parts need these
-// symbols to have entries in the symbol table.
-func (ctxt *Link) mangleTypeSym() {
- if ctxt.BuildMode != BuildModeShared && !ctxt.linkShared && ctxt.BuildMode != BuildModePlugin && !ctxt.CanUsePlugins() {
- return
- }
-
- for _, s := range ctxt.Syms.Allsym {
- newName := typeSymbolMangle(s.Name)
- if newName != s.Name {
- ctxt.Syms.Rename(s.Name, newName, int(s.Version), ctxt.Reachparent)
- }
- }
-}
-
-// typeSymbolMangle mangles the given symbol name into something shorter.
-//
-// Keep the type.. prefix, which parts of the linker (like the
-// DWARF generator) know means the symbol is not decodable.
-// Leave type.runtime. symbols alone, because other parts of
-// the linker manipulates them.
-func typeSymbolMangle(name string) string {
- if !strings.HasPrefix(name, "type.") {
- return name
- }
- if strings.HasPrefix(name, "type.runtime.") {
- return name
- }
- if len(name) <= 14 && !strings.Contains(name, "@") { // Issue 19529
- return name
- }
- hash := sha1.Sum([]byte(name))
- prefix := "type."
- if name[5] == '.' {
- prefix = "type.."
- }
- return prefix + base64.StdEncoding.EncodeToString(hash[:6])
-}
-
-/*
- * look for the next file in an archive.
- * adapted from libmach.
- */
-func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 {
- if off&1 != 0 {
- off++
- }
- bp.MustSeek(off, 0)
- var buf [SAR_HDR]byte
- if n, err := io.ReadFull(bp, buf[:]); err != nil {
- if n == 0 && err != io.EOF {
- return -1
- }
- return 0
- }
-
- a.name = artrim(buf[0:16])
- a.date = artrim(buf[16:28])
- a.uid = artrim(buf[28:34])
- a.gid = artrim(buf[34:40])
- a.mode = artrim(buf[40:48])
- a.size = artrim(buf[48:58])
- a.fmag = artrim(buf[58:60])
-
- arsize := atolwhex(a.size)
- if arsize&1 != 0 {
- arsize++
- }
- return arsize + SAR_HDR
-}
-
-func genhash(ctxt *Link, lib *sym.Library) {
- f, err := bio.Open(lib.File)
- if err != nil {
- Errorf(nil, "cannot open file %s for hash generation: %v", lib.File, err)
- return
- }
- defer f.Close()
-
- var magbuf [len(ARMAG)]byte
- if _, err := io.ReadFull(f, magbuf[:]); err != nil {
- Exitf("file %s too short", lib.File)
- }
-
- if string(magbuf[:]) != ARMAG {
- Exitf("%s is not an archive file", lib.File)
- }
-
- var arhdr ArHdr
- l := nextar(f, f.Offset(), &arhdr)
- if l <= 0 {
- Errorf(nil, "%s: short read on archive file symbol header", lib.File)
- return
- }
- if arhdr.name != pkgdef {
- Errorf(nil, "%s: missing package data entry", lib.File)
- return
- }
-
- h := sha1.New()
-
- // To compute the hash of a package, we hash the first line of
- // __.PKGDEF (which contains the toolchain version and any
- // GOEXPERIMENT flags) and the export data (which is between
- // the first two occurrences of "\n$$").
-
- pkgDefBytes := make([]byte, atolwhex(arhdr.size))
- _, err = io.ReadFull(f, pkgDefBytes)
- if err != nil {
- Errorf(nil, "%s: error reading package data: %v", lib.File, err)
- return
- }
- firstEOL := bytes.IndexByte(pkgDefBytes, '\n')
- if firstEOL < 0 {
- Errorf(nil, "cannot parse package data of %s for hash generation, no newline found", lib.File)
- return
- }
- firstDoubleDollar := bytes.Index(pkgDefBytes, []byte("\n$$"))
- if firstDoubleDollar < 0 {
- Errorf(nil, "cannot parse package data of %s for hash generation, no \\n$$ found", lib.File)
- return
- }
- secondDoubleDollar := bytes.Index(pkgDefBytes[firstDoubleDollar+1:], []byte("\n$$"))
- if secondDoubleDollar < 0 {
- Errorf(nil, "cannot parse package data of %s for hash generation, only one \\n$$ found", lib.File)
- return
- }
- h.Write(pkgDefBytes[0:firstEOL])
- h.Write(pkgDefBytes[firstDoubleDollar : firstDoubleDollar+secondDoubleDollar])
- lib.Hash = hex.EncodeToString(h.Sum(nil))
-}
-
-func loadobjfile(ctxt *Link, lib *sym.Library) {
- pkg := objabi.PathToPrefix(lib.Pkg)
-
- if ctxt.Debugvlog > 1 {
- ctxt.Logf("ldobj: %s (%s)\n", lib.File, pkg)
- }
- f, err := bio.Open(lib.File)
- if err != nil {
- Exitf("cannot open file %s: %v", lib.File, err)
- }
- defer f.Close()
- defer func() {
- if pkg == "main" && !lib.Main {
- Exitf("%s: not package main", lib.File)
- }
-
- // Ideally, we'd check that *all* object files within
- // the archive were marked safe, but here we settle
- // for *any*.
- //
- // Historically, cmd/link only checked the __.PKGDEF
- // file, which in turn came from the first object
- // file, typically produced by cmd/compile. The
- // remaining object files are normally produced by
- // cmd/asm, which doesn't support marking files as
- // safe anyway. So at least in practice, this matches
- // how safe mode has always worked.
- if *flagU && !lib.Safe {
- Exitf("%s: load of unsafe package %s", lib.File, pkg)
- }
- }()
-
- for i := 0; i < len(ARMAG); i++ {
- if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
- continue
- }
-
- /* load it as a regular file */
- l := f.MustSeek(0, 2)
- f.MustSeek(0, 0)
- ldobj(ctxt, f, lib, l, lib.File, lib.File)
- return
- }
-
- /*
- * load all the object files from the archive now.
- * this gives us sequential file access and keeps us
- * from needing to come back later to pick up more
- * objects. it breaks the usual C archive model, but
- * this is Go, not C. the common case in Go is that
- * we need to load all the objects, and then we throw away
- * the individual symbols that are unused.
- *
- * loading every object will also make it possible to
- * load foreign objects not referenced by __.PKGDEF.
- */
- var arhdr ArHdr
- off := f.Offset()
- for {
- l := nextar(f, off, &arhdr)
- if l == 0 {
- break
- }
- if l < 0 {
- Exitf("%s: malformed archive", lib.File)
- }
- off += l
-
- // __.PKGDEF isn't a real Go object file, and it's
- // absent in -linkobj builds anyway. Skipping it
- // ensures consistency between -linkobj and normal
- // build modes.
- if arhdr.name == pkgdef {
- continue
- }
-
- // Skip other special (non-object-file) sections that
- // build tools may have added. Such sections must have
- // short names so that the suffix is not truncated.
- if len(arhdr.name) < 16 {
- if ext := filepath.Ext(arhdr.name); ext != ".o" && ext != ".syso" {
- continue
- }
- }
-
- pname := fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
- l = atolwhex(arhdr.size)
- ldobj(ctxt, f, lib, l, pname, lib.File)
- }
-}
-
-type Hostobj struct {
- ld func(*Link, *bio.Reader, string, int64, string)
- pkg string
- pn string
- file string
- off int64
- length int64
-}
-
-var hostobj []Hostobj
-
-// These packages can use internal linking mode.
-// Others trigger external mode.
-var internalpkg = []string{
- "crypto/x509",
- "net",
- "os/user",
- "runtime/cgo",
- "runtime/race",
- "runtime/msan",
-}
-
-func ldhostobj(ld func(*Link, *bio.Reader, string, int64, string), headType objabi.HeadType, f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
- isinternal := false
- for _, intpkg := range internalpkg {
- if pkg == intpkg {
- isinternal = true
- break
- }
- }
-
- // DragonFly declares errno with __thread, which results in a symbol
- // type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
- // currently know how to handle TLS relocations, hence we have to
- // force external linking for any libraries that link in code that
- // uses errno. This can be removed if the Go linker ever supports
- // these relocation types.
- if headType == objabi.Hdragonfly {
- if pkg == "net" || pkg == "os/user" {
- isinternal = false
- }
- }
-
- if !isinternal {
- externalobj = true
- }
-
- hostobj = append(hostobj, Hostobj{})
- h := &hostobj[len(hostobj)-1]
- h.ld = ld
- h.pkg = pkg
- h.pn = pn
- h.file = file
- h.off = f.Offset()
- h.length = length
- return h
-}
-
-func hostobjs(ctxt *Link) {
- if ctxt.LinkMode != LinkInternal {
- return
- }
- var h *Hostobj
-
- for i := 0; i < len(hostobj); i++ {
- h = &hostobj[i]
- f, err := bio.Open(h.file)
- if err != nil {
- Exitf("cannot reopen %s: %v", h.pn, err)
- }
-
- f.MustSeek(h.off, 0)
- h.ld(ctxt, f, h.pkg, h.length, h.pn)
- f.Close()
- }
-}
-
-func hostlinksetup(ctxt *Link) {
- if ctxt.LinkMode != LinkExternal {
- return
- }
-
- // For external link, record that we need to tell the external linker -s,
- // and turn off -s internally: the external linker needs the symbol
- // information for its final link.
- debug_s = *FlagS
- *FlagS = false
-
- // create temporary directory and arrange cleanup
- if *flagTmpdir == "" {
- dir, err := ioutil.TempDir("", "go-link-")
- if err != nil {
- log.Fatal(err)
- }
- *flagTmpdir = dir
- ownTmpDir = true
- AtExit(func() {
- ctxt.Out.f.Close()
- os.RemoveAll(*flagTmpdir)
- })
- }
-
- // change our output to temporary object file
- ctxt.Out.f.Close()
- mayberemoveoutfile()
-
- p := filepath.Join(*flagTmpdir, "go.o")
- var err error
- f, err := os.OpenFile(p, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
- if err != nil {
- Exitf("cannot create %s: %v", p, err)
- }
-
- ctxt.Out.w = bufio.NewWriter(f)
- ctxt.Out.f = f
- ctxt.Out.off = 0
-}
-
-// hostobjCopy creates a copy of the object files in hostobj in a
-// temporary directory.
-func hostobjCopy() (paths []string) {
- var wg sync.WaitGroup
- sema := make(chan struct{}, runtime.NumCPU()) // limit open file descriptors
- for i, h := range hostobj {
- h := h
- dst := filepath.Join(*flagTmpdir, fmt.Sprintf("%06d.o", i))
- paths = append(paths, dst)
-
- wg.Add(1)
- go func() {
- sema <- struct{}{}
- defer func() {
- <-sema
- wg.Done()
- }()
- f, err := os.Open(h.file)
- if err != nil {
- Exitf("cannot reopen %s: %v", h.pn, err)
- }
- defer f.Close()
- if _, err := f.Seek(h.off, 0); err != nil {
- Exitf("cannot seek %s: %v", h.pn, err)
- }
-
- w, err := os.Create(dst)
- if err != nil {
- Exitf("cannot create %s: %v", dst, err)
- }
- if _, err := io.CopyN(w, f, h.length); err != nil {
- Exitf("cannot write %s: %v", dst, err)
- }
- if err := w.Close(); err != nil {
- Exitf("cannot close %s: %v", dst, err)
- }
- }()
- }
- wg.Wait()
- return paths
-}
-
-// writeGDBLinkerScript creates gcc linker script file in temp
-// directory. writeGDBLinkerScript returns created file path.
-// The script is used to work around gcc bug
-// (see https://golang.org/issue/20183 for details).
-func writeGDBLinkerScript() string {
- name := "fix_debug_gdb_scripts.ld"
- path := filepath.Join(*flagTmpdir, name)
- src := `SECTIONS
-{
- .debug_gdb_scripts BLOCK(__section_alignment__) (NOLOAD) :
- {
- *(.debug_gdb_scripts)
- }
-}
-INSERT AFTER .debug_types;
-`
- err := ioutil.WriteFile(path, []byte(src), 0666)
- if err != nil {
- Errorf(nil, "WriteFile %s failed: %v", name, err)
- }
- return path
-}
-
-// archive builds a .a archive from the hostobj object files.
-func (ctxt *Link) archive() {
- if ctxt.BuildMode != BuildModeCArchive {
- return
- }
-
- exitIfErrors()
-
- if *flagExtar == "" {
- *flagExtar = "ar"
- }
-
- mayberemoveoutfile()
-
- // Force the buffer to flush here so that external
- // tools will see a complete file.
- ctxt.Out.Flush()
- if err := ctxt.Out.f.Close(); err != nil {
- Exitf("close: %v", err)
- }
- ctxt.Out.f = nil
-
- argv := []string{*flagExtar, "-q", "-c", "-s"}
- if ctxt.HeadType == objabi.Haix {
- argv = append(argv, "-X64")
- }
- argv = append(argv, *flagOutfile)
- argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
- argv = append(argv, hostobjCopy()...)
-
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("archive: %s\n", strings.Join(argv, " "))
- }
-
- // If supported, use syscall.Exec() to invoke the archive command,
- // which should be the final remaining step needed for the link.
- // This will reduce peak RSS for the link (and speed up linking of
- // large applications), since when the archive command runs we
- // won't be holding onto all of the linker's live memory.
- if syscallExecSupported && !ownTmpDir {
- runAtExitFuncs()
- ctxt.execArchive(argv)
- panic("should not get here")
- }
-
- // Otherwise invoke 'ar' in the usual way (fork + exec).
- if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
- Exitf("running %s failed: %v\n%s", argv[0], err, out)
- }
-}
-
-func (ctxt *Link) hostlink() {
- if ctxt.LinkMode != LinkExternal || nerrors > 0 {
- return
- }
- if ctxt.BuildMode == BuildModeCArchive {
- return
- }
-
- var argv []string
- argv = append(argv, ctxt.extld())
- argv = append(argv, hostlinkArchArgs(ctxt.Arch)...)
-
- if *FlagS || debug_s {
- if ctxt.HeadType == objabi.Hdarwin {
- // Recent versions of macOS print
- // ld: warning: option -s is obsolete and being ignored
- // so do not pass any arguments.
- } else {
- argv = append(argv, "-s")
- }
- }
-
- switch ctxt.HeadType {
- case objabi.Hdarwin:
- if machoPlatform == PLATFORM_MACOS {
- // -headerpad is incompatible with -fembed-bitcode.
- argv = append(argv, "-Wl,-headerpad,1144")
- }
- if ctxt.DynlinkingGo() && !ctxt.Arch.InFamily(sys.ARM, sys.ARM64) {
- argv = append(argv, "-Wl,-flat_namespace")
- }
- case objabi.Hopenbsd:
- argv = append(argv, "-Wl,-nopie")
- case objabi.Hwindows:
- if windowsgui {
- argv = append(argv, "-mwindows")
- } else {
- argv = append(argv, "-mconsole")
- }
- // Mark as having awareness of terminal services, to avoid
- // ancient compatibility hacks.
- argv = append(argv, "-Wl,--tsaware")
-
- // Enable DEP
- argv = append(argv, "-Wl,--nxcompat")
-
- argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", PeMinimumTargetMajorVersion))
- argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", PeMinimumTargetMinorVersion))
- argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", PeMinimumTargetMajorVersion))
- argv = append(argv, fmt.Sprintf("-Wl,--minor-subsystem-version=%d", PeMinimumTargetMinorVersion))
- case objabi.Haix:
- argv = append(argv, "-pthread")
- // prevent ld to reorder .text functions to keep the same
- // first/last functions for moduledata.
- argv = append(argv, "-Wl,-bnoobjreorder")
- // mcmodel=large is needed for every gcc generated files, but
- // ld still need -bbigtoc in order to allow larger TOC.
- argv = append(argv, "-mcmodel=large")
- argv = append(argv, "-Wl,-bbigtoc")
- }
-
- switch ctxt.BuildMode {
- case BuildModeExe:
- if ctxt.HeadType == objabi.Hdarwin {
- if machoPlatform == PLATFORM_MACOS {
- argv = append(argv, "-Wl,-no_pie")
- argv = append(argv, "-Wl,-pagezero_size,4000000")
- }
- }
- case BuildModePIE:
- switch ctxt.HeadType {
- case objabi.Hdarwin, objabi.Haix:
- case objabi.Hwindows:
- // Enable ASLR.
- argv = append(argv, "-Wl,--dynamicbase")
- // enable high-entropy ASLR on 64-bit.
- if ctxt.Arch.PtrSize >= 8 {
- argv = append(argv, "-Wl,--high-entropy-va")
- }
- // Work around binutils limitation that strips relocation table for dynamicbase.
- // See https://sourceware.org/bugzilla/show_bug.cgi?id=19011
- argv = append(argv, "-Wl,--export-all-symbols")
- default:
- // ELF.
- if ctxt.UseRelro() {
- argv = append(argv, "-Wl,-z,relro")
- }
- argv = append(argv, "-pie")
- }
- case BuildModeCShared:
- if ctxt.HeadType == objabi.Hdarwin {
- argv = append(argv, "-dynamiclib")
- if ctxt.Arch.Family != sys.AMD64 {
- argv = append(argv, "-Wl,-read_only_relocs,suppress")
- }
- } else {
- // ELF.
- argv = append(argv, "-Wl,-Bsymbolic")
- if ctxt.UseRelro() {
- argv = append(argv, "-Wl,-z,relro")
- }
- argv = append(argv, "-shared")
- if ctxt.HeadType != objabi.Hwindows {
- // Pass -z nodelete to mark the shared library as
- // non-closeable: a dlclose will do nothing.
- argv = append(argv, "-Wl,-z,nodelete")
- }
- }
- case BuildModeShared:
- if ctxt.UseRelro() {
- argv = append(argv, "-Wl,-z,relro")
- }
- argv = append(argv, "-shared")
- case BuildModePlugin:
- if ctxt.HeadType == objabi.Hdarwin {
- argv = append(argv, "-dynamiclib")
- } else {
- if ctxt.UseRelro() {
- argv = append(argv, "-Wl,-z,relro")
- }
- argv = append(argv, "-shared")
- }
- }
-
- if ctxt.IsELF && ctxt.DynlinkingGo() {
- // We force all symbol resolution to be done at program startup
- // because lazy PLT resolution can use large amounts of stack at
- // times we cannot allow it to do so.
- argv = append(argv, "-Wl,-znow")
-
- // Do not let the host linker generate COPY relocations. These
- // can move symbols out of sections that rely on stable offsets
- // from the beginning of the section (like sym.STYPE).
- argv = append(argv, "-Wl,-znocopyreloc")
-
- if ctxt.Arch.InFamily(sys.ARM, sys.ARM64) && objabi.GOOS == "linux" {
- // On ARM, the GNU linker will generate COPY relocations
- // even with -znocopyreloc set.
- // https://sourceware.org/bugzilla/show_bug.cgi?id=19962
- //
- // On ARM64, the GNU linker will fail instead of
- // generating COPY relocations.
- //
- // In both cases, switch to gold.
- argv = append(argv, "-fuse-ld=gold")
-
- // If gold is not installed, gcc will silently switch
- // back to ld.bfd. So we parse the version information
- // and provide a useful error if gold is missing.
- cmd := exec.Command(*flagExtld, "-fuse-ld=gold", "-Wl,--version")
- if out, err := cmd.CombinedOutput(); err == nil {
- if !bytes.Contains(out, []byte("GNU gold")) {
- log.Fatalf("ARM external linker must be gold (issue #15696), but is not: %s", out)
- }
- }
- }
- }
-
- if ctxt.Arch.Family == sys.ARM64 && objabi.GOOS == "freebsd" {
- // Switch to ld.bfd on freebsd/arm64.
- argv = append(argv, "-fuse-ld=bfd")
-
- // Provide a useful error if ld.bfd is missing.
- cmd := exec.Command(*flagExtld, "-fuse-ld=bfd", "-Wl,--version")
- if out, err := cmd.CombinedOutput(); err == nil {
- if !bytes.Contains(out, []byte("GNU ld")) {
- log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
- }
- }
- }
-
- if ctxt.IsELF && len(buildinfo) > 0 {
- argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
- }
-
- // On Windows, given -o foo, GCC will append ".exe" to produce
- // "foo.exe". We have decided that we want to honor the -o
- // option. To make this work, we append a '.' so that GCC
- // will decide that the file already has an extension. We
- // only want to do this when producing a Windows output file
- // on a Windows host.
- outopt := *flagOutfile
- if objabi.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
- outopt += "."
- }
- argv = append(argv, "-o")
- argv = append(argv, outopt)
-
- if rpath.val != "" {
- argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
- }
-
- // Force global symbols to be exported for dlopen, etc.
- if ctxt.IsELF {
- argv = append(argv, "-rdynamic")
- }
- if ctxt.HeadType == objabi.Haix {
- fileName := xcoffCreateExportFile(ctxt)
- argv = append(argv, "-Wl,-bE:"+fileName)
- }
-
- if strings.Contains(argv[0], "clang") {
- argv = append(argv, "-Qunused-arguments")
- }
-
- const compressDWARF = "-Wl,--compress-debug-sections=zlib-gnu"
- if ctxt.compressDWARF && linkerFlagSupported(argv[0], compressDWARF) {
- argv = append(argv, compressDWARF)
- }
-
- argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
- argv = append(argv, hostobjCopy()...)
- if ctxt.HeadType == objabi.Haix {
- // We want to have C files after Go files to remove
- // trampolines csects made by ld.
- argv = append(argv, "-nostartfiles")
- argv = append(argv, "/lib/crt0_64.o")
-
- extld := ctxt.extld()
- // Get starting files.
- getPathFile := func(file string) string {
- args := []string{"-maix64", "--print-file-name=" + file}
- out, err := exec.Command(extld, args...).CombinedOutput()
- if err != nil {
- log.Fatalf("running %s failed: %v\n%s", extld, err, out)
- }
- return strings.Trim(string(out), "\n")
- }
- argv = append(argv, getPathFile("crtcxa.o"))
- argv = append(argv, getPathFile("crtdbase.o"))
- }
-
- if ctxt.linkShared {
- seenDirs := make(map[string]bool)
- seenLibs := make(map[string]bool)
- addshlib := func(path string) {
- dir, base := filepath.Split(path)
- if !seenDirs[dir] {
- argv = append(argv, "-L"+dir)
- if !rpath.set {
- argv = append(argv, "-Wl,-rpath="+dir)
- }
- seenDirs[dir] = true
- }
- base = strings.TrimSuffix(base, ".so")
- base = strings.TrimPrefix(base, "lib")
- if !seenLibs[base] {
- argv = append(argv, "-l"+base)
- seenLibs[base] = true
- }
- }
- for _, shlib := range ctxt.Shlibs {
- addshlib(shlib.Path)
- for _, dep := range shlib.Deps {
- if dep == "" {
- continue
- }
- libpath := findshlib(ctxt, dep)
- if libpath != "" {
- addshlib(libpath)
- }
- }
- }
- }
-
- // clang, unlike GCC, passes -rdynamic to the linker
- // even when linking with -static, causing a linker
- // error when using GNU ld. So take out -rdynamic if
- // we added it. We do it in this order, rather than
- // only adding -rdynamic later, so that -*extldflags
- // can override -rdynamic without using -static.
- checkStatic := func(arg string) {
- if ctxt.IsELF && arg == "-static" {
- for i := range argv {
- if argv[i] == "-rdynamic" {
- argv[i] = "-static"
- }
- }
- }
- }
-
- for _, p := range ldflag {
- argv = append(argv, p)
- checkStatic(p)
- }
-
- // When building a program with the default -buildmode=exe the
- // gc compiler generates code requires DT_TEXTREL in a
- // position independent executable (PIE). On systems where the
- // toolchain creates PIEs by default, and where DT_TEXTREL
- // does not work, the resulting programs will not run. See
- // issue #17847. To avoid this problem pass -no-pie to the
- // toolchain if it is supported.
- if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared {
- // GCC uses -no-pie, clang uses -nopie.
- for _, nopie := range []string{"-no-pie", "-nopie"} {
- if linkerFlagSupported(argv[0], nopie) {
- argv = append(argv, nopie)
- break
- }
- }
- }
-
- for _, p := range strings.Fields(*flagExtldflags) {
- argv = append(argv, p)
- checkStatic(p)
- }
- if ctxt.HeadType == objabi.Hwindows {
- // use gcc linker script to work around gcc bug
- // (see https://golang.org/issue/20183 for details).
- p := writeGDBLinkerScript()
- argv = append(argv, "-Wl,-T,"+p)
- // libmingw32 and libmingwex have some inter-dependencies,
- // so must use linker groups.
- argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
- argv = append(argv, peimporteddlls()...)
- }
-
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("host link:")
- for _, v := range argv {
- ctxt.Logf(" %q", v)
- }
- ctxt.Logf("\n")
- }
-
- out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput()
- if err != nil {
- Exitf("running %s failed: %v\n%s", argv[0], err, out)
- }
-
- // Filter out useless linker warnings caused by bugs outside Go.
- // See also cmd/go/internal/work/exec.go's gccld method.
- var save [][]byte
- var skipLines int
- for _, line := range bytes.SplitAfter(out, []byte("\n")) {
- // golang.org/issue/26073 - Apple Xcode bug
- if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
- continue
- }
-
- if skipLines > 0 {
- skipLines--
- continue
- }
-
- // Remove TOC overflow warning on AIX.
- if bytes.Contains(line, []byte("ld: 0711-783")) {
- skipLines = 2
- continue
- }
-
- save = append(save, line)
- }
- out = bytes.Join(save, nil)
-
- if len(out) > 0 {
- // always print external output even if the command is successful, so that we don't
- // swallow linker warnings (see https://golang.org/issue/17935).
- ctxt.Logf("%s", out)
- }
-
- if !*FlagS && !*FlagW && !debug_s && ctxt.HeadType == objabi.Hdarwin {
- dsym := filepath.Join(*flagTmpdir, "go.dwarf")
- if out, err := exec.Command("dsymutil", "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
- Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
- }
- // Skip combining if `dsymutil` didn't generate a file. See #11994.
- if _, err := os.Stat(dsym); os.IsNotExist(err) {
- return
- }
- // For os.Rename to work reliably, must be in same directory as outfile.
- combinedOutput := *flagOutfile + "~"
- exef, err := os.Open(*flagOutfile)
- if err != nil {
- Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
- }
- defer exef.Close()
- exem, err := macho.NewFile(exef)
- if err != nil {
- Exitf("%s: parsing Mach-O header failed: %v", os.Args[0], err)
- }
- // Only macOS supports unmapped segments such as our __DWARF segment.
- if machoPlatform == PLATFORM_MACOS {
- if err := machoCombineDwarf(ctxt, exef, exem, dsym, combinedOutput); err != nil {
- Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
- }
- os.Remove(*flagOutfile)
- if err := os.Rename(combinedOutput, *flagOutfile); err != nil {
- Exitf("%s: %v", os.Args[0], err)
- }
- }
- }
-}
-
-var createTrivialCOnce sync.Once
-
-func linkerFlagSupported(linker, flag string) bool {
- createTrivialCOnce.Do(func() {
- src := filepath.Join(*flagTmpdir, "trivial.c")
- if err := ioutil.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
- Errorf(nil, "WriteFile trivial.c failed: %v", err)
- }
- })
-
- flagsWithNextArgSkip := []string{
- "-F",
- "-l",
- "-L",
- "-framework",
- "-Wl,-framework",
- "-Wl,-rpath",
- "-Wl,-undefined",
- }
- flagsWithNextArgKeep := []string{
- "-arch",
- "-isysroot",
- "--sysroot",
- "-target",
- }
- prefixesToKeep := []string{
- "-f",
- "-m",
- "-p",
- "-Wl,",
- "-arch",
- "-isysroot",
- "--sysroot",
- "-target",
- }
-
- var flags []string
- keep := false
- skip := false
- extldflags := strings.Fields(*flagExtldflags)
- for _, f := range append(extldflags, ldflag...) {
- if keep {
- flags = append(flags, f)
- keep = false
- } else if skip {
- skip = false
- } else if f == "" || f[0] != '-' {
- } else if contains(flagsWithNextArgSkip, f) {
- skip = true
- } else if contains(flagsWithNextArgKeep, f) {
- flags = append(flags, f)
- keep = true
- } else {
- for _, p := range prefixesToKeep {
- if strings.HasPrefix(f, p) {
- flags = append(flags, f)
- break
- }
- }
- }
- }
-
- flags = append(flags, flag, "trivial.c")
-
- cmd := exec.Command(linker, flags...)
- cmd.Dir = *flagTmpdir
- cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
- out, err := cmd.CombinedOutput()
- // GCC says "unrecognized command line option ‘-no-pie’"
- // clang says "unknown argument: '-no-pie'"
- return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
-}
-
-// hostlinkArchArgs returns arguments to pass to the external linker
-// based on the architecture.
-func hostlinkArchArgs(arch *sys.Arch) []string {
- switch arch.Family {
- case sys.I386:
- return []string{"-m32"}
- case sys.AMD64, sys.S390X:
- return []string{"-m64"}
- case sys.ARM:
- return []string{"-marm"}
- case sys.ARM64:
- // nothing needed
- case sys.MIPS64:
- return []string{"-mabi=64"}
- case sys.MIPS:
- return []string{"-mabi=32"}
- case sys.PPC64:
- if objabi.GOOS == "aix" {
- return []string{"-maix64"}
- } else {
- return []string{"-m64"}
- }
-
- }
- return nil
-}
-
-// ldobj loads an input object. If it is a host object (an object
-// compiled by a non-Go compiler) it returns the Hostobj pointer. If
-// it is a Go object, it returns nil.
-func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
- pkg := objabi.PathToPrefix(lib.Pkg)
-
- eof := f.Offset() + length
- start := f.Offset()
- c1 := bgetc(f)
- c2 := bgetc(f)
- c3 := bgetc(f)
- c4 := bgetc(f)
- f.MustSeek(start, 0)
-
- unit := &sym.CompilationUnit{Lib: lib}
- lib.Units = append(lib.Units, unit)
-
- magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
- if magic == 0x7f454c46 { // \x7F E L F
- if *flagNewobj {
- ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.Syms, f, pkg, length, pn, ehdr.flags)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ehdr.flags = flags
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
- } else {
- ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, flags, err := loadelf.LoadOld(ctxt.Arch, ctxt.Syms, f, pkg, length, pn, ehdr.flags)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ehdr.flags = flags
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
- }
- }
-
- if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
- if *flagNewobj {
- ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
- } else {
- ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, err := loadmacho.LoadOld(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
- }
- }
-
- if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 {
- if *flagNewobj {
- ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- if rsrc != nil {
- setpersrc(ctxt, rsrc)
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
- } else {
- ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, rsrc, err := loadpe.LoadOld(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- if rsrc != nil {
- setpersrc(ctxt, rsrc)
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
- }
- }
-
- if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
- if *flagNewobj {
- ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
- } else {
- ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, err := loadxcoff.LoadOld(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
- }
- }
-
- /* check the header */
- line, err := f.ReadString('\n')
- if err != nil {
- Errorf(nil, "truncated object file: %s: %v", pn, err)
- return nil
- }
-
- if !strings.HasPrefix(line, "go object ") {
- if strings.HasSuffix(pn, ".go") {
- Exitf("%s: uncompiled .go source file", pn)
- return nil
- }
-
- if line == ctxt.Arch.Name {
- // old header format: just $GOOS
- Errorf(nil, "%s: stale object file", pn)
- return nil
- }
-
- Errorf(nil, "%s: not an object file", pn)
- return nil
- }
-
- // First, check that the basic GOOS, GOARCH, and Version match.
- t := fmt.Sprintf("%s %s %s ", objabi.GOOS, objabi.GOARCH, objabi.Version)
-
- line = strings.TrimRight(line, "\n")
- if !strings.HasPrefix(line[10:]+" ", t) && !*flagF {
- Errorf(nil, "%s: object is [%s] expected [%s]", pn, line[10:], t)
- return nil
- }
-
- // Second, check that longer lines match each other exactly,
- // so that the Go compiler and write additional information
- // that must be the same from run to run.
- if len(line) >= len(t)+10 {
- if theline == "" {
- theline = line[10:]
- } else if theline != line[10:] {
- Errorf(nil, "%s: object is [%s] expected [%s]", pn, line[10:], theline)
- return nil
- }
- }
-
- // Skip over exports and other info -- ends with \n!\n.
- //
- // Note: It's possible for "\n!\n" to appear within the binary
- // package export data format. To avoid truncating the package
- // definition prematurely (issue 21703), we keep track of
- // how many "$$" delimiters we've seen.
-
- import0 := f.Offset()
-
- c1 = '\n' // the last line ended in \n
- c2 = bgetc(f)
- c3 = bgetc(f)
- markers := 0
- for {
- if c1 == '\n' {
- if markers%2 == 0 && c2 == '!' && c3 == '\n' {
- break
- }
- if c2 == '$' && c3 == '$' {
- markers++
- }
- }
-
- c1 = c2
- c2 = c3
- c3 = bgetc(f)
- if c3 == -1 {
- Errorf(nil, "truncated object file: %s", pn)
- return nil
- }
- }
-
- import1 := f.Offset()
-
- f.MustSeek(import0, 0)
- ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
- f.MustSeek(import1, 0)
-
- flags := 0
- switch *FlagStrictDups {
- case 0:
- break
- case 1:
- flags = objfile.StrictDupsWarnFlag
- case 2:
- flags = objfile.StrictDupsErrFlag
- default:
- log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
- }
- var c int
- if *flagNewobj {
- ctxt.loader.Preload(ctxt.Arch, ctxt.Syms, f, lib, unit, eof-f.Offset(), pn, flags)
- } else {
- c = objfile.Load(ctxt.Arch, ctxt.Syms, f, lib, unit, eof-f.Offset(), pn, flags)
- }
- strictDupMsgCount += c
- addImports(ctxt, lib, pn)
- return nil
-}
-
-func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
- data := make([]byte, sym.Size)
- sect := f.Sections[sym.Section]
- if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
- Errorf(nil, "reading %s from non-data section", sym.Name)
- }
- n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
- if uint64(n) != sym.Size {
- Errorf(nil, "reading contents of %s: %v", sym.Name, err)
- }
- return data
-}
-
-func readwithpad(r io.Reader, sz int32) ([]byte, error) {
- data := make([]byte, Rnd(int64(sz), 4))
- _, err := io.ReadFull(r, data)
- if err != nil {
- return nil, err
- }
- data = data[:sz]
- return data, nil
-}
-
-func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
- for _, sect := range f.Sections {
- if sect.Type != elf.SHT_NOTE {
- continue
- }
- r := sect.Open()
- for {
- var namesize, descsize, noteType int32
- err := binary.Read(r, f.ByteOrder, &namesize)
- if err != nil {
- if err == io.EOF {
- break
- }
- return nil, fmt.Errorf("read namesize failed: %v", err)
- }
- err = binary.Read(r, f.ByteOrder, &descsize)
- if err != nil {
- return nil, fmt.Errorf("read descsize failed: %v", err)
- }
- err = binary.Read(r, f.ByteOrder, ¬eType)
- if err != nil {
- return nil, fmt.Errorf("read type failed: %v", err)
- }
- noteName, err := readwithpad(r, namesize)
- if err != nil {
- return nil, fmt.Errorf("read name failed: %v", err)
- }
- desc, err := readwithpad(r, descsize)
- if err != nil {
- return nil, fmt.Errorf("read desc failed: %v", err)
- }
- if string(name) == string(noteName) && typ == noteType {
- return desc, nil
- }
- }
- }
- return nil, nil
-}
-
-func findshlib(ctxt *Link, shlib string) string {
- if filepath.IsAbs(shlib) {
- return shlib
- }
- for _, libdir := range ctxt.Libdir {
- libpath := filepath.Join(libdir, shlib)
- if _, err := os.Stat(libpath); err == nil {
- return libpath
- }
- }
- Errorf(nil, "cannot find shared library: %s", shlib)
- return ""
-}
-
-func ldshlibsyms(ctxt *Link, shlib string) {
- var libpath string
- if filepath.IsAbs(shlib) {
- libpath = shlib
- shlib = filepath.Base(shlib)
- } else {
- libpath = findshlib(ctxt, shlib)
- if libpath == "" {
- return
- }
- }
- for _, processedlib := range ctxt.Shlibs {
- if processedlib.Path == libpath {
- return
- }
- }
- if ctxt.Debugvlog > 1 {
- ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
- }
-
- f, err := elf.Open(libpath)
- if err != nil {
- Errorf(nil, "cannot open shared library: %s", libpath)
- return
- }
- defer f.Close()
-
- hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
- if err != nil {
- Errorf(nil, "cannot read ABI hash from shared library %s: %v", libpath, err)
- return
- }
-
- depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
- if err != nil {
- Errorf(nil, "cannot read dep list from shared library %s: %v", libpath, err)
- return
- }
- var deps []string
- for _, dep := range strings.Split(string(depsbytes), "\n") {
- if dep == "" {
- continue
- }
- if !filepath.IsAbs(dep) {
- // If the dep can be interpreted as a path relative to the shlib
- // in which it was found, do that. Otherwise, we will leave it
- // to be resolved by libdir lookup.
- abs := filepath.Join(filepath.Dir(libpath), dep)
- if _, err := os.Stat(abs); err == nil {
- dep = abs
- }
- }
- deps = append(deps, dep)
- }
-
- syms, err := f.DynamicSymbols()
- if err != nil {
- Errorf(nil, "cannot read symbols from shared library: %s", libpath)
- return
- }
- gcdataLocations := make(map[uint64]*sym.Symbol)
- for _, elfsym := range syms {
- if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
- continue
- }
-
- // Symbols whose names start with "type." are compiler
- // generated, so make functions with that prefix internal.
- ver := 0
- if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type.") {
- ver = sym.SymVerABIInternal
- }
-
- var lsym *sym.Symbol
- if *flagNewobj {
- i := ctxt.loader.AddExtSym(elfsym.Name, ver)
- if i == 0 {
- continue
- }
- lsym = ctxt.Syms.Newsym(elfsym.Name, ver)
- ctxt.loader.Syms[i] = lsym
- } else {
- lsym = ctxt.Syms.Lookup(elfsym.Name, ver)
- }
- // Because loadlib above loads all .a files before loading any shared
- // libraries, any non-dynimport symbols we find that duplicate symbols
- // already loaded should be ignored (the symbols from the .a files
- // "win").
- if lsym.Type != 0 && lsym.Type != sym.SDYNIMPORT {
- continue
- }
- lsym.Type = sym.SDYNIMPORT
- lsym.SetElfType(elf.ST_TYPE(elfsym.Info))
- lsym.Size = int64(elfsym.Size)
- if elfsym.Section != elf.SHN_UNDEF {
- // Set .File for the library that actually defines the symbol.
- lsym.File = libpath
- // The decodetype_* functions in decodetype.go need access to
- // the type data.
- if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
- lsym.P = readelfsymboldata(ctxt, f, &elfsym)
- gcdataLocations[elfsym.Value+2*uint64(ctxt.Arch.PtrSize)+8+1*uint64(ctxt.Arch.PtrSize)] = lsym
- }
- }
- // For function symbols, we don't know what ABI is
- // available, so alias it under both ABIs.
- //
- // TODO(austin): This is almost certainly wrong once
- // the ABIs are actually different. We might have to
- // mangle Go function names in the .so to include the
- // ABI.
- if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
- var alias *sym.Symbol
- if *flagNewobj {
- i := ctxt.loader.AddExtSym(elfsym.Name, sym.SymVerABIInternal)
- if i == 0 {
- continue
- }
- alias = ctxt.Syms.Newsym(elfsym.Name, sym.SymVerABIInternal)
- ctxt.loader.Syms[i] = alias
- } else {
- alias = ctxt.Syms.Lookup(elfsym.Name, sym.SymVerABIInternal)
- }
- if alias.Type != 0 {
- continue
- }
- alias.Type = sym.SABIALIAS
- alias.R = []sym.Reloc{{Sym: lsym}}
- }
- }
- gcdataAddresses := make(map[*sym.Symbol]uint64)
- if ctxt.Arch.Family == sys.ARM64 {
- for _, sect := range f.Sections {
- if sect.Type == elf.SHT_RELA {
- var rela elf.Rela64
- rdr := sect.Open()
- for {
- err := binary.Read(rdr, f.ByteOrder, &rela)
- if err == io.EOF {
- break
- } else if err != nil {
- Errorf(nil, "reading relocation failed %v", err)
- return
- }
- t := elf.R_AARCH64(rela.Info & 0xffff)
- if t != elf.R_AARCH64_RELATIVE {
- continue
- }
- if lsym, ok := gcdataLocations[rela.Off]; ok {
- gcdataAddresses[lsym] = uint64(rela.Addend)
- }
- }
- }
- }
- }
-
- ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdataAddresses: gcdataAddresses})
-}
-
-func addsection(arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
- sect := new(sym.Section)
- sect.Rwx = uint8(rwx)
- sect.Name = name
- sect.Seg = seg
- sect.Align = int32(arch.PtrSize) // everything is at least pointer-aligned
- seg.Sections = append(seg.Sections, sect)
- return sect
-}
-
-type chain struct {
- sym *sym.Symbol
- up *chain
- limit int // limit on entry to sym
-}
-
-var morestack *sym.Symbol
-
-// TODO: Record enough information in new object files to
-// allow stack checks here.
-
-func haslinkregister(ctxt *Link) bool {
- return ctxt.FixedFrameSize() != 0
-}
-
-func callsize(ctxt *Link) int {
- if haslinkregister(ctxt) {
- return 0
- }
- return ctxt.Arch.RegSize
-}
-
-func (ctxt *Link) dostkcheck() {
- var ch chain
-
- morestack = ctxt.Syms.Lookup("runtime.morestack", 0)
-
- // Every splitting function ensures that there are at least StackLimit
- // bytes available below SP when the splitting prologue finishes.
- // If the splitting function calls F, then F begins execution with
- // at least StackLimit - callsize() bytes available.
- // Check that every function behaves correctly with this amount
- // of stack, following direct calls in order to piece together chains
- // of non-splitting functions.
- ch.up = nil
-
- ch.limit = objabi.StackLimit - callsize(ctxt)
- if objabi.GOARCH == "arm64" {
- // need extra 8 bytes below SP to save FP
- ch.limit -= 8
- }
-
- // Check every function, but do the nosplit functions in a first pass,
- // to make the printed failure chains as short as possible.
- for _, s := range ctxt.Textp {
- // runtime.racesymbolizethunk is called from gcc-compiled C
- // code running on the operating system thread stack.
- // It uses more than the usual amount of stack but that's okay.
- if s.Name == "runtime.racesymbolizethunk" {
- continue
- }
-
- if s.Attr.NoSplit() {
- ch.sym = s
- stkcheck(ctxt, &ch, 0)
- }
- }
-
- for _, s := range ctxt.Textp {
- if !s.Attr.NoSplit() {
- ch.sym = s
- stkcheck(ctxt, &ch, 0)
- }
- }
-}
-
-func stkcheck(ctxt *Link, up *chain, depth int) int {
- limit := up.limit
- s := up.sym
-
- // Don't duplicate work: only need to consider each
- // function at top of safe zone once.
- top := limit == objabi.StackLimit-callsize(ctxt)
- if top {
- if s.Attr.StackCheck() {
- return 0
- }
- s.Attr |= sym.AttrStackCheck
- }
-
- if depth > 500 {
- Errorf(s, "nosplit stack check too deep")
- stkbroke(ctxt, up, 0)
- return -1
- }
-
- if s.Attr.External() || s.FuncInfo == nil {
- // external function.
- // should never be called directly.
- // onlyctxt.Diagnose the direct caller.
- // TODO(mwhudson): actually think about this.
- // TODO(khr): disabled for now. Calls to external functions can only happen on the g0 stack.
- // See the trampolines in src/runtime/sys_darwin_$ARCH.go.
- if depth == 1 && s.Type != sym.SXREF && !ctxt.DynlinkingGo() &&
- ctxt.BuildMode != BuildModeCArchive && ctxt.BuildMode != BuildModePIE && ctxt.BuildMode != BuildModeCShared && ctxt.BuildMode != BuildModePlugin {
- //Errorf(s, "call to external function")
- }
- return -1
- }
-
- if limit < 0 {
- stkbroke(ctxt, up, limit)
- return -1
- }
-
- // morestack looks like it calls functions,
- // but it switches the stack pointer first.
- if s == morestack {
- return 0
- }
-
- var ch chain
- ch.up = up
-
- if !s.Attr.NoSplit() {
- // Ensure we have enough stack to call morestack.
- ch.limit = limit - callsize(ctxt)
- ch.sym = morestack
- if stkcheck(ctxt, &ch, depth+1) < 0 {
- return -1
- }
- if !top {
- return 0
- }
- // Raise limit to allow frame.
- locals := int32(0)
- if s.FuncInfo != nil {
- locals = s.FuncInfo.Locals
- }
- limit = objabi.StackLimit + int(locals) + int(ctxt.FixedFrameSize())
- }
-
- // Walk through sp adjustments in function, consuming relocs.
- ri := 0
-
- endr := len(s.R)
- var ch1 chain
- pcsp := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
- var r *sym.Reloc
- for pcsp.Init(s.FuncInfo.Pcsp.P); !pcsp.Done; pcsp.Next() {
- // pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
-
- // Check stack size in effect for this span.
- if int32(limit)-pcsp.Value < 0 {
- stkbroke(ctxt, up, int(int32(limit)-pcsp.Value))
- return -1
- }
-
- // Process calls in this span.
- for ; ri < endr && uint32(s.R[ri].Off) < pcsp.NextPC; ri++ {
- r = &s.R[ri]
- switch {
- case r.Type.IsDirectCall():
- ch.limit = int(int32(limit) - pcsp.Value - int32(callsize(ctxt)))
- ch.sym = r.Sym
- if stkcheck(ctxt, &ch, depth+1) < 0 {
- return -1
- }
-
- // Indirect call. Assume it is a call to a splitting function,
- // so we have to make sure it can call morestack.
- // Arrange the data structures to report both calls, so that
- // if there is an error, stkprint shows all the steps involved.
- case r.Type == objabi.R_CALLIND:
- ch.limit = int(int32(limit) - pcsp.Value - int32(callsize(ctxt)))
- ch.sym = nil
- ch1.limit = ch.limit - callsize(ctxt) // for morestack in called prologue
- ch1.up = &ch
- ch1.sym = morestack
- if stkcheck(ctxt, &ch1, depth+2) < 0 {
- return -1
- }
- }
- }
- }
-
- return 0
-}
-
-func stkbroke(ctxt *Link, ch *chain, limit int) {
- Errorf(ch.sym, "nosplit stack overflow")
- stkprint(ctxt, ch, limit)
-}
-
-func stkprint(ctxt *Link, ch *chain, limit int) {
- var name string
-
- if ch.sym != nil {
- name = ch.sym.Name
- if ch.sym.Attr.NoSplit() {
- name += " (nosplit)"
- }
- } else {
- name = "function pointer"
- }
-
- if ch.up == nil {
- // top of chain. ch->sym != nil.
- if ch.sym.Attr.NoSplit() {
- fmt.Printf("\t%d\tassumed on entry to %s\n", ch.limit, name)
- } else {
- fmt.Printf("\t%d\tguaranteed after split check in %s\n", ch.limit, name)
- }
- } else {
- stkprint(ctxt, ch.up, ch.limit+callsize(ctxt))
- if !haslinkregister(ctxt) {
- fmt.Printf("\t%d\ton entry to %s\n", ch.limit, name)
- }
- }
-
- if ch.limit != limit {
- fmt.Printf("\t%d\tafter %s uses %d\n", limit, name, ch.limit-limit)
- }
-}
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
- objabi.Flagprint(os.Stderr)
- Exit(2)
-}
-
-type SymbolType int8
-
-const (
- // see also https://9p.io/magic/man2html/1/nm
- TextSym SymbolType = 'T'
- DataSym SymbolType = 'D'
- BSSSym SymbolType = 'B'
- UndefinedSym SymbolType = 'U'
- TLSSym SymbolType = 't'
- FrameSym SymbolType = 'm'
- ParamSym SymbolType = 'p'
- AutoSym SymbolType = 'a'
-
- // Deleted auto (not a real sym, just placeholder for type)
- DeletedAutoSym = 'x'
-)
-
-func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int64, *sym.Symbol)) {
- // These symbols won't show up in the first loop below because we
- // skip sym.STEXT symbols. Normal sym.STEXT symbols are emitted by walking textp.
- s := ctxt.Syms.Lookup("runtime.text", 0)
- if s.Type == sym.STEXT {
- // We've already included this symbol in ctxt.Textp
- // if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin or
- // on AIX with external linker.
- // See data.go:/textaddress
- if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- put(ctxt, s, s.Name, TextSym, s.Value, nil)
- }
- }
-
- n := 0
-
- // Generate base addresses for all text sections if there are multiple
- for _, sect := range Segtext.Sections {
- if n == 0 {
- n++
- continue
- }
- if sect.Name != ".text" || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- // On AIX, runtime.text.X are symbols already in the symtab.
- break
- }
- s = ctxt.Syms.ROLookup(fmt.Sprintf("runtime.text.%d", n), 0)
- if s == nil {
- break
- }
- if s.Type == sym.STEXT {
- put(ctxt, s, s.Name, TextSym, s.Value, nil)
- }
- n++
- }
-
- s = ctxt.Syms.Lookup("runtime.etext", 0)
- if s.Type == sym.STEXT {
- // We've already included this symbol in ctxt.Textp
- // if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin or
- // on AIX with external linker.
- // See data.go:/textaddress
- if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- put(ctxt, s, s.Name, TextSym, s.Value, nil)
- }
- }
-
- shouldBeInSymbolTable := func(s *sym.Symbol) bool {
- if s.Attr.NotInSymbolTable() {
- return false
- }
- if ctxt.HeadType == objabi.Haix && s.Name == ".go.buildinfo" {
- // On AIX, .go.buildinfo must be in the symbol table as
- // it has relocations.
- return true
- }
- if (s.Name == "" || s.Name[0] == '.') && !s.IsFileLocal() && s.Name != ".rathole" && s.Name != ".TOC." {
- return false
- }
- return true
- }
-
- for _, s := range ctxt.Syms.Allsym {
- if !shouldBeInSymbolTable(s) {
- continue
- }
- switch s.Type {
- case sym.SCONST,
- sym.SRODATA,
- sym.SSYMTAB,
- sym.SPCLNTAB,
- sym.SINITARR,
- sym.SDATA,
- sym.SNOPTRDATA,
- sym.SELFROSECT,
- sym.SMACHOGOT,
- sym.STYPE,
- sym.SSTRING,
- sym.SGOSTRING,
- sym.SGOFUNC,
- sym.SGCBITS,
- sym.STYPERELRO,
- sym.SSTRINGRELRO,
- sym.SGOSTRINGRELRO,
- sym.SGOFUNCRELRO,
- sym.SGCBITSRELRO,
- sym.SRODATARELRO,
- sym.STYPELINK,
- sym.SITABLINK,
- sym.SWINDOWS:
- if !s.Attr.Reachable() {
- continue
- }
- put(ctxt, s, s.Name, DataSym, Symaddr(s), s.Gotype)
-
- case sym.SBSS, sym.SNOPTRBSS, sym.SLIBFUZZER_EXTRA_COUNTER:
- if !s.Attr.Reachable() {
- continue
- }
- if len(s.P) > 0 {
- Errorf(s, "should not be bss (size=%d type=%v special=%v)", len(s.P), s.Type, s.Attr.Special())
- }
- put(ctxt, s, s.Name, BSSSym, Symaddr(s), s.Gotype)
-
- case sym.SUNDEFEXT:
- if ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Haix || ctxt.IsELF {
- put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
- }
-
- case sym.SHOSTOBJ:
- if !s.Attr.Reachable() {
- continue
- }
- if ctxt.HeadType == objabi.Hwindows || ctxt.IsELF {
- put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
- }
-
- case sym.SDYNIMPORT:
- if !s.Attr.Reachable() {
- continue
- }
- put(ctxt, s, s.Extname(), UndefinedSym, 0, nil)
-
- case sym.STLSBSS:
- if ctxt.LinkMode == LinkExternal {
- put(ctxt, s, s.Name, TLSSym, Symaddr(s), s.Gotype)
- }
- }
- }
-
- for _, s := range ctxt.Textp {
- put(ctxt, s, s.Name, TextSym, s.Value, s.Gotype)
-
- locals := int32(0)
- if s.FuncInfo != nil {
- locals = s.FuncInfo.Locals
- }
- // NOTE(ality): acid can't produce a stack trace without .frame symbols
- put(ctxt, nil, ".frame", FrameSym, int64(locals)+int64(ctxt.Arch.PtrSize), nil)
-
- if s.FuncInfo == nil {
- continue
- }
- }
-
- if ctxt.Debugvlog != 0 || *flagN {
- ctxt.Logf("symsize = %d\n", uint32(Symsize))
- }
-}
-
-func Symaddr(s *sym.Symbol) int64 {
- if !s.Attr.Reachable() {
- Errorf(s, "unreachable symbol in symaddr")
- }
- return s.Value
-}
-
-func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) {
- s := ctxt.Syms.Lookup(p, 0)
- s.Type = t
- s.Value = v
- s.Attr |= sym.AttrReachable
- s.Attr |= sym.AttrSpecial
- s.Attr |= sym.AttrLocal
-}
-
-func datoff(s *sym.Symbol, addr int64) int64 {
- if uint64(addr) >= Segdata.Vaddr {
- return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
- }
- if uint64(addr) >= Segtext.Vaddr {
- return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
- }
- Errorf(s, "invalid datoff %#x", addr)
- return 0
-}
-
-func Entryvalue(ctxt *Link) int64 {
- a := *flagEntrySymbol
- if a[0] >= '0' && a[0] <= '9' {
- return atolwhex(a)
- }
- s := ctxt.Syms.Lookup(a, 0)
- if s.Type == 0 {
- return *FlagTextAddr
- }
- if ctxt.HeadType != objabi.Haix && s.Type != sym.STEXT {
- Errorf(s, "entry not text")
- }
- return s.Value
-}
-
-func undefsym(ctxt *Link, s *sym.Symbol) {
- var r *sym.Reloc
-
- for i := 0; i < len(s.R); i++ {
- r = &s.R[i]
- if r.Sym == nil { // happens for some external ARM relocs
- continue
- }
- // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
- // sense and should be removed when someone has thought about it properly.
- if (r.Sym.Type == sym.Sxxx || r.Sym.Type == sym.SXREF) && !r.Sym.Attr.VisibilityHidden() {
- Errorf(s, "undefined: %q", r.Sym.Name)
- }
- if !r.Sym.Attr.Reachable() && r.Type != objabi.R_WEAKADDROFF {
- Errorf(s, "relocation target %q", r.Sym.Name)
- }
- }
-}
-
-func (ctxt *Link) undef() {
- // undefsym performs checks (almost) identical to checks
- // that report undefined relocations in relocsym.
- // Both undefsym and relocsym can report same symbol as undefined,
- // which results in error message duplication (see #10978).
- //
- // The undef is run after Arch.Asmb and could detect some
- // programming errors there, but if object being linked is already
- // failed with errors, it is better to avoid duplicated errors.
- if nerrors > 0 {
- return
- }
-
- for _, s := range ctxt.Textp {
- undefsym(ctxt, s)
- }
- for _, s := range datap {
- undefsym(ctxt, s)
- }
- if nerrors > 0 {
- errorexit()
- }
-}
-
-func (ctxt *Link) callgraph() {
- if !*FlagC {
- return
- }
-
- var i int
- var r *sym.Reloc
- for _, s := range ctxt.Textp {
- for i = 0; i < len(s.R); i++ {
- r = &s.R[i]
- if r.Sym == nil {
- continue
- }
- if r.Type.IsDirectCall() && r.Sym.Type == sym.STEXT {
- ctxt.Logf("%s calls %s\n", s.Name, r.Sym.Name)
- }
- }
- }
-}
-
-func Rnd(v int64, r int64) int64 {
- if r <= 0 {
- return v
- }
- v += r - 1
- c := v % r
- if c < 0 {
- c += r
- }
- v -= c
- return v
-}
-
-func bgetc(r *bio.Reader) int {
- c, err := r.ReadByte()
- if err != nil {
- if err != io.EOF {
- log.Fatalf("reading input: %v", err)
- }
- return -1
- }
- return int(c)
-}
-
-type markKind uint8 // for postorder traversal
-const (
- _ markKind = iota
- visiting
- visited
-)
-
-func postorder(libs []*sym.Library) []*sym.Library {
- order := make([]*sym.Library, 0, len(libs)) // hold the result
- mark := make(map[*sym.Library]markKind, len(libs))
- for _, lib := range libs {
- dfs(lib, mark, &order)
- }
- return order
-}
-
-func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library) {
- if mark[lib] == visited {
- return
- }
- if mark[lib] == visiting {
- panic("found import cycle while visiting " + lib.Pkg)
- }
- mark[lib] = visiting
- for _, i := range lib.Imports {
- dfs(i, mark, order)
- }
- mark[lib] = visited
- *order = append(*order, lib)
-}
-
-func (ctxt *Link) loadlibfull() {
- // Load full symbol contents, resolve indexed references.
- ctxt.loader.LoadFull(ctxt.Arch, ctxt.Syms)
-
- // Pull the symbols out.
- ctxt.loader.ExtractSymbols(ctxt.Syms)
-
- // Load cgo directives.
- for _, d := range ctxt.cgodata {
- setCgoAttr(ctxt, ctxt.Syms.Lookup, d.file, d.pkg, d.directives)
- }
-
- setupdynexp(ctxt)
-
- // Populate ctxt.Reachparent if appropriate.
- if ctxt.Reachparent != nil {
- for i := 0; i < len(ctxt.loader.Reachparent); i++ {
- p := ctxt.loader.Reachparent[i]
- if p == 0 {
- continue
- }
- if p == loader.Sym(i) {
- panic("self-cycle in reachparent")
- }
- sym := ctxt.loader.Syms[i]
- psym := ctxt.loader.Syms[p]
- ctxt.Reachparent[sym] = psym
- }
- }
-
- // Drop the reference.
- ctxt.loader = nil
- ctxt.cgodata = nil
-
- addToTextp(ctxt)
-}
-
-func (ctxt *Link) dumpsyms() {
- for _, s := range ctxt.Syms.Allsym {
- fmt.Printf("%s %s %p %v %v\n", s, s.Type, s, s.Attr.Reachable(), s.Attr.OnList())
- for i := range s.R {
- fmt.Println("\t", s.R[i].Type, s.R[i].Sym)
- }
- }
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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.
-
-package ld
-
-import (
- "bytes"
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/sym"
- "debug/macho"
- "encoding/binary"
- "fmt"
- "io"
- "os"
- "sort"
- "strings"
-)
-
-type MachoHdr struct {
- cpu uint32
- subcpu uint32
-}
-
-type MachoSect struct {
- name string
- segname string
- addr uint64
- size uint64
- off uint32
- align uint32
- reloc uint32
- nreloc uint32
- flag uint32
- res1 uint32
- res2 uint32
-}
-
-type MachoSeg struct {
- name string
- vsize uint64
- vaddr uint64
- fileoffset uint64
- filesize uint64
- prot1 uint32
- prot2 uint32
- nsect uint32
- msect uint32
- sect []MachoSect
- flag uint32
-}
-
-// MachoPlatformLoad represents a LC_VERSION_MIN_* or
-// LC_BUILD_VERSION load command.
-type MachoPlatformLoad struct {
- platform MachoPlatform // One of PLATFORM_* constants.
- cmd MachoLoad
-}
-
-type MachoLoad struct {
- type_ uint32
- data []uint32
-}
-
-type MachoPlatform int
-
-/*
- * Total amount of space to reserve at the start of the file
- * for Header, PHeaders, and SHeaders.
- * May waste some.
- */
-const (
- INITIAL_MACHO_HEADR = 4 * 1024
-)
-
-const (
- MACHO_CPU_AMD64 = 1<<24 | 7
- MACHO_CPU_386 = 7
- MACHO_SUBCPU_X86 = 3
- MACHO_CPU_ARM = 12
- MACHO_SUBCPU_ARM = 0
- MACHO_SUBCPU_ARMV7 = 9
- MACHO_CPU_ARM64 = 1<<24 | 12
- MACHO_SUBCPU_ARM64_ALL = 0
- MACHO32SYMSIZE = 12
- MACHO64SYMSIZE = 16
- MACHO_X86_64_RELOC_UNSIGNED = 0
- MACHO_X86_64_RELOC_SIGNED = 1
- MACHO_X86_64_RELOC_BRANCH = 2
- MACHO_X86_64_RELOC_GOT_LOAD = 3
- MACHO_X86_64_RELOC_GOT = 4
- MACHO_X86_64_RELOC_SUBTRACTOR = 5
- MACHO_X86_64_RELOC_SIGNED_1 = 6
- MACHO_X86_64_RELOC_SIGNED_2 = 7
- MACHO_X86_64_RELOC_SIGNED_4 = 8
- MACHO_ARM_RELOC_VANILLA = 0
- MACHO_ARM_RELOC_PAIR = 1
- MACHO_ARM_RELOC_SECTDIFF = 2
- MACHO_ARM_RELOC_BR24 = 5
- MACHO_ARM64_RELOC_UNSIGNED = 0
- MACHO_ARM64_RELOC_BRANCH26 = 2
- MACHO_ARM64_RELOC_PAGE21 = 3
- MACHO_ARM64_RELOC_PAGEOFF12 = 4
- MACHO_ARM64_RELOC_ADDEND = 10
- MACHO_GENERIC_RELOC_VANILLA = 0
- MACHO_FAKE_GOTPCREL = 100
-)
-
-const (
- MH_MAGIC = 0xfeedface
- MH_MAGIC_64 = 0xfeedfacf
-
- MH_OBJECT = 0x1
- MH_EXECUTE = 0x2
-
- MH_NOUNDEFS = 0x1
-)
-
-const (
- LC_SEGMENT = 0x1
- LC_SYMTAB = 0x2
- LC_SYMSEG = 0x3
- LC_THREAD = 0x4
- LC_UNIXTHREAD = 0x5
- LC_LOADFVMLIB = 0x6
- LC_IDFVMLIB = 0x7
- LC_IDENT = 0x8
- LC_FVMFILE = 0x9
- LC_PREPAGE = 0xa
- LC_DYSYMTAB = 0xb
- LC_LOAD_DYLIB = 0xc
- LC_ID_DYLIB = 0xd
- LC_LOAD_DYLINKER = 0xe
- LC_ID_DYLINKER = 0xf
- LC_PREBOUND_DYLIB = 0x10
- LC_ROUTINES = 0x11
- LC_SUB_FRAMEWORK = 0x12
- LC_SUB_UMBRELLA = 0x13
- LC_SUB_CLIENT = 0x14
- LC_SUB_LIBRARY = 0x15
- LC_TWOLEVEL_HINTS = 0x16
- LC_PREBIND_CKSUM = 0x17
- LC_LOAD_WEAK_DYLIB = 0x80000018
- LC_SEGMENT_64 = 0x19
- LC_ROUTINES_64 = 0x1a
- LC_UUID = 0x1b
- LC_RPATH = 0x8000001c
- LC_CODE_SIGNATURE = 0x1d
- LC_SEGMENT_SPLIT_INFO = 0x1e
- LC_REEXPORT_DYLIB = 0x8000001f
- LC_LAZY_LOAD_DYLIB = 0x20
- LC_ENCRYPTION_INFO = 0x21
- LC_DYLD_INFO = 0x22
- LC_DYLD_INFO_ONLY = 0x80000022
- LC_LOAD_UPWARD_DYLIB = 0x80000023
- LC_VERSION_MIN_MACOSX = 0x24
- LC_VERSION_MIN_IPHONEOS = 0x25
- LC_FUNCTION_STARTS = 0x26
- LC_DYLD_ENVIRONMENT = 0x27
- LC_MAIN = 0x80000028
- LC_DATA_IN_CODE = 0x29
- LC_SOURCE_VERSION = 0x2A
- LC_DYLIB_CODE_SIGN_DRS = 0x2B
- LC_ENCRYPTION_INFO_64 = 0x2C
- LC_LINKER_OPTION = 0x2D
- LC_LINKER_OPTIMIZATION_HINT = 0x2E
- LC_VERSION_MIN_TVOS = 0x2F
- LC_VERSION_MIN_WATCHOS = 0x30
- LC_VERSION_NOTE = 0x31
- LC_BUILD_VERSION = 0x32
-)
-
-const (
- S_REGULAR = 0x0
- S_ZEROFILL = 0x1
- S_NON_LAZY_SYMBOL_POINTERS = 0x6
- S_SYMBOL_STUBS = 0x8
- S_MOD_INIT_FUNC_POINTERS = 0x9
- S_ATTR_PURE_INSTRUCTIONS = 0x80000000
- S_ATTR_DEBUG = 0x02000000
- S_ATTR_SOME_INSTRUCTIONS = 0x00000400
-)
-
-const (
- PLATFORM_MACOS MachoPlatform = 1
- PLATFORM_IOS MachoPlatform = 2
- PLATFORM_TVOS MachoPlatform = 3
- PLATFORM_WATCHOS MachoPlatform = 4
- PLATFORM_BRIDGEOS MachoPlatform = 5
-)
-
-// Mach-O file writing
-// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
-
-var machohdr MachoHdr
-
-var load []MachoLoad
-
-var machoPlatform MachoPlatform
-
-var seg [16]MachoSeg
-
-var nseg int
-
-var ndebug int
-
-var nsect int
-
-const (
- SymKindLocal = 0 + iota
- SymKindExtdef
- SymKindUndef
- NumSymKind
-)
-
-var nkind [NumSymKind]int
-
-var sortsym []*sym.Symbol
-
-var nsortsym int
-
-// Amount of space left for adding load commands
-// that refer to dynamic libraries. Because these have
-// to go in the Mach-O header, we can't just pick a
-// "big enough" header size. The initial header is
-// one page, the non-dynamic library stuff takes
-// up about 1300 bytes; we overestimate that as 2k.
-var loadBudget = INITIAL_MACHO_HEADR - 2*1024
-
-func getMachoHdr() *MachoHdr {
- return &machohdr
-}
-
-func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
- if arch.PtrSize == 8 && (ndata&1 != 0) {
- ndata++
- }
-
- load = append(load, MachoLoad{})
- l := &load[len(load)-1]
- l.type_ = type_
- l.data = make([]uint32, ndata)
- return l
-}
-
-func newMachoSeg(name string, msect int) *MachoSeg {
- if nseg >= len(seg) {
- Exitf("too many segs")
- }
-
- s := &seg[nseg]
- nseg++
- s.name = name
- s.msect = uint32(msect)
- s.sect = make([]MachoSect, msect)
- return s
-}
-
-func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
- if seg.nsect >= seg.msect {
- Exitf("too many sects in segment %s", seg.name)
- }
-
- s := &seg.sect[seg.nsect]
- seg.nsect++
- s.name = name
- s.segname = segname
- nsect++
- return s
-}
-
-// Generic linking code.
-
-var dylib []string
-
-var linkoff int64
-
-func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
- o1 := out.Offset()
-
- loadsize := 4 * 4 * ndebug
- for i := range load {
- loadsize += 4 * (len(load[i].data) + 2)
- }
- if arch.PtrSize == 8 {
- loadsize += 18 * 4 * nseg
- loadsize += 20 * 4 * nsect
- } else {
- loadsize += 14 * 4 * nseg
- loadsize += 17 * 4 * nsect
- }
-
- if arch.PtrSize == 8 {
- out.Write32(MH_MAGIC_64)
- } else {
- out.Write32(MH_MAGIC)
- }
- out.Write32(machohdr.cpu)
- out.Write32(machohdr.subcpu)
- if linkmode == LinkExternal {
- out.Write32(MH_OBJECT) /* file type - mach object */
- } else {
- out.Write32(MH_EXECUTE) /* file type - mach executable */
- }
- out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
- out.Write32(uint32(loadsize))
- if nkind[SymKindUndef] == 0 {
- out.Write32(MH_NOUNDEFS) /* flags - no undefines */
- } else {
- out.Write32(0) /* flags */
- }
- if arch.PtrSize == 8 {
- out.Write32(0) /* reserved */
- }
-
- for i := 0; i < nseg; i++ {
- s := &seg[i]
- if arch.PtrSize == 8 {
- out.Write32(LC_SEGMENT_64)
- out.Write32(72 + 80*s.nsect)
- out.WriteStringN(s.name, 16)
- out.Write64(s.vaddr)
- out.Write64(s.vsize)
- out.Write64(s.fileoffset)
- out.Write64(s.filesize)
- out.Write32(s.prot1)
- out.Write32(s.prot2)
- out.Write32(s.nsect)
- out.Write32(s.flag)
- } else {
- out.Write32(LC_SEGMENT)
- out.Write32(56 + 68*s.nsect)
- out.WriteStringN(s.name, 16)
- out.Write32(uint32(s.vaddr))
- out.Write32(uint32(s.vsize))
- out.Write32(uint32(s.fileoffset))
- out.Write32(uint32(s.filesize))
- out.Write32(s.prot1)
- out.Write32(s.prot2)
- out.Write32(s.nsect)
- out.Write32(s.flag)
- }
-
- for j := uint32(0); j < s.nsect; j++ {
- t := &s.sect[j]
- if arch.PtrSize == 8 {
- out.WriteStringN(t.name, 16)
- out.WriteStringN(t.segname, 16)
- out.Write64(t.addr)
- out.Write64(t.size)
- out.Write32(t.off)
- out.Write32(t.align)
- out.Write32(t.reloc)
- out.Write32(t.nreloc)
- out.Write32(t.flag)
- out.Write32(t.res1) /* reserved */
- out.Write32(t.res2) /* reserved */
- out.Write32(0) /* reserved */
- } else {
- out.WriteStringN(t.name, 16)
- out.WriteStringN(t.segname, 16)
- out.Write32(uint32(t.addr))
- out.Write32(uint32(t.size))
- out.Write32(t.off)
- out.Write32(t.align)
- out.Write32(t.reloc)
- out.Write32(t.nreloc)
- out.Write32(t.flag)
- out.Write32(t.res1) /* reserved */
- out.Write32(t.res2) /* reserved */
- }
- }
- }
-
- for i := range load {
- l := &load[i]
- out.Write32(l.type_)
- out.Write32(4 * (uint32(len(l.data)) + 2))
- for j := 0; j < len(l.data); j++ {
- out.Write32(l.data[j])
- }
- }
-
- return int(out.Offset() - o1)
-}
-
-func (ctxt *Link) domacho() {
- if *FlagD {
- return
- }
-
- // Copy platform load command.
- for _, h := range hostobj {
- load, err := hostobjMachoPlatform(&h)
- if err != nil {
- Exitf("%v", err)
- }
- if load != nil {
- machoPlatform = load.platform
- ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data)))
- copy(ml.data, load.cmd.data)
- break
- }
- }
- if machoPlatform == 0 {
- switch ctxt.Arch.Family {
- default:
- machoPlatform = PLATFORM_MACOS
- if ctxt.LinkMode == LinkInternal {
- // For lldb, must say LC_VERSION_MIN_MACOSX or else
- // it won't know that this Mach-O binary is from OS X
- // (could be iOS or WatchOS instead).
- // Go on iOS uses linkmode=external, and linkmode=external
- // adds this itself. So we only need this code for linkmode=internal
- // and we can assume OS X.
- //
- // See golang.org/issues/12941.
- //
- // The version must be at least 10.9; see golang.org/issues/30488.
- ml := newMachoLoad(ctxt.Arch, LC_VERSION_MIN_MACOSX, 2)
- ml.data[0] = 10<<16 | 9<<8 | 0<<0 // OS X version 10.9.0
- ml.data[1] = 10<<16 | 9<<8 | 0<<0 // SDK 10.9.0
- }
- case sys.ARM, sys.ARM64:
- machoPlatform = PLATFORM_IOS
- }
- }
-
- // empirically, string table must begin with " \x00".
- s := ctxt.Syms.Lookup(".machosymstr", 0)
-
- s.Type = sym.SMACHOSYMSTR
- s.Attr |= sym.AttrReachable
- s.AddUint8(' ')
- s.AddUint8('\x00')
-
- s = ctxt.Syms.Lookup(".machosymtab", 0)
- s.Type = sym.SMACHOSYMTAB
- s.Attr |= sym.AttrReachable
-
- if ctxt.LinkMode != LinkExternal {
- s := ctxt.Syms.Lookup(".plt", 0) // will be __symbol_stub
- s.Type = sym.SMACHOPLT
- s.Attr |= sym.AttrReachable
-
- s = ctxt.Syms.Lookup(".got", 0) // will be __nl_symbol_ptr
- s.Type = sym.SMACHOGOT
- s.Attr |= sym.AttrReachable
- s.Align = 4
-
- s = ctxt.Syms.Lookup(".linkedit.plt", 0) // indirect table for .plt
- s.Type = sym.SMACHOINDIRECTPLT
- s.Attr |= sym.AttrReachable
-
- s = ctxt.Syms.Lookup(".linkedit.got", 0) // indirect table for .got
- s.Type = sym.SMACHOINDIRECTGOT
- s.Attr |= sym.AttrReachable
- }
-
- // Add a dummy symbol that will become the __asm marker section.
- if ctxt.LinkMode == LinkExternal {
- s := ctxt.Syms.Lookup(".llvmasm", 0)
- s.Type = sym.SMACHO
- s.Attr |= sym.AttrReachable
- s.AddUint8(0)
- }
-}
-
-func machoadddynlib(lib string, linkmode LinkMode) {
- if seenlib[lib] || linkmode == LinkExternal {
- return
- }
- seenlib[lib] = true
-
- // Will need to store the library name rounded up
- // and 24 bytes of header metadata. If not enough
- // space, grab another page of initial space at the
- // beginning of the output file.
- loadBudget -= (len(lib)+7)/8*8 + 24
-
- if loadBudget < 0 {
- HEADR += 4096
- *FlagTextAddr += 4096
- loadBudget += 4096
- }
-
- dylib = append(dylib, lib)
-}
-
-func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
- buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
-
- var msect *MachoSect
- if sect.Rwx&1 == 0 && segname != "__DWARF" && (ctxt.Arch.Family == sys.ARM64 ||
- ctxt.Arch.Family == sys.ARM ||
- (ctxt.Arch.Family == sys.AMD64 && ctxt.BuildMode != BuildModeExe)) {
- // Darwin external linker on arm and arm64, and on amd64 in c-shared/c-archive buildmode
- // complains about absolute relocs in __TEXT, so if the section is not
- // executable, put it in __DATA segment.
- msect = newMachoSect(mseg, buf, "__DATA")
- } else {
- msect = newMachoSect(mseg, buf, segname)
- }
-
- if sect.Rellen > 0 {
- msect.reloc = uint32(sect.Reloff)
- msect.nreloc = uint32(sect.Rellen / 8)
- }
-
- for 1<<msect.align < sect.Align {
- msect.align++
- }
- msect.addr = sect.Vaddr
- msect.size = sect.Length
-
- if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
- // data in file
- if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
- Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name)
- }
- msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
- } else {
- msect.off = 0
- msect.flag |= S_ZEROFILL
- }
-
- if sect.Rwx&1 != 0 {
- msect.flag |= S_ATTR_SOME_INSTRUCTIONS
- }
-
- if sect.Name == ".text" {
- msect.flag |= S_ATTR_PURE_INSTRUCTIONS
- }
-
- if sect.Name == ".plt" {
- msect.name = "__symbol_stub1"
- msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
- msect.res1 = 0 //nkind[SymKindLocal];
- msect.res2 = 6
- }
-
- if sect.Name == ".got" {
- msect.name = "__nl_symbol_ptr"
- msect.flag = S_NON_LAZY_SYMBOL_POINTERS
- msect.res1 = uint32(ctxt.Syms.Lookup(".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
- }
-
- if sect.Name == ".init_array" {
- msect.name = "__mod_init_func"
- msect.flag = S_MOD_INIT_FUNC_POINTERS
- }
-
- // Some platforms such as watchOS and tvOS require binaries with
- // bitcode enabled. The Go toolchain can't output bitcode, so use
- // a marker section in the __LLVM segment, "__asm", to tell the Apple
- // toolchain that the Go text came from assembler and thus has no
- // bitcode. This is not true, but Kotlin/Native, Rust and Flutter
- // are also using this trick.
- if sect.Name == ".llvmasm" {
- msect.name = "__asm"
- msect.segname = "__LLVM"
- }
-
- if segname == "__DWARF" {
- msect.flag |= S_ATTR_DEBUG
- }
-}
-
-func Asmbmacho(ctxt *Link) {
- /* apple MACH */
- va := *FlagTextAddr - int64(HEADR)
-
- mh := getMachoHdr()
- switch ctxt.Arch.Family {
- default:
- Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
-
- case sys.ARM:
- mh.cpu = MACHO_CPU_ARM
- mh.subcpu = MACHO_SUBCPU_ARMV7
-
- case sys.AMD64:
- mh.cpu = MACHO_CPU_AMD64
- mh.subcpu = MACHO_SUBCPU_X86
-
- case sys.ARM64:
- mh.cpu = MACHO_CPU_ARM64
- mh.subcpu = MACHO_SUBCPU_ARM64_ALL
-
- case sys.I386:
- mh.cpu = MACHO_CPU_386
- mh.subcpu = MACHO_SUBCPU_X86
- }
-
- var ms *MachoSeg
- if ctxt.LinkMode == LinkExternal {
- /* segment for entire file */
- ms = newMachoSeg("", 40)
-
- ms.fileoffset = Segtext.Fileoff
- ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
- ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
- }
-
- /* segment for zero page */
- if ctxt.LinkMode != LinkExternal {
- ms = newMachoSeg("__PAGEZERO", 0)
- ms.vsize = uint64(va)
- }
-
- /* text */
- v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound))
-
- if ctxt.LinkMode != LinkExternal {
- ms = newMachoSeg("__TEXT", 20)
- ms.vaddr = uint64(va)
- ms.vsize = uint64(v)
- ms.fileoffset = 0
- ms.filesize = uint64(v)
- ms.prot1 = 7
- ms.prot2 = 5
- }
-
- for _, sect := range Segtext.Sections {
- machoshbits(ctxt, ms, sect, "__TEXT")
- }
-
- /* data */
- if ctxt.LinkMode != LinkExternal {
- w := int64(Segdata.Length)
- ms = newMachoSeg("__DATA", 20)
- ms.vaddr = uint64(va) + uint64(v)
- ms.vsize = uint64(w)
- ms.fileoffset = uint64(v)
- ms.filesize = Segdata.Filelen
- ms.prot1 = 3
- ms.prot2 = 3
- }
-
- for _, sect := range Segdata.Sections {
- machoshbits(ctxt, ms, sect, "__DATA")
- }
-
- /* dwarf */
- if !*FlagW {
- if ctxt.LinkMode != LinkExternal {
- ms = newMachoSeg("__DWARF", 20)
- ms.vaddr = Segdwarf.Vaddr
- ms.vsize = 0
- ms.fileoffset = Segdwarf.Fileoff
- ms.filesize = Segdwarf.Filelen
- }
- for _, sect := range Segdwarf.Sections {
- machoshbits(ctxt, ms, sect, "__DWARF")
- }
- }
-
- if ctxt.LinkMode != LinkExternal {
- switch ctxt.Arch.Family {
- default:
- Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
-
- case sys.ARM:
- ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 17+2)
- ml.data[0] = 1 /* thread type */
- ml.data[1] = 17 /* word count */
- ml.data[2+15] = uint32(Entryvalue(ctxt)) /* start pc */
-
- case sys.AMD64:
- ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2)
- ml.data[0] = 4 /* thread type */
- ml.data[1] = 42 /* word count */
- ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
- ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
-
- case sys.ARM64:
- ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 68+2)
- ml.data[0] = 6 /* thread type */
- ml.data[1] = 68 /* word count */
- ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */
- ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32)
-
- case sys.I386:
- ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 16+2)
- ml.data[0] = 1 /* thread type */
- ml.data[1] = 16 /* word count */
- ml.data[2+10] = uint32(Entryvalue(ctxt)) /* start pc */
- }
- }
-
- if !*FlagD {
- // must match domacholink below
- s1 := ctxt.Syms.Lookup(".machosymtab", 0)
- s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
- s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
- s4 := ctxt.Syms.Lookup(".machosymstr", 0)
-
- if ctxt.LinkMode != LinkExternal {
- ms := newMachoSeg("__LINKEDIT", 0)
- ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(*FlagRound)))
- ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
- ms.fileoffset = uint64(linkoff)
- ms.filesize = ms.vsize
- ms.prot1 = 7
- ms.prot2 = 3
- }
-
- ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
- ml.data[0] = uint32(linkoff) /* symoff */
- ml.data[1] = uint32(nsortsym) /* nsyms */
- ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */
- ml.data[3] = uint32(s4.Size) /* strsize */
-
- machodysymtab(ctxt)
-
- if ctxt.LinkMode != LinkExternal {
- ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
- ml.data[0] = 12 /* offset to string */
- stringtouint32(ml.data[1:], "/usr/lib/dyld")
-
- for _, lib := range dylib {
- ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
- ml.data[0] = 24 /* offset of string from beginning of load */
- ml.data[1] = 0 /* time stamp */
- ml.data[2] = 0 /* version */
- ml.data[3] = 0 /* compatibility version */
- stringtouint32(ml.data[4:], lib)
- }
- }
- }
-
- a := machowrite(ctxt.Arch, ctxt.Out, ctxt.LinkMode)
- if int32(a) > HEADR {
- Exitf("HEADR too small: %d > %d", a, HEADR)
- }
-}
-
-func symkind(s *sym.Symbol) int {
- if s.Type == sym.SDYNIMPORT {
- return SymKindUndef
- }
- if s.Attr.CgoExport() {
- return SymKindExtdef
- }
- return SymKindLocal
-}
-
-func addsym(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) {
- if s == nil {
- return
- }
-
- switch type_ {
- default:
- return
-
- case DataSym, BSSSym, TextSym:
- break
- }
-
- if sortsym != nil {
- sortsym[nsortsym] = s
- nkind[symkind(s)]++
- }
-
- nsortsym++
-}
-
-type machoscmp []*sym.Symbol
-
-func (x machoscmp) Len() int {
- return len(x)
-}
-
-func (x machoscmp) Swap(i, j int) {
- x[i], x[j] = x[j], x[i]
-}
-
-func (x machoscmp) Less(i, j int) bool {
- s1 := x[i]
- s2 := x[j]
-
- k1 := symkind(s1)
- k2 := symkind(s2)
- if k1 != k2 {
- return k1 < k2
- }
-
- return s1.Extname() < s2.Extname()
-}
-
-func machogenasmsym(ctxt *Link) {
- genasmsym(ctxt, addsym)
- for _, s := range ctxt.Syms.Allsym {
- // Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
- if s.Type == sym.SDYNIMPORT && s.Dynimplib() == "/usr/lib/libSystem.B.dylib" {
- // But only on macOS.
- if machoPlatform == PLATFORM_MACOS {
- switch n := s.Extname(); n {
- case "fdopendir":
- switch objabi.GOARCH {
- case "amd64":
- s.SetExtname(n + "$INODE64")
- case "386":
- s.SetExtname(n + "$INODE64$UNIX2003")
- }
- case "readdir_r", "getfsstat":
- switch objabi.GOARCH {
- case "amd64", "386":
- s.SetExtname(n + "$INODE64")
- }
- }
- }
- }
-
- if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ || s.Type == sym.SUNDEFEXT {
- if s.Attr.Reachable() {
- addsym(ctxt, s, "", DataSym, 0, nil)
- }
- }
- }
-}
-
-func machosymorder(ctxt *Link) {
- // On Mac OS X Mountain Lion, we must sort exported symbols
- // So we sort them here and pre-allocate dynid for them
- // See https://golang.org/issue/4029
- for i := range dynexp {
- dynexp[i].Attr |= sym.AttrReachable
- }
- machogenasmsym(ctxt)
- sortsym = make([]*sym.Symbol, nsortsym)
- nsortsym = 0
- machogenasmsym(ctxt)
- sort.Sort(machoscmp(sortsym[:nsortsym]))
- for i := 0; i < nsortsym; i++ {
- sortsym[i].Dynid = int32(i)
- }
-}
-
-// machoShouldExport reports whether a symbol needs to be exported.
-//
-// When dynamically linking, all non-local variables and plugin-exported
-// symbols need to be exported.
-func machoShouldExport(ctxt *Link, s *sym.Symbol) bool {
- if !ctxt.DynlinkingGo() || s.Attr.Local() {
- return false
- }
- if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(s.Extname(), objabi.PathToPrefix(*flagPluginPath)) {
- return true
- }
- if strings.HasPrefix(s.Name, "go.itab.") {
- return true
- }
- if strings.HasPrefix(s.Name, "type.") && !strings.HasPrefix(s.Name, "type..") {
- // reduce runtime typemap pressure, but do not
- // export alg functions (type..*), as these
- // appear in pclntable.
- return true
- }
- if strings.HasPrefix(s.Name, "go.link.pkghash") {
- return true
- }
- return s.Type >= sym.SFirstWritable // only writable sections
-}
-
-func machosymtab(ctxt *Link) {
- symtab := ctxt.Syms.Lookup(".machosymtab", 0)
- symstr := ctxt.Syms.Lookup(".machosymstr", 0)
-
- for i := 0; i < nsortsym; i++ {
- s := sortsym[i]
- symtab.AddUint32(ctxt.Arch, uint32(symstr.Size))
-
- export := machoShouldExport(ctxt, s)
- isGoSymbol := strings.Contains(s.Extname(), ".")
-
- // In normal buildmodes, only add _ to C symbols, as
- // Go symbols have dot in the name.
- //
- // Do not export C symbols in plugins, as runtime C
- // symbols like crosscall2 are in pclntab and end up
- // pointing at the host binary, breaking unwinding.
- // See Issue #18190.
- cexport := !isGoSymbol && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s))
- if cexport || export || isGoSymbol {
- symstr.AddUint8('_')
- }
-
- // replace "·" as ".", because DTrace cannot handle it.
- Addstring(symstr, strings.Replace(s.Extname(), "·", ".", -1))
-
- if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ || s.Type == sym.SUNDEFEXT {
- symtab.AddUint8(0x01) // type N_EXT, external symbol
- symtab.AddUint8(0) // no section
- symtab.AddUint16(ctxt.Arch, 0) // desc
- symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
- } else {
- if s.Attr.CgoExport() || export {
- symtab.AddUint8(0x0f)
- } else {
- symtab.AddUint8(0x0e)
- }
- o := s
- for o.Outer != nil {
- o = o.Outer
- }
- if o.Sect == nil {
- Errorf(s, "missing section for symbol")
- symtab.AddUint8(0)
- } else {
- symtab.AddUint8(uint8(o.Sect.Extnum))
- }
- symtab.AddUint16(ctxt.Arch, 0) // desc
- symtab.AddUintXX(ctxt.Arch, uint64(Symaddr(s)), ctxt.Arch.PtrSize)
- }
- }
-}
-
-func machodysymtab(ctxt *Link) {
- ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
-
- n := 0
- ml.data[0] = uint32(n) /* ilocalsym */
- ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
- n += nkind[SymKindLocal]
-
- ml.data[2] = uint32(n) /* iextdefsym */
- ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
- n += nkind[SymKindExtdef]
-
- ml.data[4] = uint32(n) /* iundefsym */
- ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
-
- ml.data[6] = 0 /* tocoffset */
- ml.data[7] = 0 /* ntoc */
- ml.data[8] = 0 /* modtaboff */
- ml.data[9] = 0 /* nmodtab */
- ml.data[10] = 0 /* extrefsymoff */
- ml.data[11] = 0 /* nextrefsyms */
-
- // must match domacholink below
- s1 := ctxt.Syms.Lookup(".machosymtab", 0)
-
- s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
- s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
- ml.data[12] = uint32(linkoff + s1.Size) /* indirectsymoff */
- ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */
-
- ml.data[14] = 0 /* extreloff */
- ml.data[15] = 0 /* nextrel */
- ml.data[16] = 0 /* locreloff */
- ml.data[17] = 0 /* nlocrel */
-}
-
-func Domacholink(ctxt *Link) int64 {
- machosymtab(ctxt)
-
- // write data that will be linkedit section
- s1 := ctxt.Syms.Lookup(".machosymtab", 0)
-
- s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
- s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
- s4 := ctxt.Syms.Lookup(".machosymstr", 0)
-
- // Force the linkedit section to end on a 16-byte
- // boundary. This allows pure (non-cgo) Go binaries
- // to be code signed correctly.
- //
- // Apple's codesign_allocate (a helper utility for
- // the codesign utility) can do this fine itself if
- // it is run on a dynamic Mach-O binary. However,
- // when it is run on a pure (non-cgo) Go binary, where
- // the linkedit section is mostly empty, it fails to
- // account for the extra padding that it itself adds
- // when adding the LC_CODE_SIGNATURE load command
- // (which must be aligned on a 16-byte boundary).
- //
- // By forcing the linkedit section to end on a 16-byte
- // boundary, codesign_allocate will not need to apply
- // any alignment padding itself, working around the
- // issue.
- for s4.Size%16 != 0 {
- s4.AddUint8(0)
- }
-
- size := int(s1.Size + s2.Size + s3.Size + s4.Size)
-
- if size > 0 {
- linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
- ctxt.Out.SeekSet(linkoff)
-
- ctxt.Out.Write(s1.P[:s1.Size])
- ctxt.Out.Write(s2.P[:s2.Size])
- ctxt.Out.Write(s3.P[:s3.Size])
- ctxt.Out.Write(s4.P[:s4.Size])
- }
-
- return Rnd(int64(size), int64(*FlagRound))
-}
-
-func machorelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
- // If main section has no bits, nothing to relocate.
- if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
- return
- }
-
- sect.Reloff = uint64(ctxt.Out.Offset())
- for i, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if uint64(s.Value) >= sect.Vaddr {
- syms = syms[i:]
- break
- }
- }
-
- eaddr := int32(sect.Vaddr + sect.Length)
- for _, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if s.Value >= int64(eaddr) {
- break
- }
- for ri := range s.R {
- r := &s.R[ri]
- if r.Done {
- continue
- }
- if r.Xsym == nil {
- Errorf(s, "missing xsym in relocation")
- continue
- }
- if !r.Xsym.Attr.Reachable() {
- Errorf(s, "unreachable reloc %d (%s) target %v", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Xsym.Name)
- }
- if !thearch.Machoreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-sect.Vaddr)) {
- Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Siz, r.Sym.Name)
- }
- }
- }
-
- sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
-}
-
-func Machoemitreloc(ctxt *Link) {
- for ctxt.Out.Offset()&7 != 0 {
- ctxt.Out.Write8(0)
- }
-
- machorelocsect(ctxt, Segtext.Sections[0], ctxt.Textp)
- for _, sect := range Segtext.Sections[1:] {
- machorelocsect(ctxt, sect, datap)
- }
- for _, sect := range Segdata.Sections {
- machorelocsect(ctxt, sect, datap)
- }
- for _, sect := range Segdwarf.Sections {
- machorelocsect(ctxt, sect, dwarfp)
- }
-}
-
-// hostobjMachoPlatform returns the first platform load command found
-// in the host object, if any.
-func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
- f, err := os.Open(h.file)
- if err != nil {
- return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
- }
- defer f.Close()
- sr := io.NewSectionReader(f, h.off, h.length)
- m, err := macho.NewFile(sr)
- if err != nil {
- // Not a valid Mach-O file.
- return nil, nil
- }
- return peekMachoPlatform(m)
-}
-
-// peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION
-// load command found in the Mach-O file, if any.
-func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
- for _, cmd := range m.Loads {
- raw := cmd.Raw()
- ml := MachoLoad{
- type_: m.ByteOrder.Uint32(raw),
- }
- // Skip the type and command length.
- data := raw[8:]
- var p MachoPlatform
- switch ml.type_ {
- case LC_VERSION_MIN_IPHONEOS:
- p = PLATFORM_IOS
- case LC_VERSION_MIN_MACOSX:
- p = PLATFORM_MACOS
- case LC_VERSION_MIN_WATCHOS:
- p = PLATFORM_WATCHOS
- case LC_VERSION_MIN_TVOS:
- p = PLATFORM_TVOS
- case LC_BUILD_VERSION:
- p = MachoPlatform(m.ByteOrder.Uint32(data))
- default:
- continue
- }
- ml.data = make([]uint32, len(data)/4)
- r := bytes.NewReader(data)
- if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
- return nil, err
- }
- return &MachoPlatformLoad{
- platform: p,
- cmd: ml,
- }, nil
- }
- return nil, nil
-}
+++ /dev/null
-// 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)
-}
+++ /dev/null
-// 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)
- }
- })
- }
-}
+++ /dev/null
-// 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)
- }
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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") }
+++ /dev/null
-// 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)
-}
+++ /dev/null
-// 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))
- }
- }
-}
+++ /dev/null
-// 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.
-
-// PE (Portable Executable) file writing
-// https://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
-
-package ld
-
-import (
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/sym"
- "debug/pe"
- "encoding/binary"
- "fmt"
- "sort"
- "strconv"
- "strings"
-)
-
-type IMAGE_IMPORT_DESCRIPTOR struct {
- OriginalFirstThunk uint32
- TimeDateStamp uint32
- ForwarderChain uint32
- Name uint32
- FirstThunk uint32
-}
-
-type IMAGE_EXPORT_DIRECTORY struct {
- Characteristics uint32
- TimeDateStamp uint32
- MajorVersion uint16
- MinorVersion uint16
- Name uint32
- Base uint32
- NumberOfFunctions uint32
- NumberOfNames uint32
- AddressOfFunctions uint32
- AddressOfNames uint32
- AddressOfNameOrdinals uint32
-}
-
-const (
- PEBASE = 0x00400000
-)
-
-var (
- // SectionAlignment must be greater than or equal to FileAlignment.
- // The default is the page size for the architecture.
- PESECTALIGN int64 = 0x1000
-
- // FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
- // The default is 512. If the SectionAlignment is less than
- // the architecture's page size, then FileAlignment must match SectionAlignment.
- PEFILEALIGN int64 = 2 << 8
-)
-
-const (
- IMAGE_SCN_CNT_CODE = 0x00000020
- IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
- IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
- IMAGE_SCN_MEM_EXECUTE = 0x20000000
- IMAGE_SCN_MEM_READ = 0x40000000
- IMAGE_SCN_MEM_WRITE = 0x80000000
- IMAGE_SCN_MEM_DISCARDABLE = 0x2000000
- IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000
- IMAGE_SCN_ALIGN_32BYTES = 0x600000
-)
-
-// TODO(crawshaw): add these constants to debug/pe.
-const (
- // TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 and IMAGE_SYM_DTYPE_FUNCTION is 2
- IMAGE_SYM_TYPE_NULL = 0
- IMAGE_SYM_TYPE_STRUCT = 8
- IMAGE_SYM_DTYPE_FUNCTION = 0x20
- IMAGE_SYM_DTYPE_ARRAY = 0x30
- IMAGE_SYM_CLASS_EXTERNAL = 2
- IMAGE_SYM_CLASS_STATIC = 3
-
- IMAGE_REL_I386_DIR32 = 0x0006
- IMAGE_REL_I386_SECREL = 0x000B
- IMAGE_REL_I386_REL32 = 0x0014
-
- IMAGE_REL_AMD64_ADDR64 = 0x0001
- IMAGE_REL_AMD64_ADDR32 = 0x0002
- IMAGE_REL_AMD64_REL32 = 0x0004
- IMAGE_REL_AMD64_SECREL = 0x000B
-
- 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_SECREL = 0x000F
-
- IMAGE_REL_BASED_HIGHLOW = 3
- IMAGE_REL_BASED_DIR64 = 10
-)
-
-const (
- PeMinimumTargetMajorVersion = 6
- PeMinimumTargetMinorVersion = 1
-)
-
-// DOS stub that prints out
-// "This program cannot be run in DOS mode."
-var dosstub = []uint8{
- 0x4d,
- 0x5a,
- 0x90,
- 0x00,
- 0x03,
- 0x00,
- 0x04,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0xff,
- 0xff,
- 0x00,
- 0x00,
- 0x8b,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x80,
- 0x00,
- 0x00,
- 0x00,
- 0x0e,
- 0x1f,
- 0xba,
- 0x0e,
- 0x00,
- 0xb4,
- 0x09,
- 0xcd,
- 0x21,
- 0xb8,
- 0x01,
- 0x4c,
- 0xcd,
- 0x21,
- 0x54,
- 0x68,
- 0x69,
- 0x73,
- 0x20,
- 0x70,
- 0x72,
- 0x6f,
- 0x67,
- 0x72,
- 0x61,
- 0x6d,
- 0x20,
- 0x63,
- 0x61,
- 0x6e,
- 0x6e,
- 0x6f,
- 0x74,
- 0x20,
- 0x62,
- 0x65,
- 0x20,
- 0x72,
- 0x75,
- 0x6e,
- 0x20,
- 0x69,
- 0x6e,
- 0x20,
- 0x44,
- 0x4f,
- 0x53,
- 0x20,
- 0x6d,
- 0x6f,
- 0x64,
- 0x65,
- 0x2e,
- 0x0d,
- 0x0d,
- 0x0a,
- 0x24,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
-}
-
-type Imp struct {
- s *sym.Symbol
- off uint64
- next *Imp
- argsize int
-}
-
-type Dll struct {
- name string
- nameoff uint64
- thunkoff uint64
- ms *Imp
- next *Dll
-}
-
-var (
- rsrcsym *sym.Symbol
- PESECTHEADR int32
- PEFILEHEADR int32
- pe64 int
- dr *Dll
- dexport [1024]*sym.Symbol
- nexport int
-)
-
-// peStringTable is a COFF string table.
-type peStringTable struct {
- strings []string
- stringsLen int
-}
-
-// size returns size of string table t.
-func (t *peStringTable) size() int {
- // string table starts with 4-byte length at the beginning
- return t.stringsLen + 4
-}
-
-// add adds string str to string table t.
-func (t *peStringTable) add(str string) int {
- off := t.size()
- t.strings = append(t.strings, str)
- t.stringsLen += len(str) + 1 // each string will have 0 appended to it
- return off
-}
-
-// write writes string table t into the output file.
-func (t *peStringTable) write(out *OutBuf) {
- out.Write32(uint32(t.size()))
- for _, s := range t.strings {
- out.WriteString(s)
- out.Write8(0)
- }
-}
-
-// peSection represents section from COFF section table.
-type peSection struct {
- name string
- shortName string
- index int // one-based index into the Section Table
- virtualSize uint32
- virtualAddress uint32
- sizeOfRawData uint32
- pointerToRawData uint32
- pointerToRelocations uint32
- numberOfRelocations uint16
- characteristics uint32
-}
-
-// checkOffset verifies COFF section sect offset in the file.
-func (sect *peSection) checkOffset(off int64) {
- if off != int64(sect.pointerToRawData) {
- Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(off))
- errorexit()
- }
-}
-
-// checkSegment verifies COFF section sect matches address
-// and file offset provided in segment seg.
-func (sect *peSection) checkSegment(seg *sym.Segment) {
- if seg.Vaddr-PEBASE != uint64(sect.virtualAddress) {
- Errorf(nil, "%s.VirtualAddress = %#x, want %#x", sect.name, uint64(int64(sect.virtualAddress)), uint64(int64(seg.Vaddr-PEBASE)))
- errorexit()
- }
- if seg.Fileoff != uint64(sect.pointerToRawData) {
- Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(int64(seg.Fileoff)))
- errorexit()
- }
-}
-
-// pad adds zeros to the section sect. It writes as many bytes
-// as necessary to make section sect.SizeOfRawData bytes long.
-// It assumes that n bytes are already written to the file.
-func (sect *peSection) pad(out *OutBuf, n uint32) {
- out.WriteStringN("", int(sect.sizeOfRawData-n))
-}
-
-// write writes COFF section sect into the output file.
-func (sect *peSection) write(out *OutBuf, linkmode LinkMode) error {
- h := pe.SectionHeader32{
- VirtualSize: sect.virtualSize,
- SizeOfRawData: sect.sizeOfRawData,
- PointerToRawData: sect.pointerToRawData,
- PointerToRelocations: sect.pointerToRelocations,
- NumberOfRelocations: sect.numberOfRelocations,
- Characteristics: sect.characteristics,
- }
- if linkmode != LinkExternal {
- h.VirtualAddress = sect.virtualAddress
- }
- copy(h.Name[:], sect.shortName)
- return binary.Write(out, binary.LittleEndian, h)
-}
-
-// emitRelocations emits the relocation entries for the sect.
-// The actual relocations are emitted by relocfn.
-// This updates the corresponding PE section table entry
-// with the relocation offset and count.
-func (sect *peSection) emitRelocations(out *OutBuf, relocfn func() int) {
- sect.pointerToRelocations = uint32(out.Offset())
- // first entry: extended relocs
- out.Write32(0) // placeholder for number of relocation + 1
- out.Write32(0)
- out.Write16(0)
-
- n := relocfn() + 1
-
- cpos := out.Offset()
- out.SeekSet(int64(sect.pointerToRelocations))
- out.Write32(uint32(n))
- out.SeekSet(cpos)
- if n > 0x10000 {
- n = 0x10000
- sect.characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
- } else {
- sect.pointerToRelocations += 10 // skip the extend reloc entry
- }
- sect.numberOfRelocations = uint16(n - 1)
-}
-
-// peFile is used to build COFF file.
-type peFile struct {
- sections []*peSection
- stringTable peStringTable
- textSect *peSection
- rdataSect *peSection
- dataSect *peSection
- bssSect *peSection
- ctorsSect *peSection
- nextSectOffset uint32
- nextFileOffset uint32
- symtabOffset int64 // offset to the start of symbol table
- symbolCount int // number of symbol table records written
- dataDirectory [16]pe.DataDirectory
-}
-
-// addSection adds section to the COFF file f.
-func (f *peFile) addSection(name string, sectsize int, filesize int) *peSection {
- sect := &peSection{
- name: name,
- shortName: name,
- index: len(f.sections) + 1,
- virtualSize: uint32(sectsize),
- virtualAddress: f.nextSectOffset,
- pointerToRawData: f.nextFileOffset,
- }
- f.nextSectOffset = uint32(Rnd(int64(f.nextSectOffset)+int64(sectsize), PESECTALIGN))
- if filesize > 0 {
- sect.sizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN))
- f.nextFileOffset += sect.sizeOfRawData
- }
- f.sections = append(f.sections, sect)
- return sect
-}
-
-// addDWARFSection adds DWARF section to the COFF file f.
-// This function is similar to addSection, but DWARF section names are
-// longer than 8 characters, so they need to be stored in the string table.
-func (f *peFile) addDWARFSection(name string, size int) *peSection {
- if size == 0 {
- Exitf("DWARF section %q is empty", name)
- }
- // DWARF section names are longer than 8 characters.
- // PE format requires such names to be stored in string table,
- // and section names replaced with slash (/) followed by
- // correspondent string table index.
- // see http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx
- // for details
- off := f.stringTable.add(name)
- h := f.addSection(name, size, size)
- h.shortName = fmt.Sprintf("/%d", off)
- h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
- return h
-}
-
-// addDWARF adds DWARF information to the COFF file f.
-func (f *peFile) addDWARF() {
- if *FlagS { // disable symbol table
- return
- }
- if *FlagW { // disable dwarf
- return
- }
- for _, sect := range Segdwarf.Sections {
- h := f.addDWARFSection(sect.Name, int(sect.Length))
- fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff
- if uint64(h.pointerToRawData) != fileoff {
- Exitf("%s.PointerToRawData = %#x, want %#x", sect.Name, h.pointerToRawData, fileoff)
- }
- }
-}
-
-// addInitArray adds .ctors COFF section to the file f.
-func (f *peFile) addInitArray(ctxt *Link) *peSection {
- // The size below was determined by the specification for array relocations,
- // and by observing what GCC writes here. If the initarray section grows to
- // contain more than one constructor entry, the size will need to be 8 * constructor_count.
- // However, the entire Go runtime is initialized from just one function, so it is unlikely
- // that this will need to grow in the future.
- var size int
- switch objabi.GOARCH {
- default:
- Exitf("peFile.addInitArray: unsupported GOARCH=%q\n", objabi.GOARCH)
- case "386":
- size = 4
- case "amd64":
- size = 8
- case "arm":
- size = 4
- }
- sect := f.addSection(".ctors", size, size)
- sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
- sect.sizeOfRawData = uint32(size)
- ctxt.Out.SeekSet(int64(sect.pointerToRawData))
- sect.checkOffset(ctxt.Out.Offset())
-
- init_entry := ctxt.Syms.Lookup(*flagEntrySymbol, 0)
- addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr
- switch objabi.GOARCH {
- case "386", "arm":
- ctxt.Out.Write32(uint32(addr))
- case "amd64":
- ctxt.Out.Write64(addr)
- }
- return sect
-}
-
-// emitRelocations emits relocation entries for go.o in external linking.
-func (f *peFile) emitRelocations(ctxt *Link) {
- for ctxt.Out.Offset()&7 != 0 {
- ctxt.Out.Write8(0)
- }
-
- // relocsect relocates symbols from first in section sect, and returns
- // the total number of relocations emitted.
- relocsect := func(sect *sym.Section, syms []*sym.Symbol, base uint64) int {
- // If main section has no bits, nothing to relocate.
- if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
- return 0
- }
- relocs := 0
- sect.Reloff = uint64(ctxt.Out.Offset())
- for i, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if uint64(s.Value) >= sect.Vaddr {
- syms = syms[i:]
- break
- }
- }
- eaddr := int32(sect.Vaddr + sect.Length)
- for _, sym := range syms {
- if !sym.Attr.Reachable() {
- continue
- }
- if sym.Value >= int64(eaddr) {
- break
- }
- for ri := range sym.R {
- r := &sym.R[ri]
- if r.Done {
- continue
- }
- if r.Xsym == nil {
- Errorf(sym, "missing xsym in relocation")
- continue
- }
- if r.Xsym.Dynid < 0 {
- Errorf(sym, "reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
- }
- if !thearch.PEreloc1(ctxt.Arch, ctxt.Out, sym, r, int64(uint64(sym.Value+int64(r.Off))-base)) {
- Errorf(sym, "unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
- }
- relocs++
- }
- }
- sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
- return relocs
- }
-
- sects := []struct {
- peSect *peSection
- seg *sym.Segment
- syms []*sym.Symbol
- }{
- {f.textSect, &Segtext, ctxt.Textp},
- {f.rdataSect, &Segrodata, datap},
- {f.dataSect, &Segdata, datap},
- }
- for _, s := range sects {
- s.peSect.emitRelocations(ctxt.Out, func() int {
- var n int
- for _, sect := range s.seg.Sections {
- n += relocsect(sect, s.syms, s.seg.Vaddr)
- }
- return n
- })
- }
-
-dwarfLoop:
- for _, sect := range Segdwarf.Sections {
- for _, pesect := range f.sections {
- if sect.Name == pesect.name {
- pesect.emitRelocations(ctxt.Out, func() int {
- return relocsect(sect, dwarfp, sect.Vaddr)
- })
- continue dwarfLoop
- }
- }
- Errorf(nil, "emitRelocations: could not find %q section", sect.Name)
- }
-
- f.ctorsSect.emitRelocations(ctxt.Out, func() int {
- dottext := ctxt.Syms.Lookup(".text", 0)
- ctxt.Out.Write32(0)
- ctxt.Out.Write32(uint32(dottext.Dynid))
- switch objabi.GOARCH {
- default:
- Errorf(dottext, "unknown architecture for PE: %q\n", objabi.GOARCH)
- case "386":
- ctxt.Out.Write16(IMAGE_REL_I386_DIR32)
- case "amd64":
- ctxt.Out.Write16(IMAGE_REL_AMD64_ADDR64)
- case "arm":
- ctxt.Out.Write16(IMAGE_REL_ARM_ADDR32)
- }
- return 1
- })
-}
-
-// writeSymbol appends symbol s to file f symbol table.
-// It also sets s.Dynid to written symbol number.
-func (f *peFile) writeSymbol(out *OutBuf, s *sym.Symbol, value int64, sectidx int, typ uint16, class uint8) {
- if len(s.Name) > 8 {
- out.Write32(0)
- out.Write32(uint32(f.stringTable.add(s.Name)))
- } else {
- out.WriteStringN(s.Name, 8)
- }
- out.Write32(uint32(value))
- out.Write16(uint16(sectidx))
- out.Write16(typ)
- out.Write8(class)
- out.Write8(0) // no aux entries
-
- s.Dynid = int32(f.symbolCount)
-
- f.symbolCount++
-}
-
-// mapToPESection searches peFile f for s symbol's location.
-// It returns PE section index, and offset within that section.
-func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int, offset int64, err error) {
- if s.Sect == nil {
- return 0, 0, fmt.Errorf("could not map %s symbol with no section", s.Name)
- }
- if s.Sect.Seg == &Segtext {
- return f.textSect.index, int64(uint64(s.Value) - Segtext.Vaddr), nil
- }
- if s.Sect.Seg == &Segrodata {
- return f.rdataSect.index, int64(uint64(s.Value) - Segrodata.Vaddr), nil
- }
- if s.Sect.Seg != &Segdata {
- return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", s.Name)
- }
- v := uint64(s.Value) - Segdata.Vaddr
- if linkmode != LinkExternal {
- return f.dataSect.index, int64(v), nil
- }
- if s.Type == sym.SDATA {
- return f.dataSect.index, int64(v), nil
- }
- // Note: although address of runtime.edata (type sym.SDATA) is at the start of .bss section
- // it still belongs to the .data section, not the .bss section.
- if v < Segdata.Filelen {
- return f.dataSect.index, int64(v), nil
- }
- return f.bssSect.index, int64(v - Segdata.Filelen), nil
-}
-
-// writeSymbols writes all COFF symbol table records.
-func (f *peFile) writeSymbols(ctxt *Link) {
-
- put := func(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) {
- if s == nil {
- return
- }
- if s.Sect == nil && type_ != UndefinedSym {
- return
- }
- switch type_ {
- default:
- return
- case DataSym, BSSSym, TextSym, UndefinedSym:
- }
-
- // Only windows/386 requires underscore prefix on external symbols.
- if ctxt.Arch.Family == sys.I386 &&
- ctxt.LinkMode == LinkExternal &&
- (s.Type == sym.SHOSTOBJ || s.Type == sym.SUNDEFEXT || s.Attr.CgoExport()) {
- s.Name = "_" + s.Name
- }
-
- var typ uint16
- if ctxt.LinkMode == LinkExternal {
- typ = IMAGE_SYM_TYPE_NULL
- } else {
- // TODO: fix IMAGE_SYM_DTYPE_ARRAY value and use following expression, instead of 0x0308
- typ = IMAGE_SYM_DTYPE_ARRAY<<8 + IMAGE_SYM_TYPE_STRUCT
- typ = 0x0308 // "array of structs"
- }
- sect, value, err := f.mapToPESection(s, ctxt.LinkMode)
- if err != nil {
- if type_ == UndefinedSym {
- typ = IMAGE_SYM_DTYPE_FUNCTION
- } else {
- Errorf(s, "addpesym: %v", err)
- }
- }
- class := IMAGE_SYM_CLASS_EXTERNAL
- if s.IsFileLocal() || s.Attr.VisibilityHidden() || s.Attr.Local() {
- class = IMAGE_SYM_CLASS_STATIC
- }
- f.writeSymbol(ctxt.Out, s, value, sect, typ, uint8(class))
- }
-
- if ctxt.LinkMode == LinkExternal {
- // Include section symbols as external, because
- // .ctors and .debug_* section relocations refer to it.
- for _, pesect := range f.sections {
- sym := ctxt.Syms.Lookup(pesect.name, 0)
- f.writeSymbol(ctxt.Out, sym, 0, pesect.index, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC)
- }
- }
-
- genasmsym(ctxt, put)
-}
-
-// writeSymbolTableAndStringTable writes out symbol and string tables for peFile f.
-func (f *peFile) writeSymbolTableAndStringTable(ctxt *Link) {
- f.symtabOffset = ctxt.Out.Offset()
-
- // write COFF symbol table
- if !*FlagS || ctxt.LinkMode == LinkExternal {
- f.writeSymbols(ctxt)
- }
-
- // update COFF file header and section table
- size := f.stringTable.size() + 18*f.symbolCount
- var h *peSection
- if ctxt.LinkMode != LinkExternal {
- // We do not really need .symtab for go.o, and if we have one, ld
- // will also include it in the exe, and that will confuse windows.
- h = f.addSection(".symtab", size, size)
- h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
- h.checkOffset(f.symtabOffset)
- }
-
- // write COFF string table
- f.stringTable.write(ctxt.Out)
- if ctxt.LinkMode != LinkExternal {
- h.pad(ctxt.Out, uint32(size))
- }
-}
-
-// writeFileHeader writes COFF file header for peFile f.
-func (f *peFile) writeFileHeader(ctxt *Link) {
- var fh pe.FileHeader
-
- switch ctxt.Arch.Family {
- default:
- Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
- case sys.AMD64:
- fh.Machine = pe.IMAGE_FILE_MACHINE_AMD64
- case sys.I386:
- fh.Machine = pe.IMAGE_FILE_MACHINE_I386
- case sys.ARM:
- fh.Machine = pe.IMAGE_FILE_MACHINE_ARMNT
- }
-
- fh.NumberOfSections = uint16(len(f.sections))
-
- // Being able to produce identical output for identical input is
- // much more beneficial than having build timestamp in the header.
- fh.TimeDateStamp = 0
-
- if ctxt.LinkMode == LinkExternal {
- fh.Characteristics = pe.IMAGE_FILE_LINE_NUMS_STRIPPED
- } else {
- fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE | pe.IMAGE_FILE_DEBUG_STRIPPED
- switch ctxt.Arch.Family {
- case sys.AMD64, sys.I386:
- if ctxt.BuildMode != BuildModePIE {
- fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
- }
- }
- }
- if pe64 != 0 {
- var oh64 pe.OptionalHeader64
- fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
- fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
- } else {
- var oh pe.OptionalHeader32
- fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
- fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
- }
-
- fh.PointerToSymbolTable = uint32(f.symtabOffset)
- fh.NumberOfSymbols = uint32(f.symbolCount)
-
- binary.Write(ctxt.Out, binary.LittleEndian, &fh)
-}
-
-// writeOptionalHeader writes COFF optional header for peFile f.
-func (f *peFile) writeOptionalHeader(ctxt *Link) {
- var oh pe.OptionalHeader32
- var oh64 pe.OptionalHeader64
-
- if pe64 != 0 {
- oh64.Magic = 0x20b // PE32+
- } else {
- oh.Magic = 0x10b // PE32
- oh.BaseOfData = f.dataSect.virtualAddress
- }
-
- // Fill out both oh64 and oh. We only use one. Oh well.
- oh64.MajorLinkerVersion = 3
- oh.MajorLinkerVersion = 3
- oh64.MinorLinkerVersion = 0
- oh.MinorLinkerVersion = 0
- oh64.SizeOfCode = f.textSect.sizeOfRawData
- oh.SizeOfCode = f.textSect.sizeOfRawData
- oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData
- oh.SizeOfInitializedData = f.dataSect.sizeOfRawData
- oh64.SizeOfUninitializedData = 0
- oh.SizeOfUninitializedData = 0
- if ctxt.LinkMode != LinkExternal {
- oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
- oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
- }
- oh64.BaseOfCode = f.textSect.virtualAddress
- oh.BaseOfCode = f.textSect.virtualAddress
- oh64.ImageBase = PEBASE
- oh.ImageBase = PEBASE
- oh64.SectionAlignment = uint32(PESECTALIGN)
- oh.SectionAlignment = uint32(PESECTALIGN)
- oh64.FileAlignment = uint32(PEFILEALIGN)
- oh.FileAlignment = uint32(PEFILEALIGN)
- oh64.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
- oh.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
- oh64.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
- oh.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
- oh64.MajorImageVersion = 1
- oh.MajorImageVersion = 1
- oh64.MinorImageVersion = 0
- oh.MinorImageVersion = 0
- oh64.MajorSubsystemVersion = PeMinimumTargetMajorVersion
- oh.MajorSubsystemVersion = PeMinimumTargetMajorVersion
- oh64.MinorSubsystemVersion = PeMinimumTargetMinorVersion
- oh.MinorSubsystemVersion = PeMinimumTargetMinorVersion
- oh64.SizeOfImage = f.nextSectOffset
- oh.SizeOfImage = f.nextSectOffset
- oh64.SizeOfHeaders = uint32(PEFILEHEADR)
- oh.SizeOfHeaders = uint32(PEFILEHEADR)
- if windowsgui {
- oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
- oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
- } else {
- oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
- oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
- }
-
- // Mark as having awareness of terminal services, to avoid ancient compatibility hacks.
- oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
- oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
-
- // Enable DEP
- oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
- oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
-
- // The DLL can be relocated at load time.
- switch ctxt.Arch.Family {
- case sys.AMD64, sys.I386:
- if ctxt.BuildMode == BuildModePIE {
- oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
- oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
- }
- case sys.ARM:
- oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
- oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
- }
-
- // Image can handle a high entropy 64-bit virtual address space.
- if ctxt.BuildMode == BuildModePIE {
- oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
- }
-
- // Disable stack growth as we don't want Windows to
- // fiddle with the thread stack limits, which we set
- // ourselves to circumvent the stack checks in the
- // Windows exception dispatcher.
- // Commit size must be strictly less than reserve
- // size otherwise reserve will be rounded up to a
- // larger size, as verified with VMMap.
-
- // On 64-bit, we always reserve 2MB stacks. "Pure" Go code is
- // okay with much smaller stacks, but the syscall package
- // makes it easy to call into arbitrary C code without cgo,
- // and system calls even in "pure" Go code are actually C
- // calls that may need more stack than we think.
- //
- // The default stack reserve size directly affects only the main
- // thread, ctrlhandler thread, and profileloop thread. For
- // these, it must be greater than the stack size assumed by
- // externalthreadhandler.
- //
- // For other threads, the runtime explicitly asks the kernel
- // to use the default stack size so that all stacks are
- // consistent.
- //
- // At thread start, in minit, the runtime queries the OS for
- // the actual stack bounds so that the stack size doesn't need
- // to be hard-coded into the runtime.
- oh64.SizeOfStackReserve = 0x00200000
- if !iscgo {
- oh64.SizeOfStackCommit = 0x00001000
- } else {
- // TODO(brainman): Maybe remove optional header writing altogether for cgo.
- // For cgo it is the external linker that is building final executable.
- // And it probably does not use any information stored in optional header.
- oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages
- }
-
- oh.SizeOfStackReserve = 0x00100000
- if !iscgo {
- oh.SizeOfStackCommit = 0x00001000
- } else {
- oh.SizeOfStackCommit = 0x00100000 - 0x2000 // account for 2 guard pages
- }
-
- oh64.SizeOfHeapReserve = 0x00100000
- oh.SizeOfHeapReserve = 0x00100000
- oh64.SizeOfHeapCommit = 0x00001000
- oh.SizeOfHeapCommit = 0x00001000
- oh64.NumberOfRvaAndSizes = 16
- oh.NumberOfRvaAndSizes = 16
-
- if pe64 != 0 {
- oh64.DataDirectory = f.dataDirectory
- } else {
- oh.DataDirectory = f.dataDirectory
- }
-
- if pe64 != 0 {
- binary.Write(ctxt.Out, binary.LittleEndian, &oh64)
- } else {
- binary.Write(ctxt.Out, binary.LittleEndian, &oh)
- }
-}
-
-var pefile peFile
-
-func Peinit(ctxt *Link) {
- var l int
-
- switch ctxt.Arch.Family {
- // 64-bit architectures
- case sys.AMD64:
- pe64 = 1
- var oh64 pe.OptionalHeader64
- l = binary.Size(&oh64)
-
- // 32-bit architectures
- default:
- var oh pe.OptionalHeader32
- l = binary.Size(&oh)
-
- }
-
- if ctxt.LinkMode == LinkExternal {
- // .rdata section will contain "masks" and "shifts" symbols, and they
- // need to be aligned to 16-bytes. So make all sections aligned
- // to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external
- // linker will honour that requirement.
- PESECTALIGN = 32
- PEFILEALIGN = 0
- }
-
- var sh [16]pe.SectionHeader32
- var fh pe.FileHeader
- PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
- if ctxt.LinkMode != LinkExternal {
- PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
- } else {
- PESECTHEADR = 0
- }
- pefile.nextSectOffset = uint32(PESECTHEADR)
- pefile.nextFileOffset = uint32(PEFILEHEADR)
-
- if ctxt.LinkMode == LinkInternal {
- // some mingw libs depend on this symbol, for example, FindPESectionByName
- ctxt.xdefine("__image_base__", sym.SDATA, PEBASE)
- ctxt.xdefine("_image_base__", sym.SDATA, PEBASE)
- }
-
- HEADR = PEFILEHEADR
- if *FlagTextAddr == -1 {
- *FlagTextAddr = PEBASE + int64(PESECTHEADR)
- }
- if *FlagRound == -1 {
- *FlagRound = int(PESECTALIGN)
- }
-}
-
-func pewrite(ctxt *Link) {
- ctxt.Out.SeekSet(0)
- if ctxt.LinkMode != LinkExternal {
- ctxt.Out.Write(dosstub)
- ctxt.Out.WriteStringN("PE", 4)
- }
-
- pefile.writeFileHeader(ctxt)
-
- pefile.writeOptionalHeader(ctxt)
-
- for _, sect := range pefile.sections {
- sect.write(ctxt.Out, ctxt.LinkMode)
- }
-}
-
-func strput(out *OutBuf, s string) {
- out.WriteString(s)
- out.Write8(0)
- // string must be padded to even size
- if (len(s)+1)%2 != 0 {
- out.Write8(0)
- }
-}
-
-func initdynimport(ctxt *Link) *Dll {
- var d *Dll
-
- dr = nil
- var m *Imp
- for _, s := range ctxt.Syms.Allsym {
- if !s.Attr.Reachable() || s.Type != sym.SDYNIMPORT {
- continue
- }
- for d = dr; d != nil; d = d.next {
- if d.name == s.Dynimplib() {
- m = new(Imp)
- break
- }
- }
-
- if d == nil {
- d = new(Dll)
- d.name = s.Dynimplib()
- d.next = dr
- dr = d
- m = new(Imp)
- }
-
- // Because external link requires properly stdcall decorated name,
- // all external symbols in runtime use %n to denote that the number
- // of uinptrs this function consumes. Store the argsize and discard
- // the %n suffix if any.
- m.argsize = -1
- extName := s.Extname()
- if i := strings.IndexByte(extName, '%'); i >= 0 {
- var err error
- m.argsize, err = strconv.Atoi(extName[i+1:])
- if err != nil {
- Errorf(s, "failed to parse stdcall decoration: %v", err)
- }
- m.argsize *= ctxt.Arch.PtrSize
- s.SetExtname(extName[:i])
- }
-
- m.s = s
- m.next = d.ms
- d.ms = m
- }
-
- if ctxt.LinkMode == LinkExternal {
- // Add real symbol name
- for d := dr; d != nil; d = d.next {
- for m = d.ms; m != nil; m = m.next {
- m.s.Type = sym.SDATA
- m.s.Grow(int64(ctxt.Arch.PtrSize))
- dynName := m.s.Extname()
- // only windows/386 requires stdcall decoration
- if ctxt.Arch.Family == sys.I386 && m.argsize >= 0 {
- dynName += fmt.Sprintf("@%d", m.argsize)
- }
- dynSym := ctxt.Syms.Lookup(dynName, 0)
- dynSym.Attr |= sym.AttrReachable
- dynSym.Type = sym.SHOSTOBJ
- r := m.s.AddRel()
- r.Sym = dynSym
- r.Off = 0
- r.Siz = uint8(ctxt.Arch.PtrSize)
- r.Type = objabi.R_ADDR
- }
- }
- } else {
- dynamic := ctxt.Syms.Lookup(".windynamic", 0)
- dynamic.Attr |= sym.AttrReachable
- dynamic.Type = sym.SWINDOWS
- for d := dr; d != nil; d = d.next {
- for m = d.ms; m != nil; m = m.next {
- m.s.Type = sym.SWINDOWS
- m.s.Attr |= sym.AttrSubSymbol
- m.s.Sub = dynamic.Sub
- dynamic.Sub = m.s
- m.s.Value = dynamic.Size
- dynamic.Size += int64(ctxt.Arch.PtrSize)
- }
-
- dynamic.Size += int64(ctxt.Arch.PtrSize)
- }
- }
-
- return dr
-}
-
-// peimporteddlls returns the gcc command line argument to link all imported
-// DLLs.
-func peimporteddlls() []string {
- var dlls []string
-
- for d := dr; d != nil; d = d.next {
- dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
- }
-
- return dlls
-}
-
-func addimports(ctxt *Link, datsect *peSection) {
- startoff := ctxt.Out.Offset()
- dynamic := ctxt.Syms.Lookup(".windynamic", 0)
-
- // skip import descriptor table (will write it later)
- n := uint64(0)
-
- for d := dr; d != nil; d = d.next {
- n++
- }
- ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
-
- // write dll names
- for d := dr; d != nil; d = d.next {
- d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
- strput(ctxt.Out, d.name)
- }
-
- // write function names
- for d := dr; d != nil; d = d.next {
- for m := d.ms; m != nil; m = m.next {
- m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
- ctxt.Out.Write16(0) // hint
- strput(ctxt.Out, m.s.Extname())
- }
- }
-
- // write OriginalFirstThunks
- oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
-
- n = uint64(ctxt.Out.Offset())
- for d := dr; d != nil; d = d.next {
- d.thunkoff = uint64(ctxt.Out.Offset()) - n
- for m := d.ms; m != nil; m = m.next {
- if pe64 != 0 {
- ctxt.Out.Write64(m.off)
- } else {
- ctxt.Out.Write32(uint32(m.off))
- }
- }
-
- if pe64 != 0 {
- ctxt.Out.Write64(0)
- } else {
- ctxt.Out.Write32(0)
- }
- }
-
- // add pe section and pad it at the end
- n = uint64(ctxt.Out.Offset()) - uint64(startoff)
-
- isect := pefile.addSection(".idata", int(n), int(n))
- isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
- isect.checkOffset(startoff)
- isect.pad(ctxt.Out, uint32(n))
- endoff := ctxt.Out.Offset()
-
- // write FirstThunks (allocated in .data section)
- ftbase := uint64(dynamic.Value) - uint64(datsect.virtualAddress) - PEBASE
-
- ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
- for d := dr; d != nil; d = d.next {
- for m := d.ms; m != nil; m = m.next {
- if pe64 != 0 {
- ctxt.Out.Write64(m.off)
- } else {
- ctxt.Out.Write32(uint32(m.off))
- }
- }
-
- if pe64 != 0 {
- ctxt.Out.Write64(0)
- } else {
- ctxt.Out.Write32(0)
- }
- }
-
- // finally write import descriptor table
- out := ctxt.Out
- out.SeekSet(startoff)
-
- for d := dr; d != nil; d = d.next {
- out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
- out.Write32(0)
- out.Write32(0)
- out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
- out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
- }
-
- out.Write32(0) //end
- out.Write32(0)
- out.Write32(0)
- out.Write32(0)
- out.Write32(0)
-
- // update data directory
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE)
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size)
-
- out.SeekSet(endoff)
-}
-
-type byExtname []*sym.Symbol
-
-func (s byExtname) Len() int { return len(s) }
-func (s byExtname) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s byExtname) Less(i, j int) bool { return s[i].Extname() < s[j].Extname() }
-
-func initdynexport(ctxt *Link) {
- nexport = 0
- for _, s := range ctxt.Syms.Allsym {
- if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() {
- continue
- }
- if nexport+1 > len(dexport) {
- Errorf(s, "pe dynexport table is full")
- errorexit()
- }
-
- dexport[nexport] = s
- nexport++
- }
-
- sort.Sort(byExtname(dexport[:nexport]))
-}
-
-func addexports(ctxt *Link) {
- var e IMAGE_EXPORT_DIRECTORY
-
- size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
- for i := 0; i < nexport; i++ {
- size += len(dexport[i].Extname()) + 1
- }
-
- if nexport == 0 {
- return
- }
-
- sect := pefile.addSection(".edata", size, size)
- sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
- sect.checkOffset(ctxt.Out.Offset())
- va := int(sect.virtualAddress)
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
-
- vaName := va + binary.Size(&e) + nexport*4
- vaAddr := va + binary.Size(&e)
- vaNa := va + binary.Size(&e) + nexport*8
-
- e.Characteristics = 0
- e.MajorVersion = 0
- e.MinorVersion = 0
- e.NumberOfFunctions = uint32(nexport)
- e.NumberOfNames = uint32(nexport)
- e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
- e.Base = 1
- e.AddressOfFunctions = uint32(vaAddr)
- e.AddressOfNames = uint32(vaName)
- e.AddressOfNameOrdinals = uint32(vaNa)
-
- out := ctxt.Out
-
- // put IMAGE_EXPORT_DIRECTORY
- binary.Write(out, binary.LittleEndian, &e)
-
- // put EXPORT Address Table
- for i := 0; i < nexport; i++ {
- out.Write32(uint32(dexport[i].Value - PEBASE))
- }
-
- // put EXPORT Name Pointer Table
- v := int(e.Name + uint32(len(*flagOutfile)) + 1)
-
- for i := 0; i < nexport; i++ {
- out.Write32(uint32(v))
- v += len(dexport[i].Extname()) + 1
- }
-
- // put EXPORT Ordinal Table
- for i := 0; i < nexport; i++ {
- out.Write16(uint16(i))
- }
-
- // put Names
- out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
-
- for i := 0; i < nexport; i++ {
- out.WriteStringN(dexport[i].Extname(), len(dexport[i].Extname())+1)
- }
- sect.pad(out, uint32(size))
-}
-
-// peBaseRelocEntry represents a single relocation entry.
-type peBaseRelocEntry struct {
- typeOff uint16
- rel *sym.Reloc
- sym *sym.Symbol // For debug
-}
-
-// peBaseRelocBlock represents a Base Relocation Block. A block
-// is a collection of relocation entries in a page, where each
-// entry describes a single relocation.
-// The block page RVA (Relative Virtual Address) is the index
-// into peBaseRelocTable.blocks.
-type peBaseRelocBlock struct {
- entries []peBaseRelocEntry
-}
-
-// pePages is a type used to store the list of pages for which there
-// are base relocation blocks. This is defined as a type so that
-// it can be sorted.
-type pePages []uint32
-
-func (p pePages) Len() int { return len(p) }
-func (p pePages) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-func (p pePages) Less(i, j int) bool { return p[i] < p[j] }
-
-// A PE base relocation table is a list of blocks, where each block
-// contains relocation information for a single page. The blocks
-// must be emitted in order of page virtual address.
-// See https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-reloc-section-image-only
-type peBaseRelocTable struct {
- blocks map[uint32]peBaseRelocBlock
-
- // pePages is a list of keys into blocks map.
- // It is stored separately for ease of sorting.
- pages pePages
-}
-
-func (rt *peBaseRelocTable) init(ctxt *Link) {
- rt.blocks = make(map[uint32]peBaseRelocBlock)
-}
-
-func (rt *peBaseRelocTable) addentry(ctxt *Link, s *sym.Symbol, r *sym.Reloc) {
- // pageSize is the size in bytes of a page
- // described by a base relocation block.
- const pageSize = 0x1000
- const pageMask = pageSize - 1
-
- addr := s.Value + int64(r.Off) - int64(PEBASE)
- page := uint32(addr &^ pageMask)
- off := uint32(addr & pageMask)
-
- b, ok := rt.blocks[page]
- if !ok {
- rt.pages = append(rt.pages, page)
- }
-
- e := peBaseRelocEntry{
- typeOff: uint16(off & 0xFFF),
- rel: r,
- sym: s,
- }
-
- // Set entry type
- switch r.Siz {
- default:
- Exitf("unsupported relocation size %d\n", r.Siz)
- case 4:
- e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
- case 8:
- e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
- }
-
- b.entries = append(b.entries, e)
- rt.blocks[page] = b
-}
-
-func (rt *peBaseRelocTable) write(ctxt *Link) {
- out := ctxt.Out
-
- // sort the pages array
- sort.Sort(rt.pages)
-
- for _, p := range rt.pages {
- b := rt.blocks[p]
- const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32)
- blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
- out.Write32(p)
- out.Write32(blockSize)
-
- for _, e := range b.entries {
- out.Write16(e.typeOff)
- }
- }
-}
-
-func addPEBaseRelocSym(ctxt *Link, s *sym.Symbol, rt *peBaseRelocTable) {
- for ri := 0; ri < len(s.R); ri++ {
- r := &s.R[ri]
-
- if r.Sym == nil {
- continue
- }
- if !r.Sym.Attr.Reachable() {
- continue
- }
- if r.Type >= objabi.ElfRelocOffset {
- continue
- }
- if r.Siz == 0 { // informational relocation
- continue
- }
- if r.Type == objabi.R_DWARFFILEREF {
- continue
- }
-
- switch r.Type {
- default:
- case objabi.R_ADDR:
- rt.addentry(ctxt, s, r)
- }
- }
-}
-
-func addPEBaseReloc(ctxt *Link) {
- // Arm does not work without base relocation table.
- // 386 and amd64 will only require the table for BuildModePIE.
- switch ctxt.Arch.Family {
- default:
- return
- case sys.I386, sys.AMD64:
- if ctxt.BuildMode != BuildModePIE {
- return
- }
- case sys.ARM:
- }
-
- var rt peBaseRelocTable
- rt.init(ctxt)
-
- // Get relocation information
- for _, s := range ctxt.Textp {
- addPEBaseRelocSym(ctxt, s, &rt)
- }
- for _, s := range datap {
- addPEBaseRelocSym(ctxt, s, &rt)
- }
-
- // Write relocation information
- startoff := ctxt.Out.Offset()
- rt.write(ctxt)
- size := ctxt.Out.Offset() - startoff
-
- // Add a PE section and pad it at the end
- rsect := pefile.addSection(".reloc", int(size), int(size))
- rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
- rsect.checkOffset(startoff)
- rsect.pad(ctxt.Out, uint32(size))
-
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
-}
-
-func (ctxt *Link) dope() {
- initdynimport(ctxt)
- initdynexport(ctxt)
-}
-
-func setpersrc(ctxt *Link, sym *sym.Symbol) {
- if rsrcsym != nil {
- Errorf(sym, "too many .rsrc sections")
- }
-
- rsrcsym = sym
-}
-
-func addpersrc(ctxt *Link) {
- if rsrcsym == nil {
- return
- }
-
- h := pefile.addSection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
- h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
- h.checkOffset(ctxt.Out.Offset())
-
- // relocation
- for ri := range rsrcsym.R {
- r := &rsrcsym.R[ri]
- p := rsrcsym.P[r.Off:]
- val := uint32(int64(h.virtualAddress) + r.Add)
-
- // 32-bit little-endian
- p[0] = byte(val)
-
- p[1] = byte(val >> 8)
- p[2] = byte(val >> 16)
- p[3] = byte(val >> 24)
- }
-
- ctxt.Out.Write(rsrcsym.P)
- h.pad(ctxt.Out, uint32(rsrcsym.Size))
-
- // update data directory
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
-
- pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
-}
-
-func Asmbpe(ctxt *Link) {
- switch ctxt.Arch.Family {
- default:
- Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
- case sys.AMD64, sys.I386, sys.ARM:
- }
-
- t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
- t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
- if ctxt.LinkMode == LinkExternal {
- // some data symbols (e.g. masks) end up in the .text section, and they normally
- // expect larger alignment requirement than the default text section alignment.
- t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
- }
- t.checkSegment(&Segtext)
- pefile.textSect = t
-
- ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
- ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
- if ctxt.LinkMode == LinkExternal {
- // some data symbols (e.g. masks) end up in the .rdata section, and they normally
- // expect larger alignment requirement than the default text section alignment.
- ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
- }
- ro.checkSegment(&Segrodata)
- pefile.rdataSect = ro
-
- var d *peSection
- if ctxt.LinkMode != LinkExternal {
- d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
- d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
- d.checkSegment(&Segdata)
- pefile.dataSect = d
- } else {
- d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
- d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
- d.checkSegment(&Segdata)
- pefile.dataSect = d
-
- b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
- b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
- b.pointerToRawData = 0
- pefile.bssSect = b
- }
-
- pefile.addDWARF()
-
- if ctxt.LinkMode == LinkExternal {
- pefile.ctorsSect = pefile.addInitArray(ctxt)
- }
-
- ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
- if ctxt.LinkMode != LinkExternal {
- addimports(ctxt, d)
- addexports(ctxt)
- addPEBaseReloc(ctxt)
- }
- pefile.writeSymbolTableAndStringTable(ctxt)
- addpersrc(ctxt)
- if ctxt.LinkMode == LinkExternal {
- pefile.emitRelocations(ctxt)
- }
-
- pewrite(ctxt)
-}
+++ /dev/null
-// 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
- }
- }
-
-}
+++ /dev/null
-// 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_")
-}
+++ /dev/null
-// 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()
-}
+++ /dev/null
-// 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.
+++ /dev/null
-// This file is needed to make "go build" work for package with external functions.\r
+++ /dev/null
-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 }()
-}
+++ /dev/null
-package main
-
-import "cmd/oldlink/internal/ld/testdata/issue25459/a"
-
-var Glob int
-
-func main() {
- a.Another()
- Glob += a.ConstIf() + a.CallConstIf()
-}
+++ /dev/null
-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)
-}
+++ /dev/null
-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")
- }
-}
+++ /dev/null
-// 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;
-}
+++ /dev/null
-// 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")
-}
+++ /dev/null
-// 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()
-}
+++ /dev/null
-// 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
- }
-}
+++ /dev/null
-// 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 }
+++ /dev/null
-// 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 ld
-
-import (
- "bytes"
- "cmd/internal/objabi"
- "cmd/oldlink/internal/sym"
- "encoding/binary"
- "io/ioutil"
- "math/bits"
- "path/filepath"
- "sort"
- "strings"
-)
-
-// This file handles all algorithms related to XCOFF files generation.
-// Most of them are adaptations of the ones in cmd/oldlink/internal/pe.go
-// as PE and XCOFF are based on COFF files.
-// XCOFF files generated are 64 bits.
-
-const (
- // Total amount of space to reserve at the start of the file
- // for File Header, Auxiliary Header, and Section Headers.
- // May waste some.
- XCOFFHDRRESERVE = FILHSZ_64 + AOUTHSZ_EXEC64 + SCNHSZ_64*23
- XCOFFSECTALIGN int64 = 32 // base on dump -o
-
- // XCOFF binaries should normally have all its sections position-independent.
- // However, this is not yet possible for .text because of some R_ADDR relocations
- // inside RODATA symbols.
- // .data and .bss are position-independent so their address start inside a unreachable
- // segment during execution to force segfault if something is wrong.
- XCOFFTEXTBASE = 0x100000000 // Start of text address
- XCOFFDATABASE = 0x200000000 // Start of data address
-)
-
-// File Header
-type XcoffFileHdr64 struct {
- Fmagic uint16 // Target machine
- Fnscns uint16 // Number of sections
- Ftimedat int32 // Time and date of file creation
- Fsymptr uint64 // Byte offset to symbol table start
- Fopthdr uint16 // Number of bytes in optional header
- Fflags uint16 // Flags
- Fnsyms int32 // Number of entries in symbol table
-}
-
-const (
- U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF
-)
-
-// Flags that describe the type of the object file.
-const (
- F_RELFLG = 0x0001
- F_EXEC = 0x0002
- F_LNNO = 0x0004
- F_FDPR_PROF = 0x0010
- F_FDPR_OPTI = 0x0020
- F_DSA = 0x0040
- F_VARPG = 0x0100
- F_DYNLOAD = 0x1000
- F_SHROBJ = 0x2000
- F_LOADONLY = 0x4000
-)
-
-// Auxiliary Header
-type XcoffAoutHdr64 struct {
- Omagic int16 // Flags - Ignored If Vstamp Is 1
- Ovstamp int16 // Version
- Odebugger uint32 // Reserved For Debugger
- Otextstart uint64 // Virtual Address Of Text
- Odatastart uint64 // Virtual Address Of Data
- Otoc uint64 // Toc Address
- Osnentry int16 // Section Number For Entry Point
- Osntext int16 // Section Number For Text
- Osndata int16 // Section Number For Data
- Osntoc int16 // Section Number For Toc
- Osnloader int16 // Section Number For Loader
- Osnbss int16 // Section Number For Bss
- Oalgntext int16 // Max Text Alignment
- Oalgndata int16 // Max Data Alignment
- Omodtype [2]byte // Module Type Field
- Ocpuflag uint8 // Bit Flags - Cputypes Of Objects
- Ocputype uint8 // Reserved for CPU type
- Otextpsize uint8 // Requested text page size
- Odatapsize uint8 // Requested data page size
- Ostackpsize uint8 // Requested stack page size
- Oflags uint8 // Flags And TLS Alignment
- Otsize uint64 // Text Size In Bytes
- Odsize uint64 // Data Size In Bytes
- Obsize uint64 // Bss Size In Bytes
- Oentry uint64 // Entry Point Address
- Omaxstack uint64 // Max Stack Size Allowed
- Omaxdata uint64 // Max Data Size Allowed
- Osntdata int16 // Section Number For Tdata Section
- Osntbss int16 // Section Number For Tbss Section
- Ox64flags uint16 // Additional Flags For 64-Bit Objects
- Oresv3a int16 // Reserved
- Oresv3 [2]int32 // Reserved
-}
-
-// Section Header
-type XcoffScnHdr64 struct {
- Sname [8]byte // Section Name
- Spaddr uint64 // Physical Address
- Svaddr uint64 // Virtual Address
- Ssize uint64 // Section Size
- Sscnptr uint64 // File Offset To Raw Data
- Srelptr uint64 // File Offset To Relocation
- Slnnoptr uint64 // File Offset To Line Numbers
- Snreloc uint32 // Number Of Relocation Entries
- Snlnno uint32 // Number Of Line Number Entries
- Sflags uint32 // flags
-}
-
-// Flags defining the section type.
-const (
- STYP_DWARF = 0x0010
- STYP_TEXT = 0x0020
- STYP_DATA = 0x0040
- STYP_BSS = 0x0080
- STYP_EXCEPT = 0x0100
- STYP_INFO = 0x0200
- STYP_TDATA = 0x0400
- STYP_TBSS = 0x0800
- STYP_LOADER = 0x1000
- STYP_DEBUG = 0x2000
- STYP_TYPCHK = 0x4000
- STYP_OVRFLO = 0x8000
-)
-const (
- SSUBTYP_DWINFO = 0x10000 // DWARF info section
- SSUBTYP_DWLINE = 0x20000 // DWARF line-number section
- SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section
- SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section
- SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section
- SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section
- SSUBTYP_DWSTR = 0x70000 // DWARF strings section
- SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section
- SSUBTYP_DWLOC = 0x90000 // DWARF location lists section
- SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section
- SSUBTYP_DWMAC = 0xB0000 // DWARF macros section
-)
-
-// Headers size
-const (
- FILHSZ_32 = 20
- FILHSZ_64 = 24
- AOUTHSZ_EXEC32 = 72
- AOUTHSZ_EXEC64 = 120
- SCNHSZ_32 = 40
- SCNHSZ_64 = 72
- LDHDRSZ_32 = 32
- LDHDRSZ_64 = 56
- LDSYMSZ_64 = 24
- RELSZ_64 = 14
-)
-
-// Type representing all XCOFF symbols.
-type xcoffSym interface {
-}
-
-// Symbol Table Entry
-type XcoffSymEnt64 struct {
- Nvalue uint64 // Symbol value
- Noffset uint32 // Offset of the name in string table or .debug section
- Nscnum int16 // Section number of symbol
- Ntype uint16 // Basic and derived type specification
- Nsclass uint8 // Storage class of symbol
- Nnumaux int8 // Number of auxiliary entries
-}
-
-const SYMESZ = 18
-
-const (
- // Nscnum
- N_DEBUG = -2
- N_ABS = -1
- N_UNDEF = 0
-
- //Ntype
- SYM_V_INTERNAL = 0x1000
- SYM_V_HIDDEN = 0x2000
- SYM_V_PROTECTED = 0x3000
- SYM_V_EXPORTED = 0x4000
- SYM_TYPE_FUNC = 0x0020 // is function
-)
-
-// Storage Class.
-const (
- C_NULL = 0 // Symbol table entry marked for deletion
- C_EXT = 2 // External symbol
- C_STAT = 3 // Static symbol
- C_BLOCK = 100 // Beginning or end of inner block
- C_FCN = 101 // Beginning or end of function
- C_FILE = 103 // Source file name and compiler information
- C_HIDEXT = 107 // Unnamed external symbol
- C_BINCL = 108 // Beginning of include file
- C_EINCL = 109 // End of include file
- C_WEAKEXT = 111 // Weak external symbol
- C_DWARF = 112 // DWARF symbol
- C_GSYM = 128 // Global variable
- C_LSYM = 129 // Automatic variable allocated on stack
- C_PSYM = 130 // Argument to subroutine allocated on stack
- C_RSYM = 131 // Register variable
- C_RPSYM = 132 // Argument to function or procedure stored in register
- C_STSYM = 133 // Statically allocated symbol
- C_BCOMM = 135 // Beginning of common block
- C_ECOML = 136 // Local member of common block
- C_ECOMM = 137 // End of common block
- C_DECL = 140 // Declaration of object
- C_ENTRY = 141 // Alternate entry
- C_FUN = 142 // Function or procedure
- C_BSTAT = 143 // Beginning of static block
- C_ESTAT = 144 // End of static block
- C_GTLS = 145 // Global thread-local variable
- C_STTLS = 146 // Static thread-local variable
-)
-
-// File Auxiliary Entry
-type XcoffAuxFile64 struct {
- Xzeroes uint32 // The name is always in the string table
- Xoffset uint32 // Offset in the string table
- X_pad1 [6]byte
- Xftype uint8 // Source file string type
- X_pad2 [2]byte
- Xauxtype uint8 // Type of auxiliary entry
-}
-
-// Function Auxiliary Entry
-type XcoffAuxFcn64 struct {
- Xlnnoptr uint64 // File pointer to line number
- Xfsize uint32 // Size of function in bytes
- Xendndx uint32 // Symbol table index of next entry
- Xpad uint8 // Unused
- Xauxtype uint8 // Type of auxiliary entry
-}
-
-// csect Auxiliary Entry.
-type XcoffAuxCSect64 struct {
- Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index
- Xparmhash uint32 // Offset of parameter type-check string
- Xsnhash uint16 // .typchk section number
- Xsmtyp uint8 // Symbol alignment and type
- Xsmclas uint8 // Storage-mapping class
- Xscnlenhi uint32 // Upper 4 bytes of length or symbol table index
- Xpad uint8 // Unused
- Xauxtype uint8 // Type of auxiliary entry
-}
-
-// DWARF Auxiliary Entry
-type XcoffAuxDWARF64 struct {
- Xscnlen uint64 // Length of this symbol section
- X_pad [9]byte
- Xauxtype uint8 // Type of auxiliary entry
-}
-
-// Auxiliary type
-const (
- _AUX_EXCEPT = 255
- _AUX_FCN = 254
- _AUX_SYM = 253
- _AUX_FILE = 252
- _AUX_CSECT = 251
- _AUX_SECT = 250
-)
-
-// Xftype field
-const (
- XFT_FN = 0 // Source File Name
- XFT_CT = 1 // Compile Time Stamp
- XFT_CV = 2 // Compiler Version Number
- XFT_CD = 128 // Compiler Defined Information/
-
-)
-
-// Symbol type field.
-const (
- XTY_ER = 0 // External reference
- XTY_SD = 1 // Section definition
- XTY_LD = 2 // Label definition
- XTY_CM = 3 // Common csect definition
- XTY_WK = 0x8 // Weak symbol
- XTY_EXP = 0x10 // Exported symbol
- XTY_ENT = 0x20 // Entry point symbol
- XTY_IMP = 0x40 // Imported symbol
-)
-
-// Storage-mapping class.
-const (
- XMC_PR = 0 // Program code
- XMC_RO = 1 // Read-only constant
- XMC_DB = 2 // Debug dictionary table
- XMC_TC = 3 // TOC entry
- XMC_UA = 4 // Unclassified
- XMC_RW = 5 // Read/Write data
- XMC_GL = 6 // Global linkage
- XMC_XO = 7 // Extended operation
- XMC_SV = 8 // 32-bit supervisor call descriptor
- XMC_BS = 9 // BSS class
- XMC_DS = 10 // Function descriptor
- XMC_UC = 11 // Unnamed FORTRAN common
- XMC_TC0 = 15 // TOC anchor
- XMC_TD = 16 // Scalar data entry in the TOC
- XMC_SV64 = 17 // 64-bit supervisor call descriptor
- XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit
- XMC_TL = 20 // Read/Write thread-local data
- XMC_UL = 21 // Read/Write thread-local data (.tbss)
- XMC_TE = 22 // TOC entry
-)
-
-// Loader Header
-type XcoffLdHdr64 struct {
- Lversion int32 // Loader section version number
- Lnsyms int32 // Number of symbol table entries
- Lnreloc int32 // Number of relocation table entries
- Listlen uint32 // Length of import file ID string table
- Lnimpid int32 // Number of import file IDs
- Lstlen uint32 // Length of string table
- Limpoff uint64 // Offset to start of import file IDs
- Lstoff uint64 // Offset to start of string table
- Lsymoff uint64 // Offset to start of symbol table
- Lrldoff uint64 // Offset to start of relocation entries
-}
-
-// Loader Symbol
-type XcoffLdSym64 struct {
- Lvalue uint64 // Address field
- Loffset uint32 // Byte offset into string table of symbol name
- Lscnum int16 // Section number containing symbol
- Lsmtype int8 // Symbol type, export, import flags
- Lsmclas int8 // Symbol storage class
- Lifile int32 // Import file ID; ordinal of import file IDs
- Lparm uint32 // Parameter type-check field
-}
-
-type xcoffLoaderSymbol struct {
- sym *sym.Symbol
- smtype int8
- smclas int8
-}
-
-type XcoffLdImportFile64 struct {
- Limpidpath string
- Limpidbase string
- Limpidmem string
-}
-
-type XcoffLdRel64 struct {
- Lvaddr uint64 // Address Field
- Lrtype uint16 // Relocation Size and Type
- Lrsecnm int16 // Section Number being relocated
- Lsymndx int32 // Loader-Section symbol table index
-}
-
-// xcoffLoaderReloc holds information about a relocation made by the loader.
-type xcoffLoaderReloc struct {
- sym *sym.Symbol
- rel *sym.Reloc
- rtype uint16
- symndx int32
-}
-
-const (
- XCOFF_R_POS = 0x00 // A(sym) Positive Relocation
- XCOFF_R_NEG = 0x01 // -A(sym) Negative Relocation
- XCOFF_R_REL = 0x02 // A(sym-*) Relative to self
- XCOFF_R_TOC = 0x03 // A(sym-TOC) Relative to TOC
- XCOFF_R_TRL = 0x12 // A(sym-TOC) TOC Relative indirect load.
-
- XCOFF_R_TRLA = 0x13 // A(sym-TOC) TOC Rel load address. modifiable inst
- XCOFF_R_GL = 0x05 // A(external TOC of sym) Global Linkage
- XCOFF_R_TCL = 0x06 // A(local TOC of sym) Local object TOC address
- XCOFF_R_RL = 0x0C // A(sym) Pos indirect load. modifiable instruction
- XCOFF_R_RLA = 0x0D // A(sym) Pos Load Address. modifiable instruction
- XCOFF_R_REF = 0x0F // AL0(sym) Non relocating ref. No garbage collect
- XCOFF_R_BA = 0x08 // A(sym) Branch absolute. Cannot modify instruction
- XCOFF_R_RBA = 0x18 // A(sym) Branch absolute. modifiable instruction
- XCOFF_R_BR = 0x0A // A(sym-*) Branch rel to self. non modifiable
- XCOFF_R_RBR = 0x1A // A(sym-*) Branch rel to self. modifiable instr
-
- XCOFF_R_TLS = 0x20 // General-dynamic reference to TLS symbol
- XCOFF_R_TLS_IE = 0x21 // Initial-exec reference to TLS symbol
- XCOFF_R_TLS_LD = 0x22 // Local-dynamic reference to TLS symbol
- XCOFF_R_TLS_LE = 0x23 // Local-exec reference to TLS symbol
- XCOFF_R_TLSM = 0x24 // Module reference to TLS symbol
- XCOFF_R_TLSML = 0x25 // Module reference to local (own) module
-
- XCOFF_R_TOCU = 0x30 // Relative to TOC - high order bits
- XCOFF_R_TOCL = 0x31 // Relative to TOC - low order bits
-)
-
-type XcoffLdStr64 struct {
- size uint16
- name string
-}
-
-// xcoffFile is used to build XCOFF file.
-type xcoffFile struct {
- xfhdr XcoffFileHdr64
- xahdr XcoffAoutHdr64
- sections []*XcoffScnHdr64
- sectText *XcoffScnHdr64
- sectData *XcoffScnHdr64
- sectBss *XcoffScnHdr64
- stringTable xcoffStringTable
- sectNameToScnum map[string]int16
- loaderSize uint64
- symtabOffset int64 // offset to the start of symbol table
- symbolCount uint32 // number of symbol table records written
- symtabSym []xcoffSym // XCOFF symbols for the symbol table
- dynLibraries map[string]int // Dynamic libraries in .loader section. The integer represents its import file number (- 1)
- loaderSymbols []*xcoffLoaderSymbol // symbols inside .loader symbol table
- loaderReloc []*xcoffLoaderReloc // Reloc that must be made inside loader
-}
-
-// Var used by XCOFF Generation algorithms
-var (
- xfile xcoffFile
-)
-
-// xcoffStringTable is a XCOFF string table.
-type xcoffStringTable struct {
- strings []string
- stringsLen int
-}
-
-// size returns size of string table t.
-func (t *xcoffStringTable) size() int {
- // string table starts with 4-byte length at the beginning
- return t.stringsLen + 4
-}
-
-// add adds string str to string table t.
-func (t *xcoffStringTable) add(str string) int {
- off := t.size()
- t.strings = append(t.strings, str)
- t.stringsLen += len(str) + 1 // each string will have 0 appended to it
- return off
-}
-
-// write writes string table t into the output file.
-func (t *xcoffStringTable) write(out *OutBuf) {
- out.Write32(uint32(t.size()))
- for _, s := range t.strings {
- out.WriteString(s)
- out.Write8(0)
- }
-}
-
-// write writes XCOFF section sect into the output file.
-func (sect *XcoffScnHdr64) write(ctxt *Link) {
- binary.Write(ctxt.Out, binary.BigEndian, sect)
- ctxt.Out.Write32(0) // Add 4 empty bytes at the end to match alignment
-}
-
-// addSection adds section to the XCOFF file f.
-func (f *xcoffFile) addSection(name string, addr uint64, size uint64, fileoff uint64, flags uint32) *XcoffScnHdr64 {
- sect := &XcoffScnHdr64{
- Spaddr: addr,
- Svaddr: addr,
- Ssize: size,
- Sscnptr: fileoff,
- Sflags: flags,
- }
- copy(sect.Sname[:], name) // copy string to [8]byte
- f.sections = append(f.sections, sect)
- f.sectNameToScnum[name] = int16(len(f.sections))
- return sect
-}
-
-// addDwarfSection adds a dwarf section to the XCOFF file f.
-// This function is similar to addSection, but Dwarf section names
-// must be modified to conventional names and they are various subtypes.
-func (f *xcoffFile) addDwarfSection(s *sym.Section) *XcoffScnHdr64 {
- newName, subtype := xcoffGetDwarfSubtype(s.Name)
- return f.addSection(newName, 0, s.Length, s.Seg.Fileoff+s.Vaddr-s.Seg.Vaddr, STYP_DWARF|subtype)
-}
-
-// xcoffGetDwarfSubtype returns the XCOFF name of the DWARF section str
-// and its subtype constant.
-func xcoffGetDwarfSubtype(str string) (string, uint32) {
- switch str {
- default:
- Exitf("unknown DWARF section name for XCOFF: %s", str)
- case ".debug_abbrev":
- return ".dwabrev", SSUBTYP_DWABREV
- case ".debug_info":
- return ".dwinfo", SSUBTYP_DWINFO
- case ".debug_frame":
- return ".dwframe", SSUBTYP_DWFRAME
- case ".debug_line":
- return ".dwline", SSUBTYP_DWLINE
- case ".debug_loc":
- return ".dwloc", SSUBTYP_DWLOC
- case ".debug_pubnames":
- return ".dwpbnms", SSUBTYP_DWPBNMS
- case ".debug_pubtypes":
- return ".dwpbtyp", SSUBTYP_DWPBTYP
- case ".debug_ranges":
- return ".dwrnges", SSUBTYP_DWRNGES
- }
- // never used
- return "", 0
-}
-
-// getXCOFFscnum returns the XCOFF section number of a Go section.
-func (f *xcoffFile) getXCOFFscnum(sect *sym.Section) int16 {
- switch sect.Seg {
- case &Segtext:
- return f.sectNameToScnum[".text"]
- case &Segdata:
- if sect.Name == ".noptrbss" || sect.Name == ".bss" {
- return f.sectNameToScnum[".bss"]
- }
- if sect.Name == ".tbss" {
- return f.sectNameToScnum[".tbss"]
- }
- return f.sectNameToScnum[".data"]
- case &Segdwarf:
- name, _ := xcoffGetDwarfSubtype(sect.Name)
- return f.sectNameToScnum[name]
- case &Segrelrodata:
- return f.sectNameToScnum[".data"]
- }
- Errorf(nil, "getXCOFFscnum not implemented for section %s", sect.Name)
- return -1
-}
-
-// Xcoffinit initialised some internal value and setups
-// already known header information
-func Xcoffinit(ctxt *Link) {
- xfile.dynLibraries = make(map[string]int)
-
- HEADR = int32(Rnd(XCOFFHDRRESERVE, XCOFFSECTALIGN))
- if *FlagTextAddr != -1 {
- Errorf(nil, "-T not available on AIX")
- }
- *FlagTextAddr = XCOFFTEXTBASE + int64(HEADR)
- if *FlagRound != -1 {
- Errorf(nil, "-R not available on AIX")
- }
- *FlagRound = int(XCOFFSECTALIGN)
-
-}
-
-// SYMBOL TABLE
-
-// type records C_FILE information needed for genasmsym in XCOFF.
-type xcoffSymSrcFile struct {
- name string
- file *XcoffSymEnt64 // Symbol of this C_FILE
- csectAux *XcoffAuxCSect64 // Symbol for the current .csect
- csectSymNb uint64 // Symbol number for the current .csect
- csectSize int64
-}
-
-var (
- currDwscnoff = make(map[string]uint64) // Needed to create C_DWARF symbols
- currSymSrcFile xcoffSymSrcFile
- outerSymSize = make(map[string]int64)
-)
-
-// xcoffUpdateOuterSize stores the size of outer symbols in order to have it
-// in the symbol table.
-func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
- if size == 0 {
- return
- }
-
- switch stype {
- default:
- Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String())
- case sym.SRODATA, sym.SRODATARELRO, sym.SFUNCTAB, sym.SSTRING:
- // Nothing to do
- case sym.STYPERELRO:
- if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
- // runtime.types size must be removed, as it's a real symbol.
- outerSymSize["typerel.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
- return
- }
- fallthrough
- case sym.STYPE:
- if !ctxt.DynlinkingGo() {
- // runtime.types size must be removed, as it's a real symbol.
- outerSymSize["type.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size
- }
- case sym.SGOSTRING:
- outerSymSize["go.string.*"] = size
- case sym.SGOFUNC:
- if !ctxt.DynlinkingGo() {
- outerSymSize["go.func.*"] = size
- }
- case sym.SGOFUNCRELRO:
- outerSymSize["go.funcrel.*"] = size
- case sym.SGCBITS:
- outerSymSize["runtime.gcbits.*"] = size
- case sym.SITABLINK:
- outerSymSize["runtime.itablink"] = size
-
- }
-
-}
-
-// addSymbol writes a symbol or an auxiliary symbol entry on ctxt.out.
-func (f *xcoffFile) addSymbol(sym xcoffSym) {
- f.symtabSym = append(f.symtabSym, sym)
- f.symbolCount++
-}
-
-// xcoffAlign returns the log base 2 of the symbol's alignment.
-func xcoffAlign(x *sym.Symbol, t SymbolType) uint8 {
- align := x.Align
- if align == 0 {
- if t == TextSym {
- align = int32(Funcalign)
- } else {
- align = symalign(x)
- }
- }
- return logBase2(int(align))
-}
-
-// logBase2 returns the log in base 2 of a.
-func logBase2(a int) uint8 {
- return uint8(bits.Len(uint(a)) - 1)
-}
-
-// Write symbols needed when a new file appeared:
-// - a C_FILE with one auxiliary entry for its name
-// - C_DWARF symbols to provide debug information
-// - a C_HIDEXT which will be a csect containing all of its functions
-// It needs several parameters to create .csect symbols such as its entry point and its section number.
-//
-// Currently, a new file is in fact a new package. It seems to be OK, but it might change
-// in the future.
-func (f *xcoffFile) writeSymbolNewFile(ctxt *Link, name string, firstEntry uint64, extnum int16) {
- /* C_FILE */
- s := &XcoffSymEnt64{
- Noffset: uint32(f.stringTable.add(".file")),
- Nsclass: C_FILE,
- Nscnum: N_DEBUG,
- Ntype: 0, // Go isn't inside predefined language.
- Nnumaux: 1,
- }
- f.addSymbol(s)
- currSymSrcFile.file = s
-
- // Auxiliary entry for file name.
- auxf := &XcoffAuxFile64{
- Xoffset: uint32(f.stringTable.add(name)),
- Xftype: XFT_FN,
- Xauxtype: _AUX_FILE,
- }
- f.addSymbol(auxf)
-
- /* Dwarf */
- for _, sect := range Segdwarf.Sections {
- var dwsize uint64
- if ctxt.LinkMode == LinkInternal {
- // Find the size of this corresponding package DWARF compilation unit.
- // This size is set during DWARF generation (see dwarf.go).
- dwsize = getDwsectCUSize(sect.Name, name)
- // .debug_abbrev is common to all packages and not found with the previous function
- if sect.Name == ".debug_abbrev" {
- s := ctxt.Syms.ROLookup(sect.Name, 0)
- dwsize = uint64(s.Size)
-
- }
- } else {
- // There is only one .FILE with external linking.
- dwsize = sect.Length
- }
-
- // get XCOFF name
- name, _ := xcoffGetDwarfSubtype(sect.Name)
- s := &XcoffSymEnt64{
- Nvalue: currDwscnoff[sect.Name],
- Noffset: uint32(f.stringTable.add(name)),
- Nsclass: C_DWARF,
- Nscnum: f.getXCOFFscnum(sect),
- Nnumaux: 1,
- }
-
- if currSymSrcFile.csectAux == nil {
- // Dwarf relocations need the symbol number of .dw* symbols.
- // It doesn't need to know it for each package, one is enough.
- // currSymSrcFile.csectAux == nil means first package.
- dws := ctxt.Syms.Lookup(sect.Name, 0)
- dws.Dynid = int32(f.symbolCount)
-
- if sect.Name == ".debug_frame" && ctxt.LinkMode != LinkExternal {
- // CIE size must be added to the first package.
- dwsize += 48
- }
- }
-
- f.addSymbol(s)
-
- // update the DWARF section offset in this file
- if sect.Name != ".debug_abbrev" {
- currDwscnoff[sect.Name] += dwsize
- }
-
- // Auxiliary dwarf section
- auxd := &XcoffAuxDWARF64{
- Xscnlen: dwsize,
- Xauxtype: _AUX_SECT,
- }
-
- f.addSymbol(auxd)
- }
-
- /* .csect */
- // Check if extnum is in text.
- // This is temporary and only here to check if this algorithm is correct.
- if extnum != 1 {
- Exitf("XCOFF symtab: A new file was detected with its first symbol not in .text")
- }
-
- currSymSrcFile.csectSymNb = uint64(f.symbolCount)
-
- // No offset because no name
- s = &XcoffSymEnt64{
- Nvalue: firstEntry,
- Nscnum: extnum,
- Nsclass: C_HIDEXT,
- Ntype: 0, // check visibility ?
- Nnumaux: 1,
- }
- f.addSymbol(s)
-
- aux := &XcoffAuxCSect64{
- Xsmclas: XMC_PR,
- Xsmtyp: XTY_SD | logBase2(Funcalign)<<3,
- Xauxtype: _AUX_CSECT,
- }
- f.addSymbol(aux)
-
- currSymSrcFile.csectAux = aux
- currSymSrcFile.csectSize = 0
-}
-
-// Update values for the previous package.
-// - Svalue of the C_FILE symbol: if it is the last one, this Svalue must be -1
-// - Xsclen of the csect symbol.
-func (f *xcoffFile) updatePreviousFile(ctxt *Link, last bool) {
- // first file
- if currSymSrcFile.file == nil {
- return
- }
-
- // Update C_FILE
- cfile := currSymSrcFile.file
- if last {
- cfile.Nvalue = 0xFFFFFFFFFFFFFFFF
- } else {
- cfile.Nvalue = uint64(f.symbolCount)
- }
-
- // update csect scnlen in this auxiliary entry
- aux := currSymSrcFile.csectAux
- aux.Xscnlenlo = uint32(currSymSrcFile.csectSize & 0xFFFFFFFF)
- aux.Xscnlenhi = uint32(currSymSrcFile.csectSize >> 32)
-}
-
-// Write symbol representing a .text function.
-// The symbol table is split with C_FILE corresponding to each package
-// and not to each source file as it should be.
-func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
- // New XCOFF symbols which will be written.
- syms := []xcoffSym{}
-
- // Check if a new file is detected.
- if strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
- // Trampoline don't have a FILE so there are considered
- // in the current file.
- // Same goes for runtime.text.X symbols.
- } else if x.File == "" { // Undefined global symbol
- // If this happens, the algorithm must be redone.
- if currSymSrcFile.name != "" {
- Exitf("undefined global symbol found inside another file")
- }
- } else {
- // Current file has changed. New C_FILE, C_DWARF, etc must be generated.
- if currSymSrcFile.name != x.File {
- if ctxt.LinkMode == LinkInternal {
- // update previous file values
- xfile.updatePreviousFile(ctxt, false)
- currSymSrcFile.name = x.File
- f.writeSymbolNewFile(ctxt, x.File, uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
- } else {
- // With external linking, ld will crash if there is several
- // .FILE and DWARF debugging enable, somewhere during
- // the relocation phase.
- // Therefore, all packages are merged under a fake .FILE
- // "go_functions".
- // TODO(aix); remove once ld has been fixed or the triggering
- // relocation has been found and fixed.
- if currSymSrcFile.name == "" {
- currSymSrcFile.name = x.File
- f.writeSymbolNewFile(ctxt, "go_functions", uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
- }
- }
-
- }
- }
-
- s := &XcoffSymEnt64{
- Nsclass: C_EXT,
- Noffset: uint32(xfile.stringTable.add(x.Extname())),
- Nvalue: uint64(x.Value),
- Nscnum: f.getXCOFFscnum(x.Sect),
- Ntype: SYM_TYPE_FUNC,
- Nnumaux: 2,
- }
-
- if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() {
- s.Nsclass = C_HIDEXT
- }
-
- x.Dynid = int32(xfile.symbolCount)
- syms = append(syms, s)
-
- // Update current csect size
- currSymSrcFile.csectSize += x.Size
-
- // create auxiliary entries
- a2 := &XcoffAuxFcn64{
- Xfsize: uint32(x.Size),
- Xlnnoptr: 0, // TODO
- Xendndx: xfile.symbolCount + 3, // this symbol + 2 aux entries
- Xauxtype: _AUX_FCN,
- }
- syms = append(syms, a2)
-
- a4 := &XcoffAuxCSect64{
- Xscnlenlo: uint32(currSymSrcFile.csectSymNb & 0xFFFFFFFF),
- Xscnlenhi: uint32(currSymSrcFile.csectSymNb >> 32),
- Xsmclas: XMC_PR, // Program Code
- Xsmtyp: XTY_LD, // label definition (based on C)
- Xauxtype: _AUX_CSECT,
- }
- a4.Xsmtyp |= uint8(xcoffAlign(x, TextSym) << 3)
-
- syms = append(syms, a4)
- return syms
-}
-
-// put function used by genasmsym to write symbol table
-func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, go_ *sym.Symbol) {
-
- // All XCOFF symbols generated by this GO symbols
- // Can be a symbol entry or a auxiliary entry
- syms := []xcoffSym{}
-
- switch t {
- default:
- return
-
- case TextSym:
- if x.FuncInfo != nil || strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
- // Function within a file
- syms = xfile.writeSymbolFunc(ctxt, x)
- } else {
- // Only runtime.text and runtime.etext come through this way
- if x.Name != "runtime.text" && x.Name != "runtime.etext" && x.Name != "go.buildid" {
- Exitf("putaixsym: unknown text symbol %s", x.Name)
- }
- s := &XcoffSymEnt64{
- Nsclass: C_HIDEXT,
- Noffset: uint32(xfile.stringTable.add(str)),
- Nvalue: uint64(x.Value),
- Nscnum: xfile.getXCOFFscnum(x.Sect),
- Ntype: SYM_TYPE_FUNC,
- Nnumaux: 1,
- }
- x.Dynid = int32(xfile.symbolCount)
- syms = append(syms, s)
-
- size := uint64(x.Size)
- a4 := &XcoffAuxCSect64{
- Xauxtype: _AUX_CSECT,
- Xscnlenlo: uint32(size & 0xFFFFFFFF),
- Xscnlenhi: uint32(size >> 32),
- Xsmclas: XMC_PR,
- Xsmtyp: XTY_SD,
- }
- a4.Xsmtyp |= uint8(xcoffAlign(x, TextSym) << 3)
- syms = append(syms, a4)
-
- }
-
- case DataSym, BSSSym:
- s := &XcoffSymEnt64{
- Nsclass: C_EXT,
- Noffset: uint32(xfile.stringTable.add(str)),
- Nvalue: uint64(x.Value),
- Nscnum: xfile.getXCOFFscnum(x.Sect),
- Nnumaux: 1,
- }
-
- if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() {
- // There is more symbols in the case of a global data
- // which are related to the assembly generated
- // to access such symbols.
- // But as Golang as its own way to check if a symbol is
- // global or local (the capital letter), we don't need to
- // implement them yet.
- s.Nsclass = C_HIDEXT
- }
-
- x.Dynid = int32(xfile.symbolCount)
- syms = append(syms, s)
-
- // Create auxiliary entry
-
- // Normally, size should be the size of csect containing all
- // the data and bss symbols of one file/package.
- // However, it's easier to just have a csect for each symbol.
- // It might change
- size := uint64(x.Size)
- a4 := &XcoffAuxCSect64{
- Xauxtype: _AUX_CSECT,
- Xscnlenlo: uint32(size & 0xFFFFFFFF),
- Xscnlenhi: uint32(size >> 32),
- }
-
- if x.Type >= sym.STYPE && x.Type <= sym.SPCLNTAB {
- if ctxt.LinkMode == LinkExternal && strings.HasPrefix(x.Sect.Name, ".data.rel.ro") {
- // During external linking, read-only datas with relocation
- // must be in .data.
- a4.Xsmclas = XMC_RW
- } else {
- // Read only data
- a4.Xsmclas = XMC_RO
- }
- } else if x.Type == sym.SDATA && strings.HasPrefix(x.Name, "TOC.") && ctxt.LinkMode == LinkExternal {
- a4.Xsmclas = XMC_TC
- } else if x.Name == "TOC" {
- a4.Xsmclas = XMC_TC0
- } else {
- a4.Xsmclas = XMC_RW
- }
- if t == DataSym {
- a4.Xsmtyp |= XTY_SD
- } else {
- a4.Xsmtyp |= XTY_CM
- }
-
- a4.Xsmtyp |= uint8(xcoffAlign(x, t) << 3)
-
- syms = append(syms, a4)
-
- case UndefinedSym:
- if x.Type != sym.SDYNIMPORT && x.Type != sym.SHOSTOBJ && x.Type != sym.SUNDEFEXT {
- return
- }
- s := &XcoffSymEnt64{
- Nsclass: C_EXT,
- Noffset: uint32(xfile.stringTable.add(str)),
- Nnumaux: 1,
- }
- x.Dynid = int32(xfile.symbolCount)
- syms = append(syms, s)
-
- a4 := &XcoffAuxCSect64{
- Xauxtype: _AUX_CSECT,
- Xsmclas: XMC_DS,
- Xsmtyp: XTY_ER | XTY_IMP,
- }
-
- if x.Name == "__n_pthreads" {
- // Currently, all imported symbols made by cgo_import_dynamic are
- // syscall functions, except __n_pthreads which is a variable.
- // TODO(aix): Find a way to detect variables imported by cgo.
- a4.Xsmclas = XMC_RW
- }
-
- syms = append(syms, a4)
-
- case TLSSym:
- s := &XcoffSymEnt64{
- Nsclass: C_EXT,
- Noffset: uint32(xfile.stringTable.add(str)),
- Nscnum: xfile.getXCOFFscnum(x.Sect),
- Nvalue: uint64(x.Value),
- Nnumaux: 1,
- }
-
- x.Dynid = int32(xfile.symbolCount)
- syms = append(syms, s)
-
- size := uint64(x.Size)
- a4 := &XcoffAuxCSect64{
- Xauxtype: _AUX_CSECT,
- Xsmclas: XMC_UL,
- Xsmtyp: XTY_CM,
- Xscnlenlo: uint32(size & 0xFFFFFFFF),
- Xscnlenhi: uint32(size >> 32),
- }
-
- syms = append(syms, a4)
- }
-
- for _, s := range syms {
- xfile.addSymbol(s)
- }
-}
-
-// Generate XCOFF Symbol table.
-// It will be written in out file in Asmbxcoff, because it must be
-// at the very end, especially after relocation sections which needs symbols' index.
-func (f *xcoffFile) asmaixsym(ctxt *Link) {
- // Get correct size for symbols wrapping others symbols like go.string.*
- // sym.Size can be used directly as the symbols have already been written.
- for name, size := range outerSymSize {
- sym := ctxt.Syms.ROLookup(name, 0)
- if sym == nil {
- Errorf(nil, "unknown outer symbol with name %s", name)
- } else {
- sym.Size = size
- }
- }
-
- genasmsym(ctxt, putaixsym)
- xfile.updatePreviousFile(ctxt, true)
-}
-
-func (f *xcoffFile) genDynSym(ctxt *Link) {
- var dynsyms []*sym.Symbol
- for _, s := range ctxt.Syms.Allsym {
- if s.Type != sym.SHOSTOBJ && s.Type != sym.SDYNIMPORT {
- continue
- }
- dynsyms = append(dynsyms, s)
- }
-
- for _, s := range dynsyms {
- f.adddynimpsym(ctxt, s)
-
- if _, ok := f.dynLibraries[s.Dynimplib()]; !ok {
- f.dynLibraries[s.Dynimplib()] = len(f.dynLibraries)
- }
-
- }
-
-}
-
-// (*xcoffFile)adddynimpsym adds the dynamic symbol "s" to a XCOFF file.
-// A new symbol named s.Extname() is created to be the actual dynamic symbol
-// in the .loader section and in the symbol table as an External Reference.
-// The symbol "s" is transformed to SXCOFFTOC to end up in .data section.
-// However, there is no writing protection on those symbols and
-// it might need to be added.
-// TODO(aix): Handles dynamic symbols without library.
-func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) {
- // Check that library name is given.
- // Pattern is already checked when compiling.
- if ctxt.LinkMode == LinkInternal && s.Dynimplib() == "" {
- Errorf(s, "imported symbol must have a given library")
- }
-
- s.Type = sym.SXCOFFTOC
-
- // Create new dynamic symbol
- extsym := ctxt.Syms.Lookup(s.Extname(), 0)
- extsym.Type = sym.SDYNIMPORT
- extsym.Attr |= sym.AttrReachable
- extsym.SetDynimplib(s.Dynimplib())
- extsym.SetExtname(s.Extname())
- extsym.SetDynimpvers(s.Dynimpvers())
-
- // Add loader symbol
- lds := &xcoffLoaderSymbol{
- sym: extsym,
- smtype: XTY_IMP,
- smclas: XMC_DS,
- }
- if s.Name == "__n_pthreads" {
- // Currently, all imported symbols made by cgo_import_dynamic are
- // syscall functions, except __n_pthreads which is a variable.
- // TODO(aix): Find a way to detect variables imported by cgo.
- lds.smclas = XMC_RW
- }
- f.loaderSymbols = append(f.loaderSymbols, lds)
-
- // Relocation to retrieve the external address
- s.AddBytes(make([]byte, 8))
- s.SetAddr(ctxt.Arch, 0, extsym)
-
-}
-
-// Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
-// This relocation will be made by the loader.
-func Xcoffadddynrel(ctxt *Link, s *sym.Symbol, r *sym.Reloc) bool {
- if ctxt.LinkMode == LinkExternal {
- return true
- }
- if s.Type <= sym.SPCLNTAB {
- Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name)
- return false
- }
-
- ldr := &xcoffLoaderReloc{
- sym: s,
- rel: r,
- }
-
- switch r.Type {
- default:
- Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", r.Sym.Name, r.Type.String())
- return false
- case objabi.R_ADDR:
- if s.Type == sym.SXCOFFTOC && r.Sym.Type == sym.SDYNIMPORT {
- // Imported symbol relocation
- for i, dynsym := range xfile.loaderSymbols {
- if dynsym.sym.Name == r.Sym.Name {
- ldr.symndx = int32(i + 3) // +3 because of 3 section symbols
- break
- }
- }
- } else if s.Type == sym.SDATA {
- switch r.Sym.Sect.Seg {
- default:
- Errorf(s, "unknown segment for .loader relocation with symbol %s", r.Sym.Name)
- case &Segtext:
- case &Segrodata:
- ldr.symndx = 0 // .text
- case &Segdata:
- if r.Sym.Type == sym.SBSS || r.Sym.Type == sym.SNOPTRBSS {
- ldr.symndx = 2 // .bss
- } else {
- ldr.symndx = 1 // .data
- }
-
- }
-
- } else {
- Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", r.Sym.Name, s.Type, r.Sym.Type)
- return false
- }
-
- ldr.rtype = 0x3F<<8 + XCOFF_R_POS
- }
-
- xfile.loaderReloc = append(xfile.loaderReloc, ldr)
- return true
-}
-
-func (ctxt *Link) doxcoff() {
- if *FlagD {
- // All XCOFF files have dynamic symbols because of the syscalls.
- Exitf("-d is not available on AIX")
- }
-
- // TOC
- toc := ctxt.Syms.Lookup("TOC", 0)
- toc.Type = sym.SXCOFFTOC
- toc.Attr |= sym.AttrReachable
- toc.Attr |= sym.AttrVisibilityHidden
-
- // Add entry point to .loader symbols.
- ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0)
- if !ep.Attr.Reachable() {
- Exitf("wrong entry point")
- }
-
- xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{
- sym: ep,
- smtype: XTY_ENT | XTY_SD,
- smclas: XMC_DS,
- })
-
- xfile.genDynSym(ctxt)
-
- for _, s := range ctxt.Syms.Allsym {
- if strings.HasPrefix(s.Name, "TOC.") {
- s.Type = sym.SXCOFFTOC
- }
- }
-
- if ctxt.LinkMode == LinkExternal {
- // Change rt0_go name to match name in runtime/cgo:main().
- rt0 := ctxt.Syms.ROLookup("runtime.rt0_go", 0)
- ctxt.Syms.Rename(rt0.Name, "runtime_rt0_go", 0, ctxt.Reachparent)
-
- for _, s := range ctxt.Syms.Allsym {
- if !s.Attr.CgoExport() {
- continue
- }
-
- name := s.Extname()
- if s.Type == sym.STEXT {
- // On AIX, a exported function must have two symbols:
- // - a .text symbol which must start with a ".".
- // - a .data symbol which is a function descriptor.
- ctxt.Syms.Rename(s.Name, "."+name, 0, ctxt.Reachparent)
-
- desc := ctxt.Syms.Lookup(name, 0)
- desc.Type = sym.SNOPTRDATA
- desc.AddAddr(ctxt.Arch, s)
- desc.AddAddr(ctxt.Arch, toc)
- desc.AddUint64(ctxt.Arch, 0)
- }
- }
- }
-}
-
-// Loader section
-// Currently, this section is created from scratch when assembling the XCOFF file
-// according to information retrieved in xfile object.
-
-// Create loader section and returns its size
-func Loaderblk(ctxt *Link, off uint64) {
- xfile.writeLdrScn(ctxt, off)
-}
-
-func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
- var symtab []*XcoffLdSym64
- var strtab []*XcoffLdStr64
- var importtab []*XcoffLdImportFile64
- var reloctab []*XcoffLdRel64
- var dynimpreloc []*XcoffLdRel64
-
- // As the string table is updated in any loader subsection,
- // its length must be computed at the same time.
- stlen := uint32(0)
-
- // Loader Header
- hdr := &XcoffLdHdr64{
- Lversion: 2,
- Lsymoff: LDHDRSZ_64,
- }
-
- /* Symbol table */
- for _, s := range f.loaderSymbols {
- lds := &XcoffLdSym64{
- Loffset: uint32(stlen + 2),
- Lsmtype: s.smtype,
- Lsmclas: s.smclas,
- }
- switch s.smtype {
- default:
- Errorf(s.sym, "unexpected loader symbol type: 0x%x", s.smtype)
- case XTY_ENT | XTY_SD:
- lds.Lvalue = uint64(s.sym.Value)
- lds.Lscnum = f.getXCOFFscnum(s.sym.Sect)
- case XTY_IMP:
- lds.Lifile = int32(f.dynLibraries[s.sym.Dynimplib()] + 1)
- }
- ldstr := &XcoffLdStr64{
- size: uint16(len(s.sym.Name) + 1), // + null terminator
- name: s.sym.Name,
- }
- stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size
- symtab = append(symtab, lds)
- strtab = append(strtab, ldstr)
-
- }
-
- hdr.Lnsyms = int32(len(symtab))
- hdr.Lrldoff = hdr.Lsymoff + uint64(24*hdr.Lnsyms) // 24 = sizeof one symbol
- off := hdr.Lrldoff // current offset is the same of reloc offset
-
- /* Reloc */
- ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0)
- ldr := &XcoffLdRel64{
- Lvaddr: uint64(ep.Value),
- Lrtype: 0x3F00,
- Lrsecnm: f.getXCOFFscnum(ep.Sect),
- Lsymndx: 0,
- }
- off += 16
- reloctab = append(reloctab, ldr)
-
- off += uint64(16 * len(f.loaderReloc))
- for _, r := range f.loaderReloc {
- ldr = &XcoffLdRel64{
- Lvaddr: uint64(r.sym.Value + int64(r.rel.Off)),
- Lrtype: r.rtype,
- Lsymndx: r.symndx,
- }
-
- if r.sym.Sect != nil {
- ldr.Lrsecnm = f.getXCOFFscnum(r.sym.Sect)
- }
-
- reloctab = append(reloctab, ldr)
- }
-
- off += uint64(16 * len(dynimpreloc))
- reloctab = append(reloctab, dynimpreloc...)
-
- hdr.Lnreloc = int32(len(reloctab))
- hdr.Limpoff = off
-
- /* Import */
- // Default import: /usr/lib:/lib
- ldimpf := &XcoffLdImportFile64{
- Limpidpath: "/usr/lib:/lib",
- }
- off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
- importtab = append(importtab, ldimpf)
-
- // The map created by adddynimpsym associates the name to a number
- // This number represents the librairie index (- 1) in this import files section
- // Therefore, they must be sorted before being put inside the section
- libsOrdered := make([]string, len(f.dynLibraries))
- for key, val := range f.dynLibraries {
- if libsOrdered[val] != "" {
- continue
- }
- libsOrdered[val] = key
- }
-
- for _, lib := range libsOrdered {
- // lib string is defined as base.a/mem.o or path/base.a/mem.o
- n := strings.Split(lib, "/")
- path := ""
- base := n[len(n)-2]
- mem := n[len(n)-1]
- if len(n) > 2 {
- path = lib[:len(lib)-len(base)-len(mem)-2]
-
- }
- ldimpf = &XcoffLdImportFile64{
- Limpidpath: path,
- Limpidbase: base,
- Limpidmem: mem,
- }
- off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
- importtab = append(importtab, ldimpf)
- }
-
- hdr.Lnimpid = int32(len(importtab))
- hdr.Listlen = uint32(off - hdr.Limpoff)
- hdr.Lstoff = off
- hdr.Lstlen = stlen
-
- /* Writing */
- ctxt.Out.SeekSet(int64(globalOff))
- binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr)
-
- for _, s := range symtab {
- binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s)
-
- }
- for _, r := range reloctab {
- binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r)
- }
- for _, f := range importtab {
- ctxt.Out.WriteString(f.Limpidpath)
- ctxt.Out.Write8(0)
- ctxt.Out.WriteString(f.Limpidbase)
- ctxt.Out.Write8(0)
- ctxt.Out.WriteString(f.Limpidmem)
- ctxt.Out.Write8(0)
- }
- for _, s := range strtab {
- ctxt.Out.Write16(s.size)
- ctxt.Out.WriteString(s.name)
- ctxt.Out.Write8(0) // null terminator
- }
-
- f.loaderSize = off + uint64(stlen)
- ctxt.Out.Flush()
-
- /* again for printing */
- if !*flagA {
- return
- }
-
- ctxt.Logf("\n.loader section")
- // write in buf
- var buf bytes.Buffer
-
- binary.Write(&buf, ctxt.Arch.ByteOrder, hdr)
- for _, s := range symtab {
- binary.Write(&buf, ctxt.Arch.ByteOrder, s)
-
- }
- for _, f := range importtab {
- buf.WriteString(f.Limpidpath)
- buf.WriteByte(0)
- buf.WriteString(f.Limpidbase)
- buf.WriteByte(0)
- buf.WriteString(f.Limpidmem)
- buf.WriteByte(0)
- }
- for _, s := range strtab {
- binary.Write(&buf, ctxt.Arch.ByteOrder, s.size)
- buf.WriteString(s.name)
- buf.WriteByte(0) // null terminator
- }
-
- // Log buffer
- ctxt.Logf("\n\t%.8x|", globalOff)
- for i, b := range buf.Bytes() {
- if i > 0 && i%16 == 0 {
- ctxt.Logf("\n\t%.8x|", uint64(globalOff)+uint64(i))
- }
- ctxt.Logf(" %.2x", b)
- }
- ctxt.Logf("\n")
-
-}
-
-// XCOFF assembling and writing file
-
-func (f *xcoffFile) writeFileHeader(ctxt *Link) {
- // File header
- f.xfhdr.Fmagic = U64_TOCMAGIC
- f.xfhdr.Fnscns = uint16(len(f.sections))
- f.xfhdr.Ftimedat = 0
-
- if !*FlagS {
- f.xfhdr.Fsymptr = uint64(f.symtabOffset)
- f.xfhdr.Fnsyms = int32(f.symbolCount)
- }
-
- if ctxt.BuildMode == BuildModeExe && ctxt.LinkMode == LinkInternal {
- f.xfhdr.Fopthdr = AOUTHSZ_EXEC64
- f.xfhdr.Fflags = F_EXEC
-
- // auxiliary header
- f.xahdr.Ovstamp = 1 // based on dump -o
- f.xahdr.Omagic = 0x10b
- copy(f.xahdr.Omodtype[:], "1L")
- entry := ctxt.Syms.ROLookup(*flagEntrySymbol, 0)
- f.xahdr.Oentry = uint64(entry.Value)
- f.xahdr.Osnentry = f.getXCOFFscnum(entry.Sect)
- toc := ctxt.Syms.ROLookup("TOC", 0)
- f.xahdr.Otoc = uint64(toc.Value)
- f.xahdr.Osntoc = f.getXCOFFscnum(toc.Sect)
-
- f.xahdr.Oalgntext = int16(logBase2(int(Funcalign)))
- f.xahdr.Oalgndata = 0x5
-
- binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
- binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr)
- } else {
- f.xfhdr.Fopthdr = 0
- binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
- }
-
-}
-
-func xcoffwrite(ctxt *Link) {
- ctxt.Out.SeekSet(0)
-
- xfile.writeFileHeader(ctxt)
-
- for _, sect := range xfile.sections {
- sect.write(ctxt)
- }
-}
-
-// Generate XCOFF assembly file
-func Asmbxcoff(ctxt *Link, fileoff int64) {
- xfile.sectNameToScnum = make(map[string]int16)
-
- // Add sections
- s := xfile.addSection(".text", Segtext.Vaddr, Segtext.Length, Segtext.Fileoff, STYP_TEXT)
- xfile.xahdr.Otextstart = s.Svaddr
- xfile.xahdr.Osntext = xfile.sectNameToScnum[".text"]
- xfile.xahdr.Otsize = s.Ssize
- xfile.sectText = s
-
- segdataVaddr := Segdata.Vaddr
- segdataFilelen := Segdata.Filelen
- segdataFileoff := Segdata.Fileoff
- segbssFilelen := Segdata.Length - Segdata.Filelen
- if len(Segrelrodata.Sections) > 0 {
- // Merge relro segment to data segment as
- // relro data are inside data segment on AIX.
- segdataVaddr = Segrelrodata.Vaddr
- segdataFileoff = Segrelrodata.Fileoff
- segdataFilelen = Segdata.Vaddr + Segdata.Filelen - Segrelrodata.Vaddr
- }
-
- s = xfile.addSection(".data", segdataVaddr, segdataFilelen, segdataFileoff, STYP_DATA)
- xfile.xahdr.Odatastart = s.Svaddr
- xfile.xahdr.Osndata = xfile.sectNameToScnum[".data"]
- xfile.xahdr.Odsize = s.Ssize
- xfile.sectData = s
-
- s = xfile.addSection(".bss", segdataVaddr+segdataFilelen, segbssFilelen, 0, STYP_BSS)
- xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"]
- xfile.xahdr.Obsize = s.Ssize
- xfile.sectBss = s
-
- if ctxt.LinkMode == LinkExternal {
- var tbss *sym.Section
- for _, s := range Segdata.Sections {
- if s.Name == ".tbss" {
- tbss = s
- break
- }
- }
- s = xfile.addSection(".tbss", tbss.Vaddr, tbss.Length, 0, STYP_TBSS)
- }
-
- // add dwarf sections
- for _, sect := range Segdwarf.Sections {
- xfile.addDwarfSection(sect)
- }
-
- // add and write remaining sections
- if ctxt.LinkMode == LinkInternal {
- // Loader section
- if ctxt.BuildMode == BuildModeExe {
- Loaderblk(ctxt, uint64(fileoff))
- s = xfile.addSection(".loader", 0, xfile.loaderSize, uint64(fileoff), STYP_LOADER)
- xfile.xahdr.Osnloader = xfile.sectNameToScnum[".loader"]
-
- // Update fileoff for symbol table
- fileoff += int64(xfile.loaderSize)
- }
- }
-
- // Create Symbol table
- xfile.asmaixsym(ctxt)
-
- if ctxt.LinkMode == LinkExternal {
- xfile.emitRelocations(ctxt, fileoff)
- }
-
- // Write Symbol table
- xfile.symtabOffset = ctxt.Out.Offset()
- for _, s := range xfile.symtabSym {
- binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s)
- }
- // write string table
- xfile.stringTable.write(ctxt.Out)
-
- ctxt.Out.Flush()
-
- // write headers
- xcoffwrite(ctxt)
-}
-
-// byOffset is used to sort relocations by offset
-type byOffset []sym.Reloc
-
-func (x byOffset) Len() int { return len(x) }
-
-func (x byOffset) Swap(i, j int) {
- x[i], x[j] = x[j], x[i]
-}
-
-func (x byOffset) Less(i, j int) bool {
- return x[i].Off < x[j].Off
-}
-
-// emitRelocations emits relocation entries for go.o in external linking.
-func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) {
- ctxt.Out.SeekSet(fileoff)
- for ctxt.Out.Offset()&7 != 0 {
- ctxt.Out.Write8(0)
- }
-
- // relocsect relocates symbols from first in section sect, and returns
- // the total number of relocations emitted.
- relocsect := func(sect *sym.Section, syms []*sym.Symbol, base uint64) uint32 {
- // ctxt.Logf("%s 0x%x\n", sect.Name, sect.Vaddr)
- // If main section has no bits, nothing to relocate.
- if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
- return 0
- }
- sect.Reloff = uint64(ctxt.Out.Offset())
- for i, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if uint64(s.Value) >= sect.Vaddr {
- syms = syms[i:]
- break
- }
- }
- eaddr := int64(sect.Vaddr + sect.Length)
- for _, s := range syms {
- if !s.Attr.Reachable() {
- continue
- }
- if s.Value >= int64(eaddr) {
- break
- }
-
- // Relocation must be ordered by address, so s.R is ordered by Off.
- sort.Sort(byOffset(s.R))
-
- for ri := range s.R {
-
- r := &s.R[ri]
-
- if r.Done {
- continue
- }
- if r.Xsym == nil {
- Errorf(s, "missing xsym in relocation")
- continue
- }
- if r.Xsym.Dynid < 0 {
- Errorf(s, "reloc %s to non-coff symbol %s (outer=%s) %d %d", r.Type.String(), r.Sym.Name, r.Xsym.Name, r.Sym.Type, r.Xsym.Dynid)
- }
- if !thearch.Xcoffreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-base)) {
- Errorf(s, "unsupported obj reloc %d(%s)/%d to %s", r.Type, r.Type.String(), r.Siz, r.Sym.Name)
- }
- }
- }
- sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
- return uint32(sect.Rellen) / RELSZ_64
- }
- sects := []struct {
- xcoffSect *XcoffScnHdr64
- segs []*sym.Segment
- }{
- {f.sectText, []*sym.Segment{&Segtext}},
- {f.sectData, []*sym.Segment{&Segrelrodata, &Segdata}},
- }
- for _, s := range sects {
- s.xcoffSect.Srelptr = uint64(ctxt.Out.Offset())
- n := uint32(0)
- for _, seg := range s.segs {
- for _, sect := range seg.Sections {
- if sect.Name == ".text" {
- n += relocsect(sect, ctxt.Textp, 0)
- } else {
- n += relocsect(sect, datap, 0)
- }
- }
- }
- s.xcoffSect.Snreloc += n
- }
-
-dwarfLoop:
- for _, sect := range Segdwarf.Sections {
- for _, xcoffSect := range f.sections {
- _, subtyp := xcoffGetDwarfSubtype(sect.Name)
- if xcoffSect.Sflags&0xF0000 == subtyp {
- xcoffSect.Srelptr = uint64(ctxt.Out.Offset())
- xcoffSect.Snreloc = relocsect(sect, dwarfp, sect.Vaddr)
- continue dwarfLoop
- }
- }
- Errorf(nil, "emitRelocations: could not find %q section", sect.Name)
- }
-}
-
-// xcoffCreateExportFile creates a file with exported symbols for
-// -Wl,-bE option.
-// ld won't export symbols unless they are listed in an export file.
-func xcoffCreateExportFile(ctxt *Link) (fname string) {
- fname = filepath.Join(*flagTmpdir, "export_file.exp")
- var buf bytes.Buffer
-
- for _, s := range ctxt.Syms.Allsym {
- if !s.Attr.CgoExport() {
- continue
- }
- if !strings.HasPrefix(s.String(), "_cgoexp_") {
- continue
- }
-
- // Retrieve the name of the initial symbol
- // exported by cgo.
- // The corresponding Go symbol is:
- // _cgoexp_hashcode_symname.
- name := strings.SplitN(s.Extname(), "_", 4)[3]
-
- buf.Write([]byte(name + "\n"))
- }
-
- err := ioutil.WriteFile(fname, buf.Bytes(), 0666)
- if err != nil {
- Errorf(nil, "WriteFile %s failed: %v", fname, err)
- }
-
- return fname
-
-}
+++ /dev/null
-// 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 loadelf implements an ELF file reader.
-package loadelf
-
-import (
- "bytes"
- "cmd/internal/bio"
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/loader"
- "cmd/oldlink/internal/sym"
- "debug/elf"
- "encoding/binary"
- "fmt"
- "io"
- "log"
- "sort"
- "strings"
-)
-
-/*
-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.
-*/
-const (
- ElfClassNone = 0
- ElfClass32 = 1
- ElfClass64 = 2
-)
-
-const (
- ElfDataNone = 0
- ElfDataLsb = 1
- ElfDataMsb = 2
-)
-
-const (
- ElfTypeNone = 0
- ElfTypeRelocatable = 1
- ElfTypeExecutable = 2
- ElfTypeSharedObject = 3
- ElfTypeCore = 4
-)
-
-const (
- ElfMachNone = 0
- ElfMach32100 = 1
- ElfMachSparc = 2
- ElfMach386 = 3
- ElfMach68000 = 4
- ElfMach88000 = 5
- ElfMach486 = 6
- ElfMach860 = 7
- ElfMachMips = 8
- ElfMachS370 = 9
- ElfMachMipsLe = 10
- ElfMachParisc = 15
- ElfMachVpp500 = 17
- ElfMachSparc32Plus = 18
- ElfMach960 = 19
- ElfMachPower = 20
- ElfMachPower64 = 21
- ElfMachS390 = 22
- ElfMachV800 = 36
- ElfMachFr20 = 37
- ElfMachRh32 = 38
- ElfMachRce = 39
- ElfMachArm = 40
- ElfMachAlpha = 41
- ElfMachSH = 42
- ElfMachSparc9 = 43
- ElfMachAmd64 = 62
- ElfMachArm64 = 183
-)
-
-const (
- ElfAbiNone = 0
- ElfAbiSystemV = 0
- ElfAbiHPUX = 1
- ElfAbiNetBSD = 2
- ElfAbiLinux = 3
- ElfAbiSolaris = 6
- ElfAbiAix = 7
- ElfAbiIrix = 8
- ElfAbiFreeBSD = 9
- ElfAbiTru64 = 10
- ElfAbiModesto = 11
- ElfAbiOpenBSD = 12
- ElfAbiARM = 97
- ElfAbiEmbedded = 255
-)
-
-const (
- ElfSectNone = 0
- ElfSectProgbits = 1
- ElfSectSymtab = 2
- ElfSectStrtab = 3
- ElfSectRela = 4
- ElfSectHash = 5
- ElfSectDynamic = 6
- ElfSectNote = 7
- ElfSectNobits = 8
- ElfSectRel = 9
- ElfSectShlib = 10
- ElfSectDynsym = 11
- ElfSectFlagWrite = 0x1
- ElfSectFlagAlloc = 0x2
- ElfSectFlagExec = 0x4
-)
-
-const (
- ElfSymBindLocal = 0
- ElfSymBindGlobal = 1
- ElfSymBindWeak = 2
-)
-
-const (
- ElfSymTypeNone = 0
- ElfSymTypeObject = 1
- ElfSymTypeFunc = 2
- ElfSymTypeSection = 3
- ElfSymTypeFile = 4
- ElfSymTypeCommon = 5
- ElfSymTypeTLS = 6
-)
-
-const (
- ElfSymShnNone = 0
- ElfSymShnAbs = 0xFFF1
- ElfSymShnCommon = 0xFFF2
-)
-
-const (
- ElfProgNone = 0
- ElfProgLoad = 1
- ElfProgDynamic = 2
- ElfProgInterp = 3
- ElfProgNote = 4
- ElfProgShlib = 5
- ElfProgPhdr = 6
- ElfProgFlagExec = 0x1
- ElfProgFlagWrite = 0x2
- ElfProgFlagRead = 0x4
-)
-
-const (
- ElfNotePrStatus = 1
- ElfNotePrFpreg = 2
- ElfNotePrPsinfo = 3
- ElfNotePrTaskstruct = 4
- ElfNotePrAuxv = 6
- ElfNotePrXfpreg = 0x46e62b7f
-)
-
-// TODO(crawshaw): de-duplicate with cmd/oldlink/internal/ld/elf.go.
-const (
- ELF64SYMSIZE = 24
- ELF32SYMSIZE = 16
-
- SHT_ARM_ATTRIBUTES = 0x70000003
-)
-
-type ElfHdrBytes struct {
- Ident [16]uint8
- Type [2]uint8
- Machine [2]uint8
- Version [4]uint8
- Entry [4]uint8
- Phoff [4]uint8
- Shoff [4]uint8
- Flags [4]uint8
- Ehsize [2]uint8
- Phentsize [2]uint8
- Phnum [2]uint8
- Shentsize [2]uint8
- Shnum [2]uint8
- Shstrndx [2]uint8
-}
-
-type ElfSectBytes struct {
- Name [4]uint8
- Type [4]uint8
- Flags [4]uint8
- Addr [4]uint8
- Off [4]uint8
- Size [4]uint8
- Link [4]uint8
- Info [4]uint8
- Align [4]uint8
- Entsize [4]uint8
-}
-
-type ElfProgBytes struct {
-}
-
-type ElfSymBytes struct {
- Name [4]uint8
- Value [4]uint8
- Size [4]uint8
- Info uint8
- Other uint8
- Shndx [2]uint8
-}
-
-type ElfHdrBytes64 struct {
- Ident [16]uint8
- Type [2]uint8
- Machine [2]uint8
- Version [4]uint8
- Entry [8]uint8
- Phoff [8]uint8
- Shoff [8]uint8
- Flags [4]uint8
- Ehsize [2]uint8
- Phentsize [2]uint8
- Phnum [2]uint8
- Shentsize [2]uint8
- Shnum [2]uint8
- Shstrndx [2]uint8
-}
-
-type ElfSectBytes64 struct {
- Name [4]uint8
- Type [4]uint8
- Flags [8]uint8
- Addr [8]uint8
- Off [8]uint8
- Size [8]uint8
- Link [4]uint8
- Info [4]uint8
- Align [8]uint8
- Entsize [8]uint8
-}
-
-type ElfProgBytes64 struct {
-}
-
-type ElfSymBytes64 struct {
- Name [4]uint8
- Info uint8
- Other uint8
- Shndx [2]uint8
- Value [8]uint8
- Size [8]uint8
-}
-
-type ElfSect struct {
- name string
- nameoff uint32
- type_ uint32
- flags uint64
- addr uint64
- off uint64
- size uint64
- link uint32
- info uint32
- align uint64
- entsize uint64
- base []byte
- sym *sym.Symbol
-}
-
-type ElfObj struct {
- f *bio.Reader
- base int64 // offset in f where ELF begins
- length int64 // length of ELF
- is64 int
- name string
- e binary.ByteOrder
- sect []ElfSect
- nsect uint
- nsymtab int
- symtab *ElfSect
- symstr *ElfSect
- type_ uint32
- machine uint32
- version uint32
- entry uint64
- phoff uint64
- shoff uint64
- flags uint32
- ehsize uint32
- phentsize uint32
- phnum uint32
- shentsize uint32
- shnum uint32
- shstrndx uint32
-}
-
-type ElfSym struct {
- name string
- value uint64
- size uint64
- bind uint8
- type_ uint8
- other uint8
- shndx uint16
- sym *sym.Symbol
-}
-
-var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'}
-
-const (
- TagFile = 1
- TagCPUName = 4
- TagCPURawName = 5
- TagCompatibility = 32
- TagNoDefaults = 64
- TagAlsoCompatibleWith = 65
- TagABIVFPArgs = 28
-)
-
-type elfAttribute struct {
- tag uint64
- sval string
- ival uint64
-}
-
-type elfAttributeList struct {
- data []byte
- err error
-}
-
-func (a *elfAttributeList) string() string {
- if a.err != nil {
- return ""
- }
- nul := bytes.IndexByte(a.data, 0)
- if nul < 0 {
- a.err = io.EOF
- return ""
- }
- s := string(a.data[:nul])
- a.data = a.data[nul+1:]
- return s
-}
-
-func (a *elfAttributeList) uleb128() uint64 {
- if a.err != nil {
- return 0
- }
- v, size := binary.Uvarint(a.data)
- a.data = a.data[size:]
- return v
-}
-
-// Read an elfAttribute from the list following the rules used on ARM systems.
-func (a *elfAttributeList) armAttr() elfAttribute {
- attr := elfAttribute{tag: a.uleb128()}
- switch {
- case attr.tag == TagCompatibility:
- attr.ival = a.uleb128()
- attr.sval = a.string()
-
- case attr.tag == 64: // Tag_nodefaults has no argument
-
- case attr.tag == 65: // Tag_also_compatible_with
- // Not really, but we don't actually care about this tag.
- attr.sval = a.string()
-
- // Tag with string argument
- case attr.tag == TagCPUName || attr.tag == TagCPURawName || (attr.tag >= 32 && attr.tag&1 != 0):
- attr.sval = a.string()
-
- default: // Tag with integer argument
- attr.ival = a.uleb128()
- }
- return attr
-}
-
-func (a *elfAttributeList) done() bool {
- if a.err != nil || len(a.data) == 0 {
- return true
- }
- return false
-}
-
-// Look for the attribute that indicates the object uses the hard-float ABI (a
-// file-level attribute with tag Tag_VFP_arch and value 1). Unfortunately the
-// format used means that we have to parse all of the file-level attributes to
-// find the one we are looking for. This format is slightly documented in "ELF
-// for the ARM Architecture" but mostly this is derived from reading the source
-// to gold and readelf.
-func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags uint32, err error) {
- found = false
- if data[0] != 'A' {
- return false, 0, fmt.Errorf(".ARM.attributes has unexpected format %c\n", data[0])
- }
- data = data[1:]
- for len(data) != 0 {
- sectionlength := e.Uint32(data)
- sectiondata := data[4:sectionlength]
- data = data[sectionlength:]
-
- nulIndex := bytes.IndexByte(sectiondata, 0)
- if nulIndex < 0 {
- return false, 0, fmt.Errorf("corrupt .ARM.attributes (section name not NUL-terminated)\n")
- }
- name := string(sectiondata[:nulIndex])
- sectiondata = sectiondata[nulIndex+1:]
-
- if name != "aeabi" {
- continue
- }
- for len(sectiondata) != 0 {
- subsectiontag, sz := binary.Uvarint(sectiondata)
- subsectionsize := e.Uint32(sectiondata[sz:])
- subsectiondata := sectiondata[sz+4 : subsectionsize]
- sectiondata = sectiondata[subsectionsize:]
-
- if subsectiontag != TagFile {
- continue
- }
- attrList := elfAttributeList{data: subsectiondata}
- for !attrList.done() {
- attr := attrList.armAttr()
- if attr.tag == TagABIVFPArgs && attr.ival == 1 {
- found = true
- ehdrFlags = 0x5000402 // has entry point, Version5 EABI, hard-float ABI
- }
- }
- if attrList.err != nil {
- return false, 0, fmt.Errorf("could not parse .ARM.attributes\n")
- }
- }
- }
- return found, ehdrFlags, nil
-}
-
-func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, flags uint32) ([]*sym.Symbol, uint32, error) {
- newSym := func(name string, version int) *sym.Symbol {
- return l.Create(name, syms)
- }
- lookup := func(name string, version int) *sym.Symbol {
- return l.LookupOrCreate(name, version, syms)
- }
- return load(arch, syms.IncVersion(), newSym, lookup, f, pkg, length, pn, flags)
-}
-
-func LoadOld(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, flags uint32) ([]*sym.Symbol, uint32, error) {
- return load(arch, syms.IncVersion(), syms.Newsym, syms.Lookup, f, pkg, length, pn, flags)
-}
-
-type lookupFunc func(string, int) *sym.Symbol
-
-// load loads the ELF file pn from f.
-// Symbols are written into syms, and a slice of the text symbols is returned.
-//
-// On ARM systems, Load will attempt to determine what ELF header flags to
-// emit by scanning the attributes in the ELF file being loaded. The
-// parameter initEhdrFlags contains the current header flags for the output
-// object, and the returned ehdrFlags contains what this Load function computes.
-// TODO: find a better place for this logic.
-func load(arch *sys.Arch, localSymVersion int, newSym, lookup lookupFunc, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []*sym.Symbol, ehdrFlags uint32, err error) {
- errorf := func(str string, args ...interface{}) ([]*sym.Symbol, uint32, error) {
- return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...))
- }
-
- base := f.Offset()
-
- var hdrbuf [64]uint8
- if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- hdr := new(ElfHdrBytes)
- binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
- if string(hdr.Ident[:4]) != "\x7FELF" {
- return errorf("malformed elf file, bad header")
- }
- var e binary.ByteOrder
- switch hdr.Ident[5] {
- case ElfDataLsb:
- e = binary.LittleEndian
-
- case ElfDataMsb:
- e = binary.BigEndian
-
- default:
- return errorf("malformed elf file, unknown header")
- }
-
- // read header
- elfobj := new(ElfObj)
-
- elfobj.e = e
- elfobj.f = f
- elfobj.base = base
- elfobj.length = length
- elfobj.name = pn
-
- is64 := 0
- if hdr.Ident[4] == ElfClass64 {
- is64 = 1
- hdr := new(ElfHdrBytes64)
- binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
- elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
- elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
- elfobj.version = e.Uint32(hdr.Version[:])
- elfobj.phoff = e.Uint64(hdr.Phoff[:])
- elfobj.shoff = e.Uint64(hdr.Shoff[:])
- elfobj.flags = e.Uint32(hdr.Flags[:])
- elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
- elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
- elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
- elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
- elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
- elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
- } else {
- elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
- elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
- elfobj.version = e.Uint32(hdr.Version[:])
- elfobj.entry = uint64(e.Uint32(hdr.Entry[:]))
- elfobj.phoff = uint64(e.Uint32(hdr.Phoff[:]))
- elfobj.shoff = uint64(e.Uint32(hdr.Shoff[:]))
- elfobj.flags = e.Uint32(hdr.Flags[:])
- elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
- elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
- elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
- elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
- elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
- elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
- }
-
- elfobj.is64 = is64
-
- if v := uint32(hdr.Ident[6]); v != elfobj.version {
- return errorf("malformed elf version: got %d, want %d", v, elfobj.version)
- }
-
- if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable {
- return errorf("elf but not elf relocatable object")
- }
-
- switch arch.Family {
- default:
- return errorf("elf %s unimplemented", arch.Name)
-
- case sys.MIPS:
- if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass32 {
- return errorf("elf object but not mips")
- }
-
- case sys.MIPS64:
- if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not mips64")
- }
-
- case sys.ARM:
- if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
- return errorf("elf object but not arm")
- }
-
- case sys.AMD64:
- if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not amd64")
- }
-
- case sys.ARM64:
- if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not arm64")
- }
-
- case sys.I386:
- if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
- return errorf("elf object but not 386")
- }
-
- case sys.PPC64:
- if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not ppc64")
- }
-
- case sys.S390X:
- if elfobj.machine != ElfMachS390 || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not s390x")
- }
- }
-
- // load section list into memory.
- elfobj.sect = make([]ElfSect, elfobj.shnum)
-
- elfobj.nsect = uint(elfobj.shnum)
- for i := 0; uint(i) < elfobj.nsect; i++ {
- f.MustSeek(int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0)
- sect := &elfobj.sect[i]
- if is64 != 0 {
- var b ElfSectBytes64
-
- if err := binary.Read(f, e, &b); err != nil {
- return errorf("malformed elf file: %v", err)
- }
-
- sect.nameoff = e.Uint32(b.Name[:])
- sect.type_ = e.Uint32(b.Type[:])
- sect.flags = e.Uint64(b.Flags[:])
- sect.addr = e.Uint64(b.Addr[:])
- sect.off = e.Uint64(b.Off[:])
- sect.size = e.Uint64(b.Size[:])
- sect.link = e.Uint32(b.Link[:])
- sect.info = e.Uint32(b.Info[:])
- sect.align = e.Uint64(b.Align[:])
- sect.entsize = e.Uint64(b.Entsize[:])
- } else {
- var b ElfSectBytes
-
- if err := binary.Read(f, e, &b); err != nil {
- return errorf("malformed elf file: %v", err)
- }
-
- sect.nameoff = e.Uint32(b.Name[:])
- sect.type_ = e.Uint32(b.Type[:])
- sect.flags = uint64(e.Uint32(b.Flags[:]))
- sect.addr = uint64(e.Uint32(b.Addr[:]))
- sect.off = uint64(e.Uint32(b.Off[:]))
- sect.size = uint64(e.Uint32(b.Size[:]))
- sect.link = e.Uint32(b.Link[:])
- sect.info = e.Uint32(b.Info[:])
- sect.align = uint64(e.Uint32(b.Align[:]))
- sect.entsize = uint64(e.Uint32(b.Entsize[:]))
- }
- }
-
- // read section string table and translate names
- if elfobj.shstrndx >= uint32(elfobj.nsect) {
- return errorf("malformed elf file: shstrndx out of range %d >= %d", elfobj.shstrndx, elfobj.nsect)
- }
-
- sect := &elfobj.sect[elfobj.shstrndx]
- if err := elfmap(elfobj, sect); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- for i := 0; uint(i) < elfobj.nsect; i++ {
- if elfobj.sect[i].nameoff != 0 {
- elfobj.sect[i].name = cstring(sect.base[elfobj.sect[i].nameoff:])
- }
- }
-
- // load string table for symbols into memory.
- elfobj.symtab = section(elfobj, ".symtab")
-
- if elfobj.symtab == nil {
- // our work is done here - no symbols means nothing can refer to this file
- return
- }
-
- if elfobj.symtab.link <= 0 || elfobj.symtab.link >= uint32(elfobj.nsect) {
- return errorf("elf object has symbol table with invalid string table link")
- }
-
- elfobj.symstr = &elfobj.sect[elfobj.symtab.link]
- if is64 != 0 {
- elfobj.nsymtab = int(elfobj.symtab.size / ELF64SYMSIZE)
- } else {
- elfobj.nsymtab = int(elfobj.symtab.size / ELF32SYMSIZE)
- }
-
- if err := elfmap(elfobj, elfobj.symtab); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- if err := elfmap(elfobj, elfobj.symstr); err != nil {
- return errorf("malformed elf file: %v", err)
- }
-
- // load text and data segments into memory.
- // they are not as small as the section lists, but we'll need
- // the memory anyway for the symbol images, so we might
- // as well use one large chunk.
-
- // create symbols for elfmapped sections
- sectsymNames := make(map[string]bool)
- counter := 0
- for i := 0; uint(i) < elfobj.nsect; i++ {
- sect = &elfobj.sect[i]
- if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" {
- if err := elfmap(elfobj, sect); err != nil {
- return errorf("%s: malformed elf file: %v", pn, err)
- }
- // We assume the soft-float ABI unless we see a tag indicating otherwise.
- if initEhdrFlags == 0x5000002 {
- ehdrFlags = 0x5000202
- } else {
- ehdrFlags = initEhdrFlags
- }
- found, newEhdrFlags, err := parseArmAttributes(e, sect.base[:sect.size])
- if err != nil {
- // TODO(dfc) should this return an error?
- log.Printf("%s: %v", pn, err)
- }
- if found {
- ehdrFlags = newEhdrFlags
- }
- }
- if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 {
- continue
- }
- if sect.type_ != ElfSectNobits {
- if err := elfmap(elfobj, sect); err != nil {
- return errorf("%s: malformed elf file: %v", pn, err)
- }
- }
-
- name := fmt.Sprintf("%s(%s)", pkg, sect.name)
- for sectsymNames[name] {
- counter++
- name = fmt.Sprintf("%s(%s%d)", pkg, sect.name, counter)
- }
- sectsymNames[name] = true
-
- s := lookup(name, localSymVersion)
-
- switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
- default:
- return errorf("%s: unexpected flags for ELF section %s", pn, sect.name)
-
- case ElfSectFlagAlloc:
- s.Type = sym.SRODATA
-
- case ElfSectFlagAlloc + ElfSectFlagWrite:
- if sect.type_ == ElfSectNobits {
- s.Type = sym.SNOPTRBSS
- } else {
- s.Type = sym.SNOPTRDATA
- }
-
- case ElfSectFlagAlloc + ElfSectFlagExec:
- s.Type = sym.STEXT
- }
-
- if sect.name == ".got" || sect.name == ".toc" {
- s.Type = sym.SELFGOT
- }
- if sect.type_ == ElfSectProgbits {
- s.P = sect.base
- s.P = s.P[:sect.size]
- }
-
- s.Size = int64(sect.size)
- s.Align = int32(sect.align)
- sect.sym = s
- }
-
- // enter sub-symbols into symbol table.
- // symbol 0 is the null symbol.
- symbols := make([]*sym.Symbol, elfobj.nsymtab)
-
- for i := 1; i < elfobj.nsymtab; i++ {
- var elfsym ElfSym
- if err := readelfsym(newSym, lookup, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
- return errorf("%s: malformed elf file: %v", pn, err)
- }
- symbols[i] = elfsym.sym
- if elfsym.type_ != ElfSymTypeFunc && elfsym.type_ != ElfSymTypeObject && elfsym.type_ != ElfSymTypeNone && elfsym.type_ != ElfSymTypeCommon {
- continue
- }
- if elfsym.shndx == ElfSymShnCommon || elfsym.type_ == ElfSymTypeCommon {
- s := elfsym.sym
- if uint64(s.Size) < elfsym.size {
- s.Size = int64(elfsym.size)
- }
- if s.Type == 0 || s.Type == sym.SXREF {
- s.Type = sym.SNOPTRBSS
- }
- continue
- }
-
- if uint(elfsym.shndx) >= elfobj.nsect || elfsym.shndx == 0 {
- continue
- }
-
- // even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols
- if elfsym.sym == nil {
- continue
- }
- sect = &elfobj.sect[elfsym.shndx]
- if sect.sym == nil {
- if strings.HasPrefix(elfsym.name, ".Linfo_string") { // clang does this
- continue
- }
-
- if elfsym.name == "" && elfsym.type_ == 0 && sect.name == ".debug_str" {
- // This reportedly happens with clang 3.7 on ARM.
- // See issue 13139.
- continue
- }
-
- if strings.HasPrefix(elfsym.name, "$d") && elfsym.type_ == 0 && sect.name == ".debug_frame" {
- // "$d" is a marker, not a real symbol.
- // This happens with gcc on ARM64.
- // See https://sourceware.org/bugzilla/show_bug.cgi?id=21809
- continue
- }
-
- if strings.HasPrefix(elfsym.name, ".LASF") { // gcc on s390x does this
- continue
- }
- return errorf("%v: sym#%d: ignoring symbol in section %d (type %d)", elfsym.sym, i, elfsym.shndx, elfsym.type_)
- }
-
- s := elfsym.sym
- 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.Sub = sect.sym.Sub
- sect.sym.Sub = s
- s.Type = sect.sym.Type
- s.Attr |= sym.AttrSubSymbol
- if !s.Attr.CgoExportDynamic() {
- s.SetDynimplib("") // satisfy dynimport
- }
- s.Value = int64(elfsym.value)
- s.Size = int64(elfsym.size)
- s.Outer = sect.sym
- if sect.sym.Type == sym.STEXT {
- if s.Attr.External() && !s.Attr.DuplicateOK() {
- return errorf("%v: duplicate symbol definition", s)
- }
- s.Attr |= sym.AttrExternal
- }
-
- if elfobj.machine == ElfMachPower64 {
- flag := int(elfsym.other) >> 5
- if 2 <= flag && flag <= 6 {
- s.SetLocalentry(1 << uint(flag-2))
- } else if flag == 7 {
- return errorf("%v: invalid sym.other 0x%x", s, elfsym.other)
- }
- }
- }
-
- // Sort outer lists by address, adding to textp.
- // This keeps textp in increasing address order.
- for i := uint(0); i < elfobj.nsect; i++ {
- s := elfobj.sect[i].sym
- if s == nil {
- continue
- }
- if s.Sub != nil {
- s.Sub = sym.SortSub(s.Sub)
- }
- 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 s = s.Sub; s != nil; s = s.Sub {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
- textp = append(textp, s)
- }
- }
- }
-
- // load relocations
- for i := uint(0); i < elfobj.nsect; i++ {
- rsect := &elfobj.sect[i]
- if rsect.type_ != ElfSectRela && rsect.type_ != ElfSectRel {
- continue
- }
- if rsect.info >= uint32(elfobj.nsect) || elfobj.sect[rsect.info].base == nil {
- continue
- }
- sect = &elfobj.sect[rsect.info]
- if err := elfmap(elfobj, rsect); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- rela := 0
- if rsect.type_ == ElfSectRela {
- rela = 1
- }
- n := int(rsect.size / uint64(4+4*is64) / uint64(2+rela))
- r := make([]sym.Reloc, n)
- p := rsect.base
- for j := 0; j < n; j++ {
- var add uint64
- var symIdx int
- var relocType uint64
-
- rp := &r[j]
- if is64 != 0 {
- // 64-bit rel/rela
- rp.Off = int32(e.Uint64(p))
-
- p = p[8:]
- switch arch.Family {
- case sys.MIPS64:
- // https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf
- // The doc shows it's different with general Linux ELF
- symIdx = int(e.Uint32(p))
- relocType = uint64(p[7])
- default:
- info := e.Uint64(p)
- relocType = info & 0xffffffff
- symIdx = int(info >> 32)
- }
- p = p[8:]
- if rela != 0 {
- add = e.Uint64(p)
- p = p[8:]
- }
- } else {
- // 32-bit rel/rela
- rp.Off = int32(e.Uint32(p))
-
- p = p[4:]
- info := e.Uint32(p)
- relocType = uint64(info & 0xff)
- symIdx = int(info >> 8)
- p = p[4:]
- if rela != 0 {
- add = uint64(e.Uint32(p))
- p = p[4:]
- }
- }
-
- if relocType == 0 { // skip R_*_NONE relocation
- j--
- n--
- continue
- }
-
- if symIdx == 0 { // absolute relocation, don't bother reading the null symbol
- rp.Sym = nil
- } else {
- var elfsym ElfSym
- if err := readelfsym(newSym, lookup, arch, elfobj, symIdx, &elfsym, 0, 0); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- elfsym.sym = symbols[symIdx]
- if elfsym.sym == nil {
- return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, symIdx, elfsym.name, elfsym.shndx, elfsym.type_)
- }
-
- rp.Sym = elfsym.sym
- }
-
- rp.Type = objabi.ElfRelocOffset + objabi.RelocType(relocType)
- rp.Siz, err = relSize(arch, pn, uint32(relocType))
- if err != nil {
- return nil, 0, err
- }
- if rela != 0 {
- rp.Add = int64(add)
- } else {
- // load addend from image
- if rp.Siz == 4 {
- rp.Add = int64(e.Uint32(sect.base[rp.Off:]))
- } else if rp.Siz == 8 {
- rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
- } else {
- return errorf("invalid rela size %d", rp.Siz)
- }
- }
-
- if rp.Siz == 2 {
- rp.Add = int64(int16(rp.Add))
- }
- if rp.Siz == 4 {
- rp.Add = int64(int32(rp.Add))
- }
- }
-
- //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
- sort.Sort(sym.RelocByOff(r[:n]))
- // just in case
-
- s := sect.sym
- s.R = r
- s.R = s.R[:n]
- }
-
- return textp, ehdrFlags, nil
-}
-
-func section(elfobj *ElfObj, name string) *ElfSect {
- for i := 0; uint(i) < elfobj.nsect; i++ {
- if elfobj.sect[i].name != "" && name != "" && elfobj.sect[i].name == name {
- return &elfobj.sect[i]
- }
- }
- return nil
-}
-
-func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
- if sect.base != nil {
- return nil
- }
-
- if sect.off+sect.size > uint64(elfobj.length) {
- err = fmt.Errorf("elf section past end of file")
- return err
- }
-
- sect.base = make([]byte, sect.size)
- elfobj.f.MustSeek(int64(uint64(elfobj.base)+sect.off), 0)
- if _, err := io.ReadFull(elfobj.f, sect.base); err != nil {
- return fmt.Errorf("short read: %v", err)
- }
-
- return nil
-}
-
-func readelfsym(newSym, lookup lookupFunc, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
- if i >= elfobj.nsymtab || i < 0 {
- err = fmt.Errorf("invalid elf symbol index")
- return err
- }
-
- if i == 0 {
- return fmt.Errorf("readym: read null symbol!")
- }
-
- if elfobj.is64 != 0 {
- b := new(ElfSymBytes64)
- binary.Read(bytes.NewReader(elfobj.symtab.base[i*ELF64SYMSIZE:(i+1)*ELF64SYMSIZE]), elfobj.e, b)
- elfsym.name = cstring(elfobj.symstr.base[elfobj.e.Uint32(b.Name[:]):])
- elfsym.value = elfobj.e.Uint64(b.Value[:])
- elfsym.size = elfobj.e.Uint64(b.Size[:])
- elfsym.shndx = elfobj.e.Uint16(b.Shndx[:])
- elfsym.bind = b.Info >> 4
- elfsym.type_ = b.Info & 0xf
- elfsym.other = b.Other
- } else {
- b := new(ElfSymBytes)
- binary.Read(bytes.NewReader(elfobj.symtab.base[i*ELF32SYMSIZE:(i+1)*ELF32SYMSIZE]), elfobj.e, b)
- elfsym.name = cstring(elfobj.symstr.base[elfobj.e.Uint32(b.Name[:]):])
- elfsym.value = uint64(elfobj.e.Uint32(b.Value[:]))
- elfsym.size = uint64(elfobj.e.Uint32(b.Size[:]))
- elfsym.shndx = elfobj.e.Uint16(b.Shndx[:])
- elfsym.bind = b.Info >> 4
- elfsym.type_ = b.Info & 0xf
- elfsym.other = b.Other
- }
-
- var s *sym.Symbol
- if elfsym.name == "_GLOBAL_OFFSET_TABLE_" {
- elfsym.name = ".got"
- }
- if elfsym.name == ".TOC." {
- // Magic symbol on ppc64. Will be set to this object
- // file's .got+0x8000.
- elfsym.bind = ElfSymBindLocal
- }
-
- switch elfsym.type_ {
- case ElfSymTypeSection:
- s = elfobj.sect[elfsym.shndx].sym
-
- case ElfSymTypeObject, ElfSymTypeFunc, ElfSymTypeNone, ElfSymTypeCommon:
- switch elfsym.bind {
- case ElfSymBindGlobal:
- if needSym != 0 {
- s = lookup(elfsym.name, 0)
-
- // for global scoped hidden symbols we should insert it into
- // symbol hash table, but mark them as hidden.
- // __i686.get_pc_thunk.bx is allowed to be duplicated, to
- // workaround that we set dupok.
- // TODO(minux): correctly handle __i686.get_pc_thunk.bx without
- // set dupok generally. See https://golang.org/cl/5823055
- // comment #5 for details.
- if s != nil && elfsym.other == 2 {
- s.Attr |= sym.AttrDuplicateOK | sym.AttrVisibilityHidden
- }
- }
-
- case ElfSymBindLocal:
- if (arch.Family == sys.ARM || arch.Family == sys.ARM64) && (strings.HasPrefix(elfsym.name, "$a") || strings.HasPrefix(elfsym.name, "$d") || strings.HasPrefix(elfsym.name, "$x")) {
- // binutils for arm and arm64 generate these mapping
- // symbols, ignore these
- break
- }
-
- if elfsym.name == ".TOC." {
- // We need to be able to look this up,
- // so put it in the hash table.
- if needSym != 0 {
- s = lookup(elfsym.name, localSymVersion)
- s.Attr |= sym.AttrVisibilityHidden
- }
-
- break
- }
-
- if needSym != 0 {
- // local names and hidden global names are unique
- // and should only be referenced by their index, not name, so we
- // don't bother to add them into the hash table
- // FIXME: pass empty string here for name? This would
- // reduce mem use, but also (possibly) make it harder
- // to debug problems.
- s = newSym(elfsym.name, localSymVersion)
-
- s.Attr |= sym.AttrVisibilityHidden
- }
-
- case ElfSymBindWeak:
- if needSym != 0 {
- s = lookup(elfsym.name, 0)
- if elfsym.other == 2 {
- s.Attr |= sym.AttrVisibilityHidden
- }
-
- // Allow weak symbols to be duplicated when already defined.
- if s.Outer != nil {
- s.Attr |= sym.AttrDuplicateOK
- }
- }
-
- default:
- err = fmt.Errorf("%s: invalid symbol binding %d", elfsym.name, elfsym.bind)
- return err
- }
- }
-
- // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
- // sense and should be removed when someone has thought about it properly.
- if s != nil && s.Type == 0 && !s.Attr.VisibilityHidden() && elfsym.type_ != ElfSymTypeSection {
- s.Type = sym.SXREF
- }
- elfsym.sym = s
-
- return nil
-}
-
-func relSize(arch *sys.Arch, pn string, elftype uint32) (uint8, error) {
- // TODO(mdempsky): Replace this with a struct-valued switch statement
- // once golang.org/issue/15164 is fixed or found to not impair cmd/link
- // performance.
-
- const (
- AMD64 = uint32(sys.AMD64)
- ARM = uint32(sys.ARM)
- ARM64 = uint32(sys.ARM64)
- I386 = uint32(sys.I386)
- PPC64 = uint32(sys.PPC64)
- S390X = uint32(sys.S390X)
- MIPS = uint32(sys.MIPS)
- MIPS64 = uint32(sys.MIPS64)
- )
-
- switch uint32(arch.Family) | elftype<<16 {
- default:
- return 0, fmt.Errorf("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
-
- case MIPS | uint32(elf.R_MIPS_HI16)<<16,
- MIPS | uint32(elf.R_MIPS_LO16)<<16,
- MIPS | uint32(elf.R_MIPS_GOT16)<<16,
- MIPS | uint32(elf.R_MIPS_GPREL16)<<16,
- MIPS | uint32(elf.R_MIPS_GOT_PAGE)<<16,
- MIPS | uint32(elf.R_MIPS_JALR)<<16,
- MIPS | uint32(elf.R_MIPS_GOT_OFST)<<16,
- MIPS64 | uint32(elf.R_MIPS_HI16)<<16,
- MIPS64 | uint32(elf.R_MIPS_LO16)<<16,
- MIPS64 | uint32(elf.R_MIPS_GOT16)<<16,
- MIPS64 | uint32(elf.R_MIPS_GPREL16)<<16,
- MIPS64 | uint32(elf.R_MIPS_GOT_PAGE)<<16,
- MIPS64 | uint32(elf.R_MIPS_JALR)<<16,
- MIPS64 | uint32(elf.R_MIPS_GOT_OFST)<<16:
- return 4, nil
-
- case S390X | uint32(elf.R_390_8)<<16:
- return 1, nil
-
- case PPC64 | uint32(elf.R_PPC64_TOC16)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_LO)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_HI)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_HA)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_DS)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_LO_DS)<<16,
- PPC64 | uint32(elf.R_PPC64_REL16_LO)<<16,
- PPC64 | uint32(elf.R_PPC64_REL16_HI)<<16,
- PPC64 | uint32(elf.R_PPC64_REL16_HA)<<16,
- S390X | uint32(elf.R_390_16)<<16,
- S390X | uint32(elf.R_390_GOT16)<<16,
- S390X | uint32(elf.R_390_PC16)<<16,
- S390X | uint32(elf.R_390_PC16DBL)<<16,
- S390X | uint32(elf.R_390_PLT16DBL)<<16:
- return 2, nil
-
- case ARM | uint32(elf.R_ARM_ABS32)<<16,
- ARM | uint32(elf.R_ARM_GOT32)<<16,
- ARM | uint32(elf.R_ARM_PLT32)<<16,
- ARM | uint32(elf.R_ARM_GOTOFF)<<16,
- ARM | uint32(elf.R_ARM_GOTPC)<<16,
- ARM | uint32(elf.R_ARM_THM_PC22)<<16,
- ARM | uint32(elf.R_ARM_REL32)<<16,
- ARM | uint32(elf.R_ARM_CALL)<<16,
- ARM | uint32(elf.R_ARM_V4BX)<<16,
- ARM | uint32(elf.R_ARM_GOT_PREL)<<16,
- ARM | uint32(elf.R_ARM_PC24)<<16,
- ARM | uint32(elf.R_ARM_JUMP24)<<16,
- ARM64 | uint32(elf.R_AARCH64_CALL26)<<16,
- ARM64 | uint32(elf.R_AARCH64_ADR_GOT_PAGE)<<16,
- ARM64 | uint32(elf.R_AARCH64_LD64_GOT_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_ADR_PREL_PG_HI21)<<16,
- ARM64 | uint32(elf.R_AARCH64_ADD_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_LDST8_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_LDST32_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_LDST64_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_LDST128_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_PREL32)<<16,
- ARM64 | uint32(elf.R_AARCH64_JUMP26)<<16,
- AMD64 | uint32(elf.R_X86_64_PC32)<<16,
- AMD64 | uint32(elf.R_X86_64_PLT32)<<16,
- AMD64 | uint32(elf.R_X86_64_GOTPCREL)<<16,
- AMD64 | uint32(elf.R_X86_64_GOTPCRELX)<<16,
- AMD64 | uint32(elf.R_X86_64_REX_GOTPCRELX)<<16,
- I386 | uint32(elf.R_386_32)<<16,
- I386 | uint32(elf.R_386_PC32)<<16,
- I386 | uint32(elf.R_386_GOT32)<<16,
- I386 | uint32(elf.R_386_PLT32)<<16,
- I386 | uint32(elf.R_386_GOTOFF)<<16,
- I386 | uint32(elf.R_386_GOTPC)<<16,
- I386 | uint32(elf.R_386_GOT32X)<<16,
- PPC64 | uint32(elf.R_PPC64_REL24)<<16,
- PPC64 | uint32(elf.R_PPC_REL32)<<16,
- S390X | uint32(elf.R_390_32)<<16,
- S390X | uint32(elf.R_390_PC32)<<16,
- S390X | uint32(elf.R_390_GOT32)<<16,
- S390X | uint32(elf.R_390_PLT32)<<16,
- S390X | uint32(elf.R_390_PC32DBL)<<16,
- S390X | uint32(elf.R_390_PLT32DBL)<<16,
- S390X | uint32(elf.R_390_GOTPCDBL)<<16,
- S390X | uint32(elf.R_390_GOTENT)<<16:
- return 4, nil
-
- case AMD64 | uint32(elf.R_X86_64_64)<<16,
- AMD64 | uint32(elf.R_X86_64_PC64)<<16,
- ARM64 | uint32(elf.R_AARCH64_ABS64)<<16,
- ARM64 | uint32(elf.R_AARCH64_PREL64)<<16,
- PPC64 | uint32(elf.R_PPC64_ADDR64)<<16,
- S390X | uint32(elf.R_390_GLOB_DAT)<<16,
- S390X | uint32(elf.R_390_RELATIVE)<<16,
- S390X | uint32(elf.R_390_GOTOFF)<<16,
- S390X | uint32(elf.R_390_GOTPC)<<16,
- S390X | uint32(elf.R_390_64)<<16,
- S390X | uint32(elf.R_390_PC64)<<16,
- S390X | uint32(elf.R_390_GOT64)<<16,
- S390X | uint32(elf.R_390_PLT64)<<16:
- return 8, nil
- }
-}
-
-func cstring(x []byte) string {
- i := bytes.IndexByte(x, '\x00')
- if i >= 0 {
- x = x[:i]
- }
- return string(x)
-}
+++ /dev/null
-// 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)
- }
-}
+++ /dev/null
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package loadmacho implements a Mach-O file reader.
-package loadmacho
-
-import (
- "bytes"
- "cmd/internal/bio"
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/loader"
- "cmd/oldlink/internal/sym"
- "encoding/binary"
- "fmt"
- "io"
- "sort"
-)
-
-/*
-Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
-http://code.swtch.com/plan9port/src/tip/src/libmach/
-
- Copyright © 2004 Russ Cox.
- Portions Copyright © 2008-2010 Google Inc.
- Portions Copyright © 2010 The Go Authors.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld
-const (
- MACHO_X86_64_RELOC_UNSIGNED = 0
- MACHO_X86_64_RELOC_SIGNED = 1
- MACHO_FAKE_GOTPCREL = 100
-)
-
-type ldMachoObj struct {
- f *bio.Reader
- base int64 // off in f where Mach-O begins
- length int64 // length of Mach-O
- is64 bool
- name string
- e binary.ByteOrder
- cputype uint
- subcputype uint
- filetype uint32
- flags uint32
- cmd []ldMachoCmd
- ncmd uint
-}
-
-type ldMachoCmd struct {
- type_ int
- off uint32
- size uint32
- seg ldMachoSeg
- sym ldMachoSymtab
- dsym ldMachoDysymtab
-}
-
-type ldMachoSeg struct {
- name string
- vmaddr uint64
- vmsize uint64
- fileoff uint32
- filesz uint32
- maxprot uint32
- initprot uint32
- nsect uint32
- flags uint32
- sect []ldMachoSect
-}
-
-type ldMachoSect struct {
- name string
- segname string
- addr uint64
- size uint64
- off uint32
- align uint32
- reloff uint32
- nreloc uint32
- flags uint32
- res1 uint32
- res2 uint32
- sym *sym.Symbol
- rel []ldMachoRel
-}
-
-type ldMachoRel struct {
- addr uint32
- symnum uint32
- pcrel uint8
- length uint8
- extrn uint8
- type_ uint8
- scattered uint8
- value uint32
-}
-
-type ldMachoSymtab struct {
- symoff uint32
- nsym uint32
- stroff uint32
- strsize uint32
- str []byte
- sym []ldMachoSym
-}
-
-type ldMachoSym struct {
- name string
- type_ uint8
- sectnum uint8
- desc uint16
- kind int8
- value uint64
- sym *sym.Symbol
-}
-
-type ldMachoDysymtab struct {
- ilocalsym uint32
- nlocalsym uint32
- iextdefsym uint32
- nextdefsym uint32
- iundefsym uint32
- nundefsym uint32
- tocoff uint32
- ntoc uint32
- modtaboff uint32
- nmodtab uint32
- extrefsymoff uint32
- nextrefsyms uint32
- indirectsymoff uint32
- nindirectsyms uint32
- extreloff uint32
- nextrel uint32
- locreloff uint32
- nlocrel uint32
- indir []uint32
-}
-
-// ldMachoSym.type_
-const (
- N_EXT = 0x01
- N_TYPE = 0x1e
- N_STAB = 0xe0
-)
-
-// ldMachoSym.desc
-const (
- N_WEAK_REF = 0x40
- N_WEAK_DEF = 0x80
-)
-
-const (
- LdMachoCpuVax = 1
- LdMachoCpu68000 = 6
- LdMachoCpu386 = 7
- LdMachoCpuAmd64 = 0x1000007
- LdMachoCpuMips = 8
- LdMachoCpu98000 = 10
- LdMachoCpuHppa = 11
- LdMachoCpuArm = 12
- LdMachoCpu88000 = 13
- LdMachoCpuSparc = 14
- LdMachoCpu860 = 15
- LdMachoCpuAlpha = 16
- LdMachoCpuPower = 18
- LdMachoCmdSegment = 1
- LdMachoCmdSymtab = 2
- LdMachoCmdSymseg = 3
- LdMachoCmdThread = 4
- LdMachoCmdDysymtab = 11
- LdMachoCmdSegment64 = 25
- LdMachoFileObject = 1
- LdMachoFileExecutable = 2
- LdMachoFileFvmlib = 3
- LdMachoFileCore = 4
- LdMachoFilePreload = 5
-)
-
-func unpackcmd(p []byte, m *ldMachoObj, c *ldMachoCmd, type_ uint, sz uint) int {
- e4 := m.e.Uint32
- e8 := m.e.Uint64
-
- c.type_ = int(type_)
- c.size = uint32(sz)
- switch type_ {
- default:
- return -1
-
- case LdMachoCmdSegment:
- if sz < 56 {
- return -1
- }
- c.seg.name = cstring(p[8:24])
- c.seg.vmaddr = uint64(e4(p[24:]))
- c.seg.vmsize = uint64(e4(p[28:]))
- c.seg.fileoff = e4(p[32:])
- c.seg.filesz = e4(p[36:])
- c.seg.maxprot = e4(p[40:])
- c.seg.initprot = e4(p[44:])
- c.seg.nsect = e4(p[48:])
- c.seg.flags = e4(p[52:])
- c.seg.sect = make([]ldMachoSect, c.seg.nsect)
- if uint32(sz) < 56+c.seg.nsect*68 {
- return -1
- }
- p = p[56:]
- var s *ldMachoSect
- for i := 0; uint32(i) < c.seg.nsect; i++ {
- s = &c.seg.sect[i]
- s.name = cstring(p[0:16])
- s.segname = cstring(p[16:32])
- s.addr = uint64(e4(p[32:]))
- s.size = uint64(e4(p[36:]))
- s.off = e4(p[40:])
- s.align = e4(p[44:])
- s.reloff = e4(p[48:])
- s.nreloc = e4(p[52:])
- s.flags = e4(p[56:])
- s.res1 = e4(p[60:])
- s.res2 = e4(p[64:])
- p = p[68:]
- }
-
- case LdMachoCmdSegment64:
- if sz < 72 {
- return -1
- }
- c.seg.name = cstring(p[8:24])
- c.seg.vmaddr = e8(p[24:])
- c.seg.vmsize = e8(p[32:])
- c.seg.fileoff = uint32(e8(p[40:]))
- c.seg.filesz = uint32(e8(p[48:]))
- c.seg.maxprot = e4(p[56:])
- c.seg.initprot = e4(p[60:])
- c.seg.nsect = e4(p[64:])
- c.seg.flags = e4(p[68:])
- c.seg.sect = make([]ldMachoSect, c.seg.nsect)
- if uint32(sz) < 72+c.seg.nsect*80 {
- return -1
- }
- p = p[72:]
- var s *ldMachoSect
- for i := 0; uint32(i) < c.seg.nsect; i++ {
- s = &c.seg.sect[i]
- s.name = cstring(p[0:16])
- s.segname = cstring(p[16:32])
- s.addr = e8(p[32:])
- s.size = e8(p[40:])
- s.off = e4(p[48:])
- s.align = e4(p[52:])
- s.reloff = e4(p[56:])
- s.nreloc = e4(p[60:])
- s.flags = e4(p[64:])
- s.res1 = e4(p[68:])
- s.res2 = e4(p[72:])
-
- // p+76 is reserved
- p = p[80:]
- }
-
- case LdMachoCmdSymtab:
- if sz < 24 {
- return -1
- }
- c.sym.symoff = e4(p[8:])
- c.sym.nsym = e4(p[12:])
- c.sym.stroff = e4(p[16:])
- c.sym.strsize = e4(p[20:])
-
- case LdMachoCmdDysymtab:
- if sz < 80 {
- return -1
- }
- c.dsym.ilocalsym = e4(p[8:])
- c.dsym.nlocalsym = e4(p[12:])
- c.dsym.iextdefsym = e4(p[16:])
- c.dsym.nextdefsym = e4(p[20:])
- c.dsym.iundefsym = e4(p[24:])
- c.dsym.nundefsym = e4(p[28:])
- c.dsym.tocoff = e4(p[32:])
- c.dsym.ntoc = e4(p[36:])
- c.dsym.modtaboff = e4(p[40:])
- c.dsym.nmodtab = e4(p[44:])
- c.dsym.extrefsymoff = e4(p[48:])
- c.dsym.nextrefsyms = e4(p[52:])
- c.dsym.indirectsymoff = e4(p[56:])
- c.dsym.nindirectsyms = e4(p[60:])
- c.dsym.extreloff = e4(p[64:])
- c.dsym.nextrel = e4(p[68:])
- c.dsym.locreloff = e4(p[72:])
- c.dsym.nlocrel = e4(p[76:])
- }
-
- return 0
-}
-
-func macholoadrel(m *ldMachoObj, sect *ldMachoSect) int {
- if sect.rel != nil || sect.nreloc == 0 {
- return 0
- }
- rel := make([]ldMachoRel, sect.nreloc)
- n := int(sect.nreloc * 8)
- buf := make([]byte, n)
- m.f.MustSeek(m.base+int64(sect.reloff), 0)
- if _, err := io.ReadFull(m.f, buf); err != nil {
- return -1
- }
- for i := uint32(0); i < sect.nreloc; i++ {
- r := &rel[i]
- p := buf[i*8:]
- r.addr = m.e.Uint32(p)
-
- // TODO(rsc): Wrong interpretation for big-endian bitfields?
- if r.addr&0x80000000 != 0 {
- // scatterbrained relocation
- r.scattered = 1
-
- v := r.addr >> 24
- r.addr &= 0xFFFFFF
- r.type_ = uint8(v & 0xF)
- v >>= 4
- r.length = 1 << (v & 3)
- v >>= 2
- r.pcrel = uint8(v & 1)
- r.value = m.e.Uint32(p[4:])
- } else {
- v := m.e.Uint32(p[4:])
- r.symnum = v & 0xFFFFFF
- v >>= 24
- r.pcrel = uint8(v & 1)
- v >>= 1
- r.length = 1 << (v & 3)
- v >>= 2
- r.extrn = uint8(v & 1)
- v >>= 1
- r.type_ = uint8(v)
- }
- }
-
- sect.rel = rel
- return 0
-}
-
-func macholoaddsym(m *ldMachoObj, d *ldMachoDysymtab) int {
- n := int(d.nindirectsyms)
-
- p := make([]byte, n*4)
- m.f.MustSeek(m.base+int64(d.indirectsymoff), 0)
- if _, err := io.ReadFull(m.f, p); err != nil {
- return -1
- }
-
- d.indir = make([]uint32, n)
- for i := 0; i < n; i++ {
- d.indir[i] = m.e.Uint32(p[4*i:])
- }
- return 0
-}
-
-func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int {
- if symtab.sym != nil {
- return 0
- }
-
- strbuf := make([]byte, symtab.strsize)
- m.f.MustSeek(m.base+int64(symtab.stroff), 0)
- if _, err := io.ReadFull(m.f, strbuf); err != nil {
- return -1
- }
-
- symsize := 12
- if m.is64 {
- symsize = 16
- }
- n := int(symtab.nsym * uint32(symsize))
- symbuf := make([]byte, n)
- m.f.MustSeek(m.base+int64(symtab.symoff), 0)
- if _, err := io.ReadFull(m.f, symbuf); err != nil {
- return -1
- }
- sym := make([]ldMachoSym, symtab.nsym)
- p := symbuf
- for i := uint32(0); i < symtab.nsym; i++ {
- s := &sym[i]
- v := m.e.Uint32(p)
- if v >= symtab.strsize {
- return -1
- }
- s.name = cstring(strbuf[v:])
- s.type_ = p[4]
- s.sectnum = p[5]
- s.desc = m.e.Uint16(p[6:])
- if m.is64 {
- s.value = m.e.Uint64(p[8:])
- } else {
- s.value = uint64(m.e.Uint32(p[8:]))
- }
- p = p[symsize:]
- }
-
- symtab.str = strbuf
- symtab.sym = sym
- return 0
-}
-
-func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) ([]*sym.Symbol, error) {
- newSym := func(name string, version int) *sym.Symbol {
- return l.LookupOrCreate(name, version, syms)
- }
- return load(arch, syms.IncVersion(), newSym, f, pkg, length, pn)
-}
-
-func LoadOld(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
- return load(arch, syms.IncVersion(), syms.Lookup, f, pkg, length, pn)
-}
-
-// load the Mach-O file pn from f.
-// Symbols are written into syms, and a slice of the text symbols is returned.
-func load(arch *sys.Arch, localSymVersion int, lookup func(string, int) *sym.Symbol, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
- errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
- return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...))
- }
-
- base := f.Offset()
-
- var hdr [7 * 4]uint8
- if _, err := io.ReadFull(f, hdr[:]); err != nil {
- return errorf("reading hdr: %v", err)
- }
-
- var e binary.ByteOrder
- if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
- e = binary.BigEndian
- } else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
- e = binary.LittleEndian
- } else {
- return errorf("bad magic - not mach-o file")
- }
-
- is64 := e.Uint32(hdr[:]) == 0xFEEDFACF
- ncmd := e.Uint32(hdr[4*4:])
- cmdsz := e.Uint32(hdr[5*4:])
- if ncmd > 0x10000 || cmdsz >= 0x01000000 {
- return errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
- }
-
- if is64 {
- f.MustSeek(4, 1) // skip reserved word in header
- }
-
- m := &ldMachoObj{
- f: f,
- e: e,
- cputype: uint(e.Uint32(hdr[1*4:])),
- subcputype: uint(e.Uint32(hdr[2*4:])),
- filetype: e.Uint32(hdr[3*4:]),
- ncmd: uint(ncmd),
- flags: e.Uint32(hdr[6*4:]),
- is64: is64,
- base: base,
- length: length,
- name: pn,
- }
-
- switch arch.Family {
- default:
- return errorf("mach-o %s unimplemented", arch.Name)
-
- case sys.AMD64:
- if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
- return errorf("mach-o object but not amd64")
- }
- }
-
- m.cmd = make([]ldMachoCmd, ncmd)
- cmdp := make([]byte, cmdsz)
- if _, err := io.ReadFull(f, cmdp); err != nil {
- return errorf("reading cmds: %v", err)
- }
-
- // read and parse load commands
- var c *ldMachoCmd
-
- var symtab *ldMachoSymtab
- var dsymtab *ldMachoDysymtab
-
- off := uint32(len(hdr))
- for i := uint32(0); i < ncmd; i++ {
- ty := e.Uint32(cmdp)
- sz := e.Uint32(cmdp[4:])
- m.cmd[i].off = off
- unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz))
- cmdp = cmdp[sz:]
- off += sz
- if ty == LdMachoCmdSymtab {
- if symtab != nil {
- return errorf("multiple symbol tables")
- }
-
- symtab = &m.cmd[i].sym
- macholoadsym(m, symtab)
- }
-
- if ty == LdMachoCmdDysymtab {
- dsymtab = &m.cmd[i].dsym
- macholoaddsym(m, dsymtab)
- }
-
- if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
- if c != nil {
- return errorf("multiple load commands")
- }
-
- c = &m.cmd[i]
- }
- }
-
- // load text and data segments into memory.
- // they are not as small as the load commands, but we'll need
- // the memory anyway for the symbol images, so we might
- // as well use one large chunk.
- if c == nil {
- return errorf("no load command")
- }
-
- if symtab == nil {
- // our work is done here - no symbols means nothing can refer to this file
- return
- }
-
- if int64(c.seg.fileoff+c.seg.filesz) >= length {
- return errorf("load segment out of range")
- }
-
- f.MustSeek(m.base+int64(c.seg.fileoff), 0)
- dat := make([]byte, c.seg.filesz)
- if _, err := io.ReadFull(f, dat); err != nil {
- return errorf("cannot load object data: %v", err)
- }
-
- for i := uint32(0); i < c.seg.nsect; i++ {
- sect := &c.seg.sect[i]
- if sect.segname != "__TEXT" && sect.segname != "__DATA" {
- continue
- }
- if sect.name == "__eh_frame" {
- continue
- }
- name := fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
- s := lookup(name, localSymVersion)
- if s.Type != 0 {
- return errorf("duplicate %s/%s", sect.segname, sect.name)
- }
-
- if sect.flags&0xff == 1 { // S_ZEROFILL
- s.P = make([]byte, sect.size)
- } else {
- s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size]
- }
- s.Size = int64(len(s.P))
-
- if sect.segname == "__TEXT" {
- if sect.name == "__text" {
- s.Type = sym.STEXT
- } else {
- s.Type = sym.SRODATA
- }
- } else {
- if sect.name == "__bss" {
- s.Type = sym.SNOPTRBSS
- s.P = s.P[:0]
- } else {
- s.Type = sym.SNOPTRDATA
- }
- }
-
- sect.sym = s
- }
-
- // enter sub-symbols into symbol table.
- // have to guess sizes from next symbol.
- for i := uint32(0); i < symtab.nsym; i++ {
- machsym := &symtab.sym[i]
- if machsym.type_&N_STAB != 0 {
- continue
- }
-
- // TODO: check sym->type against outer->type.
- name := machsym.name
-
- if name[0] == '_' && name[1] != '\x00' {
- name = name[1:]
- }
- v := 0
- if machsym.type_&N_EXT == 0 {
- v = localSymVersion
- }
- s := lookup(name, v)
- if machsym.type_&N_EXT == 0 {
- s.Attr |= sym.AttrDuplicateOK
- }
- if machsym.desc&(N_WEAK_REF|N_WEAK_DEF) != 0 {
- s.Attr |= sym.AttrDuplicateOK
- }
- machsym.sym = s
- if machsym.sectnum == 0 { // undefined
- continue
- }
- if uint32(machsym.sectnum) > c.seg.nsect {
- return errorf("reference to invalid section %d", machsym.sectnum)
- }
-
- sect := &c.seg.sect[machsym.sectnum-1]
- outer := sect.sym
- if outer == nil {
- continue // ignore reference to invalid section
- }
-
- if s.Outer != nil {
- if s.Attr.DuplicateOK() {
- continue
- }
- return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name)
- }
-
- s.Type = outer.Type
- s.Attr |= sym.AttrSubSymbol
- s.Sub = outer.Sub
- outer.Sub = s
- s.Outer = outer
- s.Value = int64(machsym.value - sect.addr)
- if !s.Attr.CgoExportDynamic() {
- s.SetDynimplib("") // satisfy dynimport
- }
- if outer.Type == sym.STEXT {
- if s.Attr.External() && !s.Attr.DuplicateOK() {
- return errorf("%v: duplicate symbol definition", s)
- }
- s.Attr |= sym.AttrExternal
- }
-
- machsym.sym = s
- }
-
- // Sort outer lists by address, adding to textp.
- // This keeps textp in increasing address order.
- for i := 0; uint32(i) < c.seg.nsect; i++ {
- sect := &c.seg.sect[i]
- s := sect.sym
- if s == nil {
- continue
- }
- if s.Sub != nil {
- s.Sub = sym.SortSub(s.Sub)
-
- // assign sizes, now that we know symbols in sorted order.
- for s1 := s.Sub; s1 != nil; s1 = s1.Sub {
- if s1.Sub != nil {
- s1.Size = s1.Sub.Value - s1.Value
- } else {
- s1.Size = s.Value + s.Size - s1.Value
- }
- }
- }
-
- if s.Type == sym.STEXT {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
- textp = append(textp, s)
- for s1 := s.Sub; s1 != nil; s1 = s1.Sub {
- if s1.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s1.Name)
- }
- s1.Attr |= sym.AttrOnList
- textp = append(textp, s1)
- }
- }
- }
-
- // load relocations
- for i := 0; uint32(i) < c.seg.nsect; i++ {
- sect := &c.seg.sect[i]
- s := sect.sym
- if s == nil {
- continue
- }
- macholoadrel(m, sect)
- if sect.rel == nil {
- continue
- }
- r := make([]sym.Reloc, sect.nreloc)
- rpi := 0
- for j := uint32(0); j < sect.nreloc; j++ {
- rp := &r[rpi]
- rel := §.rel[j]
- if rel.scattered != 0 {
- // mach-o only uses scattered relocation on 32-bit platforms,
- // which are no longer supported.
- return errorf("%v: unexpected scattered relocation", s)
- }
-
- rp.Siz = rel.length
- rp.Type = objabi.MachoRelocOffset + (objabi.RelocType(rel.type_) << 1) + objabi.RelocType(rel.pcrel)
- rp.Off = int32(rel.addr)
-
- // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
- if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
- // Calculate the addend as the offset into the section.
- //
- // The rip-relative offset stored in the object file is encoded
- // as follows:
- //
- // movsd 0x00000360(%rip),%xmm0
- //
- // To get the absolute address of the value this rip-relative address is pointing
- // to, we must add the address of the next instruction to it. This is done by
- // taking the address of the relocation and adding 4 to it (since the rip-relative
- // offset can at most be 32 bits long). To calculate the offset into the section the
- // relocation is referencing, we subtract the vaddr of the start of the referenced
- // section found in the original object file.
- //
- // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
- secaddr := c.seg.sect[rel.symnum-1].addr
-
- rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr)
- } else {
- rp.Add = int64(int32(e.Uint32(s.P[rp.Off:])))
- }
-
- // An unsigned internal relocation has a value offset
- // by the section address.
- if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_UNSIGNED {
- secaddr := c.seg.sect[rel.symnum-1].addr
- rp.Add -= int64(secaddr)
- }
-
- if rel.extrn == 0 {
- if rel.symnum < 1 || rel.symnum > c.seg.nsect {
- return errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
- }
-
- rp.Sym = c.seg.sect[rel.symnum-1].sym
- if rp.Sym == nil {
- return errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
- }
- } else {
- if rel.symnum >= symtab.nsym {
- return errorf("invalid relocation: symbol reference out of range")
- }
-
- rp.Sym = symtab.sym[rel.symnum].sym
- }
-
- rpi++
- }
-
- sort.Sort(sym.RelocByOff(r[:rpi]))
- s.R = r
- s.R = s.R[:rpi]
- }
-
- return textp, nil
-}
-
-func cstring(x []byte) string {
- i := bytes.IndexByte(x, '\x00')
- if i >= 0 {
- x = x[:i]
- }
- return string(x)
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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)
-
- }
- }
-}
+++ /dev/null
-// 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))
- }
-}
+++ /dev/null
-// 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
-)
+++ /dev/null
-// 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
- }
- }
-}
+++ /dev/null
-// 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))
- }
-}
+++ /dev/null
-// 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
-)
+++ /dev/null
-// 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
- }
- }
-}
+++ /dev/null
-// 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]
-}
+++ /dev/null
-// 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
-
-import (
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/ld"
- "cmd/oldlink/internal/sym"
- "debug/elf"
- "encoding/binary"
- "fmt"
- "log"
- "strings"
-)
-
-func genplt(ctxt *ld.Link) {
- // The ppc64 ABI PLT has similar concepts to other
- // architectures, but is laid out quite differently. When we
- // see an R_PPC64_REL24 relocation to a dynamic symbol
- // (indicating that the call needs to go through the PLT), we
- // generate up to three stubs and reserve a PLT slot.
- //
- // 1) The call site will be bl x; nop (where the relocation
- // applies to the bl). We rewrite this to bl x_stub; ld
- // r2,24(r1). The ld is necessary because x_stub will save
- // r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
- //
- // 2) We reserve space for a pointer in the .plt section (once
- // per referenced dynamic function). .plt is a data
- // section filled solely by the dynamic linker (more like
- // .plt.got on other architectures). Initially, the
- // dynamic linker will fill each slot with a pointer to the
- // corresponding x@plt entry point.
- //
- // 3) We generate the "call stub" x_stub (once per dynamic
- // function/object file pair). This saves the TOC in the
- // TOC save slot, reads the function pointer from x's .plt
- // slot and calls it like any other global entry point
- // (including setting r12 to the function address).
- //
- // 4) We generate the "symbol resolver stub" x@plt (once per
- // dynamic function). This is solely a branch to the glink
- // resolver stub.
- //
- // 5) We generate the glink resolver stub (only once). This
- // computes which symbol resolver stub we came through and
- // invokes the dynamic resolver via a pointer provided by
- // the dynamic linker. This will patch up the .plt slot to
- // point directly at the function so future calls go
- // straight from the call stub to the real function, and
- // then call the function.
-
- // NOTE: It's possible we could make ppc64 closer to other
- // architectures: ppc64's .plt is like .plt.got on other
- // platforms and ppc64's .glink is like .plt on other
- // platforms.
-
- // Find all R_PPC64_REL24 relocations that reference dynamic
- // imports. Reserve PLT entries for these symbols and
- // generate call stubs. The call stubs need to live in .text,
- // which is why we need to do this pass this early.
- //
- // This assumes "case 1" from the ABI, where the caller needs
- // us to save and restore the TOC pointer.
- var stubs []*sym.Symbol
- for _, s := range ctxt.Textp {
- for i := range s.R {
- r := &s.R[i]
- if r.Type != objabi.ElfRelocOffset+objabi.RelocType(elf.R_PPC64_REL24) || r.Sym.Type != sym.SDYNIMPORT {
- continue
- }
-
- // Reserve PLT entry and generate symbol
- // resolver
- addpltsym(ctxt, r.Sym)
-
- // Generate call stub
- n := fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
-
- stub := ctxt.Syms.Lookup(n, 0)
- if s.Attr.Reachable() {
- stub.Attr |= sym.AttrReachable
- }
- if stub.Size == 0 {
- // Need outer to resolve .TOC.
- stub.Outer = s
- stubs = append(stubs, stub)
- gencallstub(ctxt, 1, stub, r.Sym)
- }
-
- // Update the relocation to use the call stub
- r.Sym = stub
-
- // Restore TOC after bl. The compiler put a
- // nop here for us to overwrite.
- const o1 = 0xe8410018 // ld r2,24(r1)
- ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
- }
- }
- // Put call stubs at the beginning (instead of the end).
- // So when resolving the relocations to calls to the stubs,
- // the addresses are known and trampolines can be inserted
- // when necessary.
- ctxt.Textp = append(stubs, ctxt.Textp...)
-}
-
-func genaddmoduledata(ctxt *ld.Link) {
- addmoduledata := ctxt.Syms.ROLookup("runtime.addmoduledata", sym.SymVerABI0)
- if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
- 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)
- }
- // addis r2, r12, .TOC.-func@ha
- rel := initfunc.AddRel()
- rel.Off = int32(initfunc.Size)
- rel.Siz = 8
- rel.Sym = ctxt.Syms.Lookup(".TOC.", 0)
- rel.Sym.Attr |= sym.AttrReachable
- rel.Type = objabi.R_ADDRPOWER_PCREL
- o(0x3c4c0000)
- // addi r2, r2, .TOC.-func@l
- o(0x38420000)
- // mflr r31
- o(0x7c0802a6)
- // stdu r31, -32(r1)
- o(0xf801ffe1)
- // addis r3, r2, local.moduledata@got@ha
- rel = initfunc.AddRel()
- rel.Off = int32(initfunc.Size)
- rel.Siz = 8
- if s := ctxt.Syms.ROLookup("local.moduledata", 0); s != nil {
- rel.Sym = s
- } else if s := ctxt.Syms.ROLookup("local.pluginmoduledata", 0); s != nil {
- rel.Sym = s
- } else {
- rel.Sym = ctxt.Syms.Lookup("runtime.firstmoduledata", 0)
- }
- rel.Sym.Attr |= sym.AttrReachable
- rel.Sym.Attr |= sym.AttrLocal
- rel.Type = objabi.R_ADDRPOWER_GOT
- o(0x3c620000)
- // ld r3, local.moduledata@got@l(r3)
- o(0xe8630000)
- // bl runtime.addmoduledata
- rel = initfunc.AddRel()
- rel.Off = int32(initfunc.Size)
- rel.Siz = 4
- rel.Sym = addmoduledata
- rel.Type = objabi.R_CALLPOWER
- o(0x48000001)
- // nop
- o(0x60000000)
- // ld r31, 0(r1)
- o(0xe8010000)
- // mtlr r31
- o(0x7c0803a6)
- // addi r1,r1,32
- o(0x38210020)
- // blr
- o(0x4e800020)
-
- if ctxt.BuildMode == ld.BuildModePlugin {
- ctxt.Textp = append(ctxt.Textp, addmoduledata)
- }
- initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
- ctxt.Textp = append(ctxt.Textp, initfunc)
- initarray_entry.Attr |= sym.AttrReachable
- initarray_entry.Attr |= sym.AttrLocal
- initarray_entry.Type = sym.SINITARR
- initarray_entry.AddAddr(ctxt.Arch, initfunc)
-}
-
-func gentext(ctxt *ld.Link) {
- if ctxt.DynlinkingGo() {
- genaddmoduledata(ctxt)
- }
-
- if ctxt.LinkMode == ld.LinkInternal {
- genplt(ctxt)
- }
-}
-
-// Construct a call stub in stub that calls symbol targ via its PLT
-// entry.
-func gencallstub(ctxt *ld.Link, abicase int, stub *sym.Symbol, targ *sym.Symbol) {
- if abicase != 1 {
- // If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
- // relocations, we'll need to implement cases 2 and 3.
- log.Fatalf("gencallstub only implements case 1 calls")
- }
-
- plt := ctxt.Syms.Lookup(".plt", 0)
-
- stub.Type = sym.STEXT
-
- // Save TOC pointer in TOC save slot
- stub.AddUint32(ctxt.Arch, 0xf8410018) // std r2,24(r1)
-
- // Load the function pointer from the PLT.
- r := stub.AddRel()
-
- r.Off = int32(stub.Size)
- r.Sym = plt
- r.Add = int64(targ.Plt())
- r.Siz = 2
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- r.Off += int32(r.Siz)
- }
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_HA
- stub.AddUint32(ctxt.Arch, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
- r = stub.AddRel()
- r.Off = int32(stub.Size)
- r.Sym = plt
- r.Add = int64(targ.Plt())
- r.Siz = 2
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- r.Off += int32(r.Siz)
- }
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_LO
- stub.AddUint32(ctxt.Arch, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
-
- // Jump to the loaded pointer
- stub.AddUint32(ctxt.Arch, 0x7d8903a6) // mtctr r12
- stub.AddUint32(ctxt.Arch, 0x4e800420) // bctr
-}
-
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
- if ctxt.IsELF {
- return addelfdynrel(ctxt, s, r)
- } else if ctxt.HeadType == objabi.Haix {
- return ld.Xcoffadddynrel(ctxt, s, r)
- }
- return false
-}
-func addelfdynrel(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 (%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_PPC64_REL24):
- r.Type = objabi.R_CALLPOWER
-
- // This is a local call, so the caller isn't setting
- // up r12 and r2 is the same for the caller and
- // callee. Hence, we need to go to the local entry
- // point. (If we don't do this, the callee will try
- // to use r12 to compute r2.)
- r.Add += int64(r.Sym.Localentry()) * 4
-
- if targ.Type == sym.SDYNIMPORT {
- // Should have been handled in elfsetupplt
- ld.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC_REL32):
- r.Type = objabi.R_PCREL
- r.Add += 4
-
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_ADDR64):
- r.Type = objabi.R_ADDR
- if targ.Type == sym.SDYNIMPORT {
- // These happen in .toc sections
- ld.Adddynsym(ctxt, targ)
-
- rela := ctxt.Syms.Lookup(".rela", 0)
- rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
- rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_PPC64_ADDR64)))
- rela.AddUint64(ctxt.Arch, uint64(r.Add))
- r.Type = objabi.ElfRelocOffset // ignore during relocsym
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_LO | sym.RV_CHECK_OVERFLOW
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_LO
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HA):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HI):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_DS):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_DS | sym.RV_CHECK_OVERFLOW
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO_DS):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_DS
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_LO):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_POWER_LO
- r.Add += 2 // Compensate for relocation size of 2
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HI):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
- r.Add += 2
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HA):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
- r.Add += 2
- return true
- }
-
- // Handle references to ELF symbols from our own object files.
- if targ.Type != sym.SDYNIMPORT {
- return true
- }
-
- // TODO(austin): Translate our relocations to ELF
-
- return false
-}
-
-func xcoffreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
- rs := r.Xsym
-
- emitReloc := func(v uint16, off uint64) {
- out.Write64(uint64(sectoff) + off)
- out.Write32(uint32(rs.Dynid))
- out.Write16(v)
- }
-
- var v uint16
- switch r.Type {
- default:
- return false
- case objabi.R_ADDR:
- v = ld.XCOFF_R_POS
- if r.Siz == 4 {
- v |= 0x1F << 8
- } else {
- v |= 0x3F << 8
- }
- emitReloc(v, 0)
- case objabi.R_ADDRPOWER_TOCREL:
- case objabi.R_ADDRPOWER_TOCREL_DS:
- emitReloc(ld.XCOFF_R_TOCU|(0x0F<<8), 2)
- emitReloc(ld.XCOFF_R_TOCL|(0x0F<<8), 6)
- case objabi.R_POWER_TLS_LE:
- emitReloc(ld.XCOFF_R_TLS_LE|0x0F<<8, 2)
- case objabi.R_CALLPOWER:
- if r.Siz != 4 {
- return false
- }
- emitReloc(ld.XCOFF_R_RBR|0x19<<8, 0)
- case objabi.R_XCOFFREF:
- emitReloc(ld.XCOFF_R_REF|0x3F<<8, 0)
-
- }
- return true
-
-}
-
-func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
- // Beware that bit0~bit15 start from the third byte of a instruction in Big-Endian machines.
- if r.Type == objabi.R_ADDR || r.Type == objabi.R_POWER_TLS || r.Type == objabi.R_CALLPOWER {
- } else {
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- sectoff += 2
- }
- }
- 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_PPC64_ADDR32) | uint64(elfsym)<<32)
- case 8:
- ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR64) | uint64(elfsym)<<32)
- default:
- return false
- }
- case objabi.R_POWER_TLS:
- ctxt.Out.Write64(uint64(elf.R_PPC64_TLS) | uint64(elfsym)<<32)
- case objabi.R_POWER_TLS_LE:
- ctxt.Out.Write64(uint64(elf.R_PPC64_TPREL16) | uint64(elfsym)<<32)
- case objabi.R_POWER_TLS_IE:
- ctxt.Out.Write64(uint64(elf.R_PPC64_GOT_TPREL16_HA) | uint64(elfsym)<<32)
- ctxt.Out.Write64(uint64(r.Xadd))
- ctxt.Out.Write64(uint64(sectoff + 4))
- ctxt.Out.Write64(uint64(elf.R_PPC64_GOT_TPREL16_LO_DS) | uint64(elfsym)<<32)
- case objabi.R_ADDRPOWER:
- ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR16_HA) | uint64(elfsym)<<32)
- ctxt.Out.Write64(uint64(r.Xadd))
- ctxt.Out.Write64(uint64(sectoff + 4))
- ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR16_LO) | uint64(elfsym)<<32)
- case objabi.R_ADDRPOWER_DS:
- ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR16_HA) | uint64(elfsym)<<32)
- ctxt.Out.Write64(uint64(r.Xadd))
- ctxt.Out.Write64(uint64(sectoff + 4))
- ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR16_LO_DS) | uint64(elfsym)<<32)
- case objabi.R_ADDRPOWER_GOT:
- ctxt.Out.Write64(uint64(elf.R_PPC64_GOT16_HA) | uint64(elfsym)<<32)
- ctxt.Out.Write64(uint64(r.Xadd))
- ctxt.Out.Write64(uint64(sectoff + 4))
- ctxt.Out.Write64(uint64(elf.R_PPC64_GOT16_LO_DS) | uint64(elfsym)<<32)
- case objabi.R_ADDRPOWER_PCREL:
- ctxt.Out.Write64(uint64(elf.R_PPC64_REL16_HA) | uint64(elfsym)<<32)
- ctxt.Out.Write64(uint64(r.Xadd))
- ctxt.Out.Write64(uint64(sectoff + 4))
- ctxt.Out.Write64(uint64(elf.R_PPC64_REL16_LO) | uint64(elfsym)<<32)
- r.Xadd += 4
- case objabi.R_ADDRPOWER_TOCREL:
- ctxt.Out.Write64(uint64(elf.R_PPC64_TOC16_HA) | uint64(elfsym)<<32)
- ctxt.Out.Write64(uint64(r.Xadd))
- ctxt.Out.Write64(uint64(sectoff + 4))
- ctxt.Out.Write64(uint64(elf.R_PPC64_TOC16_LO) | uint64(elfsym)<<32)
- case objabi.R_ADDRPOWER_TOCREL_DS:
- ctxt.Out.Write64(uint64(elf.R_PPC64_TOC16_HA) | uint64(elfsym)<<32)
- ctxt.Out.Write64(uint64(r.Xadd))
- ctxt.Out.Write64(uint64(sectoff + 4))
- ctxt.Out.Write64(uint64(elf.R_PPC64_TOC16_LO_DS) | uint64(elfsym)<<32)
- case objabi.R_CALLPOWER:
- if r.Siz != 4 {
- return false
- }
- ctxt.Out.Write64(uint64(elf.R_PPC64_REL24) | uint64(elfsym)<<32)
-
- }
- ctxt.Out.Write64(uint64(r.Xadd))
-
- return true
-}
-
-func elfsetupplt(ctxt *ld.Link) {
- plt := ctxt.Syms.Lookup(".plt", 0)
- if plt.Size == 0 {
- // The dynamic linker stores the address of the
- // dynamic resolver and the DSO identifier in the two
- // doublewords at the beginning of the .plt section
- // before the PLT array. Reserve space for these.
- plt.Size = 16
- }
-}
-
-func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
- return false
-}
-
-// Return the value of .TOC. for symbol s
-func symtoc(ctxt *ld.Link, s *sym.Symbol) int64 {
- var toc *sym.Symbol
-
- if s.Outer != nil {
- toc = ctxt.Syms.ROLookup(".TOC.", int(s.Outer.Version))
- } else {
- toc = ctxt.Syms.ROLookup(".TOC.", int(s.Version))
- }
-
- if toc == nil {
- ld.Errorf(s, "TOC-relative relocation in object without .TOC.")
- return 0
- }
-
- return toc.Value
-}
-
-// archreloctoc relocates a TOC relative symbol.
-// If the symbol pointed by this TOC relative symbol is in .data or .bss, the
-// default load instruction can be changed to an addi instruction and the
-// symbol address can be used directly.
-// This code is for AIX only.
-func archreloctoc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
- if ctxt.HeadType == objabi.Hlinux {
- ld.Errorf(s, "archrelocaddr called for %s relocation\n", r.Sym.Name)
- }
- var o1, o2 uint32
-
- o1 = uint32(val >> 32)
- o2 = uint32(val)
-
- var t int64
- useAddi := false
- const prefix = "TOC."
- var tarSym *sym.Symbol
- if strings.HasPrefix(r.Sym.Name, prefix) {
- tarSym = r.Sym.R[0].Sym
- } else {
- ld.Errorf(s, "archreloctoc called for a symbol without TOC anchor")
- }
-
- if ctxt.LinkMode == ld.LinkInternal && tarSym != nil && tarSym.Attr.Reachable() && (tarSym.Sect.Seg == &ld.Segdata) {
- t = ld.Symaddr(tarSym) + r.Add - ctxt.Syms.ROLookup("TOC", 0).Value
- // change ld to addi in the second instruction
- o2 = (o2 & 0x03FF0000) | 0xE<<26
- useAddi = true
- } else {
- t = ld.Symaddr(r.Sym) + r.Add - ctxt.Syms.ROLookup("TOC", 0).Value
- }
-
- if t != int64(int32(t)) {
- ld.Errorf(s, "TOC relocation for %s is too big to relocate %s: 0x%x", s.Name, r.Sym, t)
- }
-
- if t&0x8000 != 0 {
- t += 0x10000
- }
-
- o1 |= uint32((t >> 16) & 0xFFFF)
-
- switch r.Type {
- case objabi.R_ADDRPOWER_TOCREL_DS:
- if useAddi {
- o2 |= uint32(t) & 0xFFFF
- } else {
- if t&3 != 0 {
- ld.Errorf(s, "bad DS reloc for %s: %d", s.Name, ld.Symaddr(r.Sym))
- }
- o2 |= uint32(t) & 0xFFFC
- }
- default:
- return -1
- }
-
- return int64(o1)<<32 | int64(o2)
-}
-
-// archrelocaddr relocates a symbol address.
-// This code is for AIX only.
-func archrelocaddr(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
- if ctxt.HeadType == objabi.Haix {
- ld.Errorf(s, "archrelocaddr called for %s relocation\n", r.Sym.Name)
- }
- 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)
- }
-
- // We are spreading a 31-bit address across two instructions, putting the
- // high (adjusted) part in the low 16 bits of the first instruction and the
- // low part in the low 16 bits of the second instruction, or, in the DS case,
- // bits 15-2 (inclusive) of the address into bits 15-2 of the second
- // instruction (it is an error in this case if the low 2 bits of the address
- // are non-zero).
-
- t := ld.Symaddr(r.Sym) + r.Add
- if t < 0 || t >= 1<<31 {
- ld.Errorf(s, "relocation for %s is too big (>=2G): 0x%x", s.Name, ld.Symaddr(r.Sym))
- }
- if t&0x8000 != 0 {
- t += 0x10000
- }
-
- switch r.Type {
- case objabi.R_ADDRPOWER:
- o1 |= (uint32(t) >> 16) & 0xffff
- o2 |= uint32(t) & 0xffff
- case objabi.R_ADDRPOWER_DS:
- o1 |= (uint32(t) >> 16) & 0xffff
- if t&3 != 0 {
- ld.Errorf(s, "bad DS reloc for %s: %d", s.Name, ld.Symaddr(r.Sym))
- }
- o2 |= uint32(t) & 0xfffc
- default:
- return -1
- }
-
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- return int64(o1)<<32 | int64(o2)
- }
- return int64(o2)<<32 | int64(o1)
-}
-
-// resolve direct jump relocation r in s, and add trampoline if necessary
-func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
-
- // Trampolines are created if the branch offset is too large and the linker cannot insert a call stub to handle it.
- // For internal linking, trampolines are always created for long calls.
- // For external linking, the linker can insert a call stub to handle a long call, but depends on having the TOC address in
- // r2. For those build modes with external linking where the TOC address is not maintained in r2, trampolines must be created.
- if ctxt.LinkMode == ld.LinkExternal && (ctxt.DynlinkingGo() || ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE) {
- // No trampolines needed since r2 contains the TOC
- return
- }
-
- t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
- switch r.Type {
- case objabi.R_CALLPOWER:
-
- // If branch offset is too far then create a trampoline.
-
- if (ctxt.LinkMode == ld.LinkExternal && s.Sect != r.Sym.Sect) || (ctxt.LinkMode == ld.LinkInternal && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
- var tramp *sym.Symbol
- for i := 0; ; i++ {
-
- // Using r.Add as part of the name is significant in functions like duffzero where the call
- // target is at some offset within the function. Calls to duff+8 and duff+256 must appear as
- // distinct trampolines.
-
- name := r.Sym.Name
- if r.Add == 0 {
- name = name + fmt.Sprintf("-tramp%d", i)
- } else {
- name = name + fmt.Sprintf("%+x-tramp%d", r.Add, i)
- }
-
- // Look up the trampoline in case it already exists
-
- tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
- if tramp.Value == 0 {
- break
- }
-
- t = ld.Symaddr(tramp) + r.Add - (s.Value + int64(r.Off))
-
- // With internal linking, the trampoline can be used if it is not too far.
- // With external linking, the trampoline must be in this section for it to be reused.
- if (ctxt.LinkMode == ld.LinkInternal && int64(int32(t<<6)>>6) == t) || (ctxt.LinkMode == ld.LinkExternal && s.Sect == tramp.Sect) {
- break
- }
- }
- if tramp.Type == 0 {
- if ctxt.DynlinkingGo() || ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE {
- // Should have returned for above cases
- ld.Errorf(s, "unexpected trampoline for shared or dynamic linking\n")
- } else {
- ctxt.AddTramp(tramp)
- gentramp(ctxt, tramp, r.Sym, r.Add)
- }
- }
- r.Sym = tramp
- r.Add = 0 // This was folded into the trampoline target address
- r.Done = false
- }
- default:
- ld.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
- }
-}
-
-func gentramp(ctxt *ld.Link, tramp, target *sym.Symbol, offset int64) {
- tramp.Size = 16 // 4 instructions
- tramp.P = make([]byte, tramp.Size)
- t := ld.Symaddr(target) + offset
- var o1, o2 uint32
-
- if ctxt.HeadType == objabi.Haix {
- // On AIX, the address is retrieved with a TOC symbol.
- // For internal linking, the "Linux" way might still be used.
- // However, all text symbols are accessed with a TOC symbol as
- // text relocations aren't supposed to be possible.
- // So, keep using the external linking way to be more AIX friendly.
- o1 = uint32(0x3fe20000) // lis r2, toctargetaddr hi
- o2 = uint32(0xebff0000) // ld r31, toctargetaddr lo
-
- toctramp := ctxt.Syms.Lookup("TOC."+tramp.Name, 0)
- toctramp.Type = sym.SXCOFFTOC
- toctramp.Attr |= sym.AttrReachable
- toctramp.AddAddr(ctxt.Arch, target)
-
- tr := tramp.AddRel()
- tr.Off = 0
- tr.Type = objabi.R_ADDRPOWER_TOCREL_DS
- tr.Siz = 8 // generates 2 relocations: HA + LO
- tr.Sym = toctramp
- tr.Add = offset
- } else {
- // Used for default build mode for an executable
- // Address of the call target is generated using
- // relocation and doesn't depend on r2 (TOC).
- o1 = uint32(0x3fe00000) // lis r31,targetaddr hi
- o2 = uint32(0x3bff0000) // addi r31,targetaddr lo
-
- // With external linking, the target address must be
- // relocated using LO and HA
- if ctxt.LinkMode == ld.LinkExternal {
- tr := tramp.AddRel()
- tr.Off = 0
- tr.Type = objabi.R_ADDRPOWER
- tr.Siz = 8 // generates 2 relocations: HA + LO
- tr.Sym = target
- tr.Add = offset
-
- } else {
- // adjustment needed if lo has sign bit set
- // when using addi to compute address
- val := uint32((t & 0xffff0000) >> 16)
- if t&0x8000 != 0 {
- val += 1
- }
- o1 |= val // hi part of addr
- o2 |= uint32(t & 0xffff) // lo part of addr
- }
- }
-
- o3 := uint32(0x7fe903a6) // mtctr r31
- o4 := uint32(0x4e800420) // bctr
- ctxt.Arch.ByteOrder.PutUint32(tramp.P, o1)
- ctxt.Arch.ByteOrder.PutUint32(tramp.P[4:], o2)
- ctxt.Arch.ByteOrder.PutUint32(tramp.P[8:], o3)
- ctxt.Arch.ByteOrder.PutUint32(tramp.P[12:], o4)
-}
-
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
- if ctxt.LinkMode == ld.LinkExternal {
- // On AIX, relocations (except TLS ones) must be also done to the
- // value with the current addresses.
- switch r.Type {
- default:
- if ctxt.HeadType != objabi.Haix {
- return val, false
- }
- case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE:
- r.Done = false
- // check Outer is nil, Type is TLSBSS?
- r.Xadd = r.Add
- r.Xsym = r.Sym
- return val, true
- case objabi.R_ADDRPOWER,
- objabi.R_ADDRPOWER_DS,
- objabi.R_ADDRPOWER_TOCREL,
- objabi.R_ADDRPOWER_TOCREL_DS,
- objabi.R_ADDRPOWER_GOT,
- objabi.R_ADDRPOWER_PCREL:
- 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.Type != sym.SUNDEFEXT && rs.Sect == nil {
- ld.Errorf(s, "missing section for %s", rs.Name)
- }
- r.Xsym = rs
-
- if ctxt.HeadType != objabi.Haix {
- return val, true
- }
- case objabi.R_CALLPOWER:
- r.Done = false
- r.Xsym = r.Sym
- r.Xadd = r.Add
- if ctxt.HeadType != objabi.Haix {
- 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_ADDRPOWER_TOCREL, objabi.R_ADDRPOWER_TOCREL_DS:
- return archreloctoc(ctxt, r, s, val), true
- case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS:
- return archrelocaddr(ctxt, r, s, val), true
- case objabi.R_CALLPOWER:
- // Bits 6 through 29 = (S + A - P) >> 2
-
- t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
-
- if t&3 != 0 {
- ld.Errorf(s, "relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
- }
- // If branch offset is too far then create a trampoline.
-
- if int64(int32(t<<6)>>6) != t {
- ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
- }
- return val | int64(uint32(t)&^0xfc000003), true
- case objabi.R_POWER_TOC: // S + A - .TOC.
- return ld.Symaddr(r.Sym) + r.Add - symtoc(ctxt, s), true
-
- case objabi.R_POWER_TLS_LE:
- // The thread pointer points 0x7000 bytes after the start of the
- // thread local storage area as documented in section "3.7.2 TLS
- // Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI
- // Specification".
- v := r.Sym.Value - 0x7000
- if ctxt.HeadType == objabi.Haix {
- // On AIX, the thread pointer points 0x7800 bytes after
- // the TLS.
- v -= 0x800
- }
- if int64(int16(v)) != v {
- ld.Errorf(s, "TLS offset out of range %d", v)
- }
- return (val &^ 0xffff) | (v & 0xffff), 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)
- fallthrough
-
- case sym.RV_NONE:
- return t
-
- case sym.RV_POWER_LO:
- if r.Variant&sym.RV_CHECK_OVERFLOW != 0 {
- // Whether to check for signed or unsigned
- // overflow depends on the instruction
- var o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- o1 = binary.BigEndian.Uint32(s.P[r.Off-2:])
- } else {
- o1 = binary.LittleEndian.Uint32(s.P[r.Off:])
- }
- switch o1 >> 26 {
- case 24, // ori
- 26, // xori
- 28: // andi
- if t>>16 != 0 {
- goto overflow
- }
-
- default:
- if int64(int16(t)) != t {
- goto overflow
- }
- }
- }
-
- return int64(int16(t))
-
- case sym.RV_POWER_HA:
- t += 0x8000
- fallthrough
-
- // Fallthrough
- case sym.RV_POWER_HI:
- t >>= 16
-
- if r.Variant&sym.RV_CHECK_OVERFLOW != 0 {
- // Whether to check for signed or unsigned
- // overflow depends on the instruction
- var o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- o1 = binary.BigEndian.Uint32(s.P[r.Off-2:])
- } else {
- o1 = binary.LittleEndian.Uint32(s.P[r.Off:])
- }
- switch o1 >> 26 {
- case 25, // oris
- 27, // xoris
- 29: // andis
- if t>>16 != 0 {
- goto overflow
- }
-
- default:
- if int64(int16(t)) != t {
- goto overflow
- }
- }
- }
-
- return int64(int16(t))
-
- case sym.RV_POWER_DS:
- var o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
- o1 = uint32(binary.BigEndian.Uint16(s.P[r.Off:]))
- } else {
- o1 = uint32(binary.LittleEndian.Uint16(s.P[r.Off:]))
- }
- if t&3 != 0 {
- ld.Errorf(s, "relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
- }
- if (r.Variant&sym.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
- goto overflow
- }
- return int64(o1)&0x3 | int64(int16(t))
- }
-
-overflow:
- ld.Errorf(s, "relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
- return t
-}
-
-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)
- rela := ctxt.Syms.Lookup(".rela.plt", 0)
- if plt.Size == 0 {
- elfsetupplt(ctxt)
- }
-
- // Create the glink resolver if necessary
- glink := ensureglinkresolver(ctxt)
-
- // Write symbol resolver stub (just a branch to the
- // glink resolver stub)
- r := glink.AddRel()
-
- r.Sym = glink
- r.Off = int32(glink.Size)
- r.Siz = 4
- r.Type = objabi.R_CALLPOWER
- glink.AddUint32(ctxt.Arch, 0x48000000) // b .glink
-
- // In the ppc64 ABI, the dynamic linker is responsible
- // for writing the entire PLT. We just need to
- // reserve 8 bytes for each PLT entry and generate a
- // JMP_SLOT dynamic relocation for it.
- //
- // TODO(austin): ABI v1 is different
- s.SetPlt(int32(plt.Size))
-
- plt.Size += 8
-
- rela.AddAddrPlus(ctxt.Arch, plt, int64(s.Plt()))
- rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_PPC64_JMP_SLOT)))
- rela.AddUint64(ctxt.Arch, 0)
- } else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
- }
-}
-
-// Generate the glink resolver stub if necessary and return the .glink section
-func ensureglinkresolver(ctxt *ld.Link) *sym.Symbol {
- glink := ctxt.Syms.Lookup(".glink", 0)
- if glink.Size != 0 {
- return glink
- }
-
- // This is essentially the resolver from the ppc64 ELF ABI.
- // At entry, r12 holds the address of the symbol resolver stub
- // for the target routine and the argument registers hold the
- // arguments for the target routine.
- //
- // This stub is PIC, so first get the PC of label 1 into r11.
- // Other things will be relative to this.
- glink.AddUint32(ctxt.Arch, 0x7c0802a6) // mflr r0
- glink.AddUint32(ctxt.Arch, 0x429f0005) // bcl 20,31,1f
- glink.AddUint32(ctxt.Arch, 0x7d6802a6) // 1: mflr r11
- glink.AddUint32(ctxt.Arch, 0x7c0803a6) // mtlf r0
-
- // Compute the .plt array index from the entry point address.
- // Because this is PIC, everything is relative to label 1b (in
- // r11):
- // r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
- glink.AddUint32(ctxt.Arch, 0x3800ffd0) // li r0,-(res_0-1b)=-48
- glink.AddUint32(ctxt.Arch, 0x7c006214) // add r0,r0,r12
- glink.AddUint32(ctxt.Arch, 0x7c0b0050) // sub r0,r0,r11
- glink.AddUint32(ctxt.Arch, 0x7800f082) // srdi r0,r0,2
-
- // r11 = address of the first byte of the PLT
- r := glink.AddRel()
-
- r.Off = int32(glink.Size)
- r.Sym = ctxt.Syms.Lookup(".plt", 0)
- r.Siz = 8
- r.Type = objabi.R_ADDRPOWER
-
- glink.AddUint32(ctxt.Arch, 0x3d600000) // addis r11,0,.plt@ha
- glink.AddUint32(ctxt.Arch, 0x396b0000) // addi r11,r11,.plt@l
-
- // Load r12 = dynamic resolver address and r11 = DSO
- // identifier from the first two doublewords of the PLT.
- glink.AddUint32(ctxt.Arch, 0xe98b0000) // ld r12,0(r11)
- glink.AddUint32(ctxt.Arch, 0xe96b0008) // ld r11,8(r11)
-
- // Jump to the dynamic resolver
- glink.AddUint32(ctxt.Arch, 0x7d8903a6) // mtctr r12
- glink.AddUint32(ctxt.Arch, 0x4e800420) // bctr
-
- // The symbol resolvers must immediately follow.
- // res_0:
-
- // Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
- // before the first symbol resolver stub.
- s := ctxt.Syms.Lookup(".dynamic", 0)
-
- ld.Elfwritedynentsymplus(ctxt, s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
-
- return glink
-}
-
-func asmb(ctxt *ld.Link) {
- if ctxt.IsELF {
- ld.Asmbelfsetup()
- }
-
- for _, sect := range ld.Segtext.Sections {
- ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- // Handle additional text sections with Codeblk
- if sect.Name == ".text" {
- ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
- } else {
- 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.Haix:
- // Nothing to do
- }
-
- 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.Haix:
- // symtab must be added once sections have been created in ld.Asmbxcoff
- ctxt.Out.Flush()
- }
- }
-
- 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.Haix:
- fileoff := uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
- fileoff = uint32(ld.Rnd(int64(fileoff), int64(*ld.FlagRound)))
- ld.Asmbxcoff(ctxt, int64(fileoff))
- }
-
- ctxt.Out.Flush()
- if *ld.FlagC {
- fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
- fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
- 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))
- }
-}
+++ /dev/null
-// 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
-)
+++ /dev/null
-// 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)
- }
-}
+++ /dev/null
-// 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))
- }
-}
+++ /dev/null
-// 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
-)
+++ /dev/null
-// 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)
- }
-}
+++ /dev/null
-// 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))
- }
-}
+++ /dev/null
-// 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
-)
+++ /dev/null
-// 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
- }
- }
-}
+++ /dev/null
-// 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
- }
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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)
- }
- }
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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
- }
- }
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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]]
-}
+++ /dev/null
-// 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)
- }
-}
+++ /dev/null
-// 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
- }
-}
+++ /dev/null
-// 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()
-}
+++ /dev/null
-// 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
-)
+++ /dev/null
-// Inferno utils/8l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/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 x86
-
-import (
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/ld"
-)
-
-func Init() (*sys.Arch, ld.Arch) {
- arch := sys.Arch386
-
- 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,
-
- Linuxdynld: "/lib/ld-linux.so.2",
- Freebsddynld: "/usr/libexec/ld-elf.so.1",
- Openbsddynld: "/usr/libexec/ld.so",
- Netbsddynld: "/usr/libexec/ld.elf_so",
- Solarisdynld: "/lib/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
-
- if *ld.FlagTextAddr == -1 {
- *ld.FlagTextAddr = 4096 + int64(ld.HEADR)
- }
- if *ld.FlagRound == -1 {
- *ld.FlagRound = 4096
- }
-
- 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
- }
-
- case objabi.Hlinux, /* elf32 executable */
- objabi.Hfreebsd,
- objabi.Hnetbsd,
- objabi.Hopenbsd:
- ld.Elfinit(ctxt)
-
- ld.HEADR = ld.ELFRESERVE
- if *ld.FlagTextAddr == -1 {
- *ld.FlagTextAddr = 0x08048000 + 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
- }
-}
+++ /dev/null
-// 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.
-
-// TODO(go115newobj): delete.
-
-package main
-
-import (
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/oldlink/internal/amd64"
- "cmd/oldlink/internal/arm"
- "cmd/oldlink/internal/arm64"
- "cmd/oldlink/internal/ld"
- "cmd/oldlink/internal/mips"
- "cmd/oldlink/internal/mips64"
- "cmd/oldlink/internal/ppc64"
- "cmd/oldlink/internal/riscv64"
- "cmd/oldlink/internal/s390x"
- "cmd/oldlink/internal/wasm"
- "cmd/oldlink/internal/x86"
- "fmt"
- "os"
-)
-
-// The bulk of the linker implementation lives in cmd/oldlink/internal/ld.
-// Architecture-specific code lives in cmd/oldlink/internal/GOARCH.
-//
-// Program initialization:
-//
-// Before any argument parsing is done, the Init function of relevant
-// architecture package is called. The only job done in Init is
-// configuration of the architecture-specific variables.
-//
-// Then control flow passes to ld.Main, which parses flags, makes
-// some configuration decisions, and then gives the architecture
-// packages a second chance to modify the linker's configuration
-// via the ld.Arch.Archinit function.
-
-func main() {
- var arch *sys.Arch
- var theArch ld.Arch
-
- switch objabi.GOARCH {
- default:
- fmt.Fprintf(os.Stderr, "link: unknown architecture %q\n", objabi.GOARCH)
- os.Exit(2)
- case "386":
- arch, theArch = x86.Init()
- case "amd64":
- arch, theArch = amd64.Init()
- case "arm":
- arch, theArch = arm.Init()
- case "arm64":
- arch, theArch = arm64.Init()
- case "mips", "mipsle":
- arch, theArch = mips.Init()
- case "mips64", "mips64le":
- arch, theArch = mips64.Init()
- case "ppc64", "ppc64le":
- arch, theArch = ppc64.Init()
- case "riscv64":
- arch, theArch = riscv64.Init()
- case "s390x":
- arch, theArch = s390x.Init()
- case "wasm":
- arch, theArch = wasm.Init()
- }
- ld.Main(arch, theArch)
-}