From: Cherry Zhang Date: Fri, 1 May 2020 23:13:30 +0000 (-0400) Subject: [dev.link] cmd: delete old object support X-Git-Tag: go1.16beta1~1378^2~156 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c89251204e2b80a8234bd2e82fd3b11d912b0630;p=gostls13.git [dev.link] cmd: delete old object support We are not going to merge to master until Go 1.16 cycle. The old object support can go now. Change-Id: I93e6f584974c7749d0a0c2e7a96def35134dc566 Reviewed-on: https://go-review.googlesource.com/c/go/+/231918 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Than McIntosh --- diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go index e8535ae9ac..1df9df9563 100644 --- a/src/cmd/asm/internal/flags/flags.go +++ b/src/cmd/asm/internal/flags/flags.go @@ -25,8 +25,6 @@ var ( SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble") Importpath = flag.String("p", "", "set expected package import to path") Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)") - - Go115Newobj = flag.Bool("go115newobj", true, "use new object file format") ) var ( diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go index 9ca9797a45..71ee04128c 100644 --- a/src/cmd/asm/main.go +++ b/src/cmd/asm/main.go @@ -40,7 +40,6 @@ func main() { } ctxt.Flag_dynlink = *flags.Dynlink ctxt.Flag_shared = *flags.Shared || *flags.Dynlink - ctxt.Flag_go115newobj = *flags.Go115Newobj ctxt.IsAsm = true switch *flags.Spectre { default: diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go index 35b8d985cb..32cc50fda1 100644 --- a/src/cmd/compile/internal/gc/iexport.go +++ b/src/cmd/compile/internal/gc/iexport.go @@ -997,18 +997,16 @@ func (w *exportWriter) linkname(s *types.Sym) { } func (w *exportWriter) symIdx(s *types.Sym) { - if Ctxt.Flag_go115newobj { - lsym := s.Linksym() - if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" { - // Don't export index for non-package symbols, linkname'd symbols, - // 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)) } } diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go index f3e65ff736..7c0764c677 100644 --- a/src/cmd/compile/internal/gc/iimport.go +++ b/src/cmd/compile/internal/gc/iimport.go @@ -696,16 +696,14 @@ func (r *importReader) linkname(s *types.Sym) { } func (r *importReader) symIdx(s *types.Sym) { - if Ctxt.Flag_go115newobj { - lsym := s.Linksym() - idx := int32(r.int64()) - if idx != -1 { - 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) } } diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 756cdbd3c9..ba40582f4f 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -281,7 +281,6 @@ func Main(archInit func(*Arch)) { flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`") flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects") flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF") - flag.BoolVar(&Ctxt.Flag_go115newobj, "go115newobj", true, "use new object file format") flag.StringVar(&jsonLogOpt, "json", "", "version,destination for JSON compiler/optimizer logging") objabi.Flagparse(usage) @@ -315,7 +314,7 @@ func Main(archInit func(*Arch)) { // Record flags that affect the build result. (And don't // record flags that don't, since that would cause spurious // changes in the binary.) - recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre", "go115newobj") + recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre") if smallFrames { maxStackVarSize = 128 * 1024 diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go index db013999da..6ab83639ac 100644 --- a/src/cmd/internal/dwarf/dwarf.go +++ b/src/cmd/internal/dwarf/dwarf.go @@ -18,21 +18,9 @@ import ( "strings" ) -// TODO(go115newobj): clean up. Some constant prefixes here are no longer -// needed in the new object files. - // InfoPrefix is the prefix for all the symbols containing DWARF info entries. const InfoPrefix = "go.info." -// RangePrefix is the prefix for all the symbols containing DWARF location lists. -const LocPrefix = "go.loc." - -// RangePrefix is the prefix for all the symbols containing DWARF range lists. -const RangePrefix = "go.range." - -// DebugLinesPrefix is the prefix for all the symbols containing DWARF debug_line information from the compiler. -const DebugLinesPrefix = "go.debuglines." - // ConstInfoPrefix is the prefix for all symbols containing DWARF info // entries that contain constants. const ConstInfoPrefix = "go.constinfo." diff --git a/src/cmd/internal/goobj/goobj_test.go b/src/cmd/internal/goobj/goobj_test.go index 9f827c6a32..4acd30edc6 100644 --- a/src/cmd/internal/goobj/goobj_test.go +++ b/src/cmd/internal/goobj/goobj_test.go @@ -151,12 +151,9 @@ func buildGoobj() error { return nil } -// Check that a symbol has a given name, accepting both -// new and old objects. -// TODO(go115newobj): remove. +// Check that a symbol has a given name. func matchSymName(symname, want string) bool { - return symname == want || - strings.HasPrefix(symname, want+"#") // new style, with index + return strings.HasPrefix(symname, want+"#") // new style, with index } func TestParseGoobj(t *testing.T) { diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 32906a3e05..1b54df2c26 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -656,7 +656,6 @@ type Link struct { Flag_linkshared bool Flag_optimize bool Flag_locationlists bool - Flag_go115newobj bool // use new object file format Retpoline bool // emit use of retpoline stubs for indirect jmp/call Bso *bufio.Writer Pathname string diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 6d7f42ed0b..6701b9bfba 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -2,234 +2,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Writing of Go object files. - package obj import ( - "bufio" - "cmd/internal/bio" "cmd/internal/dwarf" "cmd/internal/objabi" "cmd/internal/sys" "fmt" "io" - "log" - "path/filepath" "sort" - "strings" "sync" ) -// objWriter writes Go object files. -type objWriter struct { - wr *bufio.Writer - ctxt *Link - // Temporary buffer for zigzag int writing. - varintbuf [10]uint8 - - // Number of objects written of each type. - nRefs int - nData int - nReloc int - nPcdata int - nFuncdata int - nFile int - - pkgpath string // the package import path (escaped), "" if unknown -} - -func (w *objWriter) addLengths(s *LSym) { - w.nData += len(s.P) - w.nReloc += len(s.R) - - if s.Type != objabi.STEXT { - return - } - - pc := &s.Func.Pcln - - data := 0 - data += len(pc.Pcsp.P) - data += len(pc.Pcfile.P) - data += len(pc.Pcline.P) - data += len(pc.Pcinline.P) - for _, pcd := range pc.Pcdata { - data += len(pcd.P) - } - - w.nData += data - w.nPcdata += len(pc.Pcdata) - - w.nFuncdata += len(pc.Funcdataoff) - w.nFile += len(pc.File) -} - -func (w *objWriter) writeLengths() { - w.writeInt(int64(w.nData)) - w.writeInt(int64(w.nReloc)) - w.writeInt(int64(w.nPcdata)) - w.writeInt(int64(0)) // TODO: remove at next object file rev - w.writeInt(int64(w.nFuncdata)) - w.writeInt(int64(w.nFile)) -} - -func newObjWriter(ctxt *Link, b *bufio.Writer, pkgpath string) *objWriter { - return &objWriter{ - ctxt: ctxt, - wr: b, - pkgpath: objabi.PathToPrefix(pkgpath), - } -} - -func WriteObjFile(ctxt *Link, bout *bio.Writer, pkgpath string) { - if ctxt.Flag_go115newobj { - WriteObjFile2(ctxt, bout, pkgpath) - return - } - - b := bout.Writer - w := newObjWriter(ctxt, b, pkgpath) - - // Magic header - w.wr.WriteString("\x00go114ld") - - // Version - w.wr.WriteByte(1) - - // Autolib - for _, p := range ctxt.Imports { - w.writeString(p.Pkg) - // This object format ignores p.Fingerprint. - } - w.writeString("") - - // DWARF File Table - fileTable := ctxt.PosTable.DebugLinesFileTable() - w.writeInt(int64(len(fileTable))) - for _, str := range fileTable { - w.writeString(filepath.ToSlash(str)) - } - - // Symbol references - for _, s := range ctxt.Text { - w.writeRefs(s) - w.addLengths(s) - } - - if ctxt.Headtype == objabi.Haix { - // Data must be sorted to keep a constant order in TOC symbols. - // As they are created during Progedit, two symbols can be switched between - // two different compilations. Therefore, BuildID will be different. - // TODO: find a better place and optimize to only sort TOC symbols - sort.Slice(ctxt.Data, func(i, j int) bool { - return ctxt.Data[i].Name < ctxt.Data[j].Name - }) - } - - for _, s := range ctxt.Data { - w.writeRefs(s) - w.addLengths(s) - } - for _, s := range ctxt.ABIAliases { - w.writeRefs(s) - w.addLengths(s) - } - // End symbol references - w.wr.WriteByte(0xff) - - // Lengths - w.writeLengths() - - // Data block - for _, s := range ctxt.Text { - w.wr.Write(s.P) - pc := &s.Func.Pcln - w.wr.Write(pc.Pcsp.P) - w.wr.Write(pc.Pcfile.P) - w.wr.Write(pc.Pcline.P) - w.wr.Write(pc.Pcinline.P) - for _, pcd := range pc.Pcdata { - w.wr.Write(pcd.P) - } - } - for _, s := range ctxt.Data { - if len(s.P) > 0 { - switch s.Type { - case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS: - ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name) - } - } - w.wr.Write(s.P) - } - - // Symbols - for _, s := range ctxt.Text { - w.writeSym(s) - } - for _, s := range ctxt.Data { - w.writeSym(s) - } - for _, s := range ctxt.ABIAliases { - w.writeSym(s) - } - - // Magic footer - w.wr.WriteString("\xffgo114ld") -} - -// Symbols are prefixed so their content doesn't get confused with the magic footer. -const symPrefix = 0xfe - -func (w *objWriter) writeRef(s *LSym, isPath bool) { - if s == nil || s.RefIdx != 0 { - return - } - w.wr.WriteByte(symPrefix) - if isPath { - w.writeString(filepath.ToSlash(s.Name)) - } else if w.pkgpath != "" { - // w.pkgpath is already escaped. - n := strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1) - w.writeString(n) - } else { - w.writeString(s.Name) - } - // Write ABI/static information. - abi := int64(s.ABI()) - if s.Static() { - abi = -1 - } - w.writeInt(abi) - w.nRefs++ - s.RefIdx = w.nRefs -} - -func (w *objWriter) writeRefs(s *LSym) { - w.writeRef(s, false) - w.writeRef(s.Gotype, false) - for _, r := range s.R { - w.writeRef(r.Sym, false) - } - - if s.Type == objabi.STEXT { - pc := &s.Func.Pcln - for _, d := range pc.Funcdata { - w.writeRef(d, false) - } - for _, f := range pc.File { - fsym := w.ctxt.Lookup(f) - w.writeRef(fsym, true) - } - for _, call := range pc.InlTree.nodes { - w.writeRef(call.Func, false) - f, _ := linkgetlineFromPos(w.ctxt, call.Pos) - fsym := w.ctxt.Lookup(f) - w.writeRef(fsym, true) - } - } -} - func (ctxt *Link) writeSymDebug(s *LSym) { ctxt.writeSymDebugNamed(s, s.Name) } @@ -311,138 +95,6 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) { } } -func (w *objWriter) writeSym(s *LSym) { - ctxt := w.ctxt - if ctxt.Debugasm > 0 { - w.ctxt.writeSymDebug(s) - } - - w.wr.WriteByte(symPrefix) - w.wr.WriteByte(byte(s.Type)) - w.writeRefIndex(s) - flags := int64(0) - if s.DuplicateOK() { - flags |= 1 - } - if s.Local() { - flags |= 1 << 1 - } - if s.MakeTypelink() { - flags |= 1 << 2 - } - w.writeInt(flags) - w.writeInt(s.Size) - w.writeRefIndex(s.Gotype) - w.writeInt(int64(len(s.P))) - - w.writeInt(int64(len(s.R))) - var r *Reloc - for i := range s.R { - r = &s.R[i] - w.writeInt(int64(r.Off)) - w.writeInt(int64(r.Siz)) - w.writeInt(int64(r.Type)) - w.writeInt(r.Add) - w.writeRefIndex(r.Sym) - } - - if s.Type != objabi.STEXT { - return - } - - w.writeInt(int64(s.Func.Args)) - w.writeInt(int64(s.Func.Locals)) - w.writeInt(int64(s.Func.Align)) - w.writeBool(s.NoSplit()) - flags = int64(0) - if s.Leaf() { - flags |= 1 - } - if s.CFunc() { - flags |= 1 << 1 - } - if s.ReflectMethod() { - flags |= 1 << 2 - } - if ctxt.Flag_shared { - flags |= 1 << 3 - } - if s.TopFrame() { - flags |= 1 << 4 - } - w.writeInt(flags) - w.writeInt(int64(0)) // TODO: remove at next object file rev - - pc := &s.Func.Pcln - w.writeInt(int64(len(pc.Pcsp.P))) - w.writeInt(int64(len(pc.Pcfile.P))) - w.writeInt(int64(len(pc.Pcline.P))) - w.writeInt(int64(len(pc.Pcinline.P))) - w.writeInt(int64(len(pc.Pcdata))) - for _, pcd := range pc.Pcdata { - w.writeInt(int64(len(pcd.P))) - } - w.writeInt(int64(len(pc.Funcdataoff))) - for i := range pc.Funcdataoff { - w.writeRefIndex(pc.Funcdata[i]) - } - for i := range pc.Funcdataoff { - w.writeInt(pc.Funcdataoff[i]) - } - w.writeInt(int64(len(pc.File))) - for _, f := range pc.File { - fsym := ctxt.Lookup(f) - w.writeRefIndex(fsym) - } - w.writeInt(int64(len(pc.InlTree.nodes))) - for _, call := range pc.InlTree.nodes { - w.writeInt(int64(call.Parent)) - f, l := linkgetlineFromPos(w.ctxt, call.Pos) - fsym := ctxt.Lookup(f) - w.writeRefIndex(fsym) - w.writeInt(int64(l)) - w.writeRefIndex(call.Func) - w.writeInt(int64(call.ParentPC)) - } -} - -func (w *objWriter) writeBool(b bool) { - if b { - w.writeInt(1) - } else { - w.writeInt(0) - } -} - -func (w *objWriter) writeInt(sval int64) { - var v uint64 - uv := (uint64(sval) << 1) ^ uint64(sval>>63) - p := w.varintbuf[:] - for v = uv; v >= 0x80; v >>= 7 { - p[0] = uint8(v | 0x80) - p = p[1:] - } - p[0] = uint8(v) - p = p[1:] - w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)]) -} - -func (w *objWriter) writeString(s string) { - w.writeInt(int64(len(s))) - w.wr.WriteString(s) -} - -func (w *objWriter) writeRefIndex(s *LSym) { - if s == nil { - w.writeInt(0) - return - } - if s.RefIdx == 0 { - log.Fatalln("writing an unreferenced symbol", s.Name) - } - w.writeInt(int64(s.RefIdx)) -} - // relocByOff sorts relocations by their offsets. type relocByOff []Reloc @@ -510,17 +162,11 @@ func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) { ls := s.(*LSym) rsym := f.(*LSym) - if c.Link.Flag_go115newobj { - fidx := c.Link.PosTable.FileIndex(rsym.Name) - // Note the +1 here -- the value we're writing is going to be an - // index into the DWARF line table file section, whose entries - // are numbered starting at 1, not 0. - ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1)) - } else { - ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0) - r := &ls.R[len(ls.R)-1] - r.Type = objabi.R_DWARFFILEREF - } + 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 { @@ -558,28 +204,19 @@ func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, ctxt.Diag("dwarfSym of non-TEXT %v", s) } if s.Func.dwarfInfoSym == nil { - if ctxt.Flag_go115newobj { - s.Func.dwarfInfoSym = &LSym{ - Type: objabi.SDWARFINFO, - } - 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) diff --git a/src/cmd/internal/obj/objfile2.go b/src/cmd/internal/obj/objfile2.go index 061e43c434..0b3b2be41b 100644 --- a/src/cmd/internal/obj/objfile2.go +++ b/src/cmd/internal/obj/objfile2.go @@ -17,7 +17,7 @@ import ( ) // Entry point of writing new object file. -func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) { +func WriteObjFile(ctxt *Link, b *bio.Writer, pkgpath string) { debugAsmEmit(ctxt) diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go index 44ec4602de..c82257c9e9 100644 --- a/src/cmd/internal/obj/plist.go +++ b/src/cmd/internal/obj/plist.go @@ -139,26 +139,7 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) { ctxt.Text = append(ctxt.Text, s) // Set up DWARF entries for s - info, loc, ranges, _, lines := ctxt.dwarfSym(s) - - // When using new object files, the DWARF symbols are unnamed aux - // symbols and don't need to be added to ctxt.Data. - // But the old object file still needs them. - if !ctxt.Flag_go115newobj { - info.Type = objabi.SDWARFINFO - info.Set(AttrDuplicateOK, s.DuplicateOK()) - if loc != nil { - loc.Type = objabi.SDWARFLOC - loc.Set(AttrDuplicateOK, s.DuplicateOK()) - ctxt.Data = append(ctxt.Data, loc) - } - ranges.Type = objabi.SDWARFRANGE - ranges.Set(AttrDuplicateOK, s.DuplicateOK()) - ctxt.Data = append(ctxt.Data, info, ranges) - lines.Type = objabi.SDWARFLINES - lines.Set(AttrDuplicateOK, s.DuplicateOK()) - ctxt.Data = append(ctxt.Data, lines) - } + ctxt.dwarfSym(s) } func (ctxt *Link) Globl(s *LSym, size int64, flag int) { diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go index 4a8b0ebb6f..61ef6ff2ce 100644 --- a/src/cmd/internal/obj/sym.go +++ b/src/cmd/internal/obj/sym.go @@ -165,10 +165,6 @@ func (ctxt *Link) Int64Sym(i int64) *LSym { // asm is set to true if this is called by the assembler (i.e. not the compiler), // in which case all the symbols are non-package (for now). func (ctxt *Link) NumberSyms(asm bool) { - if !ctxt.Flag_go115newobj { - return - } - if ctxt.Headtype == objabi.Haix { // Data must be sorted to keep a constant order in TOC symbols. // As they are created during Progedit, two symbols can be switched between diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 1ed8ccb828..b95bab3d89 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -39,7 +39,6 @@ import ( "flag" "log" "os" - "os/exec" "runtime" "runtime/pprof" "strings" @@ -99,8 +98,6 @@ var ( benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking") benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof") - - flagGo115Newobj = flag.Bool("go115newobj", true, "use new object file format") ) // Main is the main entry point for the linker code. @@ -140,10 +137,6 @@ func Main(arch *sys.Arch, theArch Arch) { objabi.Flagparse(usage) - if !*flagGo115Newobj { - oldlink() - } - switch *flagHeadType { case "": case "windowsgui": @@ -415,48 +408,3 @@ func startProfile() { }) } } - -// Invoke the old linker and exit. -func oldlink() { - linker := os.Args[0] - if strings.HasSuffix(linker, "link") { - linker = linker[:len(linker)-4] + "oldlink" - } else if strings.HasSuffix(linker, "link.exe") { - linker = linker[:len(linker)-8] + "oldlink.exe" - } else { - log.Fatal("cannot find oldlink. arg0=", linker) - } - - // Copy args, filter out -go115newobj flag - args := make([]string, 0, len(os.Args)-1) - skipNext := false - for i, a := range os.Args { - if i == 0 { - continue // skip arg0 - } - if skipNext { - skipNext = false - continue - } - if a == "-go115newobj" { - skipNext = true - continue - } - if strings.HasPrefix(a, "-go115newobj=") { - continue - } - args = append(args, a) - } - - cmd := exec.Command(linker, args...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - if err == nil { - os.Exit(0) - } - if _, ok := err.(*exec.ExitError); ok { - os.Exit(2) // would be nice to use ExitError.ExitCode(), but that is too new - } - log.Fatal("invoke oldlink failed:", err) -} diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 1b62d05197..02cd0b89d8 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -1914,7 +1914,7 @@ func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, uni r := goobj2.NewReaderFromBytes(roObject, readonly) if r == nil { if len(roObject) >= 8 && bytes.Equal(roObject[:8], []byte("\x00go114ld")) { - log.Fatalf("found object file %s in old format, but -go115newobj is true\nset -go115newobj consistently in all -gcflags, -asmflags, and -ldflags", f.File().Name()) + log.Fatalf("found object file %s in old format", f.File().Name()) } panic("cannot read object file") } diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 1c9e177911..145eb3c4ae 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -535,30 +535,6 @@ func TestStrictDup(t *testing.T) { } } -func TestOldLink(t *testing.T) { - // Test that old object file format still works. - // TODO(go115newobj): delete. - - testenv.MustHaveGoBuild(t) - - tmpdir, err := ioutil.TempDir("", "TestOldLink") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - src := filepath.Join(tmpdir, "main.go") - err = ioutil.WriteFile(src, []byte("package main; func main(){}\n"), 0666) - if err != nil { - t.Fatal(err) - } - - cmd := exec.Command(testenv.GoToolPath(t), "run", "-gcflags=all=-go115newobj=false", "-asmflags=all=-go115newobj=false", "-ldflags=-go115newobj=false", src) - if out, err := cmd.CombinedOutput(); err != nil { - t.Errorf("%v: %v:\n%s", cmd.Args, err, out) - } -} - const testFuncAlignSrc = ` package main import ( diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index a49423b212..cdffb68067 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -335,11 +335,11 @@ func TestGoLib(t *testing.T) { } // Check that a symbol has a given name, accepting both -// new and old objects. -// TODO(go115newobj): remove. +// with (for packaged symbols) and without index (for +// non-package symbols). func matchSymName(symname, want string) bool { return symname == want || - strings.HasPrefix(symname, want+"#") // new style, with index + strings.HasPrefix(symname, want+"#") } const testexec = ` diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go index 814cbf4564..be271e4fa6 100644 --- a/src/cmd/objdump/objdump_test.go +++ b/src/cmd/objdump/objdump_test.go @@ -286,9 +286,8 @@ func TestDisasmGoobj(t *testing.T) { t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out) } - // TODO(go115newobj): drop old object file support. need := []string{ - `main(#\d+)?\(SB\)`, // either new or old object file + `main#\d+\(SB\)`, `fmthello\.go:6`, } diff --git a/src/cmd/oldlink/doc.go b/src/cmd/oldlink/doc.go deleted file mode 100644 index 219499be0a..0000000000 --- a/src/cmd/oldlink/doc.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Link, typically invoked as ``go tool link,'' reads the Go archive or object -for a package main, along with its dependencies, and combines them -into an executable binary. - -Command Line - -Usage: - - go tool link [flags] main.a - -Flags: - - -B note - Add an ELF_NT_GNU_BUILD_ID note when using ELF. - The value should start with 0x and be an even number of hex digits. - -D address - Set data segment address. - -E entry - Set entry symbol name. - -H type - Set executable format type. - The default format is inferred from GOOS and GOARCH. - On Windows, -H windowsgui writes a "GUI binary" instead of a "console binary." - -I interpreter - Set the ELF dynamic linker to use. - -L dir1 -L dir2 - Search for imported packages in dir1, dir2, etc, - after consulting $GOROOT/pkg/$GOOS_$GOARCH. - -R quantum - Set address rounding quantum. - -T address - Set text segment address. - -V - Print linker version and exit. - -X importpath.name=value - Set the value of the string variable in importpath named name to value. - This is only effective if the variable is declared in the source code either uninitialized - or initialized to a constant string expression. -X will not work if the initializer makes - a function call or refers to other variables. - Note that before Go 1.5 this option took two separate arguments. - -a - Disassemble output. - -buildid id - Record id as Go toolchain build id. - -buildmode mode - Set build mode (default exe). - -c - Dump call graphs. - -compressdwarf - Compress DWARF if possible (default true). - -cpuprofile file - Write CPU profile to file. - -d - Disable generation of dynamic executables. - The emitted code is the same in either case; the option - controls only whether a dynamic header is included. - The dynamic header is on by default, even without any - references to dynamic libraries, because many common - system tools now assume the presence of the header. - -debugtramp int - Debug trampolines. - -dumpdep - Dump symbol dependency graph. - -extar ar - Set the external archive program (default "ar"). - Used only for -buildmode=c-archive. - -extld linker - Set the external linker (default "clang" or "gcc"). - -extldflags flags - Set space-separated flags to pass to the external linker. - -f - Ignore version mismatch in the linked archives. - -g - Disable Go package data checks. - -importcfg file - Read import configuration from file. - In the file, set packagefile, packageshlib to specify import resolution. - -installsuffix suffix - Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix - instead of $GOROOT/pkg/$GOOS_$GOARCH. - -k symbol - Set field tracking symbol. Use this flag when GOEXPERIMENT=fieldtrack is set. - -libgcc file - Set name of compiler support library. - This is only used in internal link mode. - If not set, default value comes from running the compiler, - which may be set by the -extld option. - Set to "none" to use no support library. - -linkmode mode - Set link mode (internal, external, auto). - This sets the linking mode as described in cmd/cgo/doc.go. - -linkshared - Link against installed Go shared libraries (experimental). - -memprofile file - Write memory profile to file. - -memprofilerate rate - Set runtime.MemProfileRate to rate. - -msan - Link with C/C++ memory sanitizer support. - -n - Dump symbol table. - -o file - Write output to file (default a.out, or a.out.exe on Windows). - -pluginpath path - The path name used to prefix exported plugin symbols. - -r dir1:dir2:... - Set the ELF dynamic linker search path. - -race - Link with race detection libraries. - -s - Omit the symbol table and debug information. - -shared - Generated shared object (implies -linkmode external; experimental). - -tmpdir dir - Write temporary files to dir. - Temporary files are only used in external linking mode. - -u - Reject unsafe packages. - -v - Print trace of linker operations. - -w - Omit the DWARF symbol table. -*/ -package main diff --git a/src/cmd/oldlink/internal/amd64/asm.go b/src/cmd/oldlink/internal/amd64/asm.go deleted file mode 100644 index c120e4ea81..0000000000 --- a/src/cmd/oldlink/internal/amd64/asm.go +++ /dev/null @@ -1,874 +0,0 @@ -// Inferno utils/6l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package amd64 - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" - "cmd/oldlink/internal/sym" - "debug/elf" - "log" -) - -func PADDR(x uint32) uint32 { - return x &^ 0x80000000 -} - -func Addcall(ctxt *ld.Link, s *sym.Symbol, t *sym.Symbol) int64 { - s.Attr |= sym.AttrReachable - i := s.Size - s.Size += 4 - s.Grow(s.Size) - r := s.AddRel() - r.Sym = t - r.Off = int32(i) - r.Type = objabi.R_CALL - r.Siz = 4 - return i + int64(r.Siz) -} - -func gentext(ctxt *ld.Link) { - if !ctxt.DynlinkingGo() { - return - } - addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0) - if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin { - // we're linking a module containing the runtime -> no need for - // an init function - return - } - addmoduledata.Attr |= sym.AttrReachable - initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0) - initfunc.Type = sym.STEXT - initfunc.Attr |= sym.AttrLocal - initfunc.Attr |= sym.AttrReachable - o := func(op ...uint8) { - for _, op1 := range op { - initfunc.AddUint8(op1) - } - } - // 0000000000000000 : - // 0: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 7 - // 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 - // 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) - } -} diff --git a/src/cmd/oldlink/internal/amd64/l.go b/src/cmd/oldlink/internal/amd64/l.go deleted file mode 100644 index 393da6bf28..0000000000 --- a/src/cmd/oldlink/internal/amd64/l.go +++ /dev/null @@ -1,43 +0,0 @@ -// Inferno utils/6l/l.h -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package amd64 - -const ( - maxAlign = 32 // max data alignment - minAlign = 1 // min data alignment - funcAlign = 16 -) - -/* Used by ../internal/ld/dwarf.go */ -const ( - dwarfRegSP = 7 - dwarfRegLR = 16 -) diff --git a/src/cmd/oldlink/internal/amd64/obj.go b/src/cmd/oldlink/internal/amd64/obj.go deleted file mode 100644 index 655d9f1e03..0000000000 --- a/src/cmd/oldlink/internal/amd64/obj.go +++ /dev/null @@ -1,117 +0,0 @@ -// Inferno utils/6l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package amd64 - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" -) - -func Init() (*sys.Arch, ld.Arch) { - arch := sys.ArchAMD64 - - theArch := ld.Arch{ - Funcalign: funcAlign, - Maxalign: maxAlign, - Minalign: minAlign, - Dwarfregsp: dwarfRegSP, - Dwarfreglr: dwarfRegLR, - - Adddynrel: adddynrel, - Archinit: archinit, - Archreloc: archreloc, - Archrelocvariant: archrelocvariant, - Asmb: asmb, - Asmb2: asmb2, - Elfreloc1: elfreloc1, - Elfsetupplt: elfsetupplt, - Gentext: gentext, - Machoreloc1: machoreloc1, - PEreloc1: pereloc1, - TLSIEtoLE: tlsIEtoLE, - - Linuxdynld: "/lib64/ld-linux-x86-64.so.2", - Freebsddynld: "/libexec/ld-elf.so.1", - Openbsddynld: "/usr/libexec/ld.so", - Netbsddynld: "/libexec/ld.elf_so", - Dragonflydynld: "/usr/libexec/ld-elf.so.2", - Solarisdynld: "/lib/amd64/ld.so.1", - } - - return arch, theArch -} - -func archinit(ctxt *ld.Link) { - switch ctxt.HeadType { - default: - ld.Exitf("unknown -H option: %v", ctxt.HeadType) - - case objabi.Hplan9: /* plan 9 */ - ld.HEADR = 32 + 8 - - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0x200000 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 0x200000 - } - - case objabi.Hdarwin: /* apple MACH */ - ld.HEADR = ld.INITIAL_MACHO_HEADR - if *ld.FlagRound == -1 { - *ld.FlagRound = 4096 - } - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0x1000000 + int64(ld.HEADR) - } - - case objabi.Hlinux, /* elf64 executable */ - objabi.Hfreebsd, /* freebsd */ - objabi.Hnetbsd, /* netbsd */ - objabi.Hopenbsd, /* openbsd */ - objabi.Hdragonfly, /* dragonfly */ - objabi.Hsolaris: /* solaris */ - ld.Elfinit(ctxt) - - ld.HEADR = ld.ELFRESERVE - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = (1 << 22) + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 4096 - } - - case objabi.Hwindows: /* PE executable */ - // ld.HEADR, ld.FlagTextAddr, ld.FlagRound are set in ld.Peinit - return - } -} diff --git a/src/cmd/oldlink/internal/arm/asm.go b/src/cmd/oldlink/internal/arm/asm.go deleted file mode 100644 index de6173569a..0000000000 --- a/src/cmd/oldlink/internal/arm/asm.go +++ /dev/null @@ -1,786 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package arm - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" - "cmd/oldlink/internal/sym" - "debug/elf" - "fmt" - "log" -) - -// This assembler: -// -// .align 2 -// local.dso_init: -// ldr r0, .Lmoduledata -// .Lloadfrom: -// ldr r0, [r0] -// b runtime.addmoduledata@plt -// .align 2 -// .Lmoduledata: -// .word local.moduledata(GOT_PREL) + (. - (.Lloadfrom + 4)) -// assembles to: -// -// 00000000 : -// 0: e59f0004 ldr r0, [pc, #4] ; c -// 4: e5900000 ldr r0, [r0] -// 8: eafffffe b 0 -// 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)) - } -} diff --git a/src/cmd/oldlink/internal/arm/l.go b/src/cmd/oldlink/internal/arm/l.go deleted file mode 100644 index a83d26bf06..0000000000 --- a/src/cmd/oldlink/internal/arm/l.go +++ /dev/null @@ -1,75 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package arm - -// Writing object files. - -// Inferno utils/5l/l.h -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -const ( - maxAlign = 8 // max data alignment - minAlign = 1 // min data alignment - funcAlign = 4 // single-instruction alignment -) - -/* Used by ../internal/ld/dwarf.go */ -const ( - dwarfRegSP = 13 - dwarfRegLR = 14 -) diff --git a/src/cmd/oldlink/internal/arm/obj.go b/src/cmd/oldlink/internal/arm/obj.go deleted file mode 100644 index c423937355..0000000000 --- a/src/cmd/oldlink/internal/arm/obj.go +++ /dev/null @@ -1,107 +0,0 @@ -// Inferno utils/5l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package arm - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" -) - -func Init() (*sys.Arch, ld.Arch) { - arch := sys.ArchARM - - theArch := ld.Arch{ - Funcalign: funcAlign, - Maxalign: maxAlign, - Minalign: minAlign, - Dwarfregsp: dwarfRegSP, - Dwarfreglr: dwarfRegLR, - - Adddynrel: adddynrel, - Archinit: archinit, - Archreloc: archreloc, - Archrelocvariant: archrelocvariant, - Trampoline: trampoline, - Asmb: asmb, - Asmb2: asmb2, - Elfreloc1: elfreloc1, - Elfsetupplt: elfsetupplt, - Gentext: gentext, - Machoreloc1: machoreloc1, - PEreloc1: pereloc1, - - Linuxdynld: "/lib/ld-linux.so.3", // 2 for OABI, 3 for EABI - Freebsddynld: "/usr/libexec/ld-elf.so.1", - Openbsddynld: "/usr/libexec/ld.so", - Netbsddynld: "/libexec/ld.elf_so", - Dragonflydynld: "XXX", - Solarisdynld: "XXX", - } - - return arch, theArch -} - -func archinit(ctxt *ld.Link) { - switch ctxt.HeadType { - default: - ld.Exitf("unknown -H option: %v", ctxt.HeadType) - - case objabi.Hplan9: /* plan 9 */ - ld.HEADR = 32 - - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 4128 - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 4096 - } - - case objabi.Hlinux, /* arm elf */ - objabi.Hfreebsd, - objabi.Hnetbsd, - objabi.Hopenbsd: - *ld.FlagD = false - // with dynamic linking - ld.Elfinit(ctxt) - ld.HEADR = ld.ELFRESERVE - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 0x10000 - } - - case objabi.Hwindows: /* PE executable */ - // ld.HEADR, ld.FlagTextAddr, ld.FlagRound are set in ld.Peinit - return - } -} diff --git a/src/cmd/oldlink/internal/arm64/asm.go b/src/cmd/oldlink/internal/arm64/asm.go deleted file mode 100644 index a97671222d..0000000000 --- a/src/cmd/oldlink/internal/arm64/asm.go +++ /dev/null @@ -1,946 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package arm64 - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" - "cmd/oldlink/internal/sym" - "debug/elf" - "encoding/binary" - "fmt" - "log" -) - -func gentext(ctxt *ld.Link) { - if !ctxt.DynlinkingGo() { - return - } - addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0) - if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin { - // we're linking a module containing the runtime -> no need for - // an init function - return - } - addmoduledata.Attr |= sym.AttrReachable - initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0) - initfunc.Type = sym.STEXT - initfunc.Attr |= sym.AttrLocal - initfunc.Attr |= sym.AttrReachable - o := func(op uint32) { - initfunc.AddUint32(ctxt.Arch, op) - } - // 0000000000000000 : - // 0: 90000000 adrp x0, 0 - // 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 - // 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 - - // is the offset value of &got[2] to &got[0], the same below - // ldr x17, [x16, ] - 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, - 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 - - // is the offset value of &got.plt[n] to &got.plt[0] - // ldr x17, [x16, ] - 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, - 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)) - } -} diff --git a/src/cmd/oldlink/internal/arm64/l.go b/src/cmd/oldlink/internal/arm64/l.go deleted file mode 100644 index 5f3530335e..0000000000 --- a/src/cmd/oldlink/internal/arm64/l.go +++ /dev/null @@ -1,74 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package arm64 - -// Writing object files. - -// cmd/9l/l.h from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -const ( - maxAlign = 32 // max data alignment - minAlign = 1 // min data alignment - funcAlign = 16 -) - -/* Used by ../internal/ld/dwarf.go */ -const ( - dwarfRegSP = 31 - dwarfRegLR = 30 -) diff --git a/src/cmd/oldlink/internal/arm64/obj.go b/src/cmd/oldlink/internal/arm64/obj.go deleted file mode 100644 index 2dcc999dd1..0000000000 --- a/src/cmd/oldlink/internal/arm64/obj.go +++ /dev/null @@ -1,110 +0,0 @@ -// Inferno utils/5l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package arm64 - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" -) - -func Init() (*sys.Arch, ld.Arch) { - arch := sys.ArchARM64 - - theArch := ld.Arch{ - Funcalign: funcAlign, - Maxalign: maxAlign, - Minalign: minAlign, - Dwarfregsp: dwarfRegSP, - Dwarfreglr: dwarfRegLR, - - Adddynrel: adddynrel, - Archinit: archinit, - Archreloc: archreloc, - Archrelocvariant: archrelocvariant, - Asmb: asmb, - Asmb2: asmb2, - Elfreloc1: elfreloc1, - Elfsetupplt: elfsetupplt, - Gentext: gentext, - Machoreloc1: machoreloc1, - - Androiddynld: "/system/bin/linker64", - Linuxdynld: "/lib/ld-linux-aarch64.so.1", - - Freebsddynld: "/usr/libexec/ld-elf.so.1", - Openbsddynld: "/usr/libexec/ld.so", - Netbsddynld: "/libexec/ld.elf_so", - Dragonflydynld: "XXX", - Solarisdynld: "XXX", - } - - return arch, theArch -} - -func archinit(ctxt *ld.Link) { - switch ctxt.HeadType { - default: - ld.Exitf("unknown -H option: %v", ctxt.HeadType) - - case objabi.Hplan9: /* plan 9 */ - ld.HEADR = 32 - - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 4096 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 4096 - } - - case objabi.Hlinux, /* arm64 elf */ - objabi.Hfreebsd, - objabi.Hnetbsd, - objabi.Hopenbsd: - ld.Elfinit(ctxt) - ld.HEADR = ld.ELFRESERVE - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 0x10000 - } - - case objabi.Hdarwin: /* apple MACH */ - ld.HEADR = ld.INITIAL_MACHO_HEADR - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 4096 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 4096 - } - } -} diff --git a/src/cmd/oldlink/internal/ld/ar.go b/src/cmd/oldlink/internal/ld/ar.go deleted file mode 100644 index 8df859f11c..0000000000 --- a/src/cmd/oldlink/internal/ld/ar.go +++ /dev/null @@ -1,193 +0,0 @@ -// Inferno utils/include/ar.h -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/include/ar.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ld - -import ( - "cmd/internal/bio" - "cmd/internal/objabi" - "cmd/oldlink/internal/sym" - "encoding/binary" - "fmt" - "io" - "os" -) - -const ( - SARMAG = 8 - SAR_HDR = 16 + 44 -) - -const ( - ARMAG = "!\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 -} diff --git a/src/cmd/oldlink/internal/ld/config.go b/src/cmd/oldlink/internal/ld/config.go deleted file mode 100644 index 2373b500e3..0000000000 --- a/src/cmd/oldlink/internal/ld/config.go +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "fmt" - "log" -) - -// A BuildMode indicates the sort of object we are building. -// -// Possible build modes are the same as those for the -buildmode flag -// in cmd/go, and are documented in 'go help buildmode'. -type BuildMode uint8 - -const ( - BuildModeUnset BuildMode = iota - BuildModeExe - BuildModePIE - BuildModeCArchive - BuildModeCShared - BuildModeShared - BuildModePlugin -) - -func (mode *BuildMode) Set(s string) error { - badmode := func() error { - return fmt.Errorf("buildmode %s not supported on %s/%s", s, objabi.GOOS, objabi.GOARCH) - } - switch s { - default: - return fmt.Errorf("invalid buildmode: %q", s) - case "exe": - *mode = BuildModeExe - case "pie": - switch objabi.GOOS { - case "aix", "android", "linux", "windows": - case "darwin", "freebsd": - switch objabi.GOARCH { - case "amd64": - default: - return badmode() - } - default: - return badmode() - } - *mode = BuildModePIE - case "c-archive": - switch objabi.GOOS { - case "aix", "darwin", "linux": - case "freebsd": - switch objabi.GOARCH { - case "amd64": - default: - return badmode() - } - case "windows": - switch objabi.GOARCH { - case "amd64", "386", "arm": - default: - return badmode() - } - default: - return badmode() - } - *mode = BuildModeCArchive - case "c-shared": - switch objabi.GOARCH { - case "386", "amd64", "arm", "arm64", "ppc64le", "s390x": - default: - return badmode() - } - *mode = BuildModeCShared - case "shared": - switch objabi.GOOS { - case "linux": - switch objabi.GOARCH { - case "386", "amd64", "arm", "arm64", "ppc64le", "s390x": - default: - return badmode() - } - default: - return badmode() - } - *mode = BuildModeShared - case "plugin": - switch objabi.GOOS { - case "linux": - switch objabi.GOARCH { - case "386", "amd64", "arm", "arm64", "s390x", "ppc64le": - default: - return badmode() - } - case "darwin", "freebsd": - switch objabi.GOARCH { - case "amd64": - default: - return badmode() - } - default: - return badmode() - } - *mode = BuildModePlugin - } - return nil -} - -func (mode *BuildMode) String() string { - switch *mode { - case BuildModeUnset: - return "" // avoid showing a default in usage message - case BuildModeExe: - return "exe" - case BuildModePIE: - return "pie" - case BuildModeCArchive: - return "c-archive" - case BuildModeCShared: - return "c-shared" - case BuildModeShared: - return "shared" - case BuildModePlugin: - return "plugin" - } - return fmt.Sprintf("BuildMode(%d)", uint8(*mode)) -} - -// LinkMode indicates whether an external linker is used for the final link. -type LinkMode uint8 - -const ( - LinkAuto LinkMode = iota - LinkInternal - LinkExternal -) - -func (mode *LinkMode) Set(s string) error { - switch s { - default: - return fmt.Errorf("invalid linkmode: %q", s) - case "auto": - *mode = LinkAuto - case "internal": - *mode = LinkInternal - case "external": - *mode = LinkExternal - } - return nil -} - -func (mode *LinkMode) String() string { - switch *mode { - case LinkAuto: - return "auto" - case LinkInternal: - return "internal" - case LinkExternal: - return "external" - } - return fmt.Sprintf("LinkMode(%d)", uint8(*mode)) -} - -// mustLinkExternal reports whether the program being linked requires -// the external linker be used to complete the link. -func mustLinkExternal(ctxt *Link) (res bool, reason string) { - if ctxt.Debugvlog > 1 { - defer func() { - if res { - log.Printf("external linking is forced by: %s\n", reason) - } - }() - } - - if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) { - return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH) - } - - if *flagMsan { - return true, "msan" - } - - // Internally linking cgo is incomplete on some architectures. - // https://golang.org/issue/14449 - // https://golang.org/issue/21961 - if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64) { - return true, objabi.GOARCH + " does not support internal cgo" - } - if iscgo && objabi.GOOS == "android" { - return true, objabi.GOOS + " does not support internal cgo" - } - - // When the race flag is set, the LLVM tsan relocatable file is linked - // into the final binary, which means external linking is required because - // internal linking does not support it. - if *flagRace && ctxt.Arch.InFamily(sys.PPC64) { - return true, "race on " + objabi.GOARCH - } - - // Some build modes require work the internal linker cannot do (yet). - switch ctxt.BuildMode { - case BuildModeCArchive: - return true, "buildmode=c-archive" - case BuildModeCShared: - return true, "buildmode=c-shared" - case BuildModePIE: - switch objabi.GOOS + "/" + objabi.GOARCH { - case "linux/amd64", "linux/arm64", "android/arm64": - case "windows/386", "windows/amd64", "windows/arm": - default: - // Internal linking does not support TLS_IE. - return true, "buildmode=pie" - } - case BuildModePlugin: - return true, "buildmode=plugin" - case BuildModeShared: - return true, "buildmode=shared" - } - if ctxt.linkShared { - return true, "dynamically linking with a shared library" - } - - return false, "" -} - -// determineLinkMode sets ctxt.LinkMode. -// -// It is called after flags are processed and inputs are processed, -// so the ctxt.LinkMode variable has an initial value from the -linkmode -// flag and the iscgo externalobj variables are set. -func determineLinkMode(ctxt *Link) { - extNeeded, extReason := mustLinkExternal(ctxt) - via := "" - - if ctxt.LinkMode == LinkAuto { - // The environment variable GO_EXTLINK_ENABLED controls the - // default value of -linkmode. If it is not set when the - // linker is called we take the value it was set to when - // cmd/link was compiled. (See make.bash.) - switch objabi.Getgoextlinkenabled() { - case "0": - ctxt.LinkMode = LinkInternal - via = "via GO_EXTLINK_ENABLED " - case "1": - ctxt.LinkMode = LinkExternal - via = "via GO_EXTLINK_ENABLED " - default: - if extNeeded || (iscgo && externalobj) { - ctxt.LinkMode = LinkExternal - } else { - ctxt.LinkMode = LinkInternal - } - } - } - - switch ctxt.LinkMode { - case LinkInternal: - if extNeeded { - Exitf("internal linking requested %sbut external linking required: %s", via, extReason) - } - case LinkExternal: - switch { - case objabi.GOARCH == "riscv64": - Exitf("external linking not supported for %s/riscv64", objabi.GOOS) - case objabi.GOARCH == "ppc64" && objabi.GOOS != "aix": - Exitf("external linking not supported for %s/ppc64", objabi.GOOS) - } - } -} diff --git a/src/cmd/oldlink/internal/ld/data.go b/src/cmd/oldlink/internal/ld/data.go deleted file mode 100644 index ba4a74156b..0000000000 --- a/src/cmd/oldlink/internal/ld/data.go +++ /dev/null @@ -1,2501 +0,0 @@ -// Derived from Inferno utils/6l/obj.c and utils/6l/span.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ld - -import ( - "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 := "" - var addr int64 - if r.Sym != nil { - nam = r.Sym.Name - addr = Symaddr(r.Sym) - } - xnam := "" - 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() -} diff --git a/src/cmd/oldlink/internal/ld/deadcode.go b/src/cmd/oldlink/internal/ld/deadcode.go deleted file mode 100644 index 6a6813aa58..0000000000 --- a/src/cmd/oldlink/internal/ld/deadcode.go +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/sym" - "fmt" - "strings" - "unicode" -) - -// deadcode marks all reachable symbols. -// -// The basis of the dead code elimination is a flood fill of symbols, -// following their relocations, beginning at *flagEntrySymbol. -// -// This flood fill is wrapped in logic for pruning unused methods. -// All methods are mentioned by relocations on their receiver's *rtype. -// These relocations are specially defined as R_METHODOFF by the compiler -// so we can detect and manipulated them here. -// -// There are three ways a method of a reachable type can be invoked: -// -// 1. direct call -// 2. through a reachable interface type -// 3. reflect.Value.Method (or MethodByName), or reflect.Type.Method -// (or MethodByName) -// -// The first case is handled by the flood fill, a directly called method -// is marked as reachable. -// -// The second case is handled by decomposing all reachable interface -// types into method signatures. Each encountered method is compared -// against the interface method signatures, if it matches it is marked -// as reachable. This is extremely conservative, but easy and correct. -// -// The third case is handled by looking to see if any of: -// - reflect.Value.Method or MethodByName is reachable -// - reflect.Type.Method or MethodByName is called (through the -// REFLECTMETHOD attribute marked by the compiler). -// If any of these happen, all bets are off and all exported methods -// of reachable types are marked reachable. -// -// Any unreached text symbols are removed from ctxt.Textp. -func deadcode(ctxt *Link) { - if ctxt.Debugvlog != 0 { - ctxt.Logf("deadcode\n") - } - - if *flagNewobj { - deadcode2(ctxt) - return - } - - d := &deadcodepass{ - ctxt: ctxt, - ifaceMethod: make(map[methodsig]bool), - } - - // First, flood fill any symbols directly reachable in the call - // graph from *flagEntrySymbol. Ignore all methods not directly called. - d.init() - d.flood() - - methSym := ctxt.Syms.ROLookup("reflect.Value.Method", sym.SymVerABIInternal) - methByNameSym := ctxt.Syms.ROLookup("reflect.Value.MethodByName", sym.SymVerABIInternal) - reflectSeen := false - - if ctxt.DynlinkingGo() { - // Exported methods may satisfy interfaces we don't know - // about yet when dynamically linking. - reflectSeen = true - } - - for { - if !reflectSeen { - if d.reflectMethod || (methSym != nil && methSym.Attr.Reachable()) || (methByNameSym != nil && methByNameSym.Attr.Reachable()) { - // Methods might be called via reflection. Give up on - // static analysis, mark all exported methods of - // all reachable types as reachable. - reflectSeen = true - } - } - - // Mark all methods that could satisfy a discovered - // interface as reachable. We recheck old marked interfaces - // as new types (with new methods) may have been discovered - // in the last pass. - var rem []methodref - for _, m := range d.markableMethods { - if (reflectSeen && m.isExported()) || d.ifaceMethod[m.m] { - d.markMethod(m) - } else { - rem = append(rem, m) - } - } - d.markableMethods = rem - - if len(d.markQueue) == 0 { - // No new work was discovered. Done. - break - } - d.flood() - } - - // Remove all remaining unreached R_METHODOFF relocations. - for _, m := range d.markableMethods { - for _, r := range m.r { - d.cleanupReloc(r) - } - } - - if ctxt.BuildMode != BuildModeShared { - // Keep a itablink if the symbol it points at is being kept. - // (When BuildModeShared, always keep itablinks.) - for _, s := range ctxt.Syms.Allsym { - if strings.HasPrefix(s.Name, "go.itablink.") { - s.Attr.Set(sym.AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable()) - } - } - } - - addToTextp(ctxt) -} - -func addToTextp(ctxt *Link) { - // Remove dead text but keep file information (z symbols). - textp := []*sym.Symbol{} - for _, s := range ctxt.Textp { - if s.Attr.Reachable() { - textp = append(textp, s) - } - } - - // Put reachable text symbols into Textp. - // do it in postorder so that packages are laid down in dependency order - // internal first, then everything else - ctxt.Library = postorder(ctxt.Library) - for _, doInternal := range [2]bool{true, false} { - for _, lib := range ctxt.Library { - if isRuntimeDepPkg(lib.Pkg) != doInternal { - continue - } - libtextp := lib.Textp[:0] - for _, s := range lib.Textp { - if s.Attr.Reachable() { - textp = append(textp, s) - libtextp = append(libtextp, s) - if s.Unit != nil { - s.Unit.Textp = append(s.Unit.Textp, s) - } - } - } - for _, s := range lib.DupTextSyms { - if s.Attr.Reachable() && !s.Attr.OnList() { - textp = append(textp, s) - libtextp = append(libtextp, s) - if s.Unit != nil { - s.Unit.Textp = append(s.Unit.Textp, s) - } - s.Attr |= sym.AttrOnList - // dupok symbols may be defined in multiple packages. its - // associated package is chosen sort of arbitrarily (the - // first containing package that the linker loads). canonicalize - // it here to the package with which it will be laid down - // in text. - s.File = objabi.PathToPrefix(lib.Pkg) - } - } - lib.Textp = libtextp - } - } - ctxt.Textp = textp - - if len(ctxt.Shlibs) > 0 { - // We might have overwritten some functions above (this tends to happen for the - // autogenerated type equality/hashing functions) and we don't want to generated - // pcln table entries for these any more so remove them from Textp. - textp := make([]*sym.Symbol, 0, len(ctxt.Textp)) - for _, s := range ctxt.Textp { - if s.Type != sym.SDYNIMPORT { - textp = append(textp, s) - } - } - ctxt.Textp = textp - } -} - -// methodref holds the relocations from a receiver type symbol to its -// method. There are three relocations, one for each of the fields in -// the reflect.method struct: mtyp, ifn, and tfn. -type methodref struct { - m methodsig - src *sym.Symbol // receiver type symbol - r [3]*sym.Reloc // R_METHODOFF relocations to fields of runtime.method -} - -func (m methodref) ifn() *sym.Symbol { return m.r[1].Sym } - -func (m methodref) isExported() bool { - for _, r := range m.m { - return unicode.IsUpper(r) - } - panic("methodref has no signature") -} - -// deadcodepass holds state for the deadcode flood fill. -type deadcodepass struct { - ctxt *Link - markQueue []*sym.Symbol // symbols to flood fill in next pass - ifaceMethod map[methodsig]bool // methods declared in reached interfaces - markableMethods []methodref // methods of reached types - reflectMethod bool -} - -func (d *deadcodepass) cleanupReloc(r *sym.Reloc) { - if r.Sym.Attr.Reachable() { - r.Type = objabi.R_ADDROFF - } else { - if d.ctxt.Debugvlog > 1 { - d.ctxt.Logf("removing method %s\n", r.Sym.Name) - } - r.Sym = nil - r.Siz = 0 - } -} - -// mark appends a symbol to the mark queue for flood filling. -func (d *deadcodepass) mark(s, parent *sym.Symbol) { - if s == nil || s.Attr.Reachable() { - return - } - if s.Attr.ReflectMethod() { - d.reflectMethod = true - } - if *flagDumpDep { - p := "_" - if parent != nil { - p = parent.Name - } - fmt.Printf("%s -> %s\n", p, s.Name) - } - s.Attr |= sym.AttrReachable - if d.ctxt.Reachparent != nil { - d.ctxt.Reachparent[s] = parent - } - d.markQueue = append(d.markQueue, s) -} - -// markMethod marks a method as reachable. -func (d *deadcodepass) markMethod(m methodref) { - for _, r := range m.r { - d.mark(r.Sym, m.src) - r.Type = objabi.R_ADDROFF - } -} - -// init marks all initial symbols as reachable. -// In a typical binary, this is *flagEntrySymbol. -func (d *deadcodepass) init() { - var names []string - - if d.ctxt.BuildMode == BuildModeShared { - // Mark all symbols defined in this library as reachable when - // building a shared library. - for _, s := range d.ctxt.Syms.Allsym { - if s.Type != 0 && s.Type != sym.SDYNIMPORT { - d.mark(s, nil) - } - } - } else { - // In a normal binary, start at main.main and the init - // functions and mark what is reachable from there. - - if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) { - names = append(names, "main.main", "main..inittask") - } else { - // The external linker refers main symbol directly. - if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) { - if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 { - *flagEntrySymbol = "_main" - } else { - *flagEntrySymbol = "main" - } - } - names = append(names, *flagEntrySymbol) - if d.ctxt.BuildMode == BuildModePlugin { - names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs") - - // We don't keep the go.plugin.exports symbol, - // but we do keep the symbols it refers to. - exports := d.ctxt.Syms.ROLookup("go.plugin.exports", 0) - if exports != nil { - for i := range exports.R { - d.mark(exports.R[i].Sym, nil) - } - } - } - } - for _, s := range dynexp { - d.mark(s, nil) - } - } - - for _, name := range names { - // Mark symbol as a data/ABI0 symbol. - d.mark(d.ctxt.Syms.ROLookup(name, 0), nil) - // Also mark any Go functions (internal ABI). - d.mark(d.ctxt.Syms.ROLookup(name, sym.SymVerABIInternal), nil) - } -} - -// flood fills symbols reachable from the markQueue symbols. -// As it goes, it collects methodref and interface method declarations. -func (d *deadcodepass) flood() { - for len(d.markQueue) > 0 { - s := d.markQueue[0] - d.markQueue = d.markQueue[1:] - if s.Type == sym.STEXT { - if d.ctxt.Debugvlog > 1 { - d.ctxt.Logf("marktext %s\n", s.Name) - } - } - - if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' { - if len(s.P) == 0 { - // Probably a bug. The undefined symbol check - // later will give a better error than deadcode. - continue - } - if decodetypeKind(d.ctxt.Arch, s.P)&kindMask == kindInterface { - for _, sig := range decodeIfaceMethods(d.ctxt.Arch, s) { - if d.ctxt.Debugvlog > 1 { - d.ctxt.Logf("reached iface method: %s\n", sig) - } - d.ifaceMethod[sig] = true - } - } - } - - mpos := 0 // 0-3, the R_METHODOFF relocs of runtime.uncommontype - var methods []methodref - for i := range s.R { - r := &s.R[i] - if r.Sym == nil { - continue - } - if r.Type == objabi.R_WEAKADDROFF { - // An R_WEAKADDROFF relocation is not reason - // enough to mark the pointed-to symbol as - // reachable. - continue - } - if r.Sym.Type == sym.SABIALIAS { - // Patch this relocation through the - // ABI alias before marking. - r.Sym = resolveABIAlias(r.Sym) - } - if r.Type != objabi.R_METHODOFF { - d.mark(r.Sym, s) - continue - } - // Collect rtype pointers to methods for - // later processing in deadcode. - if mpos == 0 { - m := methodref{src: s} - m.r[0] = r - methods = append(methods, m) - } else { - methods[len(methods)-1].r[mpos] = r - } - mpos++ - if mpos == len(methodref{}.r) { - mpos = 0 - } - } - if len(methods) > 0 { - // Decode runtime type information for type methods - // to help work out which methods can be called - // dynamically via interfaces. - methodsigs := decodetypeMethods(d.ctxt.Arch, s) - if len(methods) != len(methodsigs) { - panic(fmt.Sprintf("%q has %d method relocations for %d methods", s.Name, len(methods), len(methodsigs))) - } - for i, m := range methodsigs { - name := string(m) - name = name[:strings.Index(name, "(")] - if !strings.HasSuffix(methods[i].ifn().Name, name) { - panic(fmt.Sprintf("%q relocation for %q does not match method %q", s.Name, methods[i].ifn().Name, name)) - } - methods[i].m = m - } - d.markableMethods = append(d.markableMethods, methods...) - } - - if s.FuncInfo != nil { - for i := range s.FuncInfo.Funcdata { - d.mark(s.FuncInfo.Funcdata[i], s) - } - } - d.mark(s.Gotype, s) - d.mark(s.Sub, s) - d.mark(s.Outer, s) - } -} diff --git a/src/cmd/oldlink/internal/ld/deadcode2.go b/src/cmd/oldlink/internal/ld/deadcode2.go deleted file mode 100644 index 82bfd60a47..0000000000 --- a/src/cmd/oldlink/internal/ld/deadcode2.go +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "bytes" - "cmd/internal/dwarf" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/loader" - "cmd/oldlink/internal/sym" - "container/heap" - "fmt" - "unicode" -) - -var _ = fmt.Print - -type workQueue []loader.Sym - -// Implement container/heap.Interface. -func (q *workQueue) Len() int { return len(*q) } -func (q *workQueue) Less(i, j int) bool { return (*q)[i] < (*q)[j] } -func (q *workQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] } -func (q *workQueue) Push(i interface{}) { *q = append(*q, i.(loader.Sym)) } -func (q *workQueue) Pop() interface{} { i := (*q)[len(*q)-1]; *q = (*q)[:len(*q)-1]; return i } - -// Functions for deadcode pass to use. -// Deadcode pass should call push/pop, not Push/Pop. -func (q *workQueue) push(i loader.Sym) { heap.Push(q, i) } -func (q *workQueue) pop() loader.Sym { return heap.Pop(q).(loader.Sym) } -func (q *workQueue) empty() bool { return len(*q) == 0 } - -type deadcodePass2 struct { - ctxt *Link - ldr *loader.Loader - wq workQueue - rtmp []loader.Reloc - - ifaceMethod map[methodsig]bool // methods declared in reached interfaces - markableMethods []methodref2 // methods of reached types - reflectSeen bool // whether we have seen a reflect method call -} - -func (d *deadcodePass2) init() { - d.ldr.InitReachable() - d.ifaceMethod = make(map[methodsig]bool) - if d.ctxt.Reachparent != nil { - d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym()) - } - heap.Init(&d.wq) - - if d.ctxt.BuildMode == BuildModeShared { - // Mark all symbols defined in this library as reachable when - // building a shared library. - n := d.ldr.NDef() - for i := 1; i < n; i++ { - s := loader.Sym(i) - if !d.ldr.IsDup(s) { - d.mark(s, 0) - } - } - return - } - - var names []string - - // In a normal binary, start at main.main and the init - // functions and mark what is reachable from there. - if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) { - names = append(names, "main.main", "main..inittask") - } else { - // The external linker refers main symbol directly. - if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) { - if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 { - *flagEntrySymbol = "_main" - } else { - *flagEntrySymbol = "main" - } - } - names = append(names, *flagEntrySymbol) - if d.ctxt.BuildMode == BuildModePlugin { - names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs") - - // We don't keep the go.plugin.exports symbol, - // but we do keep the symbols it refers to. - exportsIdx := d.ldr.Lookup("go.plugin.exports", 0) - if exportsIdx != 0 { - d.ReadRelocs(exportsIdx) - for i := 0; i < len(d.rtmp); i++ { - d.mark(d.rtmp[i].Sym, 0) - } - } - } - } - - dynexpMap := d.ctxt.cgo_export_dynamic - if d.ctxt.LinkMode == LinkExternal { - dynexpMap = d.ctxt.cgo_export_static - } - for exp := range dynexpMap { - names = append(names, exp) - } - - // DWARF constant DIE symbols are not referenced, but needed by - // the dwarf pass. - if !*FlagW { - for _, lib := range d.ctxt.Library { - names = append(names, dwarf.ConstInfoPrefix+lib.Pkg) - } - } - - for _, name := range names { - // Mark symbol as a data/ABI0 symbol. - d.mark(d.ldr.Lookup(name, 0), 0) - // Also mark any Go functions (internal ABI). - d.mark(d.ldr.Lookup(name, sym.SymVerABIInternal), 0) - } -} - -func (d *deadcodePass2) flood() { - symRelocs := []loader.Reloc{} - auxSyms := []loader.Sym{} - for !d.wq.empty() { - symIdx := d.wq.pop() - - d.reflectSeen = d.reflectSeen || d.ldr.IsReflectMethod(symIdx) - - relocs := d.ldr.Relocs(symIdx) - symRelocs = relocs.ReadAll(symRelocs) - - if d.ldr.IsGoType(symIdx) { - p := d.ldr.Data(symIdx) - if len(p) != 0 && decodetypeKind(d.ctxt.Arch, p)&kindMask == kindInterface { - for _, sig := range d.decodeIfaceMethods2(d.ldr, d.ctxt.Arch, symIdx, symRelocs) { - if d.ctxt.Debugvlog > 1 { - d.ctxt.Logf("reached iface method: %s\n", sig) - } - d.ifaceMethod[sig] = true - } - } - } - - var methods []methodref2 - for i := 0; i < relocs.Count; i++ { - r := symRelocs[i] - if r.Type == objabi.R_WEAKADDROFF { - continue - } - if r.Type == objabi.R_METHODOFF { - if i+2 >= relocs.Count { - panic("expect three consecutive R_METHODOFF relocs") - } - methods = append(methods, methodref2{src: symIdx, r: i}) - i += 2 - continue - } - if r.Type == objabi.R_USETYPE { - // type symbol used for DWARF. we need to load the symbol but it may not - // be otherwise reachable in the program. - // do nothing for now as we still load all type symbols. - continue - } - d.mark(r.Sym, symIdx) - } - auxSyms = d.ldr.ReadAuxSyms(symIdx, auxSyms) - for i := 0; i < len(auxSyms); i++ { - d.mark(auxSyms[i], symIdx) - } - // Some host object symbols have an outer object, which acts like a - // "carrier" symbol, or it holds all the symbols for a particular - // section. We need to mark all "referenced" symbols from that carrier, - // so we make sure we're pulling in all outer symbols, and their sub - // symbols. This is not ideal, and these carrier/section symbols could - // be removed. - d.mark(d.ldr.OuterSym(symIdx), symIdx) - d.mark(d.ldr.SubSym(symIdx), symIdx) - - if len(methods) != 0 { - // Decode runtime type information for type methods - // to help work out which methods can be called - // dynamically via interfaces. - methodsigs := d.decodetypeMethods2(d.ldr, d.ctxt.Arch, symIdx, symRelocs) - if len(methods) != len(methodsigs) { - panic(fmt.Sprintf("%q has %d method relocations for %d methods", d.ldr.SymName(symIdx), len(methods), len(methodsigs))) - } - for i, m := range methodsigs { - methods[i].m = m - } - d.markableMethods = append(d.markableMethods, methods...) - } - } -} - -func (d *deadcodePass2) mark(symIdx, parent loader.Sym) { - if symIdx != 0 && !d.ldr.Reachable.Has(symIdx) { - d.wq.push(symIdx) - d.ldr.Reachable.Set(symIdx) - if d.ctxt.Reachparent != nil { - d.ldr.Reachparent[symIdx] = parent - } - if *flagDumpDep { - to := d.ldr.SymName(symIdx) - if to != "" { - from := "_" - if parent != 0 { - from = d.ldr.SymName(parent) - } - fmt.Printf("%s -> %s\n", from, to) - } - } - } -} - -func (d *deadcodePass2) markMethod(m methodref2) { - d.ReadRelocs(m.src) - d.mark(d.rtmp[m.r].Sym, m.src) - d.mark(d.rtmp[m.r+1].Sym, m.src) - d.mark(d.rtmp[m.r+2].Sym, m.src) -} - -func deadcode2(ctxt *Link) { - ldr := ctxt.loader - d := deadcodePass2{ctxt: ctxt, ldr: ldr} - d.init() - d.flood() - - callSym := ldr.Lookup("reflect.Value.Call", sym.SymVerABIInternal) - methSym := ldr.Lookup("reflect.Value.Method", sym.SymVerABIInternal) - if ctxt.DynlinkingGo() { - // Exported methods may satisfy interfaces we don't know - // about yet when dynamically linking. - d.reflectSeen = true - } - - for { - // Methods might be called via reflection. Give up on - // static analysis, mark all exported methods of - // all reachable types as reachable. - d.reflectSeen = d.reflectSeen || (callSym != 0 && ldr.Reachable.Has(callSym)) || (methSym != 0 && ldr.Reachable.Has(methSym)) - - // Mark all methods that could satisfy a discovered - // interface as reachable. We recheck old marked interfaces - // as new types (with new methods) may have been discovered - // in the last pass. - rem := d.markableMethods[:0] - for _, m := range d.markableMethods { - if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] { - d.markMethod(m) - } else { - rem = append(rem, m) - } - } - d.markableMethods = rem - - if d.wq.empty() { - // No new work was discovered. Done. - break - } - d.flood() - } - - n := ldr.NSym() - - if ctxt.BuildMode != BuildModeShared { - // Keep a itablink if the symbol it points at is being kept. - // (When BuildModeShared, always keep itablinks.) - for i := 1; i < n; i++ { - s := loader.Sym(i) - if ldr.IsItabLink(s) { - relocs := ldr.Relocs(s) - if relocs.Count > 0 && ldr.Reachable.Has(relocs.At(0).Sym) { - ldr.Reachable.Set(s) - } - } - } - } -} - -// methodref2 holds the relocations from a receiver type symbol to its -// method. There are three relocations, one for each of the fields in -// the reflect.method struct: mtyp, ifn, and tfn. -type methodref2 struct { - m methodsig - src loader.Sym // receiver type symbol - r int // the index of R_METHODOFF relocations -} - -func (m methodref2) isExported() bool { - for _, r := range m.m { - return unicode.IsUpper(r) - } - panic("methodref has no signature") -} - -// decodeMethodSig2 decodes an array of method signature information. -// Each element of the array is size bytes. The first 4 bytes is a -// nameOff for the method name, and the next 4 bytes is a typeOff for -// the function type. -// -// Conveniently this is the layout of both runtime.method and runtime.imethod. -func (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, off, size, count int) []methodsig { - var buf bytes.Buffer - var methods []methodsig - for i := 0; i < count; i++ { - buf.WriteString(decodetypeName2(ldr, symIdx, symRelocs, off)) - mtypSym := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off+4)) - // FIXME: add some sort of caching here, since we may see some of the - // same symbols over time for param types. - d.ReadRelocs(mtypSym) - mp := ldr.Data(mtypSym) - - buf.WriteRune('(') - inCount := decodetypeFuncInCount(arch, mp) - for i := 0; i < inCount; i++ { - if i > 0 { - buf.WriteString(", ") - } - a := d.decodetypeFuncInType2(ldr, arch, mtypSym, d.rtmp, i) - buf.WriteString(ldr.SymName(a)) - } - buf.WriteString(") (") - outCount := decodetypeFuncOutCount(arch, mp) - for i := 0; i < outCount; i++ { - if i > 0 { - buf.WriteString(", ") - } - a := d.decodetypeFuncOutType2(ldr, arch, mtypSym, d.rtmp, i) - buf.WriteString(ldr.SymName(a)) - } - buf.WriteRune(')') - - off += size - methods = append(methods, methodsig(buf.String())) - buf.Reset() - } - return methods -} - -func (d *deadcodePass2) decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []methodsig { - p := ldr.Data(symIdx) - if decodetypeKind(arch, p)&kindMask != kindInterface { - panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx))) - } - rel := decodeReloc2(ldr, symIdx, symRelocs, int32(commonsize(arch)+arch.PtrSize)) - if rel.Sym == 0 { - return nil - } - if rel.Sym != symIdx { - panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", ldr.SymName(symIdx))) - } - off := int(rel.Add) // array of reflect.imethod values - numMethods := int(decodetypeIfaceMethodCount(arch, p)) - sizeofIMethod := 4 + 4 - return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofIMethod, numMethods) -} - -func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []methodsig { - p := ldr.Data(symIdx) - if !decodetypeHasUncommon(arch, p) { - panic(fmt.Sprintf("no methods on %q", ldr.SymName(symIdx))) - } - off := commonsize(arch) // reflect.rtype - switch decodetypeKind(arch, p) & kindMask { - case kindStruct: // reflect.structType - off += 4 * arch.PtrSize - case kindPtr: // reflect.ptrType - off += arch.PtrSize - case kindFunc: // reflect.funcType - off += arch.PtrSize // 4 bytes, pointer aligned - case kindSlice: // reflect.sliceType - off += arch.PtrSize - case kindArray: // reflect.arrayType - off += 3 * arch.PtrSize - case kindChan: // reflect.chanType - off += 2 * arch.PtrSize - case kindMap: // reflect.mapType - off += 4*arch.PtrSize + 8 - case kindInterface: // reflect.interfaceType - off += 3 * arch.PtrSize - default: - // just Sizeof(rtype) - } - - mcount := int(decodeInuxi(arch, p[off+4:], 2)) - moff := int(decodeInuxi(arch, p[off+4+2+2:], 4)) - off += moff // offset to array of reflect.method values - const sizeofMethod = 4 * 4 // sizeof reflect.method in program - return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofMethod, mcount) -} - -func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Reloc { - for j := 0; j < len(symRelocs); j++ { - rel := symRelocs[j] - if rel.Off == off { - return rel - } - } - return loader.Reloc{} -} - -func decodeRelocSym2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Sym { - return decodeReloc2(ldr, symIdx, symRelocs, off).Sym -} - -// decodetypeName2 decodes the name from a reflect.name. -func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int) string { - r := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off)) - if r == 0 { - return "" - } - - data := ldr.Data(r) - namelen := int(uint16(data[1])<<8 | uint16(data[2])) - return string(data[3 : 3+namelen]) -} - -func (d *deadcodePass2) decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym { - uadd := commonsize(arch) + 4 - if arch.PtrSize == 8 { - uadd += 4 - } - if decodetypeHasUncommon(arch, ldr.Data(symIdx)) { - uadd += uncommonSize() - } - return decodeRelocSym2(ldr, symIdx, symRelocs, int32(uadd+i*arch.PtrSize)) -} - -func (d *deadcodePass2) decodetypeFuncOutType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym { - return d.decodetypeFuncInType2(ldr, arch, symIdx, symRelocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx))) -} - -// readRelocs reads the relocations for the specified symbol into the -// deadcode relocs work array. Use with care, since the work array -// is a singleton. -func (d *deadcodePass2) ReadRelocs(symIdx loader.Sym) { - relocs := d.ldr.Relocs(symIdx) - d.rtmp = relocs.ReadAll(d.rtmp) -} diff --git a/src/cmd/oldlink/internal/ld/decodesym.go b/src/cmd/oldlink/internal/ld/decodesym.go deleted file mode 100644 index 0676e94e2c..0000000000 --- a/src/cmd/oldlink/internal/ld/decodesym.go +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "bytes" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/sym" - "debug/elf" - "fmt" -) - -// Decoding the type.* symbols. This has to be in sync with -// ../../runtime/type.go, or more specifically, with what -// cmd/compile/internal/gc/reflect.go stuffs in these. - -// tflag is documented in reflect/type.go. -// -// tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go -// cmd/oldlink/internal/ld/decodesym.go -// reflect/type.go -// runtime/type.go -const ( - tflagUncommon = 1 << 0 - tflagExtraStar = 1 << 1 -) - -func decodeReloc(s *sym.Symbol, off int32) *sym.Reloc { - for i := range s.R { - if s.R[i].Off == off { - return &s.R[i] - } - } - return nil -} - -func decodeRelocSym(s *sym.Symbol, off int32) *sym.Symbol { - r := decodeReloc(s, off) - if r == nil { - return nil - } - return r.Sym -} - -func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 { - switch sz { - case 2: - return uint64(arch.ByteOrder.Uint16(p)) - case 4: - return uint64(arch.ByteOrder.Uint32(p)) - case 8: - return arch.ByteOrder.Uint64(p) - default: - Exitf("dwarf: decode inuxi %d", sz) - panic("unreachable") - } -} - -func commonsize(arch *sys.Arch) int { return 4*arch.PtrSize + 8 + 8 } // runtime._type -func structfieldSize(arch *sys.Arch) int { return 3 * arch.PtrSize } // runtime.structfield -func uncommonSize() int { return 4 + 2 + 2 + 4 + 4 } // runtime.uncommontype - -// Type.commonType.kind -func decodetypeKind(arch *sys.Arch, p []byte) uint8 { - return p[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f -} - -// Type.commonType.kind -func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 { - return p[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f -} - -// Type.commonType.size -func decodetypeSize(arch *sys.Arch, p []byte) int64 { - return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10 -} - -// Type.commonType.ptrdata -func decodetypePtrdata(arch *sys.Arch, p []byte) int64 { - return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10 -} - -// Type.commonType.tflag -func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool { - return p[2*arch.PtrSize+4]&tflagUncommon != 0 -} - -// Find the elf.Section of a given shared library that contains a given address. -func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section { - for _, shlib := range ctxt.Shlibs { - if shlib.Path == path { - for _, sect := range shlib.File.Sections { - if sect.Addr <= addr && addr <= sect.Addr+sect.Size { - return sect - } - } - } - } - return nil -} - -// Type.commonType.gc -func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte { - if s.Type == sym.SDYNIMPORT { - addr := decodetypeGcprogShlib(ctxt, s) - sect := findShlibSection(ctxt, s.File, addr) - if sect != nil { - // A gcprog is a 4-byte uint32 indicating length, followed by - // the actual program. - progsize := make([]byte, 4) - sect.ReadAt(progsize, int64(addr-sect.Addr)) - progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize)) - sect.ReadAt(progbytes, int64(addr-sect.Addr+4)) - return append(progsize, progbytes...) - } - Exitf("cannot find gcprog for %s", s.Name) - return nil - } - return decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)).P -} - -func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 { - if ctxt.Arch.Family == sys.ARM64 { - for _, shlib := range ctxt.Shlibs { - if shlib.Path == s.File { - return shlib.gcdataAddresses[s] - } - } - return 0 - } - return decodeInuxi(ctxt.Arch, s.P[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize) -} - -func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte { - if s.Type == sym.SDYNIMPORT { - addr := decodetypeGcprogShlib(ctxt, s) - ptrdata := decodetypePtrdata(ctxt.Arch, s.P) - sect := findShlibSection(ctxt, s.File, addr) - if sect != nil { - r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize)) - sect.ReadAt(r, int64(addr-sect.Addr)) - return r - } - Exitf("cannot find gcmask for %s", s.Name) - return nil - } - mask := decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)) - return mask.P -} - -// Type.ArrayType.elem and Type.SliceType.Elem -func decodetypeArrayElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol { - return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30 -} - -func decodetypeArrayLen(arch *sys.Arch, s *sym.Symbol) int64 { - return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize)) -} - -// Type.PtrType.elem -func decodetypePtrElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol { - return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30 -} - -// Type.MapType.key, elem -func decodetypeMapKey(arch *sys.Arch, s *sym.Symbol) *sym.Symbol { - return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30 -} - -func decodetypeMapValue(arch *sys.Arch, s *sym.Symbol) *sym.Symbol { - return decodeRelocSym(s, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38 -} - -// Type.ChanType.elem -func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol { - return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30 -} - -// Type.FuncType.dotdotdot -func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool { - return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0 -} - -// Type.FuncType.inCount -func decodetypeFuncInCount(arch *sys.Arch, p []byte) int { - return int(decodeInuxi(arch, p[commonsize(arch):], 2)) -} - -func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int { - return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1)) -} - -func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol { - uadd := commonsize(arch) + 4 - if arch.PtrSize == 8 { - uadd += 4 - } - if decodetypeHasUncommon(arch, s.P) { - uadd += uncommonSize() - } - return decodeRelocSym(s, int32(uadd+i*arch.PtrSize)) -} - -func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol { - return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s.P)) -} - -// Type.StructType.fields.Slice::length -func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int { - return int(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize)) -} - -func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int { - off := commonsize(arch) + 4*arch.PtrSize - if decodetypeHasUncommon(arch, s.P) { - off += uncommonSize() - } - off += i * structfieldSize(arch) - return off -} - -// decodetypeStr returns the contents of an rtype's str field (a nameOff). -func decodetypeStr(arch *sys.Arch, s *sym.Symbol) string { - str := decodetypeName(s, 4*arch.PtrSize+8) - if s.P[2*arch.PtrSize+4]&tflagExtraStar != 0 { - return str[1:] - } - return str -} - -// decodetypeName decodes the name from a reflect.name. -func decodetypeName(s *sym.Symbol, off int) string { - r := decodeReloc(s, int32(off)) - if r == nil { - return "" - } - - data := r.Sym.P - namelen := int(uint16(data[1])<<8 | uint16(data[2])) - return string(data[3 : 3+namelen]) -} - -func decodetypeStructFieldName(arch *sys.Arch, s *sym.Symbol, i int) string { - off := decodetypeStructFieldArrayOff(arch, s, i) - return decodetypeName(s, off) -} - -func decodetypeStructFieldType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol { - off := decodetypeStructFieldArrayOff(arch, s, i) - return decodeRelocSym(s, int32(off+arch.PtrSize)) -} - -func decodetypeStructFieldOffs(arch *sys.Arch, s *sym.Symbol, i int) int64 { - return decodetypeStructFieldOffsAnon(arch, s, i) >> 1 -} - -func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 { - off := decodetypeStructFieldArrayOff(arch, s, i) - return int64(decodeInuxi(arch, s.P[off+2*arch.PtrSize:], arch.PtrSize)) -} - -// InterfaceType.methods.length -func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 { - return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize)) -} - -// methodsig is a fully qualified typed method signature, like -// "Visit(type.go/ast.Node) (type.go/ast.Visitor)". -type methodsig string - -// Matches runtime/typekind.go and reflect.Kind. -const ( - kindArray = 17 - kindChan = 18 - kindFunc = 19 - kindInterface = 20 - kindMap = 21 - kindPtr = 22 - kindSlice = 23 - kindStruct = 25 - kindMask = (1 << 5) - 1 -) - -// decodeMethodSig decodes an array of method signature information. -// Each element of the array is size bytes. The first 4 bytes is a -// nameOff for the method name, and the next 4 bytes is a typeOff for -// the function type. -// -// Conveniently this is the layout of both runtime.method and runtime.imethod. -func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []methodsig { - var buf bytes.Buffer - var methods []methodsig - for i := 0; i < count; i++ { - buf.WriteString(decodetypeName(s, off)) - mtypSym := decodeRelocSym(s, int32(off+4)) - - buf.WriteRune('(') - inCount := decodetypeFuncInCount(arch, mtypSym.P) - for i := 0; i < inCount; i++ { - if i > 0 { - buf.WriteString(", ") - } - buf.WriteString(decodetypeFuncInType(arch, mtypSym, i).Name) - } - buf.WriteString(") (") - outCount := decodetypeFuncOutCount(arch, mtypSym.P) - for i := 0; i < outCount; i++ { - if i > 0 { - buf.WriteString(", ") - } - buf.WriteString(decodetypeFuncOutType(arch, mtypSym, i).Name) - } - buf.WriteRune(')') - - off += size - methods = append(methods, methodsig(buf.String())) - buf.Reset() - } - return methods -} - -func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig { - if decodetypeKind(arch, s.P)&kindMask != kindInterface { - panic(fmt.Sprintf("symbol %q is not an interface", s.Name)) - } - r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize)) - if r == nil { - return nil - } - if r.Sym != s { - panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name)) - } - off := int(r.Add) // array of reflect.imethod values - numMethods := int(decodetypeIfaceMethodCount(arch, s.P)) - sizeofIMethod := 4 + 4 - return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods) -} - -func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig { - if !decodetypeHasUncommon(arch, s.P) { - panic(fmt.Sprintf("no methods on %q", s.Name)) - } - off := commonsize(arch) // reflect.rtype - switch decodetypeKind(arch, s.P) & kindMask { - case kindStruct: // reflect.structType - off += 4 * arch.PtrSize - case kindPtr: // reflect.ptrType - off += arch.PtrSize - case kindFunc: // reflect.funcType - off += arch.PtrSize // 4 bytes, pointer aligned - case kindSlice: // reflect.sliceType - off += arch.PtrSize - case kindArray: // reflect.arrayType - off += 3 * arch.PtrSize - case kindChan: // reflect.chanType - off += 2 * arch.PtrSize - case kindMap: // reflect.mapType - off += 4*arch.PtrSize + 8 - case kindInterface: // reflect.interfaceType - off += 3 * arch.PtrSize - default: - // just Sizeof(rtype) - } - - mcount := int(decodeInuxi(arch, s.P[off+4:], 2)) - moff := int(decodeInuxi(arch, s.P[off+4+2+2:], 4)) - off += moff // offset to array of reflect.method values - const sizeofMethod = 4 * 4 // sizeof reflect.method in program - return decodeMethodSig(arch, s, off, sizeofMethod, mcount) -} diff --git a/src/cmd/oldlink/internal/ld/dwarf.go b/src/cmd/oldlink/internal/ld/dwarf.go deleted file mode 100644 index 3d5220cbfb..0000000000 --- a/src/cmd/oldlink/internal/ld/dwarf.go +++ /dev/null @@ -1,2044 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// 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, "") - } - - if !strings.HasPrefix(gotype.Name, "type.") { - Errorf(gotype, "dwarf: type name doesn't start with \"type.\"") - return mustFind(ctxt, "") - } - - 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, "")) - } - - 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 - 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 - 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 - 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 - 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 - 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 - 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("_%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, "", 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.") -} diff --git a/src/cmd/oldlink/internal/ld/elf.go b/src/cmd/oldlink/internal/ld/elf.go deleted file mode 100644 index 28cab75751..0000000000 --- a/src/cmd/oldlink/internal/ld/elf.go +++ /dev/null @@ -1,2448 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -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 -} diff --git a/src/cmd/oldlink/internal/ld/execarchive.go b/src/cmd/oldlink/internal/ld/execarchive.go deleted file mode 100644 index fe5cc40865..0000000000 --- a/src/cmd/oldlink/internal/ld/execarchive.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !wasm,!windows - -package ld - -import ( - "os" - "os/exec" - "path/filepath" - "syscall" -) - -const syscallExecSupported = true - -// execArchive invokes the archiver tool with syscall.Exec(), with -// the expectation that this is the last thing that takes place -// in the linking operation. -func (ctxt *Link) execArchive(argv []string) { - var err error - argv0 := argv[0] - if filepath.Base(argv0) == argv0 { - argv0, err = exec.LookPath(argv0) - if err != nil { - Exitf("cannot find %s: %v", argv[0], err) - } - } - if ctxt.Debugvlog != 0 { - ctxt.Logf("invoking archiver with syscall.Exec()\n") - } - err = syscall.Exec(argv0, argv, os.Environ()) - if err != nil { - Exitf("running %s failed: %v", argv[0], err) - } -} diff --git a/src/cmd/oldlink/internal/ld/execarchive_noexec.go b/src/cmd/oldlink/internal/ld/execarchive_noexec.go deleted file mode 100644 index a70dea9fda..0000000000 --- a/src/cmd/oldlink/internal/ld/execarchive_noexec.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build wasm windows - -package ld - -const syscallExecSupported = false - -func (ctxt *Link) execArchive(argv []string) { - panic("should never arrive here") -} diff --git a/src/cmd/oldlink/internal/ld/go.go b/src/cmd/oldlink/internal/ld/go.go deleted file mode 100644 index b05265580b..0000000000 --- a/src/cmd/oldlink/internal/ld/go.go +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// go-specific code shared across loaders (5l, 6l, 8l). - -package ld - -import ( - "bytes" - "cmd/internal/bio" - "cmd/internal/objabi" - "cmd/oldlink/internal/sym" - "encoding/json" - "fmt" - "io" - "os" - "strings" -) - -// go-specific code shared across loaders (5l, 6l, 8l). - -// replace all "". with pkg. -func expandpkg(t0 string, pkg string) string { - return strings.Replace(t0, `"".`, pkg+".", -1) -} - -func resolveABIAlias(s *sym.Symbol) *sym.Symbol { - if s.Type != sym.SABIALIAS { - return s - } - target := s.R[0].Sym - if target.Type == sym.SABIALIAS { - panic(fmt.Sprintf("ABI alias %s references another ABI alias %s", s, target)) - } - return target -} - -// TODO: -// generate debugging section in binary. -// once the dust settles, try to move some code to -// libmach, so that other linkers and ar can share. - -func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) { - if *flagG { - return - } - - if int64(int(length)) != length { - fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename) - if *flagU { - errorexit() - } - return - } - - bdata := make([]byte, length) - if _, err := io.ReadFull(f, bdata); err != nil { - fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) - if *flagU { - errorexit() - } - return - } - data := string(bdata) - - // process header lines - for data != "" { - var line string - if i := strings.Index(data, "\n"); i >= 0 { - line, data = data[:i], data[i+1:] - } else { - line, data = data, "" - } - if line == "safe" { - lib.Safe = true - } - if line == "main" { - lib.Main = true - } - if line == "" { - break - } - } - - // look for cgo section - p0 := strings.Index(data, "\n$$ // cgo") - var p1 int - if p0 >= 0 { - p0 += p1 - i := strings.IndexByte(data[p0+1:], '\n') - if i < 0 { - fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename) - if *flagU { - errorexit() - } - return - } - p0 += 1 + i - - p1 = strings.Index(data[p0:], "\n$$") - if p1 < 0 { - p1 = strings.Index(data[p0:], "\n!\n") - } - if p1 < 0 { - fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename) - if *flagU { - errorexit() - } - return - } - p1 += p0 - loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1]) - } -} - -func loadcgo(ctxt *Link, file string, pkg string, p string) { - var directives [][]string - if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil { - fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err) - nerrors++ - return - } - - // Find cgo_export symbols. They are roots in the deadcode pass. - for _, f := range directives { - switch f[0] { - case "cgo_export_static", "cgo_export_dynamic": - if len(f) < 2 || len(f) > 3 { - continue - } - local := f[1] - switch ctxt.BuildMode { - case BuildModeCShared, BuildModeCArchive, BuildModePlugin: - if local == "main" { - continue - } - } - local = expandpkg(local, pkg) - if f[0] == "cgo_export_static" { - ctxt.cgo_export_static[local] = true - } else { - ctxt.cgo_export_dynamic[local] = true - } - } - } - - if *flagNewobj { - // Record the directives. We'll process them later after Symbols are created. - ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives}) - } else { - setCgoAttr(ctxt, ctxt.Syms.Lookup, file, pkg, directives) - } -} - -// Set symbol attributes or flags based on cgo directives. -func setCgoAttr(ctxt *Link, lookup func(string, int) *sym.Symbol, file string, pkg string, directives [][]string) { - for _, f := range directives { - switch f[0] { - case "cgo_import_dynamic": - if len(f) < 2 || len(f) > 4 { - break - } - - local := f[1] - remote := local - if len(f) > 2 { - remote = f[2] - } - lib := "" - if len(f) > 3 { - lib = f[3] - } - - if *FlagD { - fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file) - nerrors++ - return - } - - if local == "_" && remote == "_" { - // allow #pragma dynimport _ _ "foo.so" - // to force a link of foo.so. - havedynamic = 1 - - if ctxt.HeadType == objabi.Hdarwin { - machoadddynlib(lib, ctxt.LinkMode) - } else { - dynlib = append(dynlib, lib) - } - continue - } - - local = expandpkg(local, pkg) - q := "" - if i := strings.Index(remote, "#"); i >= 0 { - remote, q = remote[:i], remote[i+1:] - } - s := lookup(local, 0) - if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS || s.Type == sym.SHOSTOBJ { - s.SetDynimplib(lib) - s.SetExtname(remote) - s.SetDynimpvers(q) - if s.Type != sym.SHOSTOBJ { - s.Type = sym.SDYNIMPORT - } - havedynamic = 1 - } - - continue - - case "cgo_import_static": - if len(f) != 2 { - break - } - local := f[1] - - s := lookup(local, 0) - s.Type = sym.SHOSTOBJ - s.Size = 0 - continue - - case "cgo_export_static", "cgo_export_dynamic": - if len(f) < 2 || len(f) > 3 { - break - } - local := f[1] - remote := local - if len(f) > 2 { - remote = f[2] - } - local = expandpkg(local, pkg) - - // The compiler arranges for an ABI0 wrapper - // to be available for all cgo-exported - // functions. Link.loadlib will resolve any - // ABI aliases we find here (since we may not - // yet know it's an alias). - s := lookup(local, 0) - - switch ctxt.BuildMode { - case BuildModeCShared, BuildModeCArchive, BuildModePlugin: - if s == lookup("main", 0) { - continue - } - } - - // export overrides import, for openbsd/cgo. - // see issue 4878. - if s.Dynimplib() != "" { - s.ResetDyninfo() - s.SetExtname("") - s.Type = 0 - } - - if !s.Attr.CgoExport() { - s.SetExtname(remote) - } else if s.Extname() != remote { - fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote) - nerrors++ - return - } - - if f[0] == "cgo_export_static" { - s.Attr |= sym.AttrCgoExportStatic - } else { - s.Attr |= sym.AttrCgoExportDynamic - } - continue - - case "cgo_dynamic_linker": - if len(f) != 2 { - break - } - - if *flagInterpreter == "" { - if interpreter != "" && interpreter != f[1] { - fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1]) - nerrors++ - return - } - - interpreter = f[1] - } - continue - - case "cgo_ldflag": - if len(f) != 2 { - break - } - ldflag = append(ldflag, f[1]) - continue - } - - fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f) - nerrors++ - } -} - -var seenlib = make(map[string]bool) - -func adddynlib(ctxt *Link, lib string) { - if seenlib[lib] || ctxt.LinkMode == LinkExternal { - return - } - seenlib[lib] = true - - if ctxt.IsELF { - s := ctxt.Syms.Lookup(".dynstr", 0) - if s.Size == 0 { - Addstring(s, "") - } - Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib))) - } else { - Errorf(nil, "adddynlib: unsupported binary format") - } -} - -func Adddynsym(ctxt *Link, s *sym.Symbol) { - if s.Dynid >= 0 || ctxt.LinkMode == LinkExternal { - return - } - - if ctxt.IsELF { - elfadddynsym(ctxt, s) - } else if ctxt.HeadType == objabi.Hdarwin { - Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname()) - } else if ctxt.HeadType == objabi.Hwindows { - // already taken care of - } else { - Errorf(s, "adddynsym: unsupported binary format") - } -} - -func fieldtrack(ctxt *Link) { - // record field tracking references - var buf bytes.Buffer - for _, s := range ctxt.Syms.Allsym { - if strings.HasPrefix(s.Name, "go.track.") { - s.Attr |= sym.AttrSpecial // do not lay out in data segment - s.Attr |= sym.AttrNotInSymbolTable - if s.Attr.Reachable() { - buf.WriteString(s.Name[9:]) - for p := ctxt.Reachparent[s]; p != nil; p = ctxt.Reachparent[p] { - buf.WriteString("\t") - buf.WriteString(p.Name) - } - buf.WriteString("\n") - } - - s.Type = sym.SCONST - s.Value = 0 - } - } - - if *flagFieldTrack == "" { - return - } - s := ctxt.Syms.ROLookup(*flagFieldTrack, 0) - if s == nil || !s.Attr.Reachable() { - return - } - s.Type = sym.SDATA - addstrdata(ctxt, *flagFieldTrack, buf.String()) -} - -func (ctxt *Link) addexport() { - // Track undefined external symbols during external link. - if ctxt.LinkMode == LinkExternal { - for _, s := range ctxt.Syms.Allsym { - if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() { - continue - } - if s.Type != sym.STEXT { - continue - } - for i := range s.R { - r := &s.R[i] - if r.Sym != nil && r.Sym.Type == sym.Sxxx { - r.Sym.Type = sym.SUNDEFEXT - } - } - } - } - - // TODO(aix) - if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix { - return - } - - for _, exp := range dynexp { - Adddynsym(ctxt, exp) - } - for _, lib := range dynlib { - adddynlib(ctxt, lib) - } -} - -type Pkg struct { - mark bool - checked bool - path string - impby []*Pkg -} - -var pkgall []*Pkg - -func (p *Pkg) cycle() *Pkg { - if p.checked { - return nil - } - - if p.mark { - nerrors++ - fmt.Printf("import cycle:\n") - fmt.Printf("\t%s\n", p.path) - return p - } - - p.mark = true - for _, q := range p.impby { - if bad := q.cycle(); bad != nil { - p.mark = false - p.checked = true - fmt.Printf("\timports %s\n", p.path) - if bad == p { - return nil - } - return bad - } - } - - p.checked = true - p.mark = false - return nil -} - -func importcycles() { - for _, p := range pkgall { - p.cycle() - } -} diff --git a/src/cmd/oldlink/internal/ld/ld.go b/src/cmd/oldlink/internal/ld/ld.go deleted file mode 100644 index 7420dce9de..0000000000 --- a/src/cmd/oldlink/internal/ld/ld.go +++ /dev/null @@ -1,217 +0,0 @@ -// Derived from Inferno utils/6l/obj.c and utils/6l/span.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ld - -import ( - "cmd/oldlink/internal/sym" - "io/ioutil" - "log" - "os" - "path" - "path/filepath" - "strconv" - "strings" -) - -func (ctxt *Link) readImportCfg(file string) { - ctxt.PackageFile = make(map[string]string) - ctxt.PackageShlib = make(map[string]string) - data, err := ioutil.ReadFile(file) - if err != nil { - log.Fatalf("-importcfg: %v", err) - } - - for lineNum, line := range strings.Split(string(data), "\n") { - lineNum++ // 1-based - line = strings.TrimSpace(line) - if line == "" { - continue - } - if line == "" || strings.HasPrefix(line, "#") { - continue - } - - var verb, args string - if i := strings.Index(line, " "); i < 0 { - verb = line - } else { - verb, args = line[:i], strings.TrimSpace(line[i+1:]) - } - var before, after string - if i := strings.Index(args, "="); i >= 0 { - before, after = args[:i], args[i+1:] - } - switch verb { - default: - log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb) - case "packagefile": - if before == "" || after == "" { - log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum) - } - ctxt.PackageFile[before] = after - case "packageshlib": - if before == "" || after == "" { - log.Fatalf(`%s:%d: invalid packageshlib: syntax is "packageshlib path=filename"`, file, lineNum) - } - ctxt.PackageShlib[before] = after - } - } -} - -func pkgname(ctxt *Link, lib string) string { - name := path.Clean(lib) - - // When using importcfg, we have the final package name. - if ctxt.PackageFile != nil { - return name - } - - // runtime.a -> runtime, runtime.6 -> runtime - pkg := name - if len(pkg) >= 2 && pkg[len(pkg)-2] == '.' { - pkg = pkg[:len(pkg)-2] - } - return pkg -} - -func findlib(ctxt *Link, lib string) (string, bool) { - name := path.Clean(lib) - - var pname string - isshlib := false - - if ctxt.linkShared && ctxt.PackageShlib[name] != "" { - pname = ctxt.PackageShlib[name] - isshlib = true - } else if ctxt.PackageFile != nil { - pname = ctxt.PackageFile[name] - if pname == "" { - ctxt.Logf("cannot find package %s (using -importcfg)\n", name) - return "", false - } - } else { - if filepath.IsAbs(name) { - pname = name - } else { - pkg := pkgname(ctxt, lib) - // Add .a if needed; the new -importcfg modes - // do not put .a into the package name anymore. - // This only matters when people try to mix - // compiles using -importcfg with links not using -importcfg, - // such as when running quick things like - // 'go tool compile x.go && go tool link x.o' - // by hand against a standard library built using -importcfg. - if !strings.HasSuffix(name, ".a") && !strings.HasSuffix(name, ".o") { - name += ".a" - } - // try dot, -L "libdir", and then goroot. - for _, dir := range ctxt.Libdir { - if ctxt.linkShared { - pname = filepath.Join(dir, pkg+".shlibname") - if _, err := os.Stat(pname); err == nil { - isshlib = true - break - } - } - pname = filepath.Join(dir, name) - if _, err := os.Stat(pname); err == nil { - break - } - } - } - pname = filepath.Clean(pname) - } - - return pname, isshlib -} - -func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library { - pkg := pkgname(ctxt, lib) - - // already loaded? - if l := ctxt.LibraryByPkg[pkg]; l != nil { - return l - } - - pname, isshlib := findlib(ctxt, lib) - - if ctxt.Debugvlog > 1 { - ctxt.Logf("addlib: %s %s pulls in %s isshlib %v\n", obj, src, pname, isshlib) - } - - if isshlib { - return addlibpath(ctxt, src, obj, "", pkg, pname) - } - return addlibpath(ctxt, src, obj, pname, pkg, "") -} - -/* - * add library to library list, return added library. - * srcref: src file referring to package - * objref: object file referring to package - * file: object file, e.g., /home/rsc/go/pkg/container/vector.a - * pkg: package import path, e.g. container/vector - * shlib: path to shared library, or .shlibname file holding path - */ -func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlib string) *sym.Library { - if l := ctxt.LibraryByPkg[pkg]; l != nil { - return l - } - - if ctxt.Debugvlog > 1 { - ctxt.Logf("addlibpath: srcref: %s objref: %s file: %s pkg: %s shlib: %s\n", srcref, objref, file, pkg, shlib) - } - - l := &sym.Library{} - ctxt.LibraryByPkg[pkg] = l - ctxt.Library = append(ctxt.Library, l) - l.Objref = objref - l.Srcref = srcref - l.File = file - l.Pkg = pkg - if shlib != "" { - if strings.HasSuffix(shlib, ".shlibname") { - data, err := ioutil.ReadFile(shlib) - if err != nil { - Errorf(nil, "cannot read %s: %v", shlib, err) - } - shlib = strings.TrimSpace(string(data)) - } - l.Shlib = shlib - } - return l -} - -func atolwhex(s string) int64 { - n, _ := strconv.ParseInt(s, 0, 64) - return n -} diff --git a/src/cmd/oldlink/internal/ld/lib.go b/src/cmd/oldlink/internal/ld/lib.go deleted file mode 100644 index 0fc786f1bf..0000000000 --- a/src/cmd/oldlink/internal/ld/lib.go +++ /dev/null @@ -1,2749 +0,0 @@ -// Inferno utils/8l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package 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) - } - } -} diff --git a/src/cmd/oldlink/internal/ld/link.go b/src/cmd/oldlink/internal/ld/link.go deleted file mode 100644 index 15878f3267..0000000000 --- a/src/cmd/oldlink/internal/ld/link.go +++ /dev/null @@ -1,187 +0,0 @@ -// Derived from Inferno utils/6l/l.h and related files. -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ld - -import ( - "bufio" - "cmd/internal/obj" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/loader" - "cmd/oldlink/internal/sym" - "debug/elf" - "fmt" -) - -type Shlib struct { - Path string - Hash []byte - Deps []string - File *elf.File - gcdataAddresses map[*sym.Symbol]uint64 -} - -// Link holds the context for writing object code from a compiler -// or for reading that input into the linker. -type Link struct { - Out *OutBuf - - Syms *sym.Symbols - - Arch *sys.Arch - Debugvlog int - Bso *bufio.Writer - - Loaded bool // set after all inputs have been loaded as symbols - - IsELF bool - HeadType objabi.HeadType - - linkShared bool // link against installed Go shared libraries - LinkMode LinkMode - BuildMode BuildMode - canUsePlugins bool // initialized when Loaded is set to true - compressDWARF bool - - Tlsg *sym.Symbol - Libdir []string - Library []*sym.Library - LibraryByPkg map[string]*sym.Library - Shlibs []Shlib - Tlsoffset int - Textp []*sym.Symbol - Filesyms []*sym.Symbol - Moduledata *sym.Symbol - - PackageFile map[string]string - PackageShlib map[string]string - - tramps []*sym.Symbol // trampolines - - // unresolvedSymSet is a set of erroneous unresolved references. - // Used to avoid duplicated error messages. - unresolvedSymSet map[unresolvedSymKey]bool - - // Used to implement field tracking. - Reachparent map[*sym.Symbol]*sym.Symbol - - compUnits []*sym.CompilationUnit // DWARF compilation units - runtimeCU *sym.CompilationUnit // One of the runtime CUs, the last one seen. - - relocbuf []byte // temporary buffer for applying relocations - - loader *loader.Loader - cgodata []cgodata // cgo directives to load, three strings are args for loadcgo - - cgo_export_static map[string]bool - cgo_export_dynamic map[string]bool -} - -type cgodata struct { - file string - pkg string - directives [][]string -} - -type unresolvedSymKey struct { - from *sym.Symbol // Symbol that referenced unresolved "to" - to *sym.Symbol // Unresolved symbol referenced by "from" -} - -// ErrorUnresolved prints unresolved symbol error for r.Sym that is referenced from s. -func (ctxt *Link) ErrorUnresolved(s *sym.Symbol, r *sym.Reloc) { - if ctxt.unresolvedSymSet == nil { - ctxt.unresolvedSymSet = make(map[unresolvedSymKey]bool) - } - - k := unresolvedSymKey{from: s, to: r.Sym} - if !ctxt.unresolvedSymSet[k] { - ctxt.unresolvedSymSet[k] = true - - // Try to find symbol under another ABI. - var reqABI, haveABI obj.ABI - haveABI = ^obj.ABI(0) - reqABI, ok := sym.VersionToABI(int(r.Sym.Version)) - if ok { - for abi := obj.ABI(0); abi < obj.ABICount; abi++ { - v := sym.ABIToVersion(abi) - if v == -1 { - continue - } - if rs := ctxt.Syms.ROLookup(r.Sym.Name, v); rs != nil && rs.Type != sym.Sxxx && rs.Type != sym.SXREF { - haveABI = abi - } - } - } - - // Give a special error message for main symbol (see #24809). - if r.Sym.Name == "main.main" { - Errorf(s, "function main is undeclared in the main package") - } else if haveABI != ^obj.ABI(0) { - Errorf(s, "relocation target %s not defined for %s (but is defined for %s)", r.Sym.Name, reqABI, haveABI) - } else { - Errorf(s, "relocation target %s not defined", r.Sym.Name) - } - } -} - -// The smallest possible offset from the hardware stack pointer to a local -// variable on the stack. Architectures that use a link register save its value -// on the stack in the function prologue and so always have a pointer between -// the hardware stack pointer and the local variable area. -func (ctxt *Link) FixedFrameSize() int64 { - switch ctxt.Arch.Family { - case sys.AMD64, sys.I386: - return 0 - case sys.PPC64: - // PIC code on ppc64le requires 32 bytes of stack, and it's easier to - // just use that much stack always on ppc64x. - return int64(4 * ctxt.Arch.PtrSize) - default: - return int64(ctxt.Arch.PtrSize) - } -} - -func (ctxt *Link) Logf(format string, args ...interface{}) { - fmt.Fprintf(ctxt.Bso, format, args...) - ctxt.Bso.Flush() -} - -func addImports(ctxt *Link, l *sym.Library, pn string) { - pkg := objabi.PathToPrefix(l.Pkg) - for _, importStr := range l.ImportStrings { - lib := addlib(ctxt, pkg, pn, importStr) - if lib != nil { - l.Imports = append(l.Imports, lib) - } - } - l.ImportStrings = nil -} diff --git a/src/cmd/oldlink/internal/ld/macho.go b/src/cmd/oldlink/internal/ld/macho.go deleted file mode 100644 index 960ed29067..0000000000 --- a/src/cmd/oldlink/internal/ld/macho.go +++ /dev/null @@ -1,1119 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -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< 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 -} diff --git a/src/cmd/oldlink/internal/ld/macho_combine_dwarf.go b/src/cmd/oldlink/internal/ld/macho_combine_dwarf.go deleted file mode 100644 index 9d9f916b8e..0000000000 --- a/src/cmd/oldlink/internal/ld/macho_combine_dwarf.go +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "bytes" - "compress/zlib" - "debug/macho" - "encoding/binary" - "fmt" - "io" - "os" - "reflect" - "unsafe" -) - -const ( - pageAlign = 12 // 4096 = 1 << 12 -) - -type loadCmd struct { - Cmd macho.LoadCmd - Len uint32 -} - -type dyldInfoCmd struct { - Cmd macho.LoadCmd - Len uint32 - RebaseOff, RebaseLen uint32 - BindOff, BindLen uint32 - WeakBindOff, WeakBindLen uint32 - LazyBindOff, LazyBindLen uint32 - ExportOff, ExportLen uint32 -} - -type linkEditDataCmd struct { - Cmd macho.LoadCmd - Len uint32 - DataOff, DataLen uint32 -} - -type encryptionInfoCmd struct { - Cmd macho.LoadCmd - Len uint32 - CryptOff, CryptLen uint32 - CryptId uint32 -} - -type loadCmdReader struct { - offset, next int64 - f *os.File - order binary.ByteOrder -} - -func (r *loadCmdReader) Next() (loadCmd, error) { - var cmd loadCmd - - r.offset = r.next - if _, err := r.f.Seek(r.offset, 0); err != nil { - return cmd, err - } - if err := binary.Read(r.f, r.order, &cmd); err != nil { - return cmd, err - } - r.next = r.offset + int64(cmd.Len) - return cmd, nil -} - -func (r loadCmdReader) ReadAt(offset int64, data interface{}) error { - if _, err := r.f.Seek(r.offset+offset, 0); err != nil { - return err - } - return binary.Read(r.f, r.order, data) -} - -func (r loadCmdReader) WriteAt(offset int64, data interface{}) error { - if _, err := r.f.Seek(r.offset+offset, 0); err != nil { - return err - } - return binary.Write(r.f, r.order, data) -} - -// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable. -// -// With internal linking, DWARF is embedded into the executable, this lets us do the -// same for external linking. -// exef is the file of the executable with no DWARF. It must have enough room in the macho -// header to add the DWARF sections. (Use ld's -headerpad option) -// exem is the macho representation of exef. -// dsym is the path to the macho file containing DWARF from dsymutil. -// outexe is the path where the combined executable should be saved. -func machoCombineDwarf(ctxt *Link, exef *os.File, exem *macho.File, dsym, outexe string) error { - dwarff, err := os.Open(dsym) - if err != nil { - return err - } - defer dwarff.Close() - outf, err := os.OpenFile(outexe, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - return err - } - defer outf.Close() - dwarfm, err := macho.NewFile(dwarff) - if err != nil { - return err - } - defer dwarfm.Close() - - // The string table needs to be the last thing in the file - // for code signing to work. So we'll need to move the - // linkedit section, but all the others can be copied directly. - linkseg := exem.Segment("__LINKEDIT") - if linkseg == nil { - return fmt.Errorf("missing __LINKEDIT segment") - } - - if _, err := exef.Seek(0, 0); err != nil { - return err - } - if _, err := io.CopyN(outf, exef, int64(linkseg.Offset)); err != nil { - return err - } - - realdwarf := dwarfm.Segment("__DWARF") - if realdwarf == nil { - return fmt.Errorf("missing __DWARF segment") - } - - // Try to compress the DWARF sections. This includes some Apple - // proprietary sections like __apple_types. - compressedSects, compressedBytes, err := machoCompressSections(ctxt, dwarfm) - if err != nil { - return err - } - - // Now copy the dwarf data into the output. - // Kernel requires all loaded segments to be page-aligned in the file, - // even though we mark this one as being 0 bytes of virtual address space. - dwarfstart := machoCalcStart(realdwarf.Offset, linkseg.Offset, pageAlign) - if _, err := outf.Seek(dwarfstart, 0); err != nil { - return err - } - - if _, err := dwarff.Seek(int64(realdwarf.Offset), 0); err != nil { - return err - } - - // Write out the compressed sections, or the originals if we gave up - // on compressing them. - var dwarfsize uint64 - if compressedBytes != nil { - dwarfsize = uint64(len(compressedBytes)) - if _, err := outf.Write(compressedBytes); err != nil { - return err - } - } else { - if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil { - return err - } - dwarfsize = realdwarf.Filesz - } - - // And finally the linkedit section. - if _, err := exef.Seek(int64(linkseg.Offset), 0); err != nil { - return err - } - linkstart := machoCalcStart(linkseg.Offset, uint64(dwarfstart)+dwarfsize, pageAlign) - if _, err := outf.Seek(linkstart, 0); err != nil { - return err - } - if _, err := io.Copy(outf, exef); err != nil { - return err - } - - // Now we need to update the headers. - textsect := exem.Section("__text") - if textsect == nil { - return fmt.Errorf("missing __text section") - } - - cmdOffset := unsafe.Sizeof(exem.FileHeader) - if is64bit := exem.Magic == macho.Magic64; is64bit { - // mach_header_64 has one extra uint32. - cmdOffset += unsafe.Sizeof(exem.Magic) - } - dwarfCmdOffset := uint32(cmdOffset) + exem.FileHeader.Cmdsz - availablePadding := textsect.Offset - dwarfCmdOffset - if availablePadding < realdwarf.Len { - return fmt.Errorf("no room to add dwarf info. Need at least %d padding bytes, found %d", realdwarf.Len, availablePadding) - } - // First, copy the dwarf load command into the header. It will be - // updated later with new offsets and lengths as necessary. - if _, err := outf.Seek(int64(dwarfCmdOffset), 0); err != nil { - return err - } - if _, err := io.CopyN(outf, bytes.NewReader(realdwarf.Raw()), int64(realdwarf.Len)); err != nil { - return err - } - if _, err := outf.Seek(int64(unsafe.Offsetof(exem.FileHeader.Ncmd)), 0); err != nil { - return err - } - if err := binary.Write(outf, exem.ByteOrder, exem.Ncmd+1); err != nil { - return err - } - if err := binary.Write(outf, exem.ByteOrder, exem.Cmdsz+realdwarf.Len); err != nil { - return err - } - - reader := loadCmdReader{next: int64(cmdOffset), f: outf, order: exem.ByteOrder} - for i := uint32(0); i < exem.Ncmd; i++ { - cmd, err := reader.Next() - if err != nil { - return err - } - linkoffset := uint64(linkstart) - linkseg.Offset - switch cmd.Cmd { - case macho.LoadCmdSegment64: - err = machoUpdateSegment(reader, linkseg, linkoffset, &macho.Segment64{}, &macho.Section64{}) - case macho.LoadCmdSegment: - err = machoUpdateSegment(reader, linkseg, linkoffset, &macho.Segment32{}, &macho.Section32{}) - case LC_DYLD_INFO, LC_DYLD_INFO_ONLY: - err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff") - case macho.LoadCmdSymtab: - err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &macho.SymtabCmd{}, "Symoff", "Stroff") - case macho.LoadCmdDysymtab: - err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &macho.DysymtabCmd{}, "Tocoffset", "Modtaboff", "Extrefsymoff", "Indirectsymoff", "Extreloff", "Locreloff") - case LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS: - err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &linkEditDataCmd{}, "DataOff") - case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64: - err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &encryptionInfoCmd{}, "CryptOff") - case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB, LC_SYMSEG, LC_LOADFVMLIB, LC_IDFVMLIB, LC_IDENT, LC_FVMFILE, LC_PREPAGE, LC_ID_DYLINKER, LC_ROUTINES, LC_SUB_FRAMEWORK, LC_SUB_UMBRELLA, LC_SUB_CLIENT, LC_SUB_LIBRARY, LC_TWOLEVEL_HINTS, LC_PREBIND_CKSUM, LC_ROUTINES_64, LC_LAZY_LOAD_DYLIB, LC_LOAD_UPWARD_DYLIB, LC_DYLD_ENVIRONMENT, LC_LINKER_OPTION, LC_LINKER_OPTIMIZATION_HINT, LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS, LC_VERSION_NOTE, LC_BUILD_VERSION: - // Nothing to update - default: - err = fmt.Errorf("unknown load command 0x%x (%s)", int(cmd.Cmd), cmd.Cmd) - } - if err != nil { - return err - } - } - // Do the final update of the DWARF segment's load command. - return machoUpdateDwarfHeader(&reader, compressedSects, dwarfsize, dwarfstart, realdwarf) -} - -// machoCompressSections tries to compress the DWARF segments in dwarfm, -// returning the updated sections and segment contents, nils if the sections -// weren't compressed, or an error if there was a problem reading dwarfm. -func machoCompressSections(ctxt *Link, dwarfm *macho.File) ([]*macho.Section, []byte, error) { - if !ctxt.compressDWARF { - return nil, nil, nil - } - - dwarfseg := dwarfm.Segment("__DWARF") - var sects []*macho.Section - var buf bytes.Buffer - - for _, sect := range dwarfm.Sections { - if sect.Seg != "__DWARF" { - continue - } - - // As of writing, there are no relocations in dsymutil's output - // so there's no point in worrying about them. Bail out if that - // changes. - if sect.Nreloc != 0 { - return nil, nil, nil - } - - data, err := sect.Data() - if err != nil { - return nil, nil, err - } - - compressed, contents, err := machoCompressSection(data) - if err != nil { - return nil, nil, err - } - - newSec := *sect - newSec.Offset = uint32(dwarfseg.Offset) + uint32(buf.Len()) - newSec.Addr = dwarfseg.Addr + uint64(buf.Len()) - if compressed { - newSec.Name = "__z" + sect.Name[2:] - newSec.Size = uint64(len(contents)) - } - sects = append(sects, &newSec) - buf.Write(contents) - } - return sects, buf.Bytes(), nil -} - -// machoCompressSection compresses secBytes if it results in less data. -func machoCompressSection(sectBytes []byte) (compressed bool, contents []byte, err error) { - var buf bytes.Buffer - buf.WriteString("ZLIB") - var sizeBytes [8]byte - binary.BigEndian.PutUint64(sizeBytes[:], uint64(len(sectBytes))) - buf.Write(sizeBytes[:]) - - z := zlib.NewWriter(&buf) - if _, err := z.Write(sectBytes); err != nil { - return false, nil, err - } - if err := z.Close(); err != nil { - return false, nil, err - } - if buf.Len() >= len(sectBytes) { - return false, sectBytes, nil - } - return true, buf.Bytes(), nil -} - -// machoUpdateSegment updates the load command for a moved segment. -// Only the linkedit segment should move, and it should have 0 sections. -// seg should be a macho.Segment32 or macho.Segment64 as appropriate. -// sect should be a macho.Section32 or macho.Section64 as appropriate. -func machoUpdateSegment(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64, seg, sect interface{}) error { - if err := r.ReadAt(0, seg); err != nil { - return err - } - segValue := reflect.ValueOf(seg) - offset := reflect.Indirect(segValue).FieldByName("Offset") - - // Only the linkedit segment moved, anything before that is fine. - if offset.Uint() < linkseg.Offset { - return nil - } - offset.SetUint(offset.Uint() + linkoffset) - if err := r.WriteAt(0, seg); err != nil { - return err - } - // There shouldn't be any sections, but just to make sure... - return machoUpdateSections(r, segValue, reflect.ValueOf(sect), linkoffset, nil) -} - -func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset uint64, compressedSects []*macho.Section) error { - iseg := reflect.Indirect(seg) - nsect := iseg.FieldByName("Nsect").Uint() - if nsect == 0 { - return nil - } - sectOffset := int64(iseg.Type().Size()) - - isect := reflect.Indirect(sect) - offsetField := isect.FieldByName("Offset") - reloffField := isect.FieldByName("Reloff") - addrField := isect.FieldByName("Addr") - nameField := isect.FieldByName("Name") - sizeField := isect.FieldByName("Size") - sectSize := int64(isect.Type().Size()) - for i := uint64(0); i < nsect; i++ { - if err := r.ReadAt(sectOffset, sect.Interface()); err != nil { - return err - } - if compressedSects != nil { - cSect := compressedSects[i] - var name [16]byte - copy(name[:], []byte(cSect.Name)) - nameField.Set(reflect.ValueOf(name)) - sizeField.SetUint(cSect.Size) - if cSect.Offset != 0 { - offsetField.SetUint(uint64(cSect.Offset) + deltaOffset) - } - if cSect.Addr != 0 { - addrField.SetUint(cSect.Addr) - } - } else { - if offsetField.Uint() != 0 { - offsetField.SetUint(offsetField.Uint() + deltaOffset) - } - if reloffField.Uint() != 0 { - reloffField.SetUint(reloffField.Uint() + deltaOffset) - } - if addrField.Uint() != 0 { - addrField.SetUint(addrField.Uint()) - } - } - if err := r.WriteAt(sectOffset, sect.Interface()); err != nil { - return err - } - sectOffset += sectSize - } - return nil -} - -// machoUpdateDwarfHeader updates the DWARF segment load command. -func machoUpdateDwarfHeader(r *loadCmdReader, compressedSects []*macho.Section, dwarfsize uint64, dwarfstart int64, realdwarf *macho.Segment) error { - var seg, sect interface{} - cmd, err := r.Next() - if err != nil { - return err - } - if cmd.Cmd == macho.LoadCmdSegment64 { - seg = new(macho.Segment64) - sect = new(macho.Section64) - } else { - seg = new(macho.Segment32) - sect = new(macho.Section32) - } - if err := r.ReadAt(0, seg); err != nil { - return err - } - segv := reflect.ValueOf(seg).Elem() - segv.FieldByName("Offset").SetUint(uint64(dwarfstart)) - - if compressedSects != nil { - var segSize uint64 - for _, newSect := range compressedSects { - segSize += newSect.Size - } - segv.FieldByName("Filesz").SetUint(segSize) - } else { - segv.FieldByName("Filesz").SetUint(dwarfsize) - } - - // We want the DWARF segment to be considered non-loadable, so - // force vmaddr and vmsize to zero. In addition, set the initial - // protection to zero so as to make the dynamic loader happy, - // since otherwise it may complain that that the vm size and file - // size don't match for the segment. See issues 21647 and 32673 - // for more context. Also useful to refer to the Apple dynamic - // loader source, specifically ImageLoaderMachO::sniffLoadCommands - // in ImageLoaderMachO.cpp (various versions can be found online, see - // https://opensource.apple.com/source/dyld/dyld-519.2.2/src/ImageLoaderMachO.cpp.auto.html - // as one example). - segv.FieldByName("Addr").SetUint(0) - segv.FieldByName("Memsz").SetUint(0) - segv.FieldByName("Prot").SetUint(0) - - if err := r.WriteAt(0, seg); err != nil { - return err - } - return machoUpdateSections(*r, segv, reflect.ValueOf(sect), uint64(dwarfstart)-realdwarf.Offset, compressedSects) -} - -func machoUpdateLoadCommand(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64, cmd interface{}, fields ...string) error { - if err := r.ReadAt(0, cmd); err != nil { - return err - } - value := reflect.Indirect(reflect.ValueOf(cmd)) - - for _, name := range fields { - field := value.FieldByName(name) - if fieldval := field.Uint(); fieldval >= linkseg.Offset { - field.SetUint(fieldval + linkoffset) - } - } - if err := r.WriteAt(0, cmd); err != nil { - return err - } - return nil -} - -func machoCalcStart(origAddr, newAddr uint64, alignExp uint32) int64 { - align := uint64(1 << alignExp) - origMod, newMod := origAddr%align, newAddr%align - if origMod == newMod { - return int64(newAddr) - } - return int64(newAddr + align + origMod - newMod) -} diff --git a/src/cmd/oldlink/internal/ld/main.go b/src/cmd/oldlink/internal/ld/main.go deleted file mode 100644 index f7f3700398..0000000000 --- a/src/cmd/oldlink/internal/ld/main.go +++ /dev/null @@ -1,338 +0,0 @@ -// Inferno utils/6l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ld - -import ( - "bufio" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/sym" - "flag" - "log" - "os" - "runtime" - "runtime/pprof" - "strings" -) - -var ( - pkglistfornote []byte - windowsgui bool // writes a "GUI binary" instead of a "console binary" - ownTmpDir bool // set to true if tmp dir created by linker (e.g. no -tmpdir) -) - -func init() { - flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...") -} - -// Flags used by the linker. The exported flags are used by the architecture-specific packages. -var ( - flagBuildid = flag.String("buildid", "", "record `id` as Go toolchain build id") - - flagOutfile = flag.String("o", "", "write output to `file`") - flagPluginPath = flag.String("pluginpath", "", "full path name for plugin") - - flagInstallSuffix = flag.String("installsuffix", "", "set package directory `suffix`") - flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph") - flagRace = flag.Bool("race", false, "enable race detector") - flagMsan = flag.Bool("msan", false, "enable MSan interface") - - flagFieldTrack = flag.String("k", "", "set field tracking `symbol`") - flagLibGCC = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable") - flagTmpdir = flag.String("tmpdir", "", "use `directory` for temporary files") - - flagExtld = flag.String("extld", "", "use `linker` when linking in external mode") - flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker") - flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive") - - flagA = flag.Bool("a", false, "disassemble output") - FlagC = flag.Bool("c", false, "dump call graph") - FlagD = flag.Bool("d", false, "disable dynamic executable") - flagF = flag.Bool("f", false, "ignore version mismatch") - flagG = flag.Bool("g", false, "disable go package data checks") - flagH = flag.Bool("h", false, "halt on error") - flagN = flag.Bool("n", false, "dump symbol table") - FlagS = flag.Bool("s", false, "disable symbol table") - flagU = flag.Bool("u", false, "reject unsafe packages") - FlagW = flag.Bool("w", false, "disable DWARF generation") - Flag8 bool // use 64-bit addresses in symbol table - flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker") - FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines") - FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).") - flagNewobj = flag.Bool("newobj", false, "use new object file format") - - FlagRound = flag.Int("R", -1, "set address rounding `quantum`") - FlagTextAddr = flag.Int64("T", -1, "set text segment `address`") - flagEntrySymbol = flag.String("E", "", "set `entry` symbol name") - - cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") - memprofile = flag.String("memprofile", "", "write memory profile to `file`") - memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`") -) - -// Main is the main entry point for the linker code. -func Main(arch *sys.Arch, theArch Arch) { - thearch = theArch - ctxt := linknew(arch) - ctxt.Bso = bufio.NewWriter(os.Stdout) - - // For testing behavior of go command when tools crash silently. - // Undocumented, not in standard flag parser to avoid - // exposing in usage message. - for _, arg := range os.Args { - if arg == "-crash_for_testing" { - os.Exit(2) - } - } - - final := gorootFinal() - addstrdata1(ctxt, "runtime/internal/sys.DefaultGoroot="+final) - addstrdata1(ctxt, "cmd/internal/objabi.defaultGOROOT="+final) - - // TODO(matloob): define these above and then check flag values here - if ctxt.Arch.Family == sys.AMD64 && objabi.GOOS == "plan9" { - flag.BoolVar(&Flag8, "8", false, "use 64-bit addresses in symbol table") - } - flagHeadType := flag.String("H", "", "set header `type`") - flag.BoolVar(&ctxt.linkShared, "linkshared", false, "link against installed Go shared libraries") - flag.Var(&ctxt.LinkMode, "linkmode", "set link `mode`") - flag.Var(&ctxt.BuildMode, "buildmode", "set build `mode`") - flag.BoolVar(&ctxt.compressDWARF, "compressdwarf", true, "compress DWARF if possible") - objabi.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo) - objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) }) - objabi.AddVersionFlag() // -V - objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) }) - objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog) - objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg) - - objabi.Flagparse(usage) - - switch *flagHeadType { - case "": - case "windowsgui": - ctxt.HeadType = objabi.Hwindows - windowsgui = true - default: - if err := ctxt.HeadType.Set(*flagHeadType); err != nil { - Errorf(nil, "%v", err) - usage() - } - } - - if objabi.Fieldtrack_enabled != 0 { - ctxt.Reachparent = make(map[*sym.Symbol]*sym.Symbol) - } - checkStrictDups = *FlagStrictDups - - startProfile() - if ctxt.BuildMode == BuildModeUnset { - ctxt.BuildMode = BuildModeExe - } - - if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 { - usage() - } - - if *flagOutfile == "" { - *flagOutfile = "a.out" - if ctxt.HeadType == objabi.Hwindows { - *flagOutfile += ".exe" - } - } - - interpreter = *flagInterpreter - - libinit(ctxt) // creates outfile - - if ctxt.HeadType == objabi.Hunknown { - ctxt.HeadType.Set(objabi.GOOS) - } - - ctxt.computeTLSOffset() - thearch.Archinit(ctxt) - - if ctxt.linkShared && !ctxt.IsELF { - Exitf("-linkshared can only be used on elf systems") - } - - if ctxt.Debugvlog != 0 { - ctxt.Logf("HEADER = -H%d -T0x%x -R0x%x\n", ctxt.HeadType, uint64(*FlagTextAddr), uint32(*FlagRound)) - } - - switch ctxt.BuildMode { - case BuildModeShared: - for i := 0; i < flag.NArg(); i++ { - arg := flag.Arg(i) - parts := strings.SplitN(arg, "=", 2) - var pkgpath, file string - if len(parts) == 1 { - pkgpath, file = "main", arg - } else { - pkgpath, file = parts[0], parts[1] - } - pkglistfornote = append(pkglistfornote, pkgpath...) - pkglistfornote = append(pkglistfornote, '\n') - addlibpath(ctxt, "command line", "command line", file, pkgpath, "") - } - case BuildModePlugin: - addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "") - default: - addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "") - } - ctxt.loadlib() - - deadcode(ctxt) - if *flagNewobj { - ctxt.loadlibfull() // XXX do it here for now - } - ctxt.linksetup() - ctxt.dostrdata() - - dwarfGenerateDebugInfo(ctxt) - if objabi.Fieldtrack_enabled != 0 { - fieldtrack(ctxt) - } - ctxt.mangleTypeSym() - ctxt.callgraph() - - ctxt.doelf() - if ctxt.HeadType == objabi.Hdarwin { - ctxt.domacho() - } - ctxt.dostkcheck() - if ctxt.HeadType == objabi.Hwindows { - ctxt.dope() - ctxt.windynrelocsyms() - } - if ctxt.HeadType == objabi.Haix { - ctxt.doxcoff() - } - - ctxt.addexport() - thearch.Gentext(ctxt) // trampolines, call stubs, etc. - ctxt.textbuildid() - ctxt.textaddress() - ctxt.pclntab() - ctxt.findfunctab() - ctxt.typelink() - ctxt.symtab() - ctxt.buildinfo() - ctxt.dodata() - order := ctxt.address() - dwarfcompress(ctxt) - filesize := ctxt.layout(order) - - // Write out the output file. - // It is split into two parts (Asmb and Asmb2). The first - // part writes most of the content (sections and segments), - // for which we have computed the size and offset, in a - // mmap'd region. The second part writes more content, for - // which we don't know the size. - var outputMmapped bool - if ctxt.Arch.Family != sys.Wasm { - // Don't mmap if we're building for Wasm. Wasm file - // layout is very different so filesize is meaningless. - err := ctxt.Out.Mmap(filesize) - outputMmapped = err == nil - } - if outputMmapped { - // Asmb will redirect symbols to the output file mmap, and relocations - // will be applied directly there. - thearch.Asmb(ctxt) - ctxt.reloc() - ctxt.Out.Munmap() - } else { - // If we don't mmap, we need to apply relocations before - // writing out. - ctxt.reloc() - thearch.Asmb(ctxt) - } - thearch.Asmb2(ctxt) - - ctxt.undef() - ctxt.hostlink() - if ctxt.Debugvlog != 0 { - ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym)) - ctxt.Logf("%d liveness data\n", liveness) - } - ctxt.Bso.Flush() - ctxt.archive() - - errorexit() -} - -type Rpath struct { - set bool - val string -} - -func (r *Rpath) Set(val string) error { - r.set = true - r.val = val - return nil -} - -func (r *Rpath) String() string { - return r.val -} - -func startProfile() { - if *cpuprofile != "" { - f, err := os.Create(*cpuprofile) - if err != nil { - log.Fatalf("%v", err) - } - if err := pprof.StartCPUProfile(f); err != nil { - log.Fatalf("%v", err) - } - AtExit(pprof.StopCPUProfile) - } - if *memprofile != "" { - if *memprofilerate != 0 { - runtime.MemProfileRate = int(*memprofilerate) - } - f, err := os.Create(*memprofile) - if err != nil { - log.Fatalf("%v", err) - } - AtExit(func() { - // Profile all outstanding allocations. - runtime.GC() - // compilebench parses the memory profile to extract memstats, - // which are only written in the legacy pprof format. - // See golang.org/issue/18641 and runtime/pprof/pprof.go:writeHeap. - const writeLegacyFormat = 1 - if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil { - log.Fatalf("%v", err) - } - }) - } -} diff --git a/src/cmd/oldlink/internal/ld/outbuf.go b/src/cmd/oldlink/internal/ld/outbuf.go deleted file mode 100644 index 596d2395c8..0000000000 --- a/src/cmd/oldlink/internal/ld/outbuf.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "bufio" - "cmd/internal/sys" - "cmd/oldlink/internal/sym" - "encoding/binary" - "log" - "os" -) - -// OutBuf is a buffered file writer. -// -// It is simlar to the Writer in cmd/internal/bio with a few small differences. -// -// First, it tracks the output architecture and uses it to provide -// endian helpers. -// -// Second, it provides a very cheap offset counter that doesn't require -// any system calls to read the value. -// -// It also mmaps the output file (if available). The intended usage is: -// - Mmap the output file -// - Write the content -// - possibly apply any edits in the output buffer -// - Munmap the output file -// - possibly write more content to the file, which will not be edited later. -type OutBuf struct { - arch *sys.Arch - off int64 - w *bufio.Writer - buf []byte // backing store of mmap'd output file - f *os.File - encbuf [8]byte // temp buffer used by WriteN methods -} - -func (out *OutBuf) SeekSet(p int64) { - if p == out.off { - return - } - if out.buf == nil { - out.Flush() - if _, err := out.f.Seek(p, 0); err != nil { - Exitf("seeking to %d in %s: %v", p, out.f.Name(), err) - } - } - out.off = p -} - -func (out *OutBuf) Offset() int64 { - return out.off -} - -// Write writes the contents of v to the buffer. -// -// As Write is backed by a bufio.Writer, callers do not have -// to explicitly handle the returned error as long as Flush is -// eventually called. -func (out *OutBuf) Write(v []byte) (int, error) { - if out.buf != nil { - n := copy(out.buf[out.off:], v) - out.off += int64(n) - return n, nil - } - n, err := out.w.Write(v) - out.off += int64(n) - return n, err -} - -func (out *OutBuf) Write8(v uint8) { - if out.buf != nil { - out.buf[out.off] = v - out.off++ - return - } - if err := out.w.WriteByte(v); err == nil { - out.off++ - } -} - -// WriteByte is an alias for Write8 to fulfill the io.ByteWriter interface. -func (out *OutBuf) WriteByte(v byte) error { - out.Write8(v) - return nil -} - -func (out *OutBuf) Write16(v uint16) { - out.arch.ByteOrder.PutUint16(out.encbuf[:], v) - out.Write(out.encbuf[:2]) -} - -func (out *OutBuf) Write32(v uint32) { - out.arch.ByteOrder.PutUint32(out.encbuf[:], v) - out.Write(out.encbuf[:4]) -} - -func (out *OutBuf) Write32b(v uint32) { - binary.BigEndian.PutUint32(out.encbuf[:], v) - out.Write(out.encbuf[:4]) -} - -func (out *OutBuf) Write64(v uint64) { - out.arch.ByteOrder.PutUint64(out.encbuf[:], v) - out.Write(out.encbuf[:8]) -} - -func (out *OutBuf) Write64b(v uint64) { - binary.BigEndian.PutUint64(out.encbuf[:], v) - out.Write(out.encbuf[:8]) -} - -func (out *OutBuf) WriteString(s string) { - if out.buf != nil { - n := copy(out.buf[out.off:], s) - if n != len(s) { - log.Fatalf("WriteString truncated. buffer size: %d, offset: %d, len(s)=%d", len(out.buf), out.off, len(s)) - } - out.off += int64(n) - return - } - n, _ := out.w.WriteString(s) - out.off += int64(n) -} - -// WriteStringN writes the first n bytes of s. -// If n is larger than len(s) then it is padded with zero bytes. -func (out *OutBuf) WriteStringN(s string, n int) { - out.WriteStringPad(s, n, zeros[:]) -} - -// WriteStringPad writes the first n bytes of s. -// If n is larger than len(s) then it is padded with the bytes in pad (repeated as needed). -func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) { - if len(s) >= n { - out.WriteString(s[:n]) - } else { - out.WriteString(s) - n -= len(s) - for n > len(pad) { - out.Write(pad) - n -= len(pad) - - } - out.Write(pad[:n]) - } -} - -// WriteSym writes the content of a Symbol, then changes the Symbol's content -// to point to the output buffer that we just wrote, so we can apply further -// edit to the symbol content. -// If the output file is not Mmap'd, just writes the content. -func (out *OutBuf) WriteSym(s *sym.Symbol) { - if out.buf != nil { - start := out.off - out.Write(s.P) - s.P = out.buf[start:out.off] - s.Attr.Set(sym.AttrReadOnly, false) - } else { - out.Write(s.P) - } -} - -func (out *OutBuf) Flush() { - var err error - if out.buf != nil { - err = out.Msync() - } else { - err = out.w.Flush() - } - if err != nil { - Exitf("flushing %s: %v", out.f.Name(), err) - } -} diff --git a/src/cmd/oldlink/internal/ld/outbuf_mmap.go b/src/cmd/oldlink/internal/ld/outbuf_mmap.go deleted file mode 100644 index 4075141171..0000000000 --- a/src/cmd/oldlink/internal/ld/outbuf_mmap.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux openbsd - -package ld - -import ( - "syscall" - "unsafe" -) - -func (out *OutBuf) Mmap(filesize uint64) error { - err := out.f.Truncate(int64(filesize)) - if err != nil { - Exitf("resize output file failed: %v", err) - } - out.buf, err = syscall.Mmap(int(out.f.Fd()), 0, int(filesize), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED|syscall.MAP_FILE) - return err -} - -func (out *OutBuf) Munmap() { - err := out.Msync() - if err != nil { - Exitf("msync output file failed: %v", err) - } - syscall.Munmap(out.buf) - out.buf = nil - _, err = out.f.Seek(out.off, 0) - if err != nil { - Exitf("seek output file failed: %v", err) - } -} - -func (out *OutBuf) Msync() error { - // TODO: netbsd supports mmap and msync, but the syscall package doesn't define MSYNC. - // It is excluded from the build tag for now. - _, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&out.buf[0])), uintptr(len(out.buf)), syscall.MS_SYNC) - if errno != 0 { - return errno - } - return nil -} diff --git a/src/cmd/oldlink/internal/ld/outbuf_nommap.go b/src/cmd/oldlink/internal/ld/outbuf_nommap.go deleted file mode 100644 index fba8cd8bc4..0000000000 --- a/src/cmd/oldlink/internal/ld/outbuf_nommap.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !darwin,!dragonfly,!freebsd,!linux,!openbsd,!windows - -package ld - -import "errors" - -var errNotSupported = errors.New("mmap not supported") - -func (out *OutBuf) Mmap(filesize uint64) error { return errNotSupported } -func (out *OutBuf) Munmap() { panic("unreachable") } -func (out *OutBuf) Msync() error { panic("unreachable") } diff --git a/src/cmd/oldlink/internal/ld/outbuf_windows.go b/src/cmd/oldlink/internal/ld/outbuf_windows.go deleted file mode 100644 index 1cb05c301f..0000000000 --- a/src/cmd/oldlink/internal/ld/outbuf_windows.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "reflect" - "syscall" - "unsafe" -) - -func (out *OutBuf) Mmap(filesize uint64) error { - err := out.f.Truncate(int64(filesize)) - if err != nil { - Exitf("resize output file failed: %v", err) - } - - low, high := uint32(filesize), uint32(filesize>>32) - fmap, err := syscall.CreateFileMapping(syscall.Handle(out.f.Fd()), nil, syscall.PAGE_READONLY, high, low, nil) - if err != nil { - return err - } - defer syscall.CloseHandle(fmap) - - ptr, err := syscall.MapViewOfFile(fmap, syscall.FILE_MAP_READ|syscall.FILE_MAP_WRITE, 0, 0, uintptr(filesize)) - if err != nil { - return err - } - *(*reflect.SliceHeader)(unsafe.Pointer(&out.buf)) = reflect.SliceHeader{Data: ptr, Len: int(filesize), Cap: int(filesize)} - return nil -} - -func (out *OutBuf) Munmap() { - if out.buf == nil { - return - } - err := syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&out.buf[0]))) - if err != nil { - Exitf("UnmapViewOfFile failed: %v", err) - } -} - -func (out *OutBuf) Msync() error { - if out.buf == nil { - return nil - } - return syscall.FlushViewOfFile(uintptr(unsafe.Pointer(&out.buf[0])), 0) -} diff --git a/src/cmd/oldlink/internal/ld/pcln.go b/src/cmd/oldlink/internal/ld/pcln.go deleted file mode 100644 index 7d53ab8ad4..0000000000 --- a/src/cmd/oldlink/internal/ld/pcln.go +++ /dev/null @@ -1,530 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "cmd/internal/obj" - "cmd/internal/objabi" - "cmd/internal/src" - "cmd/internal/sys" - "cmd/oldlink/internal/sym" - "encoding/binary" - "fmt" - "log" - "os" - "path/filepath" - "strings" -) - -func ftabaddstring(ftab *sym.Symbol, s string) int32 { - start := len(ftab.P) - ftab.Grow(int64(start + len(s) + 1)) // make room for s plus trailing NUL - copy(ftab.P[start:], s) - return int32(start) -} - -// numberfile assigns a file number to the file if it hasn't been assigned already. -func numberfile(ctxt *Link, file *sym.Symbol) { - if file.Type != sym.SFILEPATH { - ctxt.Filesyms = append(ctxt.Filesyms, file) - file.Value = int64(len(ctxt.Filesyms)) - file.Type = sym.SFILEPATH - path := file.Name[len(src.FileSymPrefix):] - file.Name = expandGoroot(path) - } -} - -func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) { - // Give files numbers. - for _, f := range files { - numberfile(ctxt, f) - } - - buf := make([]byte, binary.MaxVarintLen32) - newval := int32(-1) - var out sym.Pcdata - it := obj.NewPCIter(uint32(ctxt.Arch.MinLC)) - for it.Init(d.P); !it.Done; it.Next() { - // value delta - oldval := it.Value - - var val int32 - if oldval == -1 { - val = -1 - } else { - if oldval < 0 || oldval >= int32(len(files)) { - log.Fatalf("bad pcdata %d", oldval) - } - val = int32(files[oldval].Value) - } - - dv := val - newval - newval = val - - // value - n := binary.PutVarint(buf, int64(dv)) - out.P = append(out.P, buf[:n]...) - - // pc delta - pc := (it.NextPC - it.PC) / it.PCScale - n = binary.PutUvarint(buf, uint64(pc)) - out.P = append(out.P, buf[:n]...) - } - - // terminating value delta - // we want to write varint-encoded 0, which is just 0 - out.P = append(out.P, 0) - - *d = out -} - -// onlycsymbol reports whether this is a symbol that is referenced by C code. -func onlycsymbol(s *sym.Symbol) bool { - switch s.Name { - case "_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2": - return true - } - if strings.HasPrefix(s.Name, "_cgoexp_") { - return true - } - return false -} - -func emitPcln(ctxt *Link, s *sym.Symbol) bool { - if s == nil { - return true - } - if ctxt.BuildMode == BuildModePlugin && ctxt.HeadType == objabi.Hdarwin && onlycsymbol(s) { - return false - } - // We want to generate func table entries only for the "lowest level" symbols, - // not containers of subsymbols. - return !s.Attr.Container() -} - -// pclntab initializes the pclntab symbol with -// runtime function and file name information. - -var pclntabZpcln sym.FuncInfo - -// These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab. -var pclntabNfunc int32 -var pclntabFiletabOffset int32 -var pclntabPclntabOffset int32 -var pclntabFirstFunc *sym.Symbol -var pclntabLastFunc *sym.Symbol - -func (ctxt *Link) pclntab() { - funcdataBytes := int64(0) - ftab := ctxt.Syms.Lookup("runtime.pclntab", 0) - ftab.Type = sym.SPCLNTAB - ftab.Attr |= sym.AttrReachable - - // See golang.org/s/go12symtab for the format. Briefly: - // 8-byte header - // nfunc [thearch.ptrsize bytes] - // function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes] - // end PC [thearch.ptrsize bytes] - // offset to file table [4 bytes] - - // Find container symbols and mark them as such. - for _, s := range ctxt.Textp { - if s.Outer != nil { - s.Outer.Attr |= sym.AttrContainer - } - } - - // Gather some basic stats and info. - var nfunc int32 - prevSect := ctxt.Textp[0].Sect - for _, s := range ctxt.Textp { - if !emitPcln(ctxt, s) { - continue - } - nfunc++ - if pclntabFirstFunc == nil { - pclntabFirstFunc = s - } - if s.Sect != prevSect { - // With multiple text sections, the external linker may insert functions - // between the sections, which are not known by Go. This leaves holes in - // the PC range covered by the func table. We need to generate an entry - // to mark the hole. - nfunc++ - prevSect = s.Sect - } - } - - pclntabNfunc = nfunc - ftab.Grow(8 + int64(ctxt.Arch.PtrSize) + int64(nfunc)*2*int64(ctxt.Arch.PtrSize) + int64(ctxt.Arch.PtrSize) + 4) - ftab.SetUint32(ctxt.Arch, 0, 0xfffffffb) - ftab.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC)) - ftab.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize)) - ftab.SetUint(ctxt.Arch, 8, uint64(nfunc)) - pclntabPclntabOffset = int32(8 + ctxt.Arch.PtrSize) - - funcnameoff := make(map[string]int32) - nameToOffset := func(name string) int32 { - nameoff, ok := funcnameoff[name] - if !ok { - nameoff = ftabaddstring(ftab, name) - funcnameoff[name] = nameoff - } - return nameoff - } - - pctaboff := make(map[string]uint32) - writepctab := func(off int32, p []byte) int32 { - start, ok := pctaboff[string(p)] - if !ok { - if len(p) > 0 { - start = uint32(len(ftab.P)) - ftab.AddBytes(p) - } - pctaboff[string(p)] = start - } - newoff := int32(ftab.SetUint32(ctxt.Arch, int64(off), start)) - return newoff - } - - nfunc = 0 // repurpose nfunc as a running index - prevFunc := ctxt.Textp[0] - for _, s := range ctxt.Textp { - if !emitPcln(ctxt, s) { - continue - } - - if s.Sect != prevFunc.Sect { - // With multiple text sections, there may be a hole here in the address - // space (see the comment above). We use an invalid funcoff value to - // mark the hole. - // See also runtime/symtab.go:findfunc - ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), prevFunc, prevFunc.Size) - ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), ^uint64(0)) - nfunc++ - } - prevFunc = s - - pcln := s.FuncInfo - if pcln == nil { - pcln = &pclntabZpcln - } - - if len(pcln.InlTree) > 0 { - if len(pcln.Pcdata) <= objabi.PCDATA_InlTreeIndex { - // Create inlining pcdata table. - pcdata := make([]sym.Pcdata, objabi.PCDATA_InlTreeIndex+1) - copy(pcdata, pcln.Pcdata) - pcln.Pcdata = pcdata - } - - if len(pcln.Funcdataoff) <= objabi.FUNCDATA_InlTree { - // Create inline tree funcdata. - funcdata := make([]*sym.Symbol, objabi.FUNCDATA_InlTree+1) - funcdataoff := make([]int64, objabi.FUNCDATA_InlTree+1) - copy(funcdata, pcln.Funcdata) - copy(funcdataoff, pcln.Funcdataoff) - pcln.Funcdata = funcdata - pcln.Funcdataoff = funcdataoff - } - } - - funcstart := int32(len(ftab.P)) - funcstart += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1) // align to ptrsize - - ftab.SetAddr(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), s) - ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint64(funcstart)) - - // Write runtime._func. Keep in sync with ../../../../runtime/runtime2.go:/_func - // and package debug/gosym. - - // fixed size of struct, checked below - off := funcstart - - end := funcstart + int32(ctxt.Arch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(ctxt.Arch.PtrSize) - if len(pcln.Funcdata) > 0 && (end&int32(ctxt.Arch.PtrSize-1) != 0) { - end += 4 - } - ftab.Grow(int64(end)) - - // entry uintptr - off = int32(ftab.SetAddr(ctxt.Arch, int64(off), s)) - - // name int32 - nameoff := nameToOffset(s.Name) - off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(nameoff))) - - // args int32 - // TODO: Move into funcinfo. - args := uint32(0) - if s.FuncInfo != nil { - args = uint32(s.FuncInfo.Args) - } - off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args)) - - // deferreturn - deferreturn := uint32(0) - lastWasmAddr := uint32(0) - for _, r := range s.R { - if ctxt.Arch.Family == sys.Wasm && r.Type == objabi.R_ADDR { - // Wasm does not have a live variable set at the deferreturn - // call itself. Instead it has one identified by the - // resumption point immediately preceding the deferreturn. - // The wasm code has a R_ADDR relocation which is used to - // set the resumption point to PC_B. - lastWasmAddr = uint32(r.Add) - } - if r.Type.IsDirectCall() && r.Sym != nil && r.Sym.Name == "runtime.deferreturn" { - if ctxt.Arch.Family == sys.Wasm { - deferreturn = lastWasmAddr - 1 - } else { - // Note: the relocation target is in the call instruction, but - // is not necessarily the whole instruction (for instance, on - // x86 the relocation applies to bytes [1:5] of the 5 byte call - // instruction). - deferreturn = uint32(r.Off) - switch ctxt.Arch.Family { - case sys.AMD64, sys.I386: - deferreturn-- - case sys.PPC64, sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64: - // no change - case sys.RISCV64: - // TODO(jsing): The JALR instruction is marked with - // R_CALLRISCV, whereas the actual reloc is currently - // one instruction earlier starting with the AUIPC. - deferreturn -= 4 - case sys.S390X: - deferreturn -= 2 - default: - panic(fmt.Sprint("Unhandled architecture:", ctxt.Arch.Family)) - } - } - break // only need one - } - } - off = int32(ftab.SetUint32(ctxt.Arch, int64(off), deferreturn)) - - if pcln != &pclntabZpcln { - renumberfiles(ctxt, pcln.File, &pcln.Pcfile) - if false { - // Sanity check the new numbering - it := obj.NewPCIter(uint32(ctxt.Arch.MinLC)) - for it.Init(pcln.Pcfile.P); !it.Done; it.Next() { - if it.Value < 1 || it.Value > int32(len(ctxt.Filesyms)) { - Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.Value, len(ctxt.Filesyms)) - errorexit() - } - } - } - } - - if len(pcln.InlTree) > 0 { - inlTreeSym := ctxt.Syms.Lookup("inltree."+s.Name, 0) - inlTreeSym.Type = sym.SRODATA - inlTreeSym.Attr |= sym.AttrReachable | sym.AttrDuplicateOK - - for i, call := range pcln.InlTree { - // Usually, call.File is already numbered since the file - // shows up in the Pcfile table. However, two inlined calls - // might overlap exactly so that only the innermost file - // appears in the Pcfile table. In that case, this assigns - // the outer file a number. - numberfile(ctxt, call.File) - nameoff := nameToOffset(call.Func) - - inlTreeSym.SetUint16(ctxt.Arch, int64(i*20+0), uint16(call.Parent)) - inlTreeSym.SetUint8(ctxt.Arch, int64(i*20+2), uint8(objabi.GetFuncID(call.Func, ""))) - // byte 3 is unused - inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+4), uint32(call.File.Value)) - inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+8), uint32(call.Line)) - inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+12), uint32(nameoff)) - inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+16), uint32(call.ParentPC)) - } - - pcln.Funcdata[objabi.FUNCDATA_InlTree] = inlTreeSym - pcln.Pcdata[objabi.PCDATA_InlTreeIndex] = pcln.Pcinline - } - - // pcdata - off = writepctab(off, pcln.Pcsp.P) - off = writepctab(off, pcln.Pcfile.P) - off = writepctab(off, pcln.Pcline.P) - off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(len(pcln.Pcdata)))) - - // funcID uint8 - var file string - if s.FuncInfo != nil && len(s.FuncInfo.File) > 0 { - file = s.FuncInfo.File[0].Name - } - funcID := objabi.GetFuncID(s.Name, file) - - off = int32(ftab.SetUint8(ctxt.Arch, int64(off), uint8(funcID))) - - // unused - off += 2 - - // nfuncdata must be the final entry. - off = int32(ftab.SetUint8(ctxt.Arch, int64(off), uint8(len(pcln.Funcdata)))) - for i := range pcln.Pcdata { - off = writepctab(off, pcln.Pcdata[i].P) - } - - // funcdata, must be pointer-aligned and we're only int32-aligned. - // Missing funcdata will be 0 (nil pointer). - if len(pcln.Funcdata) > 0 { - if off&int32(ctxt.Arch.PtrSize-1) != 0 { - off += 4 - } - for i := range pcln.Funcdata { - dataoff := int64(off) + int64(ctxt.Arch.PtrSize)*int64(i) - if pcln.Funcdata[i] == nil { - ftab.SetUint(ctxt.Arch, dataoff, uint64(pcln.Funcdataoff[i])) - continue - } - // TODO: Dedup. - funcdataBytes += pcln.Funcdata[i].Size - ftab.SetAddrPlus(ctxt.Arch, dataoff, pcln.Funcdata[i], pcln.Funcdataoff[i]) - } - off += int32(len(pcln.Funcdata)) * int32(ctxt.Arch.PtrSize) - } - - if off != end { - Errorf(s, "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), ctxt.Arch.PtrSize) - errorexit() - } - - nfunc++ - } - - last := ctxt.Textp[len(ctxt.Textp)-1] - pclntabLastFunc = last - // Final entry of table is just end pc. - ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), last, last.Size) - - // Start file table. - start := int32(len(ftab.P)) - - start += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1) - pclntabFiletabOffset = start - ftab.SetUint32(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint32(start)) - - ftab.Grow(int64(start) + (int64(len(ctxt.Filesyms))+1)*4) - ftab.SetUint32(ctxt.Arch, int64(start), uint32(len(ctxt.Filesyms)+1)) - for i := len(ctxt.Filesyms) - 1; i >= 0; i-- { - s := ctxt.Filesyms[i] - ftab.SetUint32(ctxt.Arch, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name))) - } - - ftab.Size = int64(len(ftab.P)) - - if ctxt.Debugvlog != 0 { - ctxt.Logf("pclntab=%d bytes, funcdata total %d bytes\n", ftab.Size, funcdataBytes) - } -} - -func gorootFinal() string { - root := objabi.GOROOT - if final := os.Getenv("GOROOT_FINAL"); final != "" { - root = final - } - return root -} - -func expandGoroot(s string) string { - const n = len("$GOROOT") - if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') { - return filepath.ToSlash(filepath.Join(gorootFinal(), s[n:])) - } - return s -} - -const ( - BUCKETSIZE = 256 * MINFUNC - SUBBUCKETS = 16 - SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS - NOIDX = 0x7fffffff -) - -// findfunctab generates a lookup table to quickly find the containing -// function for a pc. See src/runtime/symtab.go:findfunc for details. -func (ctxt *Link) findfunctab() { - t := ctxt.Syms.Lookup("runtime.findfunctab", 0) - t.Type = sym.SRODATA - t.Attr |= sym.AttrReachable - t.Attr |= sym.AttrLocal - - // find min and max address - min := ctxt.Textp[0].Value - lastp := ctxt.Textp[len(ctxt.Textp)-1] - max := lastp.Value + lastp.Size - - // for each subbucket, compute the minimum of all symbol indexes - // that map to that subbucket. - n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE) - - indexes := make([]int32, n) - for i := int32(0); i < n; i++ { - indexes[i] = NOIDX - } - idx := int32(0) - for i, s := range ctxt.Textp { - if !emitPcln(ctxt, s) { - continue - } - p := s.Value - var e *sym.Symbol - i++ - if i < len(ctxt.Textp) { - e = ctxt.Textp[i] - } - for !emitPcln(ctxt, e) && i < len(ctxt.Textp) { - e = ctxt.Textp[i] - i++ - } - q := max - if e != nil { - q = e.Value - } - - //print("%d: [%lld %lld] %s\n", idx, p, q, s->name); - for ; p < q; p += SUBBUCKETSIZE { - i = int((p - min) / SUBBUCKETSIZE) - if indexes[i] > idx { - indexes[i] = idx - } - } - - i = int((q - 1 - min) / SUBBUCKETSIZE) - if indexes[i] > idx { - indexes[i] = idx - } - idx++ - } - - // allocate table - nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE) - - t.Grow(4*int64(nbuckets) + int64(n)) - - // fill in table - for i := int32(0); i < nbuckets; i++ { - base := indexes[i*SUBBUCKETS] - if base == NOIDX { - Errorf(nil, "hole in findfunctab") - } - t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base)) - for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ { - idx = indexes[i*SUBBUCKETS+j] - if idx == NOIDX { - Errorf(nil, "hole in findfunctab") - } - if idx-base >= 256 { - Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base) - } - - t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base)) - } - } -} diff --git a/src/cmd/oldlink/internal/ld/pe.go b/src/cmd/oldlink/internal/ld/pe.go deleted file mode 100644 index b40557f485..0000000000 --- a/src/cmd/oldlink/internal/ld/pe.go +++ /dev/null @@ -1,1562 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// 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) -} diff --git a/src/cmd/oldlink/internal/ld/sym.go b/src/cmd/oldlink/internal/ld/sym.go deleted file mode 100644 index 4f697d0627..0000000000 --- a/src/cmd/oldlink/internal/ld/sym.go +++ /dev/null @@ -1,109 +0,0 @@ -// Derived from Inferno utils/6l/obj.c and utils/6l/span.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ld - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/sym" - "log" -) - -func linknew(arch *sys.Arch) *Link { - ctxt := &Link{ - Syms: sym.NewSymbols(), - Out: &OutBuf{arch: arch}, - Arch: arch, - LibraryByPkg: make(map[string]*sym.Library), - } - - if objabi.GOARCH != arch.Name { - log.Fatalf("invalid objabi.GOARCH %s (want %s)", objabi.GOARCH, arch.Name) - } - - AtExit(func() { - if nerrors > 0 && ctxt.Out.f != nil { - ctxt.Out.f.Close() - mayberemoveoutfile() - } - }) - - return ctxt -} - -// computeTLSOffset records the thread-local storage offset. -// Not used for Android where the TLS offset is determined at runtime. -func (ctxt *Link) computeTLSOffset() { - switch ctxt.HeadType { - default: - log.Fatalf("unknown thread-local storage offset for %v", ctxt.HeadType) - - case objabi.Hplan9, objabi.Hwindows, objabi.Hjs, objabi.Haix: - break - - case objabi.Hlinux, - objabi.Hfreebsd, - objabi.Hnetbsd, - objabi.Hopenbsd, - objabi.Hdragonfly, - objabi.Hsolaris: - /* - * ELF uses TLS offset negative from FS. - * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS). - * Known to low-level assembly in package runtime and runtime/cgo. - */ - ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize - - case objabi.Hdarwin: - /* - * OS X system constants - offset from 0(GS) to our TLS. - */ - switch ctxt.Arch.Family { - default: - log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name) - - /* - * For x86, Apple has reserved a slot in the TLS for Go. See issue 23617. - * That slot is at offset 0x30 on amd64. - * The slot will hold the G pointer. - * These constants should match those in runtime/sys_darwin_{386,amd64}.s - * and runtime/cgo/gcc_darwin_{386,amd64}.c. - */ - case sys.AMD64: - ctxt.Tlsoffset = 0x30 - - case sys.ARM64: - ctxt.Tlsoffset = 0 // dummy value, not needed - } - } - -} diff --git a/src/cmd/oldlink/internal/ld/symtab.go b/src/cmd/oldlink/internal/ld/symtab.go deleted file mode 100644 index a324fdf600..0000000000 --- a/src/cmd/oldlink/internal/ld/symtab.go +++ /dev/null @@ -1,713 +0,0 @@ -// Inferno utils/6l/span.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ld - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/sym" - "fmt" - "path/filepath" - "strings" -) - -// Symbol table. - -func putelfstr(s string) int { - if len(Elfstrdat) == 0 && s != "" { - // first entry must be empty string - putelfstr("") - } - - off := len(Elfstrdat) - Elfstrdat = append(Elfstrdat, s...) - Elfstrdat = append(Elfstrdat, 0) - return off -} - -func putelfsyment(out *OutBuf, off int, addr int64, size int64, info int, shndx int, other int) { - if elf64 { - out.Write32(uint32(off)) - out.Write8(uint8(info)) - out.Write8(uint8(other)) - out.Write16(uint16(shndx)) - out.Write64(uint64(addr)) - out.Write64(uint64(size)) - Symsize += ELF64SYMSIZE - } else { - out.Write32(uint32(off)) - out.Write32(uint32(addr)) - out.Write32(uint32(size)) - out.Write8(uint8(info)) - out.Write8(uint8(other)) - out.Write16(uint16(shndx)) - Symsize += ELF32SYMSIZE - } -} - -var numelfsym = 1 // 0 is reserved - -var elfbind int - -func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go_ *sym.Symbol) { - var typ int - - switch t { - default: - return - - case TextSym: - typ = STT_FUNC - - case DataSym, BSSSym: - typ = STT_OBJECT - - case UndefinedSym: - // ElfType is only set for symbols read from Go shared libraries, but - // for other symbols it is left as STT_NOTYPE which is fine. - typ = int(x.ElfType()) - - case TLSSym: - typ = STT_TLS - } - - size := x.Size - if t == UndefinedSym { - size = 0 - } - - xo := x - for xo.Outer != nil { - xo = xo.Outer - } - - var elfshnum int - if xo.Type == sym.SDYNIMPORT || xo.Type == sym.SHOSTOBJ || xo.Type == sym.SUNDEFEXT { - elfshnum = SHN_UNDEF - } else { - if xo.Sect == nil { - Errorf(x, "missing section in putelfsym") - return - } - if xo.Sect.Elfsect == nil { - Errorf(x, "missing ELF section in putelfsym") - return - } - elfshnum = xo.Sect.Elfsect.(*ElfShdr).shnum - } - - // One pass for each binding: STB_LOCAL, STB_GLOBAL, - // maybe one day STB_WEAK. - bind := STB_GLOBAL - - if x.IsFileLocal() || x.Attr.VisibilityHidden() || x.Attr.Local() { - bind = STB_LOCAL - } - - // In external linking mode, we have to invoke gcc with -rdynamic - // to get the exported symbols put into the dynamic symbol table. - // To avoid filling the dynamic table with lots of unnecessary symbols, - // mark all Go symbols local (not global) in the final executable. - // But when we're dynamically linking, we need all those global symbols. - if !ctxt.DynlinkingGo() && ctxt.LinkMode == LinkExternal && !x.Attr.CgoExportStatic() && elfshnum != SHN_UNDEF { - bind = STB_LOCAL - } - - if ctxt.LinkMode == LinkExternal && elfshnum != SHN_UNDEF { - addr -= int64(xo.Sect.Vaddr) - } - other := STV_DEFAULT - if x.Attr.VisibilityHidden() { - // TODO(mwhudson): We only set AttrVisibilityHidden in ldelf, i.e. when - // internally linking. But STV_HIDDEN visibility only matters in object - // files and shared libraries, and as we are a long way from implementing - // internal linking for shared libraries and only create object files when - // externally linking, I don't think this makes a lot of sense. - other = STV_HIDDEN - } - if ctxt.Arch.Family == sys.PPC64 && typ == STT_FUNC && x.Attr.Shared() && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" { - // On ppc64 the top three bits of the st_other field indicate how - // many instructions separate the global and local entry points. In - // our case it is two instructions, indicated by the value 3. - // The conditions here match those in preprocess in - // cmd/internal/obj/ppc64/obj9.go, which is where the - // instructions are inserted. - other |= 3 << 5 - } - - // When dynamically linking, we create Symbols by reading the names from - // the symbol tables of the shared libraries and so the names need to - // match exactly. Tools like DTrace will have to wait for now. - if !ctxt.DynlinkingGo() { - // Rewrite · to . for ASCII-only tools like DTrace (sigh) - s = strings.Replace(s, "·", ".", -1) - } - - if ctxt.DynlinkingGo() && bind == STB_GLOBAL && elfbind == STB_LOCAL && x.Type == sym.STEXT { - // When dynamically linking, we want references to functions defined - // in this module to always be to the function object, not to the - // PLT. We force this by writing an additional local symbol for every - // global function symbol and making all relocations against the - // global symbol refer to this local symbol instead (see - // (*sym.Symbol).ElfsymForReloc). This is approximately equivalent to the - // ELF linker -Bsymbolic-functions option, but that is buggy on - // several platforms. - putelfsyment(ctxt.Out, putelfstr("local."+s), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other) - x.LocalElfsym = int32(numelfsym) - numelfsym++ - return - } else if bind != elfbind { - return - } - - putelfsyment(ctxt.Out, putelfstr(s), addr, size, bind<<4|typ&0xf, elfshnum, other) - x.Elfsym = int32(numelfsym) - numelfsym++ -} - -func putelfsectionsym(out *OutBuf, s *sym.Symbol, shndx int) { - putelfsyment(out, 0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0) - s.Elfsym = int32(numelfsym) - numelfsym++ -} - -func Asmelfsym(ctxt *Link) { - // the first symbol entry is reserved - putelfsyment(ctxt.Out, 0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0) - - dwarfaddelfsectionsyms(ctxt) - - // Some linkers will add a FILE sym if one is not present. - // Avoid having the working directory inserted into the symbol table. - // It is added with a name to avoid problems with external linking - // encountered on some versions of Solaris. See issue #14957. - putelfsyment(ctxt.Out, putelfstr("go.go"), 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0) - numelfsym++ - - elfbind = STB_LOCAL - genasmsym(ctxt, putelfsym) - - elfbind = STB_GLOBAL - elfglobalsymndx = numelfsym - genasmsym(ctxt, putelfsym) -} - -func putplan9sym(ctxt *Link, x *sym.Symbol, s string, typ SymbolType, addr int64, go_ *sym.Symbol) { - t := int(typ) - switch typ { - case TextSym, DataSym, BSSSym: - if x.IsFileLocal() { - t += 'a' - 'A' - } - fallthrough - - case AutoSym, ParamSym, FrameSym: - l := 4 - if ctxt.HeadType == objabi.Hplan9 && ctxt.Arch.Family == sys.AMD64 && !Flag8 { - ctxt.Out.Write32b(uint32(addr >> 32)) - l = 8 - } - - ctxt.Out.Write32b(uint32(addr)) - ctxt.Out.Write8(uint8(t + 0x80)) /* 0x80 is variable length */ - - ctxt.Out.WriteString(s) - ctxt.Out.Write8(0) - - Symsize += int32(l) + 1 + int32(len(s)) + 1 - - default: - return - } -} - -func Asmplan9sym(ctxt *Link) { - genasmsym(ctxt, putplan9sym) -} - -var symt *sym.Symbol - -type byPkg []*sym.Library - -func (libs byPkg) Len() int { - return len(libs) -} - -func (libs byPkg) Less(a, b int) bool { - return libs[a].Pkg < libs[b].Pkg -} - -func (libs byPkg) Swap(a, b int) { - libs[a], libs[b] = libs[b], libs[a] -} - -// Create a table with information on the text sections. - -func textsectionmap(ctxt *Link) uint32 { - - t := ctxt.Syms.Lookup("runtime.textsectionmap", 0) - t.Type = sym.SRODATA - t.Attr |= sym.AttrReachable - nsections := int64(0) - - for _, sect := range Segtext.Sections { - if sect.Name == ".text" { - nsections++ - } else { - break - } - } - t.Grow(3 * nsections * int64(ctxt.Arch.PtrSize)) - - off := int64(0) - n := 0 - - // The vaddr for each text section is the difference between the section's - // Vaddr and the Vaddr for the first text section as determined at compile - // time. - - // The symbol for the first text section is named runtime.text as before. - // Additional text sections are named runtime.text.n where n is the - // order of creation starting with 1. These symbols provide the section's - // address after relocation by the linker. - - textbase := Segtext.Sections[0].Vaddr - for _, sect := range Segtext.Sections { - if sect.Name != ".text" { - break - } - off = t.SetUint(ctxt.Arch, off, sect.Vaddr-textbase) - off = t.SetUint(ctxt.Arch, off, sect.Length) - if n == 0 { - s := ctxt.Syms.ROLookup("runtime.text", 0) - if s == nil { - Errorf(nil, "Unable to find symbol runtime.text\n") - } - off = t.SetAddr(ctxt.Arch, off, s) - - } else { - s := ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0) - if s == nil { - Errorf(nil, "Unable to find symbol runtime.text.%d\n", n) - } - off = t.SetAddr(ctxt.Arch, off, s) - } - n++ - } - return uint32(n) -} - -func (ctxt *Link) symtab() { - switch ctxt.BuildMode { - case BuildModeCArchive, BuildModeCShared: - for _, s := range ctxt.Syms.Allsym { - // Create a new entry in the .init_array section that points to the - // library initializer function. - if s.Name == *flagEntrySymbol && ctxt.HeadType != objabi.Haix { - addinitarrdata(ctxt, s) - } - } - } - - // Define these so that they'll get put into the symbol table. - // data.c:/^address will provide the actual values. - ctxt.xdefine("runtime.text", sym.STEXT, 0) - - ctxt.xdefine("runtime.etext", sym.STEXT, 0) - ctxt.xdefine("runtime.itablink", sym.SRODATA, 0) - ctxt.xdefine("runtime.eitablink", sym.SRODATA, 0) - ctxt.xdefine("runtime.rodata", sym.SRODATA, 0) - ctxt.xdefine("runtime.erodata", sym.SRODATA, 0) - ctxt.xdefine("runtime.types", sym.SRODATA, 0) - ctxt.xdefine("runtime.etypes", sym.SRODATA, 0) - ctxt.xdefine("runtime.noptrdata", sym.SNOPTRDATA, 0) - ctxt.xdefine("runtime.enoptrdata", sym.SNOPTRDATA, 0) - ctxt.xdefine("runtime.data", sym.SDATA, 0) - ctxt.xdefine("runtime.edata", sym.SDATA, 0) - ctxt.xdefine("runtime.bss", sym.SBSS, 0) - ctxt.xdefine("runtime.ebss", sym.SBSS, 0) - ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, 0) - ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, 0) - ctxt.xdefine("runtime.end", sym.SBSS, 0) - ctxt.xdefine("runtime.epclntab", sym.SRODATA, 0) - ctxt.xdefine("runtime.esymtab", sym.SRODATA, 0) - - // garbage collection symbols - s := ctxt.Syms.Lookup("runtime.gcdata", 0) - - s.Type = sym.SRODATA - s.Size = 0 - s.Attr |= sym.AttrReachable - ctxt.xdefine("runtime.egcdata", sym.SRODATA, 0) - - s = ctxt.Syms.Lookup("runtime.gcbss", 0) - s.Type = sym.SRODATA - s.Size = 0 - s.Attr |= sym.AttrReachable - ctxt.xdefine("runtime.egcbss", sym.SRODATA, 0) - - // pseudo-symbols to mark locations of type, string, and go string data. - var symtype *sym.Symbol - var symtyperel *sym.Symbol - if !ctxt.DynlinkingGo() { - if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) { - s = ctxt.Syms.Lookup("type.*", 0) - - s.Type = sym.STYPE - s.Size = 0 - s.Attr |= sym.AttrReachable - symtype = s - - s = ctxt.Syms.Lookup("typerel.*", 0) - - s.Type = sym.STYPERELRO - s.Size = 0 - s.Attr |= sym.AttrReachable - symtyperel = s - } else { - s = ctxt.Syms.Lookup("type.*", 0) - - s.Type = sym.STYPE - s.Size = 0 - s.Attr |= sym.AttrReachable - symtype = s - symtyperel = s - } - } - - groupSym := func(name string, t sym.SymKind) *sym.Symbol { - s := ctxt.Syms.Lookup(name, 0) - s.Type = t - s.Size = 0 - s.Attr |= sym.AttrLocal | sym.AttrReachable - return s - } - var ( - symgostring = groupSym("go.string.*", sym.SGOSTRING) - symgofunc = groupSym("go.func.*", sym.SGOFUNC) - symgcbits = groupSym("runtime.gcbits.*", sym.SGCBITS) - ) - - var symgofuncrel *sym.Symbol - if !ctxt.DynlinkingGo() { - if ctxt.UseRelro() { - symgofuncrel = groupSym("go.funcrel.*", sym.SGOFUNCRELRO) - } else { - symgofuncrel = symgofunc - } - } - - symitablink := ctxt.Syms.Lookup("runtime.itablink", 0) - symitablink.Type = sym.SITABLINK - - symt = ctxt.Syms.Lookup("runtime.symtab", 0) - symt.Attr |= sym.AttrLocal - symt.Type = sym.SSYMTAB - symt.Size = 0 - symt.Attr |= sym.AttrReachable - - nitablinks := 0 - - // assign specific types so that they sort together. - // within a type they sort by size, so the .* symbols - // just defined above will be first. - // hide the specific symbols. - for _, s := range ctxt.Syms.Allsym { - if ctxt.LinkMode != LinkExternal && isStaticTemp(s.Name) { - s.Attr |= sym.AttrNotInSymbolTable - } - - if !s.Attr.Reachable() || s.Attr.Special() || s.Type != sym.SRODATA { - continue - } - - switch { - case strings.HasPrefix(s.Name, "type."): - if !ctxt.DynlinkingGo() { - s.Attr |= sym.AttrNotInSymbolTable - } - if ctxt.UseRelro() { - s.Type = sym.STYPERELRO - s.Outer = symtyperel - } else { - s.Type = sym.STYPE - s.Outer = symtype - } - - case strings.HasPrefix(s.Name, "go.importpath.") && ctxt.UseRelro(): - // Keep go.importpath symbols in the same section as types and - // names, as they can be referred to by a section offset. - s.Type = sym.STYPERELRO - - case strings.HasPrefix(s.Name, "go.itablink."): - nitablinks++ - s.Type = sym.SITABLINK - s.Attr |= sym.AttrNotInSymbolTable - s.Outer = symitablink - - case strings.HasPrefix(s.Name, "go.string."): - s.Type = sym.SGOSTRING - s.Attr |= sym.AttrNotInSymbolTable - s.Outer = symgostring - - case strings.HasPrefix(s.Name, "runtime.gcbits."): - s.Type = sym.SGCBITS - s.Attr |= sym.AttrNotInSymbolTable - s.Outer = symgcbits - - case strings.HasSuffix(s.Name, "·f"): - if !ctxt.DynlinkingGo() { - s.Attr |= sym.AttrNotInSymbolTable - } - if ctxt.UseRelro() { - s.Type = sym.SGOFUNCRELRO - s.Outer = symgofuncrel - } else { - s.Type = sym.SGOFUNC - s.Outer = symgofunc - } - - case strings.HasPrefix(s.Name, "gcargs."), - strings.HasPrefix(s.Name, "gclocals."), - strings.HasPrefix(s.Name, "gclocals·"), - strings.HasPrefix(s.Name, "inltree."), - strings.HasSuffix(s.Name, ".opendefer"): - s.Type = sym.SGOFUNC - s.Attr |= sym.AttrNotInSymbolTable - s.Outer = symgofunc - s.Align = 4 - liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1) - } - } - - if ctxt.BuildMode == BuildModeShared { - abihashgostr := ctxt.Syms.Lookup("go.link.abihash."+filepath.Base(*flagOutfile), 0) - abihashgostr.Attr |= sym.AttrReachable - abihashgostr.Type = sym.SRODATA - hashsym := ctxt.Syms.Lookup("go.link.abihashbytes", 0) - abihashgostr.AddAddr(ctxt.Arch, hashsym) - abihashgostr.AddUint(ctxt.Arch, uint64(hashsym.Size)) - } - if ctxt.BuildMode == BuildModePlugin || ctxt.CanUsePlugins() { - for _, l := range ctxt.Library { - s := ctxt.Syms.Lookup("go.link.pkghashbytes."+l.Pkg, 0) - s.Attr |= sym.AttrReachable - s.Type = sym.SRODATA - s.Size = int64(len(l.Hash)) - s.P = []byte(l.Hash) - str := ctxt.Syms.Lookup("go.link.pkghash."+l.Pkg, 0) - str.Attr |= sym.AttrReachable - str.Type = sym.SRODATA - str.AddAddr(ctxt.Arch, s) - str.AddUint(ctxt.Arch, uint64(len(l.Hash))) - } - } - - nsections := textsectionmap(ctxt) - - // Information about the layout of the executable image for the - // runtime to use. Any changes here must be matched by changes to - // the definition of moduledata in runtime/symtab.go. - // This code uses several global variables that are set by pcln.go:pclntab. - moduledata := ctxt.Moduledata - // The pclntab slice - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0)) - moduledata.AddUint(ctxt.Arch, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size)) - moduledata.AddUint(ctxt.Arch, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size)) - // The ftab slice - moduledata.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabPclntabOffset)) - moduledata.AddUint(ctxt.Arch, uint64(pclntabNfunc+1)) - moduledata.AddUint(ctxt.Arch, uint64(pclntabNfunc+1)) - // The filetab slice - moduledata.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabFiletabOffset)) - moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Filesyms))+1) - moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Filesyms))+1) - // findfunctab - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.findfunctab", 0)) - // minpc, maxpc - moduledata.AddAddr(ctxt.Arch, pclntabFirstFunc) - moduledata.AddAddrPlus(ctxt.Arch, pclntabLastFunc, pclntabLastFunc.Size) - // pointers to specific parts of the module - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.text", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.etext", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.noptrdata", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.enoptrdata", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.data", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.edata", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.bss", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.ebss", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.noptrbss", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.enoptrbss", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.end", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.gcdata", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.gcbss", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.types", 0)) - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.etypes", 0)) - - if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal { - // Add R_REF relocation to prevent ld's garbage collection of - // runtime.rodata, runtime.erodata and runtime.epclntab. - addRef := func(name string) { - r := moduledata.AddRel() - r.Sym = ctxt.Syms.Lookup(name, 0) - r.Type = objabi.R_XCOFFREF - r.Siz = uint8(ctxt.Arch.PtrSize) - } - addRef("runtime.rodata") - addRef("runtime.erodata") - addRef("runtime.epclntab") - } - - // text section information - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.textsectionmap", 0)) - moduledata.AddUint(ctxt.Arch, uint64(nsections)) - moduledata.AddUint(ctxt.Arch, uint64(nsections)) - - // The typelinks slice - typelinkSym := ctxt.Syms.Lookup("runtime.typelink", 0) - ntypelinks := uint64(typelinkSym.Size) / 4 - moduledata.AddAddr(ctxt.Arch, typelinkSym) - moduledata.AddUint(ctxt.Arch, ntypelinks) - moduledata.AddUint(ctxt.Arch, ntypelinks) - // The itablinks slice - moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.itablink", 0)) - moduledata.AddUint(ctxt.Arch, uint64(nitablinks)) - moduledata.AddUint(ctxt.Arch, uint64(nitablinks)) - // The ptab slice - if ptab := ctxt.Syms.ROLookup("go.plugin.tabs", 0); ptab != nil && ptab.Attr.Reachable() { - ptab.Attr |= sym.AttrLocal - ptab.Type = sym.SRODATA - - nentries := uint64(len(ptab.P) / 8) // sizeof(nameOff) + sizeof(typeOff) - moduledata.AddAddr(ctxt.Arch, ptab) - moduledata.AddUint(ctxt.Arch, nentries) - moduledata.AddUint(ctxt.Arch, nentries) - } else { - moduledata.AddUint(ctxt.Arch, 0) - moduledata.AddUint(ctxt.Arch, 0) - moduledata.AddUint(ctxt.Arch, 0) - } - if ctxt.BuildMode == BuildModePlugin { - addgostring(ctxt, moduledata, "go.link.thispluginpath", objabi.PathToPrefix(*flagPluginPath)) - - pkghashes := ctxt.Syms.Lookup("go.link.pkghashes", 0) - pkghashes.Attr |= sym.AttrReachable - pkghashes.Attr |= sym.AttrLocal - pkghashes.Type = sym.SRODATA - - for i, l := range ctxt.Library { - // pkghashes[i].name - addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkgname.%d", i), l.Pkg) - // pkghashes[i].linktimehash - addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkglinkhash.%d", i), l.Hash) - // pkghashes[i].runtimehash - hash := ctxt.Syms.ROLookup("go.link.pkghash."+l.Pkg, 0) - pkghashes.AddAddr(ctxt.Arch, hash) - } - moduledata.AddAddr(ctxt.Arch, pkghashes) - moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Library))) - moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Library))) - } else { - moduledata.AddUint(ctxt.Arch, 0) // pluginpath - moduledata.AddUint(ctxt.Arch, 0) - moduledata.AddUint(ctxt.Arch, 0) // pkghashes slice - moduledata.AddUint(ctxt.Arch, 0) - moduledata.AddUint(ctxt.Arch, 0) - } - if len(ctxt.Shlibs) > 0 { - thismodulename := filepath.Base(*flagOutfile) - switch ctxt.BuildMode { - case BuildModeExe, BuildModePIE: - // When linking an executable, outfile is just "a.out". Make - // it something slightly more comprehensible. - thismodulename = "the executable" - } - addgostring(ctxt, moduledata, "go.link.thismodulename", thismodulename) - - modulehashes := ctxt.Syms.Lookup("go.link.abihashes", 0) - modulehashes.Attr |= sym.AttrReachable - modulehashes.Attr |= sym.AttrLocal - modulehashes.Type = sym.SRODATA - - for i, shlib := range ctxt.Shlibs { - // modulehashes[i].modulename - modulename := filepath.Base(shlib.Path) - addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename) - - // modulehashes[i].linktimehash - addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash)) - - // modulehashes[i].runtimehash - abihash := ctxt.Syms.Lookup("go.link.abihash."+modulename, 0) - abihash.Attr |= sym.AttrReachable - modulehashes.AddAddr(ctxt.Arch, abihash) - } - - moduledata.AddAddr(ctxt.Arch, modulehashes) - moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Shlibs))) - moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Shlibs))) - } else { - moduledata.AddUint(ctxt.Arch, 0) // modulename - moduledata.AddUint(ctxt.Arch, 0) - moduledata.AddUint(ctxt.Arch, 0) // moduleshashes slice - moduledata.AddUint(ctxt.Arch, 0) - moduledata.AddUint(ctxt.Arch, 0) - } - - hasmain := ctxt.BuildMode == BuildModeExe || ctxt.BuildMode == BuildModePIE - if hasmain { - moduledata.AddUint8(1) - } else { - moduledata.AddUint8(0) - } - - // The rest of moduledata is zero initialized. - // When linking an object that does not contain the runtime we are - // creating the moduledata from scratch and it does not have a - // compiler-provided size, so read it from the type data. - moduledatatype := ctxt.Syms.ROLookup("type.runtime.moduledata", 0) - moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype.P) - moduledata.Grow(moduledata.Size) - - lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0) - if lastmoduledatap.Type != sym.SDYNIMPORT { - lastmoduledatap.Type = sym.SNOPTRDATA - lastmoduledatap.Size = 0 // overwrite existing value - lastmoduledatap.AddAddr(ctxt.Arch, moduledata) - } -} - -func isStaticTemp(name string) bool { - if i := strings.LastIndex(name, "/"); i >= 0 { - name = name[i:] - } - return strings.Contains(name, "..stmp_") -} diff --git a/src/cmd/oldlink/internal/ld/testdata/httptest/main/main.go b/src/cmd/oldlink/internal/ld/testdata/httptest/main/main.go deleted file mode 100644 index 1bce30119a..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/httptest/main/main.go +++ /dev/null @@ -1,22 +0,0 @@ -// A small test program that uses the net/http package. There is -// nothing special about net/http here, this is just a convenient way -// to pull in a lot of code. - -package main - -import ( - "net/http" - "net/http/httptest" -) - -type statusHandler int - -func (h *statusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(int(*h)) -} - -func main() { - status := statusHandler(http.StatusNotFound) - s := httptest.NewServer(&status) - defer s.Close() -} diff --git a/src/cmd/oldlink/internal/ld/testdata/issue10978/main.go b/src/cmd/oldlink/internal/ld/testdata/issue10978/main.go deleted file mode 100644 index 5e8c09749f..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/issue10978/main.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -func undefined() - -func defined1() int { - // To check multiple errors for a single symbol, - // reference undefined more than once. - undefined() - undefined() - return 0 -} - -func defined2() { - undefined() - undefined() -} - -func init() { - _ = defined1() - defined2() -} - -// The "main" function remains undeclared. diff --git a/src/cmd/oldlink/internal/ld/testdata/issue10978/main.s b/src/cmd/oldlink/internal/ld/testdata/issue10978/main.s deleted file mode 100644 index 1d00e76c1d..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/issue10978/main.s +++ /dev/null @@ -1 +0,0 @@ -// This file is needed to make "go build" work for package with external functions. diff --git a/src/cmd/oldlink/internal/ld/testdata/issue25459/a/a.go b/src/cmd/oldlink/internal/ld/testdata/issue25459/a/a.go deleted file mode 100644 index 6032d76f49..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/issue25459/a/a.go +++ /dev/null @@ -1,27 +0,0 @@ -package a - -const Always = true - -var Count int - -type FuncReturningInt func() int - -var PointerToConstIf FuncReturningInt - -func ConstIf() int { - if Always { - return 1 - } - var imdead [4]int - imdead[Count] = 1 - return imdead[0] -} - -func CallConstIf() int { - Count += 3 - return ConstIf() -} - -func Another() { - defer func() { PointerToConstIf = ConstIf; Count += 1 }() -} diff --git a/src/cmd/oldlink/internal/ld/testdata/issue25459/main/main.go b/src/cmd/oldlink/internal/ld/testdata/issue25459/main/main.go deleted file mode 100644 index 3f5f365169..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/issue25459/main/main.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import "cmd/oldlink/internal/ld/testdata/issue25459/a" - -var Glob int - -func main() { - a.Another() - Glob += a.ConstIf() + a.CallConstIf() -} diff --git a/src/cmd/oldlink/internal/ld/testdata/issue26237/b.dir/b.go b/src/cmd/oldlink/internal/ld/testdata/issue26237/b.dir/b.go deleted file mode 100644 index ca577490bc..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/issue26237/b.dir/b.go +++ /dev/null @@ -1,16 +0,0 @@ -package b - -var q int - -func Top(x int) int { - q += 1 - if q != x { - return 3 - } - return 4 -} - -func OOO(x int) int { - defer func() { q += x & 7 }() - return Top(x + 1) -} diff --git a/src/cmd/oldlink/internal/ld/testdata/issue26237/main/main.go b/src/cmd/oldlink/internal/ld/testdata/issue26237/main/main.go deleted file mode 100644 index 88b54f1678..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/issue26237/main/main.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "fmt" - - b "cmd/oldlink/internal/ld/testdata/issue26237/b.dir" -) - -var skyx int - -func main() { - skyx += b.OOO(skyx) - if b.Top(1) == 99 { - fmt.Printf("Beware the Jabberwock, my son!\n") - } -} diff --git a/src/cmd/oldlink/internal/ld/testdata/issue32233/lib/ObjC.m b/src/cmd/oldlink/internal/ld/testdata/issue32233/lib/ObjC.m deleted file mode 100644 index 946278803e..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/issue32233/lib/ObjC.m +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#import -#import - -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; -} diff --git a/src/cmd/oldlink/internal/ld/testdata/issue32233/lib/lib.go b/src/cmd/oldlink/internal/ld/testdata/issue32233/lib/lib.go deleted file mode 100644 index 514b9b9a4a..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/issue32233/lib/lib.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lib - -/* -#cgo darwin CFLAGS: -D__MAC_OS_X_VERSION_MAX_ALLOWED=101450 -#cgo darwin LDFLAGS: -framework Foundation -framework AppKit -#include "stdlib.h" -int function(void); -*/ -import "C" -import "fmt" - -func DoC() { - C.function() - fmt.Println("called c function") -} diff --git a/src/cmd/oldlink/internal/ld/testdata/issue32233/main/main.go b/src/cmd/oldlink/internal/ld/testdata/issue32233/main/main.go deleted file mode 100644 index 9eec6cc5b5..0000000000 --- a/src/cmd/oldlink/internal/ld/testdata/issue32233/main/main.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "cmd/oldlink/internal/ld/testdata/issue32233/lib" - -func main() { - lib.DoC() -} diff --git a/src/cmd/oldlink/internal/ld/typelink.go b/src/cmd/oldlink/internal/ld/typelink.go deleted file mode 100644 index 07d04bb13d..0000000000 --- a/src/cmd/oldlink/internal/ld/typelink.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "cmd/internal/objabi" - "cmd/oldlink/internal/sym" - "sort" -) - -type byTypeStr []typelinkSortKey - -type typelinkSortKey struct { - TypeStr string - Type *sym.Symbol -} - -func (s byTypeStr) Less(i, j int) bool { return s[i].TypeStr < s[j].TypeStr } -func (s byTypeStr) Len() int { return len(s) } -func (s byTypeStr) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -// typelink generates the typelink table which is used by reflect.typelinks(). -// Types that should be added to the typelinks table are marked with the -// MakeTypelink attribute by the compiler. -func (ctxt *Link) typelink() { - typelinks := byTypeStr{} - for _, s := range ctxt.Syms.Allsym { - if s.Attr.Reachable() && s.Attr.MakeTypelink() { - typelinks = append(typelinks, typelinkSortKey{decodetypeStr(ctxt.Arch, s), s}) - } - } - sort.Sort(typelinks) - - tl := ctxt.Syms.Lookup("runtime.typelink", 0) - tl.Type = sym.STYPELINK - tl.Attr |= sym.AttrReachable | sym.AttrLocal - tl.Size = int64(4 * len(typelinks)) - tl.P = make([]byte, tl.Size) - tl.R = make([]sym.Reloc, len(typelinks)) - for i, s := range typelinks { - r := &tl.R[i] - r.Sym = s.Type - r.Off = int32(i * 4) - r.Siz = 4 - r.Type = objabi.R_ADDROFF - } -} diff --git a/src/cmd/oldlink/internal/ld/util.go b/src/cmd/oldlink/internal/ld/util.go deleted file mode 100644 index 97c9a44c1e..0000000000 --- a/src/cmd/oldlink/internal/ld/util.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import ( - "cmd/oldlink/internal/sym" - "encoding/binary" - "fmt" - "os" -) - -var atExitFuncs []func() - -func AtExit(f func()) { - atExitFuncs = append(atExitFuncs, f) -} - -// runAtExitFuncs runs the queued set of AtExit functions. -func runAtExitFuncs() { - for i := len(atExitFuncs) - 1; i >= 0; i-- { - atExitFuncs[i]() - } - atExitFuncs = nil -} - -// Exit exits with code after executing all atExitFuncs. -func Exit(code int) { - runAtExitFuncs() - os.Exit(code) -} - -// Exitf logs an error message then calls Exit(2). -func Exitf(format string, a ...interface{}) { - fmt.Fprintf(os.Stderr, os.Args[0]+": "+format+"\n", a...) - nerrors++ - Exit(2) -} - -// Errorf logs an error message. -// -// If more than 20 errors have been printed, exit with an error. -// -// Logging an error means that on exit cmd/link will delete any -// output file and return a non-zero error code. -func Errorf(s *sym.Symbol, format string, args ...interface{}) { - if s != nil { - format = s.Name + ": " + format - } - format += "\n" - fmt.Fprintf(os.Stderr, format, args...) - nerrors++ - if *flagH { - panic("error") - } - if nerrors > 20 { - Exitf("too many errors") - } -} - -func artrim(x []byte) string { - i := 0 - j := len(x) - for i < len(x) && x[i] == ' ' { - i++ - } - for j > i && x[j-1] == ' ' { - j-- - } - return string(x[i:j]) -} - -func stringtouint32(x []uint32, s string) { - for i := 0; len(s) > 0; i++ { - var buf [4]byte - s = s[copy(buf[:], s):] - x[i] = binary.LittleEndian.Uint32(buf[:]) - } -} - -// contains reports whether v is in s. -func contains(s []string, v string) bool { - for _, x := range s { - if x == v { - return true - } - } - return false -} - -// implements sort.Interface, for sorting symbols by name. -type byName []*sym.Symbol - -func (s byName) Len() int { return len(s) } -func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s byName) Less(i, j int) bool { return s[i].Name < s[j].Name } diff --git a/src/cmd/oldlink/internal/ld/xcoff.go b/src/cmd/oldlink/internal/ld/xcoff.go deleted file mode 100644 index 4d66d6d75e..0000000000 --- a/src/cmd/oldlink/internal/ld/xcoff.go +++ /dev/null @@ -1,1685 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package 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 - -} diff --git a/src/cmd/oldlink/internal/loadelf/ldelf.go b/src/cmd/oldlink/internal/loadelf/ldelf.go deleted file mode 100644 index db37db9121..0000000000 --- a/src/cmd/oldlink/internal/loadelf/ldelf.go +++ /dev/null @@ -1,1282 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package 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) -} diff --git a/src/cmd/oldlink/internal/loader/loader.go b/src/cmd/oldlink/internal/loader/loader.go deleted file mode 100644 index 8c618bfe4d..0000000000 --- a/src/cmd/oldlink/internal/loader/loader.go +++ /dev/null @@ -1,629 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package loader - -import ( - "bytes" - "cmd/internal/bio" - "cmd/internal/dwarf" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/sym" - "fmt" - "log" - "sort" - "strconv" - "strings" -) - -var _ = fmt.Print - -// Sym encapsulates a global symbol index, used to identify a specific -// Go symbol. The 0-valued Sym is corresponds to an invalid symbol. -type Sym int - -// Relocs encapsulates the set of relocations on a given symbol; an -// instance of this type is returned by the Loader Relocs() method. -type Relocs struct { - Count int // number of relocs - - li int // local index of symbol whose relocs we're examining - r *oReader // object reader for containing package - l *Loader // loader - - ext *sym.Symbol // external symbol if not nil -} - -// Reloc contains the payload for a specific relocation. -// TODO: replace this with sym.Reloc, once we change the -// relocation target from "*sym.Symbol" to "loader.Sym" in sym.Reloc. -type Reloc struct { - Off int32 // offset to rewrite - Size uint8 // number of bytes to rewrite: 0, 1, 2, or 4 - Type objabi.RelocType // the relocation type - Add int64 // addend - Sym Sym // global index of symbol the reloc addresses -} - -// oReader is a wrapper type of obj.Reader, along with some -// extra information. -// TODO: rename to objReader once the old one is gone? -type oReader struct { - //*goobj2.Reader - unit *sym.CompilationUnit - version int // version of static symbol - flags uint32 // read from object file - pkgprefix string - rcache []Sym // cache mapping local PkgNone symbol to resolved Sym -} - -type objIdx struct { - r *oReader - i Sym // start index - e Sym // end index -} - -type nameVer struct { - name string - v int -} - -type bitmap []uint32 - -// set the i-th bit. -func (bm bitmap) Set(i Sym) { - n, r := uint(i)/32, uint(i)%32 - bm[n] |= 1 << r -} - -// whether the i-th bit is set. -func (bm bitmap) Has(i Sym) bool { - n, r := uint(i)/32, uint(i)%32 - return bm[n]&(1<= 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)), "") - } - } - 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) - } -} diff --git a/src/cmd/oldlink/internal/loadmacho/ldmacho.go b/src/cmd/oldlink/internal/loadmacho/ldmacho.go deleted file mode 100644 index 4846239936..0000000000 --- a/src/cmd/oldlink/internal/loadmacho/ldmacho.go +++ /dev/null @@ -1,794 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package loadmacho implements a Mach-O file reader. -package loadmacho - -import ( - "bytes" - "cmd/internal/bio" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/loader" - "cmd/oldlink/internal/sym" - "encoding/binary" - "fmt" - "io" - "sort" -) - -/* -Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c -http://code.swtch.com/plan9port/src/tip/src/libmach/ - - Copyright © 2004 Russ Cox. - Portions Copyright © 2008-2010 Google Inc. - Portions Copyright © 2010 The Go Authors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld -const ( - MACHO_X86_64_RELOC_UNSIGNED = 0 - MACHO_X86_64_RELOC_SIGNED = 1 - MACHO_FAKE_GOTPCREL = 100 -) - -type ldMachoObj struct { - f *bio.Reader - base int64 // off in f where Mach-O begins - length int64 // length of Mach-O - is64 bool - name string - e binary.ByteOrder - cputype uint - subcputype uint - filetype uint32 - flags uint32 - cmd []ldMachoCmd - ncmd uint -} - -type ldMachoCmd struct { - type_ int - off uint32 - size uint32 - seg ldMachoSeg - sym ldMachoSymtab - dsym ldMachoDysymtab -} - -type ldMachoSeg struct { - name string - vmaddr uint64 - vmsize uint64 - fileoff uint32 - filesz uint32 - maxprot uint32 - initprot uint32 - nsect uint32 - flags uint32 - sect []ldMachoSect -} - -type ldMachoSect struct { - name string - segname string - addr uint64 - size uint64 - off uint32 - align uint32 - reloff uint32 - nreloc uint32 - flags uint32 - res1 uint32 - res2 uint32 - sym *sym.Symbol - rel []ldMachoRel -} - -type ldMachoRel struct { - addr uint32 - symnum uint32 - pcrel uint8 - length uint8 - extrn uint8 - type_ uint8 - scattered uint8 - value uint32 -} - -type ldMachoSymtab struct { - symoff uint32 - nsym uint32 - stroff uint32 - strsize uint32 - str []byte - sym []ldMachoSym -} - -type ldMachoSym struct { - name string - type_ uint8 - sectnum uint8 - desc uint16 - kind int8 - value uint64 - sym *sym.Symbol -} - -type ldMachoDysymtab struct { - ilocalsym uint32 - nlocalsym uint32 - iextdefsym uint32 - nextdefsym uint32 - iundefsym uint32 - nundefsym uint32 - tocoff uint32 - ntoc uint32 - modtaboff uint32 - nmodtab uint32 - extrefsymoff uint32 - nextrefsyms uint32 - indirectsymoff uint32 - nindirectsyms uint32 - extreloff uint32 - nextrel uint32 - locreloff uint32 - nlocrel uint32 - indir []uint32 -} - -// ldMachoSym.type_ -const ( - N_EXT = 0x01 - N_TYPE = 0x1e - N_STAB = 0xe0 -) - -// ldMachoSym.desc -const ( - N_WEAK_REF = 0x40 - N_WEAK_DEF = 0x80 -) - -const ( - LdMachoCpuVax = 1 - LdMachoCpu68000 = 6 - LdMachoCpu386 = 7 - LdMachoCpuAmd64 = 0x1000007 - LdMachoCpuMips = 8 - LdMachoCpu98000 = 10 - LdMachoCpuHppa = 11 - LdMachoCpuArm = 12 - LdMachoCpu88000 = 13 - LdMachoCpuSparc = 14 - LdMachoCpu860 = 15 - LdMachoCpuAlpha = 16 - LdMachoCpuPower = 18 - LdMachoCmdSegment = 1 - LdMachoCmdSymtab = 2 - LdMachoCmdSymseg = 3 - LdMachoCmdThread = 4 - LdMachoCmdDysymtab = 11 - LdMachoCmdSegment64 = 25 - LdMachoFileObject = 1 - LdMachoFileExecutable = 2 - LdMachoFileFvmlib = 3 - LdMachoFileCore = 4 - LdMachoFilePreload = 5 -) - -func unpackcmd(p []byte, m *ldMachoObj, c *ldMachoCmd, type_ uint, sz uint) int { - e4 := m.e.Uint32 - e8 := m.e.Uint64 - - c.type_ = int(type_) - c.size = uint32(sz) - switch type_ { - default: - return -1 - - case LdMachoCmdSegment: - if sz < 56 { - return -1 - } - c.seg.name = cstring(p[8:24]) - c.seg.vmaddr = uint64(e4(p[24:])) - c.seg.vmsize = uint64(e4(p[28:])) - c.seg.fileoff = e4(p[32:]) - c.seg.filesz = e4(p[36:]) - c.seg.maxprot = e4(p[40:]) - c.seg.initprot = e4(p[44:]) - c.seg.nsect = e4(p[48:]) - c.seg.flags = e4(p[52:]) - c.seg.sect = make([]ldMachoSect, c.seg.nsect) - if uint32(sz) < 56+c.seg.nsect*68 { - return -1 - } - p = p[56:] - var s *ldMachoSect - for i := 0; uint32(i) < c.seg.nsect; i++ { - s = &c.seg.sect[i] - s.name = cstring(p[0:16]) - s.segname = cstring(p[16:32]) - s.addr = uint64(e4(p[32:])) - s.size = uint64(e4(p[36:])) - s.off = e4(p[40:]) - s.align = e4(p[44:]) - s.reloff = e4(p[48:]) - s.nreloc = e4(p[52:]) - s.flags = e4(p[56:]) - s.res1 = e4(p[60:]) - s.res2 = e4(p[64:]) - p = p[68:] - } - - case LdMachoCmdSegment64: - if sz < 72 { - return -1 - } - c.seg.name = cstring(p[8:24]) - c.seg.vmaddr = e8(p[24:]) - c.seg.vmsize = e8(p[32:]) - c.seg.fileoff = uint32(e8(p[40:])) - c.seg.filesz = uint32(e8(p[48:])) - c.seg.maxprot = e4(p[56:]) - c.seg.initprot = e4(p[60:]) - c.seg.nsect = e4(p[64:]) - c.seg.flags = e4(p[68:]) - c.seg.sect = make([]ldMachoSect, c.seg.nsect) - if uint32(sz) < 72+c.seg.nsect*80 { - return -1 - } - p = p[72:] - var s *ldMachoSect - for i := 0; uint32(i) < c.seg.nsect; i++ { - s = &c.seg.sect[i] - s.name = cstring(p[0:16]) - s.segname = cstring(p[16:32]) - s.addr = e8(p[32:]) - s.size = e8(p[40:]) - s.off = e4(p[48:]) - s.align = e4(p[52:]) - s.reloff = e4(p[56:]) - s.nreloc = e4(p[60:]) - s.flags = e4(p[64:]) - s.res1 = e4(p[68:]) - s.res2 = e4(p[72:]) - - // p+76 is reserved - p = p[80:] - } - - case LdMachoCmdSymtab: - if sz < 24 { - return -1 - } - c.sym.symoff = e4(p[8:]) - c.sym.nsym = e4(p[12:]) - c.sym.stroff = e4(p[16:]) - c.sym.strsize = e4(p[20:]) - - case LdMachoCmdDysymtab: - if sz < 80 { - return -1 - } - c.dsym.ilocalsym = e4(p[8:]) - c.dsym.nlocalsym = e4(p[12:]) - c.dsym.iextdefsym = e4(p[16:]) - c.dsym.nextdefsym = e4(p[20:]) - c.dsym.iundefsym = e4(p[24:]) - c.dsym.nundefsym = e4(p[28:]) - c.dsym.tocoff = e4(p[32:]) - c.dsym.ntoc = e4(p[36:]) - c.dsym.modtaboff = e4(p[40:]) - c.dsym.nmodtab = e4(p[44:]) - c.dsym.extrefsymoff = e4(p[48:]) - c.dsym.nextrefsyms = e4(p[52:]) - c.dsym.indirectsymoff = e4(p[56:]) - c.dsym.nindirectsyms = e4(p[60:]) - c.dsym.extreloff = e4(p[64:]) - c.dsym.nextrel = e4(p[68:]) - c.dsym.locreloff = e4(p[72:]) - c.dsym.nlocrel = e4(p[76:]) - } - - return 0 -} - -func macholoadrel(m *ldMachoObj, sect *ldMachoSect) int { - if sect.rel != nil || sect.nreloc == 0 { - return 0 - } - rel := make([]ldMachoRel, sect.nreloc) - n := int(sect.nreloc * 8) - buf := make([]byte, n) - m.f.MustSeek(m.base+int64(sect.reloff), 0) - if _, err := io.ReadFull(m.f, buf); err != nil { - return -1 - } - for i := uint32(0); i < sect.nreloc; i++ { - r := &rel[i] - p := buf[i*8:] - r.addr = m.e.Uint32(p) - - // TODO(rsc): Wrong interpretation for big-endian bitfields? - if r.addr&0x80000000 != 0 { - // scatterbrained relocation - r.scattered = 1 - - v := r.addr >> 24 - r.addr &= 0xFFFFFF - r.type_ = uint8(v & 0xF) - v >>= 4 - r.length = 1 << (v & 3) - v >>= 2 - r.pcrel = uint8(v & 1) - r.value = m.e.Uint32(p[4:]) - } else { - v := m.e.Uint32(p[4:]) - r.symnum = v & 0xFFFFFF - v >>= 24 - r.pcrel = uint8(v & 1) - v >>= 1 - r.length = 1 << (v & 3) - v >>= 2 - r.extrn = uint8(v & 1) - v >>= 1 - r.type_ = uint8(v) - } - } - - sect.rel = rel - return 0 -} - -func macholoaddsym(m *ldMachoObj, d *ldMachoDysymtab) int { - n := int(d.nindirectsyms) - - p := make([]byte, n*4) - m.f.MustSeek(m.base+int64(d.indirectsymoff), 0) - if _, err := io.ReadFull(m.f, p); err != nil { - return -1 - } - - d.indir = make([]uint32, n) - for i := 0; i < n; i++ { - d.indir[i] = m.e.Uint32(p[4*i:]) - } - return 0 -} - -func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int { - if symtab.sym != nil { - return 0 - } - - strbuf := make([]byte, symtab.strsize) - m.f.MustSeek(m.base+int64(symtab.stroff), 0) - if _, err := io.ReadFull(m.f, strbuf); err != nil { - return -1 - } - - symsize := 12 - if m.is64 { - symsize = 16 - } - n := int(symtab.nsym * uint32(symsize)) - symbuf := make([]byte, n) - m.f.MustSeek(m.base+int64(symtab.symoff), 0) - if _, err := io.ReadFull(m.f, symbuf); err != nil { - return -1 - } - sym := make([]ldMachoSym, symtab.nsym) - p := symbuf - for i := uint32(0); i < symtab.nsym; i++ { - s := &sym[i] - v := m.e.Uint32(p) - if v >= symtab.strsize { - return -1 - } - s.name = cstring(strbuf[v:]) - s.type_ = p[4] - s.sectnum = p[5] - s.desc = m.e.Uint16(p[6:]) - if m.is64 { - s.value = m.e.Uint64(p[8:]) - } else { - s.value = uint64(m.e.Uint32(p[8:])) - } - p = p[symsize:] - } - - symtab.str = strbuf - symtab.sym = sym - return 0 -} - -func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) ([]*sym.Symbol, error) { - newSym := func(name string, version int) *sym.Symbol { - return l.LookupOrCreate(name, version, syms) - } - return load(arch, syms.IncVersion(), newSym, f, pkg, length, pn) -} - -func LoadOld(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) { - return load(arch, syms.IncVersion(), syms.Lookup, f, pkg, length, pn) -} - -// load the Mach-O file pn from f. -// Symbols are written into syms, and a slice of the text symbols is returned. -func load(arch *sys.Arch, localSymVersion int, lookup func(string, int) *sym.Symbol, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) { - errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) { - return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...)) - } - - base := f.Offset() - - var hdr [7 * 4]uint8 - if _, err := io.ReadFull(f, hdr[:]); err != nil { - return errorf("reading hdr: %v", err) - } - - var e binary.ByteOrder - if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE { - e = binary.BigEndian - } else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE { - e = binary.LittleEndian - } else { - return errorf("bad magic - not mach-o file") - } - - is64 := e.Uint32(hdr[:]) == 0xFEEDFACF - ncmd := e.Uint32(hdr[4*4:]) - cmdsz := e.Uint32(hdr[5*4:]) - if ncmd > 0x10000 || cmdsz >= 0x01000000 { - return errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz) - } - - if is64 { - f.MustSeek(4, 1) // skip reserved word in header - } - - m := &ldMachoObj{ - f: f, - e: e, - cputype: uint(e.Uint32(hdr[1*4:])), - subcputype: uint(e.Uint32(hdr[2*4:])), - filetype: e.Uint32(hdr[3*4:]), - ncmd: uint(ncmd), - flags: e.Uint32(hdr[6*4:]), - is64: is64, - base: base, - length: length, - name: pn, - } - - switch arch.Family { - default: - return errorf("mach-o %s unimplemented", arch.Name) - - case sys.AMD64: - if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 { - return errorf("mach-o object but not amd64") - } - } - - m.cmd = make([]ldMachoCmd, ncmd) - cmdp := make([]byte, cmdsz) - if _, err := io.ReadFull(f, cmdp); err != nil { - return errorf("reading cmds: %v", err) - } - - // read and parse load commands - var c *ldMachoCmd - - var symtab *ldMachoSymtab - var dsymtab *ldMachoDysymtab - - off := uint32(len(hdr)) - for i := uint32(0); i < ncmd; i++ { - ty := e.Uint32(cmdp) - sz := e.Uint32(cmdp[4:]) - m.cmd[i].off = off - unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz)) - cmdp = cmdp[sz:] - off += sz - if ty == LdMachoCmdSymtab { - if symtab != nil { - return errorf("multiple symbol tables") - } - - symtab = &m.cmd[i].sym - macholoadsym(m, symtab) - } - - if ty == LdMachoCmdDysymtab { - dsymtab = &m.cmd[i].dsym - macholoaddsym(m, dsymtab) - } - - if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) { - if c != nil { - return errorf("multiple load commands") - } - - c = &m.cmd[i] - } - } - - // load text and data segments into memory. - // they are not as small as the load commands, but we'll need - // the memory anyway for the symbol images, so we might - // as well use one large chunk. - if c == nil { - return errorf("no load command") - } - - if symtab == nil { - // our work is done here - no symbols means nothing can refer to this file - return - } - - if int64(c.seg.fileoff+c.seg.filesz) >= length { - return errorf("load segment out of range") - } - - f.MustSeek(m.base+int64(c.seg.fileoff), 0) - dat := make([]byte, c.seg.filesz) - if _, err := io.ReadFull(f, dat); err != nil { - return errorf("cannot load object data: %v", err) - } - - for i := uint32(0); i < c.seg.nsect; i++ { - sect := &c.seg.sect[i] - if sect.segname != "__TEXT" && sect.segname != "__DATA" { - continue - } - if sect.name == "__eh_frame" { - continue - } - name := fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name) - s := lookup(name, localSymVersion) - if s.Type != 0 { - return errorf("duplicate %s/%s", sect.segname, sect.name) - } - - if sect.flags&0xff == 1 { // S_ZEROFILL - s.P = make([]byte, sect.size) - } else { - s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size] - } - s.Size = int64(len(s.P)) - - if sect.segname == "__TEXT" { - if sect.name == "__text" { - s.Type = sym.STEXT - } else { - s.Type = sym.SRODATA - } - } else { - if sect.name == "__bss" { - s.Type = sym.SNOPTRBSS - s.P = s.P[:0] - } else { - s.Type = sym.SNOPTRDATA - } - } - - sect.sym = s - } - - // enter sub-symbols into symbol table. - // have to guess sizes from next symbol. - for i := uint32(0); i < symtab.nsym; i++ { - machsym := &symtab.sym[i] - if machsym.type_&N_STAB != 0 { - continue - } - - // TODO: check sym->type against outer->type. - name := machsym.name - - if name[0] == '_' && name[1] != '\x00' { - name = name[1:] - } - v := 0 - if machsym.type_&N_EXT == 0 { - v = localSymVersion - } - s := lookup(name, v) - if machsym.type_&N_EXT == 0 { - s.Attr |= sym.AttrDuplicateOK - } - if machsym.desc&(N_WEAK_REF|N_WEAK_DEF) != 0 { - s.Attr |= sym.AttrDuplicateOK - } - machsym.sym = s - if machsym.sectnum == 0 { // undefined - continue - } - if uint32(machsym.sectnum) > c.seg.nsect { - return errorf("reference to invalid section %d", machsym.sectnum) - } - - sect := &c.seg.sect[machsym.sectnum-1] - outer := sect.sym - if outer == nil { - continue // ignore reference to invalid section - } - - if s.Outer != nil { - if s.Attr.DuplicateOK() { - continue - } - return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name) - } - - s.Type = outer.Type - s.Attr |= sym.AttrSubSymbol - s.Sub = outer.Sub - outer.Sub = s - s.Outer = outer - s.Value = int64(machsym.value - sect.addr) - if !s.Attr.CgoExportDynamic() { - s.SetDynimplib("") // satisfy dynimport - } - if outer.Type == sym.STEXT { - if s.Attr.External() && !s.Attr.DuplicateOK() { - return errorf("%v: duplicate symbol definition", s) - } - s.Attr |= sym.AttrExternal - } - - machsym.sym = s - } - - // Sort outer lists by address, adding to textp. - // This keeps textp in increasing address order. - for i := 0; uint32(i) < c.seg.nsect; i++ { - sect := &c.seg.sect[i] - s := sect.sym - if s == nil { - continue - } - if s.Sub != nil { - s.Sub = sym.SortSub(s.Sub) - - // assign sizes, now that we know symbols in sorted order. - for s1 := s.Sub; s1 != nil; s1 = s1.Sub { - if s1.Sub != nil { - s1.Size = s1.Sub.Value - s1.Value - } else { - s1.Size = s.Value + s.Size - s1.Value - } - } - } - - if s.Type == sym.STEXT { - if s.Attr.OnList() { - return errorf("symbol %s listed multiple times", s.Name) - } - s.Attr |= sym.AttrOnList - textp = append(textp, s) - for s1 := s.Sub; s1 != nil; s1 = s1.Sub { - if s1.Attr.OnList() { - return errorf("symbol %s listed multiple times", s1.Name) - } - s1.Attr |= sym.AttrOnList - textp = append(textp, s1) - } - } - } - - // load relocations - for i := 0; uint32(i) < c.seg.nsect; i++ { - sect := &c.seg.sect[i] - s := sect.sym - if s == nil { - continue - } - macholoadrel(m, sect) - if sect.rel == nil { - continue - } - r := make([]sym.Reloc, sect.nreloc) - rpi := 0 - for j := uint32(0); j < sect.nreloc; j++ { - rp := &r[rpi] - rel := §.rel[j] - if rel.scattered != 0 { - // mach-o only uses scattered relocation on 32-bit platforms, - // which are no longer supported. - return errorf("%v: unexpected scattered relocation", s) - } - - rp.Siz = rel.length - rp.Type = objabi.MachoRelocOffset + (objabi.RelocType(rel.type_) << 1) + objabi.RelocType(rel.pcrel) - rp.Off = int32(rel.addr) - - // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). - if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED { - // Calculate the addend as the offset into the section. - // - // The rip-relative offset stored in the object file is encoded - // as follows: - // - // movsd 0x00000360(%rip),%xmm0 - // - // To get the absolute address of the value this rip-relative address is pointing - // to, we must add the address of the next instruction to it. This is done by - // taking the address of the relocation and adding 4 to it (since the rip-relative - // offset can at most be 32 bits long). To calculate the offset into the section the - // relocation is referencing, we subtract the vaddr of the start of the referenced - // section found in the original object file. - // - // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] - secaddr := c.seg.sect[rel.symnum-1].addr - - rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr) - } else { - rp.Add = int64(int32(e.Uint32(s.P[rp.Off:]))) - } - - // An unsigned internal relocation has a value offset - // by the section address. - if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_UNSIGNED { - secaddr := c.seg.sect[rel.symnum-1].addr - rp.Add -= int64(secaddr) - } - - if rel.extrn == 0 { - if rel.symnum < 1 || rel.symnum > c.seg.nsect { - return errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect) - } - - rp.Sym = c.seg.sect[rel.symnum-1].sym - if rp.Sym == nil { - return errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name) - } - } else { - if rel.symnum >= symtab.nsym { - return errorf("invalid relocation: symbol reference out of range") - } - - rp.Sym = symtab.sym[rel.symnum].sym - } - - rpi++ - } - - sort.Sort(sym.RelocByOff(r[:rpi])) - s.R = r - s.R = s.R[:rpi] - } - - return textp, nil -} - -func cstring(x []byte) string { - i := bytes.IndexByte(x, '\x00') - if i >= 0 { - x = x[:i] - } - return string(x) -} diff --git a/src/cmd/oldlink/internal/loadpe/ldpe.go b/src/cmd/oldlink/internal/loadpe/ldpe.go deleted file mode 100644 index f7df774661..0000000000 --- a/src/cmd/oldlink/internal/loadpe/ldpe.go +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package loadpe implements a PE/COFF file reader. -package loadpe - -import ( - "cmd/internal/bio" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/loader" - "cmd/oldlink/internal/sym" - "debug/pe" - "encoding/binary" - "errors" - "fmt" - "io" - "sort" - "strings" -) - -const ( - // TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 (same with IMAGE_SYM_DTYPE_POINTER and IMAGE_SYM_DTYPE_FUNCTION) - IMAGE_SYM_UNDEFINED = 0 - IMAGE_SYM_ABSOLUTE = -1 - IMAGE_SYM_DEBUG = -2 - IMAGE_SYM_TYPE_NULL = 0 - IMAGE_SYM_TYPE_VOID = 1 - IMAGE_SYM_TYPE_CHAR = 2 - IMAGE_SYM_TYPE_SHORT = 3 - IMAGE_SYM_TYPE_INT = 4 - IMAGE_SYM_TYPE_LONG = 5 - IMAGE_SYM_TYPE_FLOAT = 6 - IMAGE_SYM_TYPE_DOUBLE = 7 - IMAGE_SYM_TYPE_STRUCT = 8 - IMAGE_SYM_TYPE_UNION = 9 - IMAGE_SYM_TYPE_ENUM = 10 - IMAGE_SYM_TYPE_MOE = 11 - IMAGE_SYM_TYPE_BYTE = 12 - IMAGE_SYM_TYPE_WORD = 13 - IMAGE_SYM_TYPE_UINT = 14 - IMAGE_SYM_TYPE_DWORD = 15 - IMAGE_SYM_TYPE_PCODE = 32768 - IMAGE_SYM_DTYPE_NULL = 0 - IMAGE_SYM_DTYPE_POINTER = 0x10 - IMAGE_SYM_DTYPE_FUNCTION = 0x20 - IMAGE_SYM_DTYPE_ARRAY = 0x30 - IMAGE_SYM_CLASS_END_OF_FUNCTION = -1 - IMAGE_SYM_CLASS_NULL = 0 - IMAGE_SYM_CLASS_AUTOMATIC = 1 - IMAGE_SYM_CLASS_EXTERNAL = 2 - IMAGE_SYM_CLASS_STATIC = 3 - IMAGE_SYM_CLASS_REGISTER = 4 - IMAGE_SYM_CLASS_EXTERNAL_DEF = 5 - IMAGE_SYM_CLASS_LABEL = 6 - IMAGE_SYM_CLASS_UNDEFINED_LABEL = 7 - IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8 - IMAGE_SYM_CLASS_ARGUMENT = 9 - IMAGE_SYM_CLASS_STRUCT_TAG = 10 - IMAGE_SYM_CLASS_MEMBER_OF_UNION = 11 - IMAGE_SYM_CLASS_UNION_TAG = 12 - IMAGE_SYM_CLASS_TYPE_DEFINITION = 13 - IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14 - IMAGE_SYM_CLASS_ENUM_TAG = 15 - IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 16 - IMAGE_SYM_CLASS_REGISTER_PARAM = 17 - IMAGE_SYM_CLASS_BIT_FIELD = 18 - IMAGE_SYM_CLASS_FAR_EXTERNAL = 68 /* Not in PECOFF v8 spec */ - IMAGE_SYM_CLASS_BLOCK = 100 - IMAGE_SYM_CLASS_FUNCTION = 101 - IMAGE_SYM_CLASS_END_OF_STRUCT = 102 - IMAGE_SYM_CLASS_FILE = 103 - IMAGE_SYM_CLASS_SECTION = 104 - IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105 - IMAGE_SYM_CLASS_CLR_TOKEN = 107 - IMAGE_REL_I386_ABSOLUTE = 0x0000 - IMAGE_REL_I386_DIR16 = 0x0001 - IMAGE_REL_I386_REL16 = 0x0002 - IMAGE_REL_I386_DIR32 = 0x0006 - IMAGE_REL_I386_DIR32NB = 0x0007 - IMAGE_REL_I386_SEG12 = 0x0009 - IMAGE_REL_I386_SECTION = 0x000A - IMAGE_REL_I386_SECREL = 0x000B - IMAGE_REL_I386_TOKEN = 0x000C - IMAGE_REL_I386_SECREL7 = 0x000D - IMAGE_REL_I386_REL32 = 0x0014 - IMAGE_REL_AMD64_ABSOLUTE = 0x0000 - IMAGE_REL_AMD64_ADDR64 = 0x0001 - IMAGE_REL_AMD64_ADDR32 = 0x0002 - IMAGE_REL_AMD64_ADDR32NB = 0x0003 - IMAGE_REL_AMD64_REL32 = 0x0004 - IMAGE_REL_AMD64_REL32_1 = 0x0005 - IMAGE_REL_AMD64_REL32_2 = 0x0006 - IMAGE_REL_AMD64_REL32_3 = 0x0007 - IMAGE_REL_AMD64_REL32_4 = 0x0008 - IMAGE_REL_AMD64_REL32_5 = 0x0009 - IMAGE_REL_AMD64_SECTION = 0x000A - IMAGE_REL_AMD64_SECREL = 0x000B - IMAGE_REL_AMD64_SECREL7 = 0x000C - IMAGE_REL_AMD64_TOKEN = 0x000D - IMAGE_REL_AMD64_SREL32 = 0x000E - IMAGE_REL_AMD64_PAIR = 0x000F - IMAGE_REL_AMD64_SSPAN32 = 0x0010 - IMAGE_REL_ARM_ABSOLUTE = 0x0000 - IMAGE_REL_ARM_ADDR32 = 0x0001 - IMAGE_REL_ARM_ADDR32NB = 0x0002 - IMAGE_REL_ARM_BRANCH24 = 0x0003 - IMAGE_REL_ARM_BRANCH11 = 0x0004 - IMAGE_REL_ARM_SECTION = 0x000E - IMAGE_REL_ARM_SECREL = 0x000F - IMAGE_REL_ARM_MOV32 = 0x0010 - IMAGE_REL_THUMB_MOV32 = 0x0011 - IMAGE_REL_THUMB_BRANCH20 = 0x0012 - IMAGE_REL_THUMB_BRANCH24 = 0x0014 - IMAGE_REL_THUMB_BLX23 = 0x0015 - IMAGE_REL_ARM_PAIR = 0x0016 -) - -// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld, ideally in debug/pe. -const ( - IMAGE_SCN_CNT_CODE = 0x00000020 - IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 - IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 - IMAGE_SCN_MEM_DISCARDABLE = 0x02000000 - IMAGE_SCN_MEM_EXECUTE = 0x20000000 - IMAGE_SCN_MEM_READ = 0x40000000 - IMAGE_SCN_MEM_WRITE = 0x80000000 -) - -// TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating peBiobuf - -// peBiobuf makes bio.Reader look like io.ReaderAt. -type peBiobuf bio.Reader - -func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) { - ret := ((*bio.Reader)(f)).MustSeek(off, 0) - if ret < 0 { - return 0, errors.New("fail to seek") - } - n, err := f.Read(p) - if err != nil { - return 0, err - } - return n, nil -} - -func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) { - lookup := func(name string, version int) *sym.Symbol { - return l.LookupOrCreate(name, version, syms) - } - return load(arch, lookup, syms.IncVersion(), input, pkg, length, pn) -} - -func LoadOld(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) { - return load(arch, syms.Lookup, syms.IncVersion(), input, pkg, length, pn) -} - -// load loads the PE file pn from input. -// Symbols are written into syms, and a slice of the text symbols is returned. -// If an .rsrc section is found, its symbol is returned as rsrc. -func load(arch *sys.Arch, lookup func(string, int) *sym.Symbol, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) { - sectsyms := make(map[*pe.Section]*sym.Symbol) - sectdata := make(map[*pe.Section][]byte) - - // Some input files are archives containing multiple of - // object files, and pe.NewFile seeks to the start of - // input file and get confused. Create section reader - // to stop pe.NewFile looking before current position. - sr := io.NewSectionReader((*peBiobuf)(input), input.Offset(), 1<<63-1) - - // TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details) - f, err := pe.NewFile(sr) - if err != nil { - return nil, nil, err - } - defer f.Close() - - // TODO return error if found .cormeta - - // create symbols for mapped sections - for _, sect := range f.Sections { - if sect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 { - continue - } - - if sect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 { - // This has been seen for .idata sections, which we - // want to ignore. See issues 5106 and 5273. - continue - } - - name := fmt.Sprintf("%s(%s)", pkg, sect.Name) - s := lookup(name, localSymVersion) - - switch sect.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) { - case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata - s.Type = sym.SRODATA - - case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss - s.Type = sym.SNOPTRBSS - - case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data - s.Type = sym.SNOPTRDATA - - case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text - s.Type = sym.STEXT - - default: - return nil, nil, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name) - } - - if s.Type != sym.SNOPTRBSS { - data, err := sect.Data() - if err != nil { - return nil, nil, err - } - sectdata[sect] = data - s.P = data - } - s.Size = int64(sect.Size) - sectsyms[sect] = s - if sect.Name == ".rsrc" { - rsrc = s - } - } - - // load relocations - for _, rsect := range f.Sections { - if _, found := sectsyms[rsect]; !found { - continue - } - if rsect.NumberOfRelocations == 0 { - continue - } - if rsect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 { - continue - } - if rsect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 { - // This has been seen for .idata sections, which we - // want to ignore. See issues 5106 and 5273. - continue - } - - rs := make([]sym.Reloc, rsect.NumberOfRelocations) - for j, r := range rsect.Relocs { - rp := &rs[j] - if int(r.SymbolTableIndex) >= len(f.COFFSymbols) { - return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols)) - } - pesym := &f.COFFSymbols[r.SymbolTableIndex] - gosym, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion) - if err != nil { - return nil, nil, err - } - if gosym == nil { - name, err := pesym.FullName(f.StringTable) - if err != nil { - name = string(pesym.Name[:]) - } - return nil, nil, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type) - } - - rp.Sym = gosym - rp.Siz = 4 - rp.Off = int32(r.VirtualAddress) - switch arch.Family { - default: - return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family) - case sys.I386, sys.AMD64: - switch r.Type { - default: - return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type) - - case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32, - IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32 - IMAGE_REL_AMD64_ADDR32NB: - rp.Type = objabi.R_PCREL - - rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) - - case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32: - rp.Type = objabi.R_ADDR - - // load addend from image - rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) - - case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 - rp.Siz = 8 - - rp.Type = objabi.R_ADDR - - // load addend from image - rp.Add = int64(binary.LittleEndian.Uint64(sectdata[rsect][rp.Off:])) - } - - case sys.ARM: - switch r.Type { - default: - return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type) - - case IMAGE_REL_ARM_SECREL: - rp.Type = objabi.R_PCREL - - rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) - - case IMAGE_REL_ARM_ADDR32: - rp.Type = objabi.R_ADDR - - rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) - - case IMAGE_REL_ARM_BRANCH24: - rp.Type = objabi.R_CALLARM - - rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) - } - } - - // ld -r could generate multiple section symbols for the - // same section but with different values, we have to take - // that into account - if issect(pesym) { - rp.Add += int64(pesym.Value) - } - } - - sort.Sort(sym.RelocByOff(rs[:rsect.NumberOfRelocations])) - - s := sectsyms[rsect] - s.R = rs - s.R = s.R[:rsect.NumberOfRelocations] - } - - // enter sub-symbols into symbol table. - for i, numaux := 0, 0; i < len(f.COFFSymbols); i += numaux + 1 { - pesym := &f.COFFSymbols[i] - - numaux = int(pesym.NumberOfAuxSymbols) - - name, err := pesym.FullName(f.StringTable) - if err != nil { - return nil, nil, err - } - if name == "" { - continue - } - if issect(pesym) { - continue - } - if int(pesym.SectionNumber) > len(f.Sections) { - continue - } - if pesym.SectionNumber == IMAGE_SYM_DEBUG { - continue - } - var sect *pe.Section - if pesym.SectionNumber > 0 { - sect = f.Sections[pesym.SectionNumber-1] - if _, found := sectsyms[sect]; !found { - continue - } - } - - s, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion) - if err != nil { - return nil, nil, err - } - - if pesym.SectionNumber == 0 { // extern - if s.Type == sym.SDYNIMPORT { - s.SetPlt(-2) // flag for dynimport in PE object files. - } - if s.Type == sym.SXREF && pesym.Value > 0 { // global data - s.Type = sym.SNOPTRDATA - s.Size = int64(pesym.Value) - } - - continue - } else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) { - sect = f.Sections[pesym.SectionNumber-1] - if _, found := sectsyms[sect]; !found { - return nil, nil, fmt.Errorf("%s: %v: missing sect.sym", pn, s) - } - } else { - return nil, nil, fmt.Errorf("%s: %v: sectnum < 0!", pn, s) - } - - if sect == nil { - return nil, rsrc, nil - } - - if s.Outer != nil { - if s.Attr.DuplicateOK() { - continue - } - return nil, nil, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sectsyms[sect].Name) - } - - sectsym := sectsyms[sect] - s.Sub = sectsym.Sub - sectsym.Sub = s - s.Type = sectsym.Type - s.Attr |= sym.AttrSubSymbol - s.Value = int64(pesym.Value) - s.Size = 4 - s.Outer = sectsym - if sectsym.Type == sym.STEXT { - if s.Attr.External() && !s.Attr.DuplicateOK() { - return nil, nil, fmt.Errorf("%s: duplicate symbol definition", s.Name) - } - s.Attr |= sym.AttrExternal - } - } - - // Sort outer lists by address, adding to textp. - // This keeps textp in increasing address order. - for _, sect := range f.Sections { - s := sectsyms[sect] - if s == nil { - continue - } - if s.Sub != nil { - s.Sub = sym.SortSub(s.Sub) - } - if s.Type == sym.STEXT { - if s.Attr.OnList() { - return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name) - } - s.Attr |= sym.AttrOnList - textp = append(textp, s) - for s = s.Sub; s != nil; s = s.Sub { - if s.Attr.OnList() { - return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name) - } - s.Attr |= sym.AttrOnList - textp = append(textp, s) - } - } - } - - return textp, rsrc, nil -} - -func issect(s *pe.COFFSymbol) bool { - return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.' -} - -func readpesym(arch *sys.Arch, lookup func(string, int) *sym.Symbol, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]*sym.Symbol, localSymVersion int) (*sym.Symbol, error) { - symname, err := pesym.FullName(f.StringTable) - if err != nil { - return nil, err - } - var name string - if issect(pesym) { - name = sectsyms[f.Sections[pesym.SectionNumber-1]].Name - } else { - name = symname - switch arch.Family { - case sys.AMD64: - if name == "__imp___acrt_iob_func" { - // Do not rename __imp___acrt_iob_func into __acrt_iob_func, - // because __imp___acrt_iob_func symbol is real - // (see commit b295099 from git://git.code.sf.net/p/mingw-w64/mingw-w64 for details). - } else { - name = strings.TrimPrefix(name, "__imp_") // __imp_Name => Name - } - case sys.I386: - if name == "__imp____acrt_iob_func" { - // Do not rename __imp____acrt_iob_func into ___acrt_iob_func, - // because __imp____acrt_iob_func symbol is real - // (see commit b295099 from git://git.code.sf.net/p/mingw-w64/mingw-w64 for details). - } else { - name = strings.TrimPrefix(name, "__imp_") // __imp_Name => Name - } - if name[0] == '_' { - name = name[1:] // _Name => Name - } - } - } - - // remove last @XXX - if i := strings.LastIndex(name, "@"); i >= 0 { - name = name[:i] - } - - var s *sym.Symbol - switch pesym.Type { - default: - return nil, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type) - - case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL: - switch pesym.StorageClass { - case IMAGE_SYM_CLASS_EXTERNAL: //global - s = lookup(name, 0) - - case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL: - s = lookup(name, localSymVersion) - s.Attr |= sym.AttrDuplicateOK - - default: - return nil, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass) - } - } - - if s != nil && s.Type == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) { - s.Type = sym.SXREF - } - if strings.HasPrefix(symname, "__imp_") { - s.SetGot(-2) // flag for __imp_ - } - - return s, nil -} diff --git a/src/cmd/oldlink/internal/loadxcoff/ldxcoff.go b/src/cmd/oldlink/internal/loadxcoff/ldxcoff.go deleted file mode 100644 index 832b1681c7..0000000000 --- a/src/cmd/oldlink/internal/loadxcoff/ldxcoff.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package loadxcoff implements a XCOFF file reader. -package loadxcoff - -import ( - "cmd/internal/bio" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/loader" - "cmd/oldlink/internal/sym" - "errors" - "fmt" - "internal/xcoff" -) - -// ldSection is an XCOFF section with its symbols. -type ldSection struct { - xcoff.Section - sym *sym.Symbol -} - -// TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating xcoffBiobuf - -// xcoffBiobuf makes bio.Reader look like io.ReaderAt. -type xcoffBiobuf bio.Reader - -func (f *xcoffBiobuf) ReadAt(p []byte, off int64) (int, error) { - ret := ((*bio.Reader)(f)).MustSeek(off, 0) - if ret < 0 { - return 0, errors.New("fail to seek") - } - n, err := f.Read(p) - if err != nil { - return 0, err - } - return n, nil -} - -// Load loads xcoff files with the indexed object files. -func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) { - lookup := func(name string, version int) *sym.Symbol { - return l.LookupOrCreate(name, version, syms) - } - return load(arch, lookup, syms.IncVersion(), input, pkg, length, pn) -} - -// LoadOld uses the old version of object loading. -func LoadOld(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) { - return load(arch, syms.Lookup, syms.IncVersion(), input, pkg, length, pn) -} - -// loads the Xcoff file pn from f. -// Symbols are written into syms, and a slice of the text symbols is returned. -func load(arch *sys.Arch, lookup func(string, int) *sym.Symbol, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) { - errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) { - return nil, fmt.Errorf("loadxcoff: %v: %v", pn, fmt.Sprintf(str, args...)) - } - - var ldSections []*ldSection - - f, err := xcoff.NewFile((*xcoffBiobuf)(input)) - if err != nil { - return nil, err - } - defer f.Close() - - for _, sect := range f.Sections { - //only text, data and bss section - if sect.Type < xcoff.STYP_TEXT || sect.Type > xcoff.STYP_BSS { - continue - } - lds := new(ldSection) - lds.Section = *sect - name := fmt.Sprintf("%s(%s)", pkg, lds.Name) - s := lookup(name, localSymVersion) - - switch lds.Type { - default: - return errorf("unrecognized section type 0x%x", lds.Type) - case xcoff.STYP_TEXT: - s.Type = sym.STEXT - case xcoff.STYP_DATA: - s.Type = sym.SNOPTRDATA - case xcoff.STYP_BSS: - s.Type = sym.SNOPTRBSS - } - - s.Size = int64(lds.Size) - if s.Type != sym.SNOPTRBSS { - data, err := lds.Section.Data() - if err != nil { - return nil, err - } - s.P = data - } - - lds.sym = s - ldSections = append(ldSections, lds) - } - - // sx = symbol from file - // s = symbol for syms - for _, sx := range f.Symbols { - // get symbol type - stype, errmsg := getSymbolType(f, sx) - if errmsg != "" { - return errorf("error reading symbol %s: %s", sx.Name, errmsg) - } - if stype == sym.Sxxx { - continue - } - - s := lookup(sx.Name, 0) - - // Text symbol - if s.Type == sym.STEXT { - if s.Attr.OnList() { - return errorf("symbol %s listed multiple times", s.Name) - } - s.Attr |= sym.AttrOnList - textp = append(textp, s) - } - } - - // Read relocations - for _, sect := range ldSections { - // TODO(aix): Dwarf section relocation if needed - if sect.Type != xcoff.STYP_TEXT && sect.Type != xcoff.STYP_DATA { - continue - } - rs := make([]sym.Reloc, sect.Nreloc) - for i, rx := range sect.Relocs { - r := &rs[i] - - r.Sym = lookup(rx.Symbol.Name, 0) - if uint64(int32(rx.VirtualAddress)) != rx.VirtualAddress { - return errorf("virtual address of a relocation is too big: 0x%x", rx.VirtualAddress) - } - r.Off = int32(rx.VirtualAddress) - switch rx.Type { - default: - return errorf("section %s: unknown relocation of type 0x%x", sect.Name, rx.Type) - case xcoff.R_POS: - // Reloc the address of r.Sym - // Length should be 64 - if rx.Length != 64 { - return errorf("section %s: relocation R_POS has length different from 64: %d", sect.Name, rx.Length) - } - r.Siz = 8 - r.Type = objabi.R_CONST - r.Add = int64(rx.Symbol.Value) - - case xcoff.R_RBR: - r.Siz = 4 - r.Type = objabi.R_CALLPOWER - r.Add = 0 // - - } - } - s := sect.sym - s.R = rs - s.R = s.R[:sect.Nreloc] - } - return textp, nil - -} - -// Convert symbol xcoff type to sym.SymKind -// Returns nil if this shouldn't be added into syms (like .file or .dw symbols ) -func getSymbolType(f *xcoff.File, s *xcoff.Symbol) (stype sym.SymKind, err string) { - // .file symbol - if s.SectionNumber == -2 { - if s.StorageClass == xcoff.C_FILE { - return sym.Sxxx, "" - } - return sym.Sxxx, "unrecognised StorageClass for sectionNumber = -2" - } - - // extern symbols - // TODO(aix) - if s.SectionNumber == 0 { - return sym.Sxxx, "" - } - - sectType := f.Sections[s.SectionNumber-1].SectionHeader.Type - switch sectType { - default: - return sym.Sxxx, fmt.Sprintf("getSymbolType for Section type 0x%x not implemented", sectType) - case xcoff.STYP_DWARF, xcoff.STYP_DEBUG: - return sym.Sxxx, "" - case xcoff.STYP_DATA, xcoff.STYP_BSS, xcoff.STYP_TEXT: - } - - switch s.StorageClass { - default: - return sym.Sxxx, fmt.Sprintf("getSymbolType for Storage class 0x%x not implemented", s.StorageClass) - case xcoff.C_HIDEXT, xcoff.C_EXT, xcoff.C_WEAKEXT: - switch s.AuxCSect.StorageMappingClass { - default: - return sym.Sxxx, fmt.Sprintf("getSymbolType for Storage class 0x%x and Storage Map 0x%x not implemented", s.StorageClass, s.AuxCSect.StorageMappingClass) - - // Program Code - case xcoff.XMC_PR: - if sectType == xcoff.STYP_TEXT { - return sym.STEXT, "" - } - return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_PR", sectType, s.StorageClass) - - // Read/Write Data - case xcoff.XMC_RW: - if sectType == xcoff.STYP_DATA { - return sym.SDATA, "" - } - if sectType == xcoff.STYP_BSS { - return sym.SBSS, "" - } - return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_RW", sectType, s.StorageClass) - - // Function descriptor - case xcoff.XMC_DS: - if sectType == xcoff.STYP_DATA { - return sym.SDATA, "" - } - return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_DS", sectType, s.StorageClass) - - // TOC anchor and TOC entry - case xcoff.XMC_TC0, xcoff.XMC_TE: - if sectType == xcoff.STYP_DATA { - return sym.SXCOFFTOC, "" - } - return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_DS", sectType, s.StorageClass) - - } - } -} diff --git a/src/cmd/oldlink/internal/mips/asm.go b/src/cmd/oldlink/internal/mips/asm.go deleted file mode 100644 index 48a2324151..0000000000 --- a/src/cmd/oldlink/internal/mips/asm.go +++ /dev/null @@ -1,230 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2016 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package mips - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" - "cmd/oldlink/internal/sym" - "debug/elf" - "fmt" - "log" -) - -func gentext(ctxt *ld.Link) { - return -} - -func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { - log.Fatalf("adddynrel not implemented") - return false -} - -func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { - ctxt.Out.Write32(uint32(sectoff)) - - elfsym := r.Xsym.ElfsymForReloc() - switch r.Type { - default: - return false - case objabi.R_ADDR: - if r.Siz != 4 { - return false - } - ctxt.Out.Write32(uint32(elf.R_MIPS_32) | uint32(elfsym)<<8) - case objabi.R_ADDRMIPS: - ctxt.Out.Write32(uint32(elf.R_MIPS_LO16) | uint32(elfsym)<<8) - case objabi.R_ADDRMIPSU: - ctxt.Out.Write32(uint32(elf.R_MIPS_HI16) | uint32(elfsym)<<8) - case objabi.R_ADDRMIPSTLS: - ctxt.Out.Write32(uint32(elf.R_MIPS_TLS_TPREL_LO16) | uint32(elfsym)<<8) - case objabi.R_CALLMIPS, objabi.R_JMPMIPS: - ctxt.Out.Write32(uint32(elf.R_MIPS_26) | uint32(elfsym)<<8) - } - - return true -} - -func elfsetupplt(ctxt *ld.Link) { - return -} - -func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool { - return false -} - -func applyrel(arch *sys.Arch, r *sym.Reloc, s *sym.Symbol, val int64, t int64) int64 { - o := arch.ByteOrder.Uint32(s.P[r.Off:]) - switch r.Type { - case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSTLS: - return int64(o&0xffff0000 | uint32(t)&0xffff) - case objabi.R_ADDRMIPSU: - return int64(o&0xffff0000 | uint32((t+(1<<15))>>16)&0xffff) - case objabi.R_CALLMIPS, objabi.R_JMPMIPS: - return int64(o&0xfc000000 | uint32(t>>2)&^0xfc000000) - default: - return val - } -} - -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { - if ctxt.LinkMode == ld.LinkExternal { - switch r.Type { - default: - return val, false - case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU: - r.Done = false - - // set up addend for eventual relocation via outer symbol. - rs := r.Sym - r.Xadd = r.Add - for rs.Outer != nil { - r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer) - rs = rs.Outer - } - - if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil { - ld.Errorf(s, "missing section for %s", rs.Name) - } - r.Xsym = rs - return applyrel(ctxt.Arch, r, s, val, r.Xadd), true - case objabi.R_ADDRMIPSTLS, objabi.R_CALLMIPS, objabi.R_JMPMIPS: - r.Done = false - r.Xsym = r.Sym - r.Xadd = r.Add - return applyrel(ctxt.Arch, r, s, val, r.Add), true - } - } - - switch r.Type { - case objabi.R_CONST: - return r.Add, true - case objabi.R_GOTOFF: - return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true - case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU: - t := ld.Symaddr(r.Sym) + r.Add - return applyrel(ctxt.Arch, r, s, val, t), true - case objabi.R_CALLMIPS, objabi.R_JMPMIPS: - t := ld.Symaddr(r.Sym) + r.Add - - if t&3 != 0 { - ld.Errorf(s, "direct call is not aligned: %s %x", r.Sym.Name, t) - } - - // check if target address is in the same 256 MB region as the next instruction - if (s.Value+int64(r.Off)+4)&0xf0000000 != (t & 0xf0000000) { - ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t) - } - - return applyrel(ctxt.Arch, r, s, val, t), true - case objabi.R_ADDRMIPSTLS: - // thread pointer is at 0x7000 offset from the start of TLS data area - t := ld.Symaddr(r.Sym) + r.Add - 0x7000 - if t < -32768 || t >= 32678 { - ld.Errorf(s, "TLS offset out of range %d", t) - } - return applyrel(ctxt.Arch, r, s, val, t), true - } - - return val, false -} - -func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { - return -1 -} - -func asmb(ctxt *ld.Link) { - if ctxt.IsELF { - ld.Asmbelfsetup() - } - - sect := ld.Segtext.Sections[0] - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) - for _, sect = range ld.Segtext.Sections[1:] { - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) - } - - if ld.Segrodata.Filelen > 0 { - ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) - } - - ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) - - ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff)) - ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) -} - -func asmb2(ctxt *ld.Link) { - /* output symbol table */ - ld.Symsize = 0 - - ld.Lcsize = 0 - symo := uint32(0) - if !*ld.FlagS { - if !ctxt.IsELF { - ld.Errorf(nil, "unsupported executable format") - } - symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) - symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound))) - - ctxt.Out.SeekSet(int64(symo)) - ld.Asmelfsym(ctxt) - ctxt.Out.Flush() - ctxt.Out.Write(ld.Elfstrdat) - - if ctxt.LinkMode == ld.LinkExternal { - ld.Elfemitreloc(ctxt) - } - } - - ctxt.Out.SeekSet(0) - switch ctxt.HeadType { - default: - ld.Errorf(nil, "unsupported operating system") - case objabi.Hlinux: - ld.Asmbelf(ctxt, int64(symo)) - } - - ctxt.Out.Flush() - if *ld.FlagC { - fmt.Printf("textsize=%d\n", ld.Segtext.Filelen) - fmt.Printf("datsize=%d\n", ld.Segdata.Filelen) - fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen) - fmt.Printf("symsize=%d\n", ld.Symsize) - fmt.Printf("lcsize=%d\n", ld.Lcsize) - fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize)) - } -} diff --git a/src/cmd/oldlink/internal/mips/l.go b/src/cmd/oldlink/internal/mips/l.go deleted file mode 100644 index adbde40f7c..0000000000 --- a/src/cmd/oldlink/internal/mips/l.go +++ /dev/null @@ -1,74 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2016 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package mips - -// Writing object files. - -// cmd/9l/l.h from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2016 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -const ( - MaxAlign = 32 // max data alignment - MinAlign = 1 // min data alignment - FuncAlign = 4 -) - -/* Used by ../internal/ld/dwarf.go */ -const ( - DWARFREGSP = 29 - DWARFREGLR = 31 -) diff --git a/src/cmd/oldlink/internal/mips/obj.go b/src/cmd/oldlink/internal/mips/obj.go deleted file mode 100644 index c80824ff14..0000000000 --- a/src/cmd/oldlink/internal/mips/obj.go +++ /dev/null @@ -1,89 +0,0 @@ -// Inferno utils/5l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2016 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package mips - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" -) - -func Init() (*sys.Arch, ld.Arch) { - arch := sys.ArchMIPS - if objabi.GOARCH == "mipsle" { - arch = sys.ArchMIPSLE - } - - theArch := ld.Arch{ - Funcalign: FuncAlign, - Maxalign: MaxAlign, - Minalign: MinAlign, - Dwarfregsp: DWARFREGSP, - Dwarfreglr: DWARFREGLR, - - Adddynrel: adddynrel, - Archinit: archinit, - Archreloc: archreloc, - Archrelocvariant: archrelocvariant, - Asmb: asmb, - Asmb2: asmb2, - Elfreloc1: elfreloc1, - Elfsetupplt: elfsetupplt, - Gentext: gentext, - Machoreloc1: machoreloc1, - - Linuxdynld: "/lib/ld.so.1", - - Freebsddynld: "XXX", - Openbsddynld: "XXX", - Netbsddynld: "XXX", - Dragonflydynld: "XXX", - Solarisdynld: "XXX", - } - - return arch, theArch -} - -func archinit(ctxt *ld.Link) { - switch ctxt.HeadType { - default: - ld.Exitf("unknown -H option: %v", ctxt.HeadType) - case objabi.Hlinux: /* mips elf */ - ld.Elfinit(ctxt) - ld.HEADR = ld.ELFRESERVE - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 0x10000 - } - } -} diff --git a/src/cmd/oldlink/internal/mips64/asm.go b/src/cmd/oldlink/internal/mips64/asm.go deleted file mode 100644 index 775b74e1fd..0000000000 --- a/src/cmd/oldlink/internal/mips64/asm.go +++ /dev/null @@ -1,278 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package mips64 - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" - "cmd/oldlink/internal/sym" - "debug/elf" - "fmt" - "log" -) - -func gentext(ctxt *ld.Link) {} - -func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { - log.Fatalf("adddynrel not implemented") - return false -} - -func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { - // mips64 ELF relocation (endian neutral) - // offset uint64 - // sym uint32 - // ssym uint8 - // type3 uint8 - // type2 uint8 - // type uint8 - // addend int64 - - ctxt.Out.Write64(uint64(sectoff)) - - elfsym := r.Xsym.ElfsymForReloc() - ctxt.Out.Write32(uint32(elfsym)) - ctxt.Out.Write8(0) - ctxt.Out.Write8(0) - ctxt.Out.Write8(0) - switch r.Type { - default: - return false - case objabi.R_ADDR: - switch r.Siz { - case 4: - ctxt.Out.Write8(uint8(elf.R_MIPS_32)) - case 8: - ctxt.Out.Write8(uint8(elf.R_MIPS_64)) - default: - return false - } - case objabi.R_ADDRMIPS: - ctxt.Out.Write8(uint8(elf.R_MIPS_LO16)) - case objabi.R_ADDRMIPSU: - ctxt.Out.Write8(uint8(elf.R_MIPS_HI16)) - case objabi.R_ADDRMIPSTLS: - ctxt.Out.Write8(uint8(elf.R_MIPS_TLS_TPREL_LO16)) - case objabi.R_CALLMIPS, - objabi.R_JMPMIPS: - ctxt.Out.Write8(uint8(elf.R_MIPS_26)) - } - ctxt.Out.Write64(uint64(r.Xadd)) - - return true -} - -func elfsetupplt(ctxt *ld.Link) { - return -} - -func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool { - return false -} - -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { - if ctxt.LinkMode == ld.LinkExternal { - switch r.Type { - default: - return val, false - case objabi.R_ADDRMIPS, - objabi.R_ADDRMIPSU: - r.Done = false - - // set up addend for eventual relocation via outer symbol. - rs := r.Sym - r.Xadd = r.Add - for rs.Outer != nil { - r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer) - rs = rs.Outer - } - - if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil { - ld.Errorf(s, "missing section for %s", rs.Name) - } - r.Xsym = rs - - return val, true - case objabi.R_ADDRMIPSTLS, - objabi.R_CALLMIPS, - objabi.R_JMPMIPS: - r.Done = false - r.Xsym = r.Sym - r.Xadd = r.Add - return val, true - } - } - - switch r.Type { - case objabi.R_CONST: - return r.Add, true - case objabi.R_GOTOFF: - return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true - case objabi.R_ADDRMIPS, - objabi.R_ADDRMIPSU: - t := ld.Symaddr(r.Sym) + r.Add - o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:]) - if r.Type == objabi.R_ADDRMIPS { - return int64(o1&0xffff0000 | uint32(t)&0xffff), true - } - return int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff), true - case objabi.R_ADDRMIPSTLS: - // thread pointer is at 0x7000 offset from the start of TLS data area - t := ld.Symaddr(r.Sym) + r.Add - 0x7000 - if t < -32768 || t >= 32678 { - ld.Errorf(s, "TLS offset out of range %d", t) - } - o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:]) - return int64(o1&0xffff0000 | uint32(t)&0xffff), true - case objabi.R_CALLMIPS, - objabi.R_JMPMIPS: - // Low 26 bits = (S + A) >> 2 - t := ld.Symaddr(r.Sym) + r.Add - o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:]) - return int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000), true - } - - return val, false -} - -func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { - return -1 -} - -func asmb(ctxt *ld.Link) { - if ctxt.IsELF { - ld.Asmbelfsetup() - } - - sect := ld.Segtext.Sections[0] - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) - for _, sect = range ld.Segtext.Sections[1:] { - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) - } - - if ld.Segrodata.Filelen > 0 { - ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) - } - if ld.Segrelrodata.Filelen > 0 { - ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen)) - } - - ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) - - ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff)) - ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) -} - -func asmb2(ctxt *ld.Link) { - /* output symbol table */ - ld.Symsize = 0 - - ld.Lcsize = 0 - symo := uint32(0) - if !*ld.FlagS { - // TODO: rationalize - switch ctxt.HeadType { - default: - if ctxt.IsELF { - symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) - symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound))) - } - - case objabi.Hplan9: - symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) - } - - ctxt.Out.SeekSet(int64(symo)) - switch ctxt.HeadType { - default: - if ctxt.IsELF { - ld.Asmelfsym(ctxt) - ctxt.Out.Flush() - ctxt.Out.Write(ld.Elfstrdat) - - if ctxt.LinkMode == ld.LinkExternal { - ld.Elfemitreloc(ctxt) - } - } - - case objabi.Hplan9: - ld.Asmplan9sym(ctxt) - ctxt.Out.Flush() - - sym := ctxt.Syms.Lookup("pclntab", 0) - if sym != nil { - ld.Lcsize = int32(len(sym.P)) - ctxt.Out.Write(sym.P) - ctxt.Out.Flush() - } - } - } - - ctxt.Out.SeekSet(0) - switch ctxt.HeadType { - default: - case objabi.Hplan9: /* plan 9 */ - magic := uint32(4*18*18 + 7) - if ctxt.Arch == sys.ArchMIPS64LE { - magic = uint32(4*26*26 + 7) - } - ctxt.Out.Write32(magic) /* magic */ - ctxt.Out.Write32(uint32(ld.Segtext.Filelen)) /* sizes */ - ctxt.Out.Write32(uint32(ld.Segdata.Filelen)) - ctxt.Out.Write32(uint32(ld.Segdata.Length - ld.Segdata.Filelen)) - ctxt.Out.Write32(uint32(ld.Symsize)) /* nsyms */ - ctxt.Out.Write32(uint32(ld.Entryvalue(ctxt))) /* va of entry */ - ctxt.Out.Write32(0) - ctxt.Out.Write32(uint32(ld.Lcsize)) - - case objabi.Hlinux, - objabi.Hfreebsd, - objabi.Hnetbsd, - objabi.Hopenbsd: - ld.Asmbelf(ctxt, int64(symo)) - } - - ctxt.Out.Flush() - if *ld.FlagC { - fmt.Printf("textsize=%d\n", ld.Segtext.Filelen) - fmt.Printf("datsize=%d\n", ld.Segdata.Filelen) - fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen) - fmt.Printf("symsize=%d\n", ld.Symsize) - fmt.Printf("lcsize=%d\n", ld.Lcsize) - fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize)) - } -} diff --git a/src/cmd/oldlink/internal/mips64/l.go b/src/cmd/oldlink/internal/mips64/l.go deleted file mode 100644 index d794122f0b..0000000000 --- a/src/cmd/oldlink/internal/mips64/l.go +++ /dev/null @@ -1,74 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package mips64 - -// Writing object files. - -// cmd/9l/l.h from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -const ( - maxAlign = 32 // max data alignment - minAlign = 1 // min data alignment - funcAlign = 8 -) - -/* Used by ../internal/ld/dwarf.go */ -const ( - dwarfRegSP = 29 - dwarfRegLR = 31 -) diff --git a/src/cmd/oldlink/internal/mips64/obj.go b/src/cmd/oldlink/internal/mips64/obj.go deleted file mode 100644 index 1ddce45c06..0000000000 --- a/src/cmd/oldlink/internal/mips64/obj.go +++ /dev/null @@ -1,98 +0,0 @@ -// Inferno utils/5l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package mips64 - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" -) - -func Init() (*sys.Arch, ld.Arch) { - arch := sys.ArchMIPS64 - if objabi.GOARCH == "mips64le" { - arch = sys.ArchMIPS64LE - } - - theArch := ld.Arch{ - Funcalign: funcAlign, - Maxalign: maxAlign, - Minalign: minAlign, - Dwarfregsp: dwarfRegSP, - Dwarfreglr: dwarfRegLR, - Adddynrel: adddynrel, - Archinit: archinit, - Archreloc: archreloc, - Archrelocvariant: archrelocvariant, - Asmb: asmb, - Asmb2: asmb2, - Elfreloc1: elfreloc1, - Elfsetupplt: elfsetupplt, - Gentext: gentext, - Machoreloc1: machoreloc1, - - Linuxdynld: "/lib64/ld64.so.1", - Freebsddynld: "XXX", - Openbsddynld: "XXX", - Netbsddynld: "XXX", - Dragonflydynld: "XXX", - Solarisdynld: "XXX", - } - - return arch, theArch -} - -func archinit(ctxt *ld.Link) { - switch ctxt.HeadType { - default: - ld.Exitf("unknown -H option: %v", ctxt.HeadType) - - case objabi.Hplan9: /* plan 9 */ - ld.HEADR = 32 - - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 16*1024 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 16 * 1024 - } - - case objabi.Hlinux: /* mips64 elf */ - ld.Elfinit(ctxt) - ld.HEADR = ld.ELFRESERVE - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 0x10000 - } - } -} diff --git a/src/cmd/oldlink/internal/objfile/objfile.go b/src/cmd/oldlink/internal/objfile/objfile.go deleted file mode 100644 index 6882b7694b..0000000000 --- a/src/cmd/oldlink/internal/objfile/objfile.go +++ /dev/null @@ -1,664 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package objfile reads Go object files for the Go linker, cmd/link. -// -// This package is similar to cmd/internal/objfile which also reads -// Go object files. -package objfile - -import ( - "bufio" - "bytes" - "cmd/internal/bio" - "cmd/internal/dwarf" - "cmd/internal/goobj2" - "cmd/internal/obj" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/sym" - "fmt" - "internal/unsafeheader" - "io" - "log" - "os" - "strconv" - "strings" - "unsafe" -) - -const ( - startmagic = "\x00go114ld" - endmagic = "\xffgo114ld" -) - -var emptyPkg = []byte(`"".`) - -// objReader reads Go object files. -type objReader struct { - rd *bio.Reader - arch *sys.Arch - syms *sym.Symbols - lib *sym.Library - unit *sym.CompilationUnit - pn string - dupSym *sym.Symbol - localSymVersion int - flags int - strictDupMsgs int - dataSize int - - // rdBuf is used by readString and readSymName as scratch for reading strings. - rdBuf []byte - - // List of symbol references for the file being read. - refs []*sym.Symbol - data []byte - reloc []sym.Reloc - pcdata []sym.Pcdata - funcdata []*sym.Symbol - funcdataoff []int64 - file []*sym.Symbol - pkgpref string // objabi.PathToPrefix(r.lib.Pkg) + "." - - roObject []byte // from read-only mmap of object file (may be nil) - roOffset int64 // offset into readonly object data examined so far - - dataReadOnly bool // whether data is backed by read-only memory -} - -// Flags to enable optional behavior during object loading/reading. - -const ( - NoFlag int = iota - - // Sanity-check duplicate symbol contents, issuing warning - // when duplicates have different lengths or contents. - StrictDupsWarnFlag - - // Similar to StrictDupsWarnFlag, but issue fatal error. - StrictDupsErrFlag -) - -// Load loads an object file f into library lib. -// The symbols loaded are added to syms. -func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) int { - start := f.Offset() - roObject := f.SliceRO(uint64(length)) - if roObject != nil { - f.MustSeek(int64(-length), os.SEEK_CUR) - } - r := &objReader{ - rd: f, - lib: lib, - unit: unit, - arch: arch, - syms: syms, - pn: pn, - dupSym: &sym.Symbol{Name: ".dup"}, - localSymVersion: syms.IncVersion(), - flags: flags, - roObject: roObject, - pkgpref: objabi.PathToPrefix(lib.Pkg) + ".", - } - r.loadObjFile() - if roObject != nil { - if r.roOffset != length { - log.Fatalf("%s: unexpected end at %d, want %d", pn, r.roOffset, start+length) - } - r.rd.MustSeek(int64(length), os.SEEK_CUR) - } else if f.Offset() != start+length { - log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length) - } - return r.strictDupMsgs -} - -func (r *objReader) loadObjFile() { - // Magic header - var buf [8]uint8 - r.readFull(buf[:]) - if string(buf[:]) != startmagic { - if string(buf[:]) == goobj2.Magic { - log.Fatalf("found object file %s in new format, but -go115newobj is false\nset -go115newobj consistently in all -gcflags, -asmflags, and -ldflags", r.pn) - } - log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]) - } - - // Version - c, err := r.readByte() - if err != nil || c != 1 { - log.Fatalf("%s: invalid file version number %d", r.pn, c) - } - - // Autolib - for { - lib := r.readString() - if lib == "" { - break - } - r.lib.ImportStrings = append(r.lib.ImportStrings, lib) - } - - // DWARF strings - count := r.readInt() - r.unit.DWARFFileTable = make([]string, count) - for i := 0; i < count; i++ { - // TODO: This should probably be a call to mkROString. - r.unit.DWARFFileTable[i] = r.readString() - } - - // Symbol references - r.refs = []*sym.Symbol{nil} // zeroth ref is nil - for { - c, err := r.peek(1) - if err != nil { - log.Fatalf("%s: peeking: %v", r.pn, err) - } - if c[0] == 0xff { - r.readByte() - break - } - r.readRef() - } - - // Lengths - r.readSlices() - - // Data section - err = r.readDataSection() - if err != nil { - log.Fatalf("%s: error reading %s", r.pn, err) - } - - // Defined symbols - for { - c, err := r.peek(1) - if err != nil { - log.Fatalf("%s: peeking: %v", r.pn, err) - } - if c[0] == 0xff { - break - } - r.readSym() - } - - // Magic footer - buf = [8]uint8{} - r.readFull(buf[:]) - if string(buf[:]) != endmagic { - log.Fatalf("%s: invalid file end", r.pn) - } -} - -func (r *objReader) readSlices() { - r.dataSize = r.readInt() - n := r.readInt() - r.reloc = make([]sym.Reloc, n) - n = r.readInt() - r.pcdata = make([]sym.Pcdata, n) - _ = r.readInt() // TODO: remove on next object file rev (autom count) - n = r.readInt() - r.funcdata = make([]*sym.Symbol, n) - r.funcdataoff = make([]int64, n) - n = r.readInt() - r.file = make([]*sym.Symbol, n) -} - -func (r *objReader) readDataSection() (err error) { - if r.roObject != nil { - r.data, r.dataReadOnly, err = - r.roObject[r.roOffset:r.roOffset+int64(r.dataSize)], true, nil - r.roOffset += int64(r.dataSize) - return - } - r.data, r.dataReadOnly, err = r.rd.Slice(uint64(r.dataSize)) - return -} - -// Symbols are prefixed so their content doesn't get confused with the magic footer. -const symPrefix = 0xfe - -func (r *objReader) readSym() { - var c byte - var err error - if c, err = r.readByte(); c != symPrefix || err != nil { - log.Fatalln("readSym out of sync") - } - if c, err = r.readByte(); err != nil { - log.Fatalln("error reading input: ", err) - } - t := sym.AbiSymKindToSymKind[c] - s := r.readSymIndex() - flags := r.readInt() - dupok := flags&1 != 0 - local := flags&2 != 0 - makeTypelink := flags&4 != 0 - size := r.readInt() - typ := r.readSymIndex() - data := r.readData() - nreloc := r.readInt() - isdup := false - - var dup *sym.Symbol - if s.Type != 0 && s.Type != sym.SXREF { - if (t == sym.SDATA || t == sym.SBSS || t == sym.SNOPTRBSS) && len(data) == 0 && nreloc == 0 { - if s.Size < int64(size) { - s.Size = int64(size) - } - if typ != nil && s.Gotype == nil { - s.Gotype = typ - } - return - } - - if (s.Type == sym.SDATA || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 { - goto overwrite - } - if s.Type != sym.SBSS && s.Type != sym.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() { - log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn) - } - if len(s.P) > 0 { - dup = s - s = r.dupSym - isdup = true - } - } - -overwrite: - s.File = r.pkgpref[:len(r.pkgpref)-1] - s.Unit = r.unit - if dupok { - s.Attr |= sym.AttrDuplicateOK - } - if t == sym.SXREF { - log.Fatalf("bad sxref") - } - if t == 0 { - log.Fatalf("missing type for %s in %s", s.Name, r.pn) - } - if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) { - t = s.Type - } - s.Type = t - if s.Size < int64(size) { - s.Size = int64(size) - } - s.Attr.Set(sym.AttrLocal, local) - s.Attr.Set(sym.AttrMakeTypelink, makeTypelink) - if typ != nil { - s.Gotype = typ - } - if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def - dup.Gotype = typ - } - s.P = data - s.Attr.Set(sym.AttrReadOnly, r.dataReadOnly) - if nreloc > 0 { - s.R = r.reloc[:nreloc:nreloc] - if !isdup { - r.reloc = r.reloc[nreloc:] - } - - for i := 0; i < nreloc; i++ { - s.R[i] = sym.Reloc{ - Off: r.readInt32(), - Siz: r.readUint8(), - Type: objabi.RelocType(r.readInt32()), - Add: r.readInt64(), - Sym: r.readSymIndex(), - } - } - } - - if s.Type == sym.STEXT { - s.FuncInfo = new(sym.FuncInfo) - pc := s.FuncInfo - - pc.Args = r.readInt32() - pc.Locals = r.readInt32() - s.Align = r.readInt32() - if r.readUint8() != 0 { - s.Attr |= sym.AttrNoSplit - } - flags := r.readInt() - if flags&(1<<2) != 0 { - s.Attr |= sym.AttrReflectMethod - } - if flags&(1<<3) != 0 { - s.Attr |= sym.AttrShared - } - if flags&(1<<4) != 0 { - s.Attr |= sym.AttrTopFrame - } - n := r.readInt() - if n != 0 { - log.Fatalf("stale object file: autom count nonzero") - } - - pc.Pcsp.P = r.readData() - pc.Pcfile.P = r.readData() - pc.Pcline.P = r.readData() - pc.Pcinline.P = r.readData() - n = r.readInt() - pc.Pcdata = r.pcdata[:n:n] - if !isdup { - r.pcdata = r.pcdata[n:] - } - for i := 0; i < n; i++ { - pc.Pcdata[i].P = r.readData() - } - n = r.readInt() - pc.Funcdata = r.funcdata[:n:n] - pc.Funcdataoff = r.funcdataoff[:n:n] - if !isdup { - r.funcdata = r.funcdata[n:] - r.funcdataoff = r.funcdataoff[n:] - } - for i := 0; i < n; i++ { - pc.Funcdata[i] = r.readSymIndex() - } - for i := 0; i < n; i++ { - pc.Funcdataoff[i] = r.readInt64() - } - n = r.readInt() - pc.File = r.file[:n:n] - if !isdup { - r.file = r.file[n:] - } - for i := 0; i < n; i++ { - pc.File[i] = r.readSymIndex() - } - n = r.readInt() - pc.InlTree = make([]sym.InlinedCall, n) - for i := 0; i < n; i++ { - pc.InlTree[i].Parent = r.readInt32() - pc.InlTree[i].File = r.readSymIndex() - pc.InlTree[i].Line = r.readInt32() - pc.InlTree[i].Func = r.readSymIndex().Name - pc.InlTree[i].ParentPC = r.readInt32() - } - - if !dupok { - if s.Attr.OnList() { - log.Fatalf("symbol %s listed multiple times", s.Name) - } - s.Attr |= sym.AttrOnList - r.lib.Textp = append(r.lib.Textp, s) - } else { - // there may ba a dup in another package - // put into a temp list and add to text later - if !isdup { - r.lib.DupTextSyms = append(r.lib.DupTextSyms, s) - } else { - r.lib.DupTextSyms = append(r.lib.DupTextSyms, dup) - } - } - } - if s.Type == sym.SDWARFINFO { - r.patchDWARFName(s) - } - - if isdup && r.flags&(StrictDupsWarnFlag|StrictDupsErrFlag) != 0 { - // Compare the just-read symbol with the previously read - // symbol of the same name, verifying that they have the same - // payload. If not, issue a warning and possibly an error. - if !bytes.Equal(s.P, dup.P) { - reason := "same length but different contents" - if len(s.P) != len(dup.P) { - reason = fmt.Sprintf("new length %d != old length %d", - len(data), len(dup.P)) - } - fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Unit.Lib, reason) - - // For the moment, whitelist DWARF subprogram DIEs for - // auto-generated wrapper functions. What seems to happen - // here is that we get different line numbers on formal - // params; I am guessing that the pos is being inherited - // from the spot where the wrapper is needed. - whitelist := (strings.HasPrefix(dup.Name, "go.info.go.interface") || - strings.HasPrefix(dup.Name, "go.info.go.builtin") || - strings.HasPrefix(dup.Name, "go.isstmt.go.builtin") || - strings.HasPrefix(dup.Name, "go.debuglines")) - if !whitelist { - r.strictDupMsgs++ - } - } - } -} - -func (r *objReader) patchDWARFName(s *sym.Symbol) { - // This is kind of ugly. Really the package name should not - // even be included here. - if s.Size < 1 || s.P[0] != dwarf.DW_ABRV_FUNCTION { - return - } - e := bytes.IndexByte(s.P, 0) - if e == -1 { - return - } - p := bytes.Index(s.P[:e], emptyPkg) - if p == -1 { - return - } - pkgprefix := []byte(r.pkgpref) - patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1) - - s.P = append(patched, s.P[e:]...) - delta := int64(len(s.P)) - s.Size - s.Size = int64(len(s.P)) - for i := range s.R { - r := &s.R[i] - if r.Off > int32(e) { - r.Off += int32(delta) - } - } -} - -func (r *objReader) readFull(b []byte) { - if r.roObject != nil { - copy(b, r.roObject[r.roOffset:]) - r.roOffset += int64(len(b)) - return - } - _, err := io.ReadFull(r.rd, b) - if err != nil { - log.Fatalf("%s: error reading %s", r.pn, err) - } -} - -func (r *objReader) readByte() (byte, error) { - if r.roObject != nil { - b := r.roObject[r.roOffset] - r.roOffset++ - return b, nil - } - return r.rd.ReadByte() -} - -func (r *objReader) peek(n int) ([]byte, error) { - if r.roObject != nil { - return r.roObject[r.roOffset : r.roOffset+int64(n)], nil - } - return r.rd.Peek(n) -} - -func (r *objReader) readRef() { - if c, err := r.readByte(); c != symPrefix || err != nil { - log.Fatalf("readSym out of sync") - } - name := r.readSymName() - var v int - if abi := r.readInt(); abi == -1 { - // Static - v = r.localSymVersion - } else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 { - // Note that data symbols are "ABI0", which maps to version 0. - v = abiver - } else { - log.Fatalf("invalid symbol ABI for %q: %d", name, abi) - } - s := r.syms.Lookup(name, v) - r.refs = append(r.refs, s) - - if s == nil || v == r.localSymVersion { - return - } - if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 { - x, err := strconv.ParseUint(s.Name[5:], 16, 64) - if err != nil { - log.Panicf("failed to parse $-symbol %s: %v", s.Name, err) - } - s.Type = sym.SRODATA - s.Attr |= sym.AttrLocal - switch s.Name[:5] { - case "$f32.": - if uint64(uint32(x)) != x { - log.Panicf("$-symbol %s too large: %d", s.Name, x) - } - s.AddUint32(r.arch, uint32(x)) - case "$f64.", "$i64.": - s.AddUint64(r.arch, x) - default: - log.Panicf("unrecognized $-symbol: %s", s.Name) - } - s.Attr.Set(sym.AttrReachable, false) - } - if strings.HasPrefix(s.Name, "runtime.gcbits.") { - s.Attr |= sym.AttrLocal - } -} - -func (r *objReader) readInt64() int64 { - uv := uint64(0) - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - log.Fatalf("corrupt input") - } - c, err := r.readByte() - if err != nil { - log.Fatalln("error reading input: ", err) - } - uv |= uint64(c&0x7F) << shift - if c&0x80 == 0 { - break - } - } - - return int64(uv>>1) ^ (int64(uv<<63) >> 63) -} - -func (r *objReader) readInt() int { - n := r.readInt64() - if int64(int(n)) != n { - log.Panicf("%v out of range for int", n) - } - return int(n) -} - -func (r *objReader) readInt32() int32 { - n := r.readInt64() - if int64(int32(n)) != n { - log.Panicf("%v out of range for int32", n) - } - return int32(n) -} - -func (r *objReader) readInt16() int16 { - n := r.readInt64() - if int64(int16(n)) != n { - log.Panicf("%v out of range for int16", n) - } - return int16(n) -} - -func (r *objReader) readUint8() uint8 { - n := r.readInt64() - if int64(uint8(n)) != n { - log.Panicf("%v out of range for uint8", n) - } - return uint8(n) -} - -func (r *objReader) readString() string { - n := r.readInt() - if cap(r.rdBuf) < n { - r.rdBuf = make([]byte, 2*n) - } - r.readFull(r.rdBuf[:n]) - return string(r.rdBuf[:n]) -} - -func (r *objReader) readData() []byte { - n := r.readInt() - p := r.data[:n:n] - r.data = r.data[n:] - return p -} - -func mkROString(rodata []byte) string { - if len(rodata) == 0 { - return "" - } - - var s string - hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) - hdr.Data = unsafe.Pointer(&rodata[0]) - hdr.Len = len(rodata) - - return s -} - -// readSymName reads a symbol name, replacing all "". with pkg. -func (r *objReader) readSymName() string { - n := r.readInt() - if n == 0 { - r.readInt64() - return "" - } - if cap(r.rdBuf) < n { - r.rdBuf = make([]byte, 2*n) - } - sOffset := r.roOffset - origName, err := r.peek(n) - if err == bufio.ErrBufferFull { - // Long symbol names are rare but exist. One source is type - // symbols for types with long string forms. See #15104. - origName = make([]byte, n) - r.readFull(origName) - } else if err != nil { - log.Fatalf("%s: error reading symbol: %v", r.pn, err) - } - adjName := r.rdBuf[:0] - nPkgRefs := 0 - for { - i := bytes.Index(origName, emptyPkg) - if i == -1 { - var s string - if r.roObject != nil && nPkgRefs == 0 { - s = mkROString(r.roObject[sOffset : sOffset+int64(n)]) - } else { - s = string(append(adjName, origName...)) - } - // Read past the peeked origName, now that we're done with it, - // using the rfBuf (also no longer used) as the scratch space. - // TODO: use bufio.Reader.Discard if available instead? - if err == nil { - r.readFull(r.rdBuf[:n]) - } - r.rdBuf = adjName[:0] // in case 2*n wasn't enough - return s - } - nPkgRefs++ - adjName = append(adjName, origName[:i]...) - adjName = append(adjName, r.pkgpref[:len(r.pkgpref)-1]...) - adjName = append(adjName, '.') - origName = origName[i+len(emptyPkg):] - } -} - -// Reads the index of a symbol reference and resolves it to a symbol -func (r *objReader) readSymIndex() *sym.Symbol { - i := r.readInt() - return r.refs[i] -} diff --git a/src/cmd/oldlink/internal/ppc64/asm.go b/src/cmd/oldlink/internal/ppc64/asm.go deleted file mode 100644 index 608bdecca6..0000000000 --- a/src/cmd/oldlink/internal/ppc64/asm.go +++ /dev/null @@ -1,1181 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ppc64 - -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)) - } -} diff --git a/src/cmd/oldlink/internal/ppc64/l.go b/src/cmd/oldlink/internal/ppc64/l.go deleted file mode 100644 index c78535be58..0000000000 --- a/src/cmd/oldlink/internal/ppc64/l.go +++ /dev/null @@ -1,74 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ppc64 - -// Writing object files. - -// cmd/9l/l.h from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -const ( - maxAlign = 32 // max data alignment - minAlign = 1 // min data alignment - funcAlign = 16 -) - -/* Used by ../internal/ld/dwarf.go */ -const ( - dwarfRegSP = 1 - dwarfRegLR = 65 -) diff --git a/src/cmd/oldlink/internal/ppc64/obj.go b/src/cmd/oldlink/internal/ppc64/obj.go deleted file mode 100644 index e9da5a36d5..0000000000 --- a/src/cmd/oldlink/internal/ppc64/obj.go +++ /dev/null @@ -1,106 +0,0 @@ -// Inferno utils/5l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package ppc64 - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" -) - -func Init() (*sys.Arch, ld.Arch) { - arch := sys.ArchPPC64 - if objabi.GOARCH == "ppc64le" { - arch = sys.ArchPPC64LE - } - - theArch := ld.Arch{ - Funcalign: funcAlign, - Maxalign: maxAlign, - Minalign: minAlign, - Dwarfregsp: dwarfRegSP, - Dwarfreglr: dwarfRegLR, - - Adddynrel: adddynrel, - Archinit: archinit, - Archreloc: archreloc, - Archrelocvariant: archrelocvariant, - Asmb: asmb, - Asmb2: asmb2, - Elfreloc1: elfreloc1, - Elfsetupplt: elfsetupplt, - Gentext: gentext, - Trampoline: trampoline, - Machoreloc1: machoreloc1, - Xcoffreloc1: xcoffreloc1, - - // TODO(austin): ABI v1 uses /usr/lib/ld.so.1, - Linuxdynld: "/lib64/ld64.so.1", - - Freebsddynld: "XXX", - Openbsddynld: "XXX", - Netbsddynld: "XXX", - Dragonflydynld: "XXX", - Solarisdynld: "XXX", - } - - return arch, theArch -} - -func archinit(ctxt *ld.Link) { - switch ctxt.HeadType { - default: - ld.Exitf("unknown -H option: %v", ctxt.HeadType) - - case objabi.Hplan9: /* plan 9 */ - ld.HEADR = 32 - - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 4128 - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 4096 - } - - case objabi.Hlinux: /* ppc64 elf */ - ld.Elfinit(ctxt) - ld.HEADR = ld.ELFRESERVE - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 0x10000 - } - - case objabi.Haix: - ld.Xcoffinit(ctxt) - } -} diff --git a/src/cmd/oldlink/internal/riscv64/asm.go b/src/cmd/oldlink/internal/riscv64/asm.go deleted file mode 100644 index f4db32df8a..0000000000 --- a/src/cmd/oldlink/internal/riscv64/asm.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package riscv64 - -import ( - "cmd/internal/obj/riscv" - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" - "cmd/oldlink/internal/sym" - "fmt" - "log" -) - -func gentext(ctxt *ld.Link) { -} - -func adddynrela(ctxt *ld.Link, rel *sym.Symbol, s *sym.Symbol, r *sym.Reloc) { - log.Fatalf("adddynrela not implemented") -} - -func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { - log.Fatalf("adddynrel not implemented") - return false -} - -func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { - log.Fatalf("elfreloc1") - return false -} - -func elfsetupplt(ctxt *ld.Link) { - log.Fatalf("elfsetuplt") -} - -func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool { - log.Fatalf("machoreloc1 not implemented") - return false -} - -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { - switch r.Type { - case objabi.R_CALLRISCV: - // Nothing to do. - return val, true - - case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE: - pc := s.Value + int64(r.Off) - off := ld.Symaddr(r.Sym) + r.Add - pc - - // Generate AUIPC and second instruction immediates. - low, high, err := riscv.Split32BitImmediate(off) - if err != nil { - ld.Errorf(s, "R_RISCV_PCREL_ relocation does not fit in 32-bits: %d", off) - } - - auipcImm, err := riscv.EncodeUImmediate(high) - if err != nil { - ld.Errorf(s, "cannot encode R_RISCV_PCREL_ AUIPC relocation offset for %s: %v", r.Sym.Name, err) - } - - var secondImm, secondImmMask int64 - switch r.Type { - case objabi.R_RISCV_PCREL_ITYPE: - secondImmMask = riscv.ITypeImmMask - secondImm, err = riscv.EncodeIImmediate(low) - if err != nil { - ld.Errorf(s, "cannot encode R_RISCV_PCREL_ITYPE I-type instruction relocation offset for %s: %v", r.Sym.Name, err) - } - case objabi.R_RISCV_PCREL_STYPE: - secondImmMask = riscv.STypeImmMask - secondImm, err = riscv.EncodeSImmediate(low) - if err != nil { - ld.Errorf(s, "cannot encode R_RISCV_PCREL_STYPE S-type instruction relocation offset for %s: %v", r.Sym.Name, err) - } - default: - panic(fmt.Sprintf("Unknown relocation type: %v", r.Type)) - } - - auipc := int64(uint32(val)) - second := int64(uint32(val >> 32)) - - auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm)) - second = (second &^ secondImmMask) | int64(uint32(secondImm)) - - return second<<32 | auipc, true - } - - return val, false -} - -func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { - log.Fatalf("archrelocvariant") - return -1 -} - -func asmb(ctxt *ld.Link) { - if ctxt.IsELF { - ld.Asmbelfsetup() - } - - sect := ld.Segtext.Sections[0] - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) - for _, sect = range ld.Segtext.Sections[1:] { - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) - } - - if ld.Segrodata.Filelen > 0 { - ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) - } - if ld.Segrelrodata.Filelen > 0 { - ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen)) - } - - ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) - - ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff)) - ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) -} - -func asmb2(ctxt *ld.Link) { - ld.Symsize = 0 - ld.Lcsize = 0 - symo := uint32(0) - - if !*ld.FlagS { - if !ctxt.IsELF { - ld.Errorf(nil, "unsupported executable format") - } - - symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) - symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound))) - ctxt.Out.SeekSet(int64(symo)) - - ld.Asmelfsym(ctxt) - ctxt.Out.Flush() - ctxt.Out.Write(ld.Elfstrdat) - - if ctxt.LinkMode == ld.LinkExternal { - ld.Elfemitreloc(ctxt) - } - } - - ctxt.Out.SeekSet(0) - switch ctxt.HeadType { - case objabi.Hlinux: - ld.Asmbelf(ctxt, int64(symo)) - default: - ld.Errorf(nil, "unsupported operating system") - } - ctxt.Out.Flush() - - if *ld.FlagC { - fmt.Printf("textsize=%d\n", ld.Segtext.Filelen) - fmt.Printf("datsize=%d\n", ld.Segdata.Filelen) - fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen) - fmt.Printf("symsize=%d\n", ld.Symsize) - fmt.Printf("lcsize=%d\n", ld.Lcsize) - fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize)) - } -} diff --git a/src/cmd/oldlink/internal/riscv64/l.go b/src/cmd/oldlink/internal/riscv64/l.go deleted file mode 100644 index a302657726..0000000000 --- a/src/cmd/oldlink/internal/riscv64/l.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package riscv64 - -const ( - maxAlign = 32 // max data alignment - minAlign = 1 - funcAlign = 8 - - dwarfRegLR = 1 - dwarfRegSP = 2 -) diff --git a/src/cmd/oldlink/internal/riscv64/obj.go b/src/cmd/oldlink/internal/riscv64/obj.go deleted file mode 100644 index a6a5adb86c..0000000000 --- a/src/cmd/oldlink/internal/riscv64/obj.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package riscv64 - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" -) - -func Init() (*sys.Arch, ld.Arch) { - arch := sys.ArchRISCV64 - - theArch := ld.Arch{ - Funcalign: funcAlign, - Maxalign: maxAlign, - Minalign: minAlign, - Dwarfregsp: dwarfRegSP, - Dwarfreglr: dwarfRegLR, - - Adddynrel: adddynrel, - Archinit: archinit, - Archreloc: archreloc, - Archrelocvariant: archrelocvariant, - Asmb: asmb, - Asmb2: asmb2, - Elfreloc1: elfreloc1, - Elfsetupplt: elfsetupplt, - Gentext: gentext, - Machoreloc1: machoreloc1, - - Linuxdynld: "/lib/ld.so.1", - - Freebsddynld: "XXX", - Netbsddynld: "XXX", - Openbsddynld: "XXX", - Dragonflydynld: "XXX", - Solarisdynld: "XXX", - } - - return arch, theArch -} - -func archinit(ctxt *ld.Link) { - switch ctxt.HeadType { - case objabi.Hlinux: - ld.Elfinit(ctxt) - ld.HEADR = ld.ELFRESERVE - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 0x10000 - } - default: - ld.Exitf("unknown -H option: %v", ctxt.HeadType) - } -} diff --git a/src/cmd/oldlink/internal/s390x/asm.go b/src/cmd/oldlink/internal/s390x/asm.go deleted file mode 100644 index 6c5744dc95..0000000000 --- a/src/cmd/oldlink/internal/s390x/asm.go +++ /dev/null @@ -1,574 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package s390x - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" - "cmd/oldlink/internal/sym" - "debug/elf" - "fmt" -) - -// gentext generates assembly to append the local moduledata to the global -// moduledata linked list at initialization time. This is only done if the runtime -// is in a different module. -// -// : -// larl %r2, -// jg -// 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, - 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 - 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)) - } -} diff --git a/src/cmd/oldlink/internal/s390x/l.go b/src/cmd/oldlink/internal/s390x/l.go deleted file mode 100644 index 87d10ee782..0000000000 --- a/src/cmd/oldlink/internal/s390x/l.go +++ /dev/null @@ -1,74 +0,0 @@ -// Inferno utils/5l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package s390x - -// Writing object files. - -// cmd/9l/l.h from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -const ( - maxAlign = 32 // max data alignment - minAlign = 2 // min data alignment - funcAlign = 16 -) - -/* Used by ../internal/ld/dwarf.go */ -const ( - dwarfRegSP = 15 - dwarfRegLR = 14 -) diff --git a/src/cmd/oldlink/internal/s390x/obj.go b/src/cmd/oldlink/internal/s390x/obj.go deleted file mode 100644 index b4af86bd75..0000000000 --- a/src/cmd/oldlink/internal/s390x/obj.go +++ /dev/null @@ -1,88 +0,0 @@ -// Inferno utils/5l/obj.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package s390x - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" -) - -func Init() (*sys.Arch, ld.Arch) { - arch := sys.ArchS390X - - theArch := ld.Arch{ - Funcalign: funcAlign, - Maxalign: maxAlign, - Minalign: minAlign, - Dwarfregsp: dwarfRegSP, - Dwarfreglr: dwarfRegLR, - - Adddynrel: adddynrel, - Archinit: archinit, - Archreloc: archreloc, - Archrelocvariant: archrelocvariant, - Asmb: asmb, // in asm.go - Asmb2: asmb2, // in asm.go - Elfreloc1: elfreloc1, - Elfsetupplt: elfsetupplt, - Gentext: gentext, - Machoreloc1: machoreloc1, - - Linuxdynld: "/lib64/ld64.so.1", - - // not relevant for s390x - Freebsddynld: "XXX", - Openbsddynld: "XXX", - Netbsddynld: "XXX", - Dragonflydynld: "XXX", - Solarisdynld: "XXX", - } - - return arch, theArch -} - -func archinit(ctxt *ld.Link) { - switch ctxt.HeadType { - default: - ld.Exitf("unknown -H option: %v", ctxt.HeadType) - - case objabi.Hlinux: // s390x ELF - ld.Elfinit(ctxt) - ld.HEADR = ld.ELFRESERVE - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR) - } - if *ld.FlagRound == -1 { - *ld.FlagRound = 0x10000 - } - } -} diff --git a/src/cmd/oldlink/internal/sym/attribute.go b/src/cmd/oldlink/internal/sym/attribute.go deleted file mode 100644 index 4b69bf32d0..0000000000 --- a/src/cmd/oldlink/internal/sym/attribute.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sym - -// Attribute is a set of common symbol attributes. -type Attribute int32 - -const ( - // AttrDuplicateOK marks a symbol that can be present in multiple object - // files. - AttrDuplicateOK Attribute = 1 << iota - // AttrExternal marks function symbols loaded from host object files. - AttrExternal - // AttrNoSplit marks functions that cannot split the stack; the linker - // cares because it checks that there are no call chains of nosplit - // functions that require more than StackLimit bytes (see - // lib.go:dostkcheck) - AttrNoSplit - // AttrReachable marks symbols that are transitively referenced from the - // entry points. Unreachable symbols are not written to the output. - AttrReachable - // AttrCgoExportDynamic and AttrCgoExportStatic mark symbols referenced - // by directives written by cgo (in response to //export directives in - // the source). - AttrCgoExportDynamic - AttrCgoExportStatic - // AttrSpecial marks symbols that do not have their address (i.e. Value) - // computed by the usual mechanism of data.go:dodata() & - // data.go:address(). - AttrSpecial - // AttrStackCheck is used by dostkcheck to only check each NoSplit - // function's stack usage once. - AttrStackCheck - // AttrNotInSymbolTable marks symbols that are not written to the symbol table. - AttrNotInSymbolTable - // AttrOnList marks symbols that are on some list (such as the list of - // all text symbols, or one of the lists of data symbols) and is - // consulted to avoid bugs where a symbol is put on a list twice. - AttrOnList - // AttrLocal marks symbols that are only visible within the module - // (executable or shared library) being linked. Only relevant when - // dynamically linking Go code. - AttrLocal - // AttrReflectMethod marks certain methods from the reflect package that - // can be used to call arbitrary methods. If no symbol with this bit set - // is marked as reachable, more dead code elimination can be done. - AttrReflectMethod - // AttrMakeTypelink Amarks types that should be added to the typelink - // table. See typelinks.go:typelinks(). - AttrMakeTypelink - // AttrShared marks symbols compiled with the -shared option. - AttrShared - // AttrVisibilityHidden symbols are ELF symbols with - // visibility set to STV_HIDDEN. They become local symbols in - // the final executable. Only relevant when internally linking - // on an ELF platform. - AttrVisibilityHidden - // AttrSubSymbol mostly means that the symbol appears on the Sub list of some - // other symbol. Unfortunately, it's not 100% reliable; at least, it's not set - // correctly for the .TOC. symbol in Link.dodata. Usually the Outer field of the - // symbol points to the symbol whose list it is on, but that it is not set for the - // symbols added to .windynamic in initdynimport in pe.go. - // - // TODO(mwhudson): fix the inconsistencies noticed above. - // - // Sub lists are used when loading host objects (sections from the host object - // become regular linker symbols and symbols go on the Sub list of their section) - // and for constructing the global offset table when internally linking a dynamic - // executable. - // - // TODO(mwhudson): perhaps a better name for this is AttrNonGoSymbol. - AttrSubSymbol - // AttrContainer is set on text symbols that are present as the .Outer for some - // other symbol. - AttrContainer - // AttrTopFrame means that the function is an entry point and unwinders - // should stop when they hit this function. - AttrTopFrame - // AttrReadOnly indicates whether the symbol's content (Symbol.P) is backed by - // read-only memory. - AttrReadOnly - // 19 attributes defined so far. -) - -func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 } -func (a Attribute) External() bool { return a&AttrExternal != 0 } -func (a Attribute) NoSplit() bool { return a&AttrNoSplit != 0 } -func (a Attribute) Reachable() bool { return a&AttrReachable != 0 } -func (a Attribute) CgoExportDynamic() bool { return a&AttrCgoExportDynamic != 0 } -func (a Attribute) CgoExportStatic() bool { return a&AttrCgoExportStatic != 0 } -func (a Attribute) Special() bool { return a&AttrSpecial != 0 } -func (a Attribute) StackCheck() bool { return a&AttrStackCheck != 0 } -func (a Attribute) NotInSymbolTable() bool { return a&AttrNotInSymbolTable != 0 } -func (a Attribute) OnList() bool { return a&AttrOnList != 0 } -func (a Attribute) Local() bool { return a&AttrLocal != 0 } -func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 } -func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 } -func (a Attribute) Shared() bool { return a&AttrShared != 0 } -func (a Attribute) VisibilityHidden() bool { return a&AttrVisibilityHidden != 0 } -func (a Attribute) SubSymbol() bool { return a&AttrSubSymbol != 0 } -func (a Attribute) Container() bool { return a&AttrContainer != 0 } -func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 } -func (a Attribute) ReadOnly() bool { return a&AttrReadOnly != 0 } - -func (a Attribute) CgoExport() bool { - return a.CgoExportDynamic() || a.CgoExportStatic() -} - -func (a *Attribute) Set(flag Attribute, value bool) { - if value { - *a |= flag - } else { - *a &^= flag - } -} diff --git a/src/cmd/oldlink/internal/sym/compilation_unit.go b/src/cmd/oldlink/internal/sym/compilation_unit.go deleted file mode 100644 index 02fb0cfab8..0000000000 --- a/src/cmd/oldlink/internal/sym/compilation_unit.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sym - -import "cmd/internal/dwarf" - -// CompilationUnit is an abstraction used by DWARF to represent a chunk of -// debug-related data. We create a CompilationUnit per Object file in a -// library (so, one for all the Go code, one for each assembly file, etc.). -type CompilationUnit struct { - Pkg string // The package name, eg ("fmt", or "runtime") - Lib *Library // Our library - Consts *Symbol // Package constants DIEs - PCs []dwarf.Range // PC ranges, relative to Textp[0] - DWInfo *dwarf.DWDie // CU root DIE - FuncDIEs []*Symbol // Function DIE subtrees - AbsFnDIEs []*Symbol // Abstract function DIE subtrees - RangeSyms []*Symbol // Symbols for debug_range - Textp []*Symbol // Text symbols in this CU - DWARFFileTable []string // The file table used to generate the .debug_lines -} diff --git a/src/cmd/oldlink/internal/sym/library.go b/src/cmd/oldlink/internal/sym/library.go deleted file mode 100644 index 4f2023b8f7..0000000000 --- a/src/cmd/oldlink/internal/sym/library.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sym - -type Library struct { - Objref string - Srcref string - File string - Pkg string - Shlib string - Hash string - ImportStrings []string - Imports []*Library - Textp []*Symbol // text symbols defined in this library - DupTextSyms []*Symbol // dupok text symbols defined in this library - Main bool - Safe bool - Units []*CompilationUnit -} - -func (l Library) String() string { - return l.Pkg -} diff --git a/src/cmd/oldlink/internal/sym/reloc.go b/src/cmd/oldlink/internal/sym/reloc.go deleted file mode 100644 index 4809db8c80..0000000000 --- a/src/cmd/oldlink/internal/sym/reloc.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sym - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "debug/elf" -) - -// Reloc is a relocation. -// -// The typical Reloc rewrites part of a symbol at offset Off to address Sym. -// A Reloc is stored in a slice on the Symbol it rewrites. -// -// Relocations are generated by the compiler as the type -// cmd/internal/obj.Reloc, which is encoded into the object file wire -// format and decoded by the linker into this type. A separate type is -// used to hold linker-specific state about the relocation. -// -// Some relocations are created by cmd/link. -type Reloc struct { - Off int32 // offset to rewrite - Siz uint8 // number of bytes to rewrite, 1, 2, or 4 - Done bool // set to true when relocation is complete - Type objabi.RelocType // the relocation type - Add int64 // addend - Sym *Symbol // symbol the relocation addresses - *relocExt // extra fields (see below), may be nil, call InitExt before use -} - -// relocExt contains extra fields in Reloc that are used only in -// certain cases. -type relocExt struct { - Xadd int64 // addend passed to external linker - Xsym *Symbol // symbol passed to external linker - Variant RelocVariant // variation on Type, currently used only on PPC64 and S390X -} - -func (r *Reloc) InitExt() { - if r.relocExt == nil { - r.relocExt = new(relocExt) - } -} - -// RelocVariant is a linker-internal variation on a relocation. -type RelocVariant uint8 - -const ( - RV_NONE RelocVariant = iota - RV_POWER_LO - RV_POWER_HI - RV_POWER_HA - RV_POWER_DS - - // RV_390_DBL is a s390x-specific relocation variant that indicates that - // the value to be placed into the relocatable field should first be - // divided by 2. - RV_390_DBL - - RV_CHECK_OVERFLOW RelocVariant = 1 << 7 - RV_TYPE_MASK RelocVariant = RV_CHECK_OVERFLOW - 1 -) - -func RelocName(arch *sys.Arch, r objabi.RelocType) string { - // We didn't have some relocation types at Go1.4. - // Uncomment code when we include those in bootstrap code. - - switch { - case r >= objabi.MachoRelocOffset: // Mach-O - // nr := (r - objabi.MachoRelocOffset)>>1 - // switch ctxt.Arch.Family { - // case sys.AMD64: - // return macho.RelocTypeX86_64(nr).String() - // case sys.ARM: - // return macho.RelocTypeARM(nr).String() - // case sys.ARM64: - // return macho.RelocTypeARM64(nr).String() - // case sys.I386: - // return macho.RelocTypeGeneric(nr).String() - // default: - // panic("unreachable") - // } - case r >= objabi.ElfRelocOffset: // ELF - nr := r - objabi.ElfRelocOffset - switch arch.Family { - case sys.AMD64: - return elf.R_X86_64(nr).String() - case sys.ARM: - return elf.R_ARM(nr).String() - case sys.ARM64: - return elf.R_AARCH64(nr).String() - case sys.I386: - return elf.R_386(nr).String() - case sys.MIPS, sys.MIPS64: - return elf.R_MIPS(nr).String() - case sys.PPC64: - return elf.R_PPC64(nr).String() - case sys.S390X: - return elf.R_390(nr).String() - default: - panic("unreachable") - } - } - - return r.String() -} - -// RelocByOff implements sort.Interface for sorting relocations by offset. -type RelocByOff []Reloc - -func (x RelocByOff) Len() int { return len(x) } - -func (x RelocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x RelocByOff) Less(i, j int) bool { - a := &x[i] - b := &x[j] - if a.Off < b.Off { - return true - } - if a.Off > b.Off { - return false - } - return false -} diff --git a/src/cmd/oldlink/internal/sym/segment.go b/src/cmd/oldlink/internal/sym/segment.go deleted file mode 100644 index d5255bf142..0000000000 --- a/src/cmd/oldlink/internal/sym/segment.go +++ /dev/null @@ -1,58 +0,0 @@ -// Inferno utils/8l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package sym - -// Terrible but standard terminology. -// A segment describes a block of file to load into memory. -// A section further describes the pieces of that block for -// use in debuggers and such. - -type Segment struct { - Rwx uint8 // permission as usual unix bits (5 = r-x etc) - Vaddr uint64 // virtual address - Length uint64 // length in memory - Fileoff uint64 // file offset - Filelen uint64 // length on disk - Sections []*Section -} - -type Section struct { - Rwx uint8 - Extnum int16 - Align int32 - Name string - Vaddr uint64 - Length uint64 - Seg *Segment - Elfsect interface{} // an *ld.ElfShdr - Reloff uint64 - Rellen uint64 -} diff --git a/src/cmd/oldlink/internal/sym/sizeof_test.go b/src/cmd/oldlink/internal/sym/sizeof_test.go deleted file mode 100644 index e6e3916dad..0000000000 --- a/src/cmd/oldlink/internal/sym/sizeof_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sym - -import ( - "reflect" - "testing" - "unsafe" -) - -// Assert that the size of important structures do not change unexpectedly. - -func TestSizeof(t *testing.T) { - const nbit = unsafe.Sizeof(uintptr(0)) * 8 - const _64bit = nbit == 64 - - var tests = []struct { - val interface{} // type as a value - _32bit uintptr // size on 32bit platforms - _64bit uintptr // size on 64bit platforms - }{ - {Symbol{}, 108, 176}, - } - - for _, tt := range tests { - want := tt._32bit - if _64bit { - want = tt._64bit - } - got := reflect.TypeOf(tt.val).Size() - if want != got { - t.Errorf("%d bit unsafe.Sizeof(%T) = %d, want %d", nbit, tt.val, got, want) - } - } -} diff --git a/src/cmd/oldlink/internal/sym/symbol.go b/src/cmd/oldlink/internal/sym/symbol.go deleted file mode 100644 index 2756acd211..0000000000 --- a/src/cmd/oldlink/internal/sym/symbol.go +++ /dev/null @@ -1,543 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sym - -import ( - "cmd/internal/obj" - "cmd/internal/objabi" - "cmd/internal/sys" - "debug/elf" - "fmt" - "log" -) - -// Symbol is an entry in the symbol table. -type Symbol struct { - Name string - Type SymKind - Version int16 - Attr Attribute - Dynid int32 - Align int32 - Elfsym int32 - LocalElfsym int32 - Value int64 - Size int64 - Sub *Symbol - Outer *Symbol - Gotype *Symbol - File string // actually package! - auxinfo *AuxSymbol - Sect *Section - FuncInfo *FuncInfo - Unit *CompilationUnit - // P contains the raw symbol data. - P []byte - R []Reloc -} - -// AuxSymbol contains less-frequently used sym.Symbol fields. -type AuxSymbol struct { - extname string - dynimplib string - dynimpvers string - localentry uint8 - plt int32 - got int32 - // ElfType is set for symbols read from shared libraries by ldshlibsyms. It - // is not set for symbols defined by the packages being linked or by symbols - // read by ldelf (and so is left as elf.STT_NOTYPE). - elftype elf.SymType -} - -const ( - SymVerABI0 = 0 - SymVerABIInternal = 1 - SymVerStatic = 10 // Minimum version used by static (file-local) syms -) - -func ABIToVersion(abi obj.ABI) int { - switch abi { - case obj.ABI0: - return SymVerABI0 - case obj.ABIInternal: - return SymVerABIInternal - } - return -1 -} - -func VersionToABI(v int) (obj.ABI, bool) { - switch v { - case SymVerABI0: - return obj.ABI0, true - case SymVerABIInternal: - return obj.ABIInternal, true - } - return ^obj.ABI(0), false -} - -func (s *Symbol) String() string { - if s.Version == 0 { - return s.Name - } - return fmt.Sprintf("%s<%d>", s.Name, s.Version) -} - -func (s *Symbol) IsFileLocal() bool { - return s.Version >= SymVerStatic -} - -func (s *Symbol) ElfsymForReloc() int32 { - // If putelfsym created a local version of this symbol, use that in all - // relocations. - if s.LocalElfsym != 0 { - return s.LocalElfsym - } else { - return s.Elfsym - } -} - -func (s *Symbol) Length(_ interface{}) int64 { - return s.Size -} - -func (s *Symbol) Grow(siz int64) { - if int64(int(siz)) != siz { - log.Fatalf("symgrow size %d too long", siz) - } - if int64(len(s.P)) >= siz { - return - } - if cap(s.P) < int(siz) { - p := make([]byte, 2*(siz+1)) - s.P = append(p[:0], s.P...) - } - s.P = s.P[:siz] -} - -func (s *Symbol) AddBytes(bytes []byte) int64 { - if s.Type == 0 { - s.Type = SDATA - } - s.Attr |= AttrReachable - s.P = append(s.P, bytes...) - s.Size = int64(len(s.P)) - - return s.Size -} - -func (s *Symbol) AddUint8(v uint8) int64 { - off := s.Size - if s.Type == 0 { - s.Type = SDATA - } - s.Attr |= AttrReachable - s.Size++ - s.P = append(s.P, v) - - return off -} - -func (s *Symbol) AddUint16(arch *sys.Arch, v uint16) int64 { - return s.AddUintXX(arch, uint64(v), 2) -} - -func (s *Symbol) AddUint32(arch *sys.Arch, v uint32) int64 { - return s.AddUintXX(arch, uint64(v), 4) -} - -func (s *Symbol) AddUint64(arch *sys.Arch, v uint64) int64 { - return s.AddUintXX(arch, v, 8) -} - -func (s *Symbol) AddUint(arch *sys.Arch, v uint64) int64 { - return s.AddUintXX(arch, v, arch.PtrSize) -} - -func (s *Symbol) SetUint8(arch *sys.Arch, r int64, v uint8) int64 { - return s.setUintXX(arch, r, uint64(v), 1) -} - -func (s *Symbol) SetUint16(arch *sys.Arch, r int64, v uint16) int64 { - return s.setUintXX(arch, r, uint64(v), 2) -} - -func (s *Symbol) SetUint32(arch *sys.Arch, r int64, v uint32) int64 { - return s.setUintXX(arch, r, uint64(v), 4) -} - -func (s *Symbol) SetUint(arch *sys.Arch, r int64, v uint64) int64 { - return s.setUintXX(arch, r, v, int64(arch.PtrSize)) -} - -func (s *Symbol) addAddrPlus(arch *sys.Arch, t *Symbol, add int64, typ objabi.RelocType) int64 { - if s.Type == 0 { - s.Type = SDATA - } - s.Attr |= AttrReachable - i := s.Size - s.Size += int64(arch.PtrSize) - s.Grow(s.Size) - r := s.AddRel() - r.Sym = t - r.Off = int32(i) - r.Siz = uint8(arch.PtrSize) - r.Type = typ - r.Add = add - return i + int64(r.Siz) -} - -func (s *Symbol) AddAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 { - return s.addAddrPlus(arch, t, add, objabi.R_ADDR) -} - -func (s *Symbol) AddCURelativeAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 { - return s.addAddrPlus(arch, t, add, objabi.R_ADDRCUOFF) -} - -func (s *Symbol) AddPCRelPlus(arch *sys.Arch, t *Symbol, add int64) int64 { - if s.Type == 0 { - s.Type = SDATA - } - s.Attr |= AttrReachable - i := s.Size - s.Size += 4 - s.Grow(s.Size) - r := s.AddRel() - r.Sym = t - r.Off = int32(i) - r.Add = add - r.Type = objabi.R_PCREL - r.Siz = 4 - if arch.Family == sys.S390X || arch.Family == sys.PPC64 { - r.InitExt() - } - if arch.Family == sys.S390X { - r.Variant = RV_390_DBL - } - return i + int64(r.Siz) -} - -func (s *Symbol) AddAddr(arch *sys.Arch, t *Symbol) int64 { - return s.AddAddrPlus(arch, t, 0) -} - -func (s *Symbol) SetAddrPlus(arch *sys.Arch, off int64, t *Symbol, add int64) int64 { - if s.Type == 0 { - s.Type = SDATA - } - s.Attr |= AttrReachable - if off+int64(arch.PtrSize) > s.Size { - s.Size = off + int64(arch.PtrSize) - s.Grow(s.Size) - } - - r := s.AddRel() - r.Sym = t - r.Off = int32(off) - r.Siz = uint8(arch.PtrSize) - r.Type = objabi.R_ADDR - r.Add = add - return off + int64(r.Siz) -} - -func (s *Symbol) SetAddr(arch *sys.Arch, off int64, t *Symbol) int64 { - return s.SetAddrPlus(arch, off, t, 0) -} - -func (s *Symbol) AddSize(arch *sys.Arch, t *Symbol) int64 { - if s.Type == 0 { - s.Type = SDATA - } - s.Attr |= AttrReachable - i := s.Size - s.Size += int64(arch.PtrSize) - s.Grow(s.Size) - r := s.AddRel() - r.Sym = t - r.Off = int32(i) - r.Siz = uint8(arch.PtrSize) - r.Type = objabi.R_SIZE - return i + int64(r.Siz) -} - -func (s *Symbol) AddAddrPlus4(t *Symbol, add int64) int64 { - if s.Type == 0 { - s.Type = SDATA - } - s.Attr |= AttrReachable - i := s.Size - s.Size += 4 - s.Grow(s.Size) - r := s.AddRel() - r.Sym = t - r.Off = int32(i) - r.Siz = 4 - r.Type = objabi.R_ADDR - r.Add = add - return i + int64(r.Siz) -} - -func (s *Symbol) AddRel() *Reloc { - s.R = append(s.R, Reloc{}) - return &s.R[len(s.R)-1] -} - -func (s *Symbol) AddUintXX(arch *sys.Arch, v uint64, wid int) int64 { - off := s.Size - s.setUintXX(arch, off, v, int64(wid)) - return off -} - -func (s *Symbol) setUintXX(arch *sys.Arch, off int64, v uint64, wid int64) int64 { - if s.Type == 0 { - s.Type = SDATA - } - s.Attr |= AttrReachable - if s.Size < off+wid { - s.Size = off + wid - s.Grow(s.Size) - } - - switch wid { - case 1: - s.P[off] = uint8(v) - case 2: - arch.ByteOrder.PutUint16(s.P[off:], uint16(v)) - case 4: - arch.ByteOrder.PutUint32(s.P[off:], uint32(v)) - case 8: - arch.ByteOrder.PutUint64(s.P[off:], v) - } - - return off + wid -} - -func (s *Symbol) makeAuxInfo() { - if s.auxinfo == nil { - s.auxinfo = &AuxSymbol{extname: s.Name, plt: -1, got: -1} - } -} - -func (s *Symbol) Extname() string { - if s.auxinfo == nil { - return s.Name - } - return s.auxinfo.extname -} - -func (s *Symbol) SetExtname(n string) { - if s.auxinfo == nil { - if s.Name == n { - return - } - s.makeAuxInfo() - } - s.auxinfo.extname = n -} - -func (s *Symbol) Dynimplib() string { - if s.auxinfo == nil { - return "" - } - return s.auxinfo.dynimplib -} - -func (s *Symbol) Dynimpvers() string { - if s.auxinfo == nil { - return "" - } - return s.auxinfo.dynimpvers -} - -func (s *Symbol) SetDynimplib(lib string) { - if s.auxinfo == nil { - s.makeAuxInfo() - } - s.auxinfo.dynimplib = lib -} - -func (s *Symbol) SetDynimpvers(vers string) { - if s.auxinfo == nil { - s.makeAuxInfo() - } - s.auxinfo.dynimpvers = vers -} - -func (s *Symbol) ResetDyninfo() { - if s.auxinfo != nil { - s.auxinfo.dynimplib = "" - s.auxinfo.dynimpvers = "" - } -} - -func (s *Symbol) Localentry() uint8 { - if s.auxinfo == nil { - return 0 - } - return s.auxinfo.localentry -} - -func (s *Symbol) SetLocalentry(val uint8) { - if s.auxinfo == nil { - if val != 0 { - return - } - s.makeAuxInfo() - } - s.auxinfo.localentry = val -} - -func (s *Symbol) Plt() int32 { - if s.auxinfo == nil { - return -1 - } - return s.auxinfo.plt -} - -func (s *Symbol) SetPlt(val int32) { - if s.auxinfo == nil { - if val == -1 { - return - } - s.makeAuxInfo() - } - s.auxinfo.plt = val -} - -func (s *Symbol) Got() int32 { - if s.auxinfo == nil { - return -1 - } - return s.auxinfo.got -} - -func (s *Symbol) SetGot(val int32) { - if s.auxinfo == nil { - if val == -1 { - return - } - s.makeAuxInfo() - } - s.auxinfo.got = val -} - -func (s *Symbol) ElfType() elf.SymType { - if s.auxinfo == nil { - return elf.STT_NOTYPE - } - return s.auxinfo.elftype -} - -func (s *Symbol) SetElfType(val elf.SymType) { - if s.auxinfo == nil { - if val == elf.STT_NOTYPE { - return - } - s.makeAuxInfo() - } - s.auxinfo.elftype = val -} - -// SortSub sorts a linked-list (by Sub) of *Symbol by Value. -// Used for sub-symbols when loading host objects (see e.g. ldelf.go). -func SortSub(l *Symbol) *Symbol { - if l == nil || l.Sub == nil { - return l - } - - l1 := l - l2 := l - for { - l2 = l2.Sub - if l2 == nil { - break - } - l2 = l2.Sub - if l2 == nil { - break - } - l1 = l1.Sub - } - - l2 = l1.Sub - l1.Sub = nil - l1 = SortSub(l) - l2 = SortSub(l2) - - /* set up lead element */ - if l1.Value < l2.Value { - l = l1 - l1 = l1.Sub - } else { - l = l2 - l2 = l2.Sub - } - - le := l - - for { - if l1 == nil { - for l2 != nil { - le.Sub = l2 - le = l2 - l2 = l2.Sub - } - - le.Sub = nil - break - } - - if l2 == nil { - for l1 != nil { - le.Sub = l1 - le = l1 - l1 = l1.Sub - } - - break - } - - if l1.Value < l2.Value { - le.Sub = l1 - le = l1 - l1 = l1.Sub - } else { - le.Sub = l2 - le = l2 - l2 = l2.Sub - } - } - - le.Sub = nil - return l -} - -type FuncInfo struct { - Args int32 - Locals int32 - Pcsp Pcdata - Pcfile Pcdata - Pcline Pcdata - Pcinline Pcdata - Pcdata []Pcdata - Funcdata []*Symbol - Funcdataoff []int64 - File []*Symbol - InlTree []InlinedCall -} - -// InlinedCall is a node in a local inlining tree (FuncInfo.InlTree). -type InlinedCall struct { - Parent int32 // index of parent in InlTree - File *Symbol // file of the inlined call - Line int32 // line number of the inlined call - Func string // name of the function that was inlined - ParentPC int32 // PC of the instruction just before the inlined body (offset from function start) -} - -type Pcdata struct { - P []byte -} diff --git a/src/cmd/oldlink/internal/sym/symbols.go b/src/cmd/oldlink/internal/sym/symbols.go deleted file mode 100644 index e772496534..0000000000 --- a/src/cmd/oldlink/internal/sym/symbols.go +++ /dev/null @@ -1,135 +0,0 @@ -// Derived from Inferno utils/6l/l.h and related files. -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package sym - -type Symbols struct { - symbolBatch []Symbol - - // Symbol lookup based on name and indexed by version. - hash []map[string]*Symbol - - Allsym []*Symbol -} - -func NewSymbols() *Symbols { - hash := make([]map[string]*Symbol, SymVerStatic) - // Preallocate about 2mb for hash of non static symbols - hash[0] = make(map[string]*Symbol, 100000) - // And another 1mb for internal ABI text symbols. - hash[SymVerABIInternal] = make(map[string]*Symbol, 50000) - return &Symbols{ - hash: hash, - Allsym: make([]*Symbol, 0, 100000), - } -} - -func (syms *Symbols) Newsym(name string, v int) *Symbol { - batch := syms.symbolBatch - if len(batch) == 0 { - batch = make([]Symbol, 1000) - } - s := &batch[0] - syms.symbolBatch = batch[1:] - - s.Dynid = -1 - s.Name = name - s.Version = int16(v) - syms.Allsym = append(syms.Allsym, s) - - return s -} - -// Look up the symbol with the given name and version, creating the -// symbol if it is not found. -func (syms *Symbols) Lookup(name string, v int) *Symbol { - m := syms.hash[v] - s := m[name] - if s != nil { - return s - } - s = syms.Newsym(name, v) - m[name] = s - return s -} - -// Look up the symbol with the given name and version, returning nil -// if it is not found. -func (syms *Symbols) ROLookup(name string, v int) *Symbol { - return syms.hash[v][name] -} - -// Add an existing symbol to the symbol table. -func (syms *Symbols) Add(s *Symbol) { - name := s.Name - v := int(s.Version) - m := syms.hash[v] - if _, ok := m[name]; ok { - panic(name + " already added") - } - m[name] = s -} - -// Allocate a new version (i.e. symbol namespace). -func (syms *Symbols) IncVersion() int { - syms.hash = append(syms.hash, make(map[string]*Symbol)) - return len(syms.hash) - 1 -} - -// Rename renames a symbol. -func (syms *Symbols) Rename(old, new string, v int, reachparent map[*Symbol]*Symbol) { - s := syms.hash[v][old] - oldExtName := s.Extname() - s.Name = new - if oldExtName == old { - s.SetExtname(new) - } - delete(syms.hash[v], old) - - dup := syms.hash[v][new] - if dup == nil { - syms.hash[v][new] = s - } else { - if s.Type == 0 { - dup.Attr |= s.Attr - if s.Attr.Reachable() && reachparent != nil { - reachparent[dup] = reachparent[s] - } - *s = *dup - } else if dup.Type == 0 { - s.Attr |= dup.Attr - if dup.Attr.Reachable() && reachparent != nil { - reachparent[s] = reachparent[dup] - } - *dup = *s - syms.hash[v][new] = s - } - } -} diff --git a/src/cmd/oldlink/internal/sym/symkind.go b/src/cmd/oldlink/internal/sym/symkind.go deleted file mode 100644 index 1933dd7b21..0000000000 --- a/src/cmd/oldlink/internal/sym/symkind.go +++ /dev/null @@ -1,168 +0,0 @@ -// Derived from Inferno utils/6l/l.h and related files. -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package sym - -// A SymKind describes the kind of memory represented by a symbol. -type SymKind uint8 - -// Defined SymKind values. -// -// TODO(rsc): Give idiomatic Go names. -//go:generate stringer -type=SymKind -const ( - Sxxx SymKind = iota - STEXT - SELFRXSECT - - // Read-only sections. - STYPE - SSTRING - SGOSTRING - SGOFUNC - SGCBITS - SRODATA - SFUNCTAB - - SELFROSECT - SMACHOPLT - - // Read-only sections with relocations. - // - // Types STYPE-SFUNCTAB above are written to the .rodata section by default. - // When linking a shared object, some conceptually "read only" types need to - // be written to by relocations and putting them in a section called - // ".rodata" interacts poorly with the system linkers. The GNU linkers - // support this situation by arranging for sections of the name - // ".data.rel.ro.XXX" to be mprotected read only by the dynamic linker after - // relocations have applied, so when the Go linker is creating a shared - // object it checks all objects of the above types and bumps any object that - // has a relocation to it to the corresponding type below, which are then - // written to sections with appropriate magic names. - STYPERELRO - SSTRINGRELRO - SGOSTRINGRELRO - SGOFUNCRELRO - SGCBITSRELRO - SRODATARELRO - SFUNCTABRELRO - - // Part of .data.rel.ro if it exists, otherwise part of .rodata. - STYPELINK - SITABLINK - SSYMTAB - SPCLNTAB - - // Writable sections. - SFirstWritable - SBUILDINFO - SELFSECT - SMACHO - SMACHOGOT - SWINDOWS - SELFGOT - SNOPTRDATA - SINITARR - SDATA - SXCOFFTOC - SBSS - SNOPTRBSS - SLIBFUZZER_EXTRA_COUNTER - STLSBSS - SXREF - SMACHOSYMSTR - SMACHOSYMTAB - SMACHOINDIRECTPLT - SMACHOINDIRECTGOT - SFILEPATH - SCONST - SDYNIMPORT - SHOSTOBJ - SUNDEFEXT // Undefined symbol for resolution by external linker - - // Sections for debugging information - SDWARFSECT - SDWARFINFO - SDWARFRANGE - SDWARFLOC - SDWARFLINES - - // ABI aliases (these never appear in the output) - SABIALIAS -) - -// AbiSymKindToSymKind maps values read from object files (which are -// of type cmd/internal/objabi.SymKind) to values of type SymKind. -var AbiSymKindToSymKind = [...]SymKind{ - Sxxx, - STEXT, - SRODATA, - SNOPTRDATA, - SDATA, - SBSS, - SNOPTRBSS, - STLSBSS, - SDWARFINFO, - SDWARFRANGE, - SDWARFLOC, - SDWARFLINES, - SABIALIAS, - SLIBFUZZER_EXTRA_COUNTER, -} - -// ReadOnly are the symbol kinds that form read-only sections. In some -// cases, if they will require relocations, they are transformed into -// rel-ro sections using relROMap. -var ReadOnly = []SymKind{ - STYPE, - SSTRING, - SGOSTRING, - SGOFUNC, - SGCBITS, - SRODATA, - SFUNCTAB, -} - -// RelROMap describes the transformation of read-only symbols to rel-ro -// symbols. -var RelROMap = map[SymKind]SymKind{ - STYPE: STYPERELRO, - SSTRING: SSTRINGRELRO, - SGOSTRING: SGOSTRINGRELRO, - SGOFUNC: SGOFUNCRELRO, - SGCBITS: SGCBITSRELRO, - SRODATA: SRODATARELRO, - SFUNCTAB: SFUNCTABRELRO, -} - -// IsData returns true if the type is a data type. -func (t SymKind) IsData() bool { - return t == SDATA || t == SNOPTRDATA || t == SBSS || t == SNOPTRBSS -} diff --git a/src/cmd/oldlink/internal/sym/symkind_string.go b/src/cmd/oldlink/internal/sym/symkind_string.go deleted file mode 100644 index 97af9925d5..0000000000 --- a/src/cmd/oldlink/internal/sym/symkind_string.go +++ /dev/null @@ -1,76 +0,0 @@ -// Code generated by "stringer -type=SymKind symkind.go"; DO NOT EDIT. - -package sym - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[Sxxx-0] - _ = x[STEXT-1] - _ = x[SELFRXSECT-2] - _ = x[STYPE-3] - _ = x[SSTRING-4] - _ = x[SGOSTRING-5] - _ = x[SGOFUNC-6] - _ = x[SGCBITS-7] - _ = x[SRODATA-8] - _ = x[SFUNCTAB-9] - _ = x[SELFROSECT-10] - _ = x[SMACHOPLT-11] - _ = x[STYPERELRO-12] - _ = x[SSTRINGRELRO-13] - _ = x[SGOSTRINGRELRO-14] - _ = x[SGOFUNCRELRO-15] - _ = x[SGCBITSRELRO-16] - _ = x[SRODATARELRO-17] - _ = x[SFUNCTABRELRO-18] - _ = x[STYPELINK-19] - _ = x[SITABLINK-20] - _ = x[SSYMTAB-21] - _ = x[SPCLNTAB-22] - _ = x[SFirstWritable-23] - _ = x[SBUILDINFO-24] - _ = x[SELFSECT-25] - _ = x[SMACHO-26] - _ = x[SMACHOGOT-27] - _ = x[SWINDOWS-28] - _ = x[SELFGOT-29] - _ = x[SNOPTRDATA-30] - _ = x[SINITARR-31] - _ = x[SDATA-32] - _ = x[SXCOFFTOC-33] - _ = x[SBSS-34] - _ = x[SNOPTRBSS-35] - _ = x[SLIBFUZZER_EXTRA_COUNTER-36] - _ = x[STLSBSS-37] - _ = x[SXREF-38] - _ = x[SMACHOSYMSTR-39] - _ = x[SMACHOSYMTAB-40] - _ = x[SMACHOINDIRECTPLT-41] - _ = x[SMACHOINDIRECTGOT-42] - _ = x[SFILEPATH-43] - _ = x[SCONST-44] - _ = x[SDYNIMPORT-45] - _ = x[SHOSTOBJ-46] - _ = x[SUNDEFEXT-47] - _ = x[SDWARFSECT-48] - _ = x[SDWARFINFO-49] - _ = x[SDWARFRANGE-50] - _ = x[SDWARFLOC-51] - _ = x[SDWARFLINES-52] - _ = x[SABIALIAS-53] -} - -const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSFirstWritableSBUILDINFOSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASXCOFFTOCSBSSSNOPTRBSSSLIBFUZZER_EXTRA_COUNTERSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSCONSTSDYNIMPORTSHOSTOBJSUNDEFEXTSDWARFSECTSDWARFINFOSDWARFRANGESDWARFLOCSDWARFLINESSABIALIAS" - -var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 220, 230, 238, 244, 253, 261, 268, 278, 286, 291, 300, 304, 313, 337, 344, 349, 361, 373, 390, 407, 416, 422, 432, 440, 449, 459, 469, 480, 489, 500, 509} - -func (i SymKind) String() string { - if i >= SymKind(len(_SymKind_index)-1) { - return "SymKind(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]] -} diff --git a/src/cmd/oldlink/internal/wasm/asm.go b/src/cmd/oldlink/internal/wasm/asm.go deleted file mode 100644 index 35bc7b1c95..0000000000 --- a/src/cmd/oldlink/internal/wasm/asm.go +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package wasm - -import ( - "bytes" - "cmd/internal/objabi" - "cmd/oldlink/internal/ld" - "cmd/oldlink/internal/sym" - "io" - "regexp" -) - -const ( - I32 = 0x7F - I64 = 0x7E - F32 = 0x7D - F64 = 0x7C -) - -const ( - sectionCustom = 0 - sectionType = 1 - sectionImport = 2 - sectionFunction = 3 - sectionTable = 4 - sectionMemory = 5 - sectionGlobal = 6 - sectionExport = 7 - sectionStart = 8 - sectionElement = 9 - sectionCode = 10 - sectionData = 11 -) - -// funcValueOffset is the offset between the PC_F value of a function and the index of the function in WebAssembly -const funcValueOffset = 0x1000 // TODO(neelance): make function addresses play nice with heap addresses - -func gentext(ctxt *ld.Link) { -} - -type wasmFunc struct { - Name string - Type uint32 - Code []byte -} - -type wasmFuncType struct { - Params []byte - Results []byte -} - -var wasmFuncTypes = map[string]*wasmFuncType{ - "_rt0_wasm_js": {Params: []byte{}}, // - "wasm_export_run": {Params: []byte{I32, I32}}, // argc, argv - "wasm_export_resume": {Params: []byte{}}, // - "wasm_export_getsp": {Results: []byte{I32}}, // sp - "wasm_pc_f_loop": {Params: []byte{}}, // - "runtime.wasmMove": {Params: []byte{I32, I32, I32}}, // dst, src, len - "runtime.wasmZero": {Params: []byte{I32, I32}}, // ptr, len - "runtime.wasmDiv": {Params: []byte{I64, I64}, Results: []byte{I64}}, // x, y -> x/y - "runtime.wasmTruncS": {Params: []byte{F64}, Results: []byte{I64}}, // x -> int(x) - "runtime.wasmTruncU": {Params: []byte{F64}, Results: []byte{I64}}, // x -> uint(x) - "runtime.gcWriteBarrier": {Params: []byte{I64, I64}}, // ptr, val - "cmpbody": {Params: []byte{I64, I64, I64, I64}, Results: []byte{I64}}, // a, alen, b, blen -> -1/0/1 - "memeqbody": {Params: []byte{I64, I64, I64}, Results: []byte{I64}}, // a, b, len -> 0/1 - "memcmp": {Params: []byte{I32, I32, I32}, Results: []byte{I32}}, // a, b, len -> <0/0/>0 - "memchr": {Params: []byte{I32, I32, I32}, Results: []byte{I32}}, // s, c, len -> index -} - -func assignAddress(ctxt *ld.Link, sect *sym.Section, n int, s *sym.Symbol, va uint64, isTramp bool) (*sym.Section, int, uint64) { - // WebAssembly functions do not live in the same address space as the linear memory. - // Instead, WebAssembly automatically assigns indices. Imported functions (section "import") - // have indices 0 to n. They are followed by native functions (sections "function" and "code") - // with indices n+1 and following. - // - // The following rules describe how wasm handles function indices and addresses: - // PC_F = funcValueOffset + WebAssembly function index (not including the imports) - // s.Value = PC = PC_F<<16 + PC_B - // - // The funcValueOffset is necessary to avoid conflicts with expectations - // that the Go runtime has about function addresses. - // The field "s.Value" corresponds to the concept of PC at runtime. - // However, there is no PC register, only PC_F and PC_B. PC_F denotes the function, - // PC_B the resume point inside of that function. The entry of the function has PC_B = 0. - s.Sect = sect - s.Value = int64(funcValueOffset+va/ld.MINFUNC) << 16 // va starts at zero - va += uint64(ld.MINFUNC) - return sect, n, va -} - -func asmb(ctxt *ld.Link) {} // dummy - -// asmb writes the final WebAssembly module binary. -// Spec: https://webassembly.github.io/spec/core/binary/modules.html -func asmb2(ctxt *ld.Link) { - types := []*wasmFuncType{ - // For normal Go functions, the single parameter is PC_B, - // the return value is - // 0 if the function returned normally or - // 1 if the stack needs to be unwound. - {Params: []byte{I32}, Results: []byte{I32}}, - } - - // collect host imports (functions that get imported from the WebAssembly host, usually JavaScript) - hostImports := []*wasmFunc{ - { - Name: "debug", - Type: lookupType(&wasmFuncType{Params: []byte{I32}}, &types), - }, - } - hostImportMap := make(map[*sym.Symbol]int64) - for _, fn := range ctxt.Textp { - for _, r := range fn.R { - if r.Type == objabi.R_WASMIMPORT { - hostImportMap[r.Sym] = int64(len(hostImports)) - hostImports = append(hostImports, &wasmFunc{ - Name: r.Sym.Name, - Type: lookupType(&wasmFuncType{Params: []byte{I32}}, &types), - }) - } - } - } - - // collect functions with WebAssembly body - var buildid []byte - fns := make([]*wasmFunc, len(ctxt.Textp)) - for i, fn := range ctxt.Textp { - wfn := new(bytes.Buffer) - if fn.Name == "go.buildid" { - writeUleb128(wfn, 0) // number of sets of locals - writeI32Const(wfn, 0) - wfn.WriteByte(0x0b) // end - buildid = fn.P - } else { - // Relocations have variable length, handle them here. - off := int32(0) - for _, r := range fn.R { - wfn.Write(fn.P[off:r.Off]) - off = r.Off - switch r.Type { - case objabi.R_ADDR: - writeSleb128(wfn, r.Sym.Value+r.Add) - case objabi.R_CALL: - writeSleb128(wfn, int64(len(hostImports))+r.Sym.Value>>16-funcValueOffset) - case objabi.R_WASMIMPORT: - writeSleb128(wfn, hostImportMap[r.Sym]) - default: - ld.Errorf(fn, "bad reloc type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type)) - continue - } - } - wfn.Write(fn.P[off:]) - } - - typ := uint32(0) - if sig, ok := wasmFuncTypes[fn.Name]; ok { - typ = lookupType(sig, &types) - } - - name := nameRegexp.ReplaceAllString(fn.Name, "_") - fns[i] = &wasmFunc{Name: name, Type: typ, Code: wfn.Bytes()} - } - - ctxt.Out.Write([]byte{0x00, 0x61, 0x73, 0x6d}) // magic - ctxt.Out.Write([]byte{0x01, 0x00, 0x00, 0x00}) // version - - // Add any buildid early in the binary: - if len(buildid) != 0 { - writeBuildID(ctxt, buildid) - } - - writeTypeSec(ctxt, types) - writeImportSec(ctxt, hostImports) - writeFunctionSec(ctxt, fns) - writeTableSec(ctxt, fns) - writeMemorySec(ctxt) - writeGlobalSec(ctxt) - writeExportSec(ctxt, len(hostImports)) - writeElementSec(ctxt, uint64(len(hostImports)), uint64(len(fns))) - writeCodeSec(ctxt, fns) - writeDataSec(ctxt) - writeProducerSec(ctxt) - if !*ld.FlagS { - writeNameSec(ctxt, len(hostImports), fns) - } - - ctxt.Out.Flush() -} - -func lookupType(sig *wasmFuncType, types *[]*wasmFuncType) uint32 { - for i, t := range *types { - if bytes.Equal(sig.Params, t.Params) && bytes.Equal(sig.Results, t.Results) { - return uint32(i) - } - } - *types = append(*types, sig) - return uint32(len(*types) - 1) -} - -func writeSecHeader(ctxt *ld.Link, id uint8) int64 { - ctxt.Out.WriteByte(id) - sizeOffset := ctxt.Out.Offset() - ctxt.Out.Write(make([]byte, 5)) // placeholder for length - return sizeOffset -} - -func writeSecSize(ctxt *ld.Link, sizeOffset int64) { - endOffset := ctxt.Out.Offset() - ctxt.Out.SeekSet(sizeOffset) - writeUleb128FixedLength(ctxt.Out, uint64(endOffset-sizeOffset-5), 5) - ctxt.Out.SeekSet(endOffset) -} - -func writeBuildID(ctxt *ld.Link, buildid []byte) { - sizeOffset := writeSecHeader(ctxt, sectionCustom) - writeName(ctxt.Out, "go.buildid") - ctxt.Out.Write(buildid) - writeSecSize(ctxt, sizeOffset) -} - -// writeTypeSec writes the section that declares all function types -// so they can be referenced by index. -func writeTypeSec(ctxt *ld.Link, types []*wasmFuncType) { - sizeOffset := writeSecHeader(ctxt, sectionType) - - writeUleb128(ctxt.Out, uint64(len(types))) - - for _, t := range types { - ctxt.Out.WriteByte(0x60) // functype - writeUleb128(ctxt.Out, uint64(len(t.Params))) - for _, v := range t.Params { - ctxt.Out.WriteByte(byte(v)) - } - writeUleb128(ctxt.Out, uint64(len(t.Results))) - for _, v := range t.Results { - ctxt.Out.WriteByte(byte(v)) - } - } - - writeSecSize(ctxt, sizeOffset) -} - -// writeImportSec writes the section that lists the functions that get -// imported from the WebAssembly host, usually JavaScript. -func writeImportSec(ctxt *ld.Link, hostImports []*wasmFunc) { - sizeOffset := writeSecHeader(ctxt, sectionImport) - - writeUleb128(ctxt.Out, uint64(len(hostImports))) // number of imports - for _, fn := range hostImports { - writeName(ctxt.Out, "go") // provided by the import object in wasm_exec.js - writeName(ctxt.Out, fn.Name) - ctxt.Out.WriteByte(0x00) // func import - writeUleb128(ctxt.Out, uint64(fn.Type)) - } - - writeSecSize(ctxt, sizeOffset) -} - -// writeFunctionSec writes the section that declares the types of functions. -// The bodies of these functions will later be provided in the "code" section. -func writeFunctionSec(ctxt *ld.Link, fns []*wasmFunc) { - sizeOffset := writeSecHeader(ctxt, sectionFunction) - - writeUleb128(ctxt.Out, uint64(len(fns))) - for _, fn := range fns { - writeUleb128(ctxt.Out, uint64(fn.Type)) - } - - writeSecSize(ctxt, sizeOffset) -} - -// writeTableSec writes the section that declares tables. Currently there is only a single table -// that is used by the CallIndirect operation to dynamically call any function. -// The contents of the table get initialized by the "element" section. -func writeTableSec(ctxt *ld.Link, fns []*wasmFunc) { - sizeOffset := writeSecHeader(ctxt, sectionTable) - - numElements := uint64(funcValueOffset + len(fns)) - writeUleb128(ctxt.Out, 1) // number of tables - ctxt.Out.WriteByte(0x70) // type: anyfunc - ctxt.Out.WriteByte(0x00) // no max - writeUleb128(ctxt.Out, numElements) // min - - writeSecSize(ctxt, sizeOffset) -} - -// writeMemorySec writes the section that declares linear memories. Currently one linear memory is being used. -// Linear memory always starts at address zero. More memory can be requested with the GrowMemory instruction. -func writeMemorySec(ctxt *ld.Link) { - sizeOffset := writeSecHeader(ctxt, sectionMemory) - - dataSection := ctxt.Syms.Lookup("runtime.data", 0).Sect - dataEnd := dataSection.Vaddr + dataSection.Length - var initialSize = dataEnd + 16<<20 // 16MB, enough for runtime init without growing - - const wasmPageSize = 64 << 10 // 64KB - - writeUleb128(ctxt.Out, 1) // number of memories - ctxt.Out.WriteByte(0x00) // no maximum memory size - writeUleb128(ctxt.Out, initialSize/wasmPageSize) // minimum (initial) memory size - - writeSecSize(ctxt, sizeOffset) -} - -// writeGlobalSec writes the section that declares global variables. -func writeGlobalSec(ctxt *ld.Link) { - sizeOffset := writeSecHeader(ctxt, sectionGlobal) - - globalRegs := []byte{ - I32, // 0: SP - I64, // 1: CTXT - I64, // 2: g - I64, // 3: RET0 - I64, // 4: RET1 - I64, // 5: RET2 - I64, // 6: RET3 - I32, // 7: PAUSE - } - - writeUleb128(ctxt.Out, uint64(len(globalRegs))) // number of globals - - for _, typ := range globalRegs { - ctxt.Out.WriteByte(typ) - ctxt.Out.WriteByte(0x01) // var - switch typ { - case I32: - writeI32Const(ctxt.Out, 0) - case I64: - writeI64Const(ctxt.Out, 0) - } - ctxt.Out.WriteByte(0x0b) // end - } - - writeSecSize(ctxt, sizeOffset) -} - -// writeExportSec writes the section that declares exports. -// Exports can be accessed by the WebAssembly host, usually JavaScript. -// The wasm_export_* functions and the linear memory get exported. -func writeExportSec(ctxt *ld.Link, lenHostImports int) { - sizeOffset := writeSecHeader(ctxt, sectionExport) - - writeUleb128(ctxt.Out, 4) // number of exports - - for _, name := range []string{"run", "resume", "getsp"} { - idx := uint32(lenHostImports) + uint32(ctxt.Syms.ROLookup("wasm_export_"+name, 0).Value>>16) - funcValueOffset - writeName(ctxt.Out, name) // inst.exports.run/resume/getsp in wasm_exec.js - ctxt.Out.WriteByte(0x00) // func export - writeUleb128(ctxt.Out, uint64(idx)) // funcidx - } - - writeName(ctxt.Out, "mem") // inst.exports.mem in wasm_exec.js - ctxt.Out.WriteByte(0x02) // mem export - writeUleb128(ctxt.Out, 0) // memidx - - writeSecSize(ctxt, sizeOffset) -} - -// writeElementSec writes the section that initializes the tables declared by the "table" section. -// The table for CallIndirect gets initialized in a very simple way so that each table index (PC_F value) -// maps linearly to the function index (numImports + PC_F). -func writeElementSec(ctxt *ld.Link, numImports, numFns uint64) { - sizeOffset := writeSecHeader(ctxt, sectionElement) - - writeUleb128(ctxt.Out, 1) // number of element segments - - writeUleb128(ctxt.Out, 0) // tableidx - writeI32Const(ctxt.Out, funcValueOffset) - ctxt.Out.WriteByte(0x0b) // end - - writeUleb128(ctxt.Out, numFns) // number of entries - for i := uint64(0); i < numFns; i++ { - writeUleb128(ctxt.Out, numImports+i) - } - - writeSecSize(ctxt, sizeOffset) -} - -// writeElementSec writes the section that provides the function bodies for the functions -// declared by the "func" section. -func writeCodeSec(ctxt *ld.Link, fns []*wasmFunc) { - sizeOffset := writeSecHeader(ctxt, sectionCode) - - writeUleb128(ctxt.Out, uint64(len(fns))) // number of code entries - for _, fn := range fns { - writeUleb128(ctxt.Out, uint64(len(fn.Code))) - ctxt.Out.Write(fn.Code) - } - - writeSecSize(ctxt, sizeOffset) -} - -// writeDataSec writes the section that provides data that will be used to initialize the linear memory. -func writeDataSec(ctxt *ld.Link) { - sizeOffset := writeSecHeader(ctxt, sectionData) - - sections := []*sym.Section{ - ctxt.Syms.Lookup("runtime.rodata", 0).Sect, - ctxt.Syms.Lookup("runtime.typelink", 0).Sect, - ctxt.Syms.Lookup("runtime.itablink", 0).Sect, - ctxt.Syms.Lookup("runtime.symtab", 0).Sect, - ctxt.Syms.Lookup("runtime.pclntab", 0).Sect, - ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect, - ctxt.Syms.Lookup("runtime.data", 0).Sect, - } - - type dataSegment struct { - offset int32 - data []byte - } - - // Omit blocks of zeroes and instead emit data segments with offsets skipping the zeroes. - // This reduces the size of the WebAssembly binary. We use 8 bytes as an estimate for the - // overhead of adding a new segment (same as wasm-opt's memory-packing optimization uses). - const segmentOverhead = 8 - - // Generate at most this many segments. A higher number of segments gets rejected by some WebAssembly runtimes. - const maxNumSegments = 100000 - - var segments []*dataSegment - for secIndex, sec := range sections { - data := ld.DatblkBytes(ctxt, int64(sec.Vaddr), int64(sec.Length)) - offset := int32(sec.Vaddr) - - // skip leading zeroes - for len(data) > 0 && data[0] == 0 { - data = data[1:] - offset++ - } - - for len(data) > 0 { - dataLen := int32(len(data)) - var segmentEnd, zeroEnd int32 - if len(segments)+(len(sections)-secIndex) == maxNumSegments { - segmentEnd = dataLen - zeroEnd = dataLen - } else { - for { - // look for beginning of zeroes - for segmentEnd < dataLen && data[segmentEnd] != 0 { - segmentEnd++ - } - // look for end of zeroes - zeroEnd = segmentEnd - for zeroEnd < dataLen && data[zeroEnd] == 0 { - zeroEnd++ - } - // emit segment if omitting zeroes reduces the output size - if zeroEnd-segmentEnd >= segmentOverhead || zeroEnd == dataLen { - break - } - segmentEnd = zeroEnd - } - } - - segments = append(segments, &dataSegment{ - offset: offset, - data: data[:segmentEnd], - }) - data = data[zeroEnd:] - offset += zeroEnd - } - } - - writeUleb128(ctxt.Out, uint64(len(segments))) // number of data entries - for _, seg := range segments { - writeUleb128(ctxt.Out, 0) // memidx - writeI32Const(ctxt.Out, seg.offset) - ctxt.Out.WriteByte(0x0b) // end - writeUleb128(ctxt.Out, uint64(len(seg.data))) - ctxt.Out.Write(seg.data) - } - - writeSecSize(ctxt, sizeOffset) -} - -// writeProducerSec writes an optional section that reports the source language and compiler version. -func writeProducerSec(ctxt *ld.Link) { - sizeOffset := writeSecHeader(ctxt, sectionCustom) - writeName(ctxt.Out, "producers") - - writeUleb128(ctxt.Out, 2) // number of fields - - writeName(ctxt.Out, "language") // field name - writeUleb128(ctxt.Out, 1) // number of values - writeName(ctxt.Out, "Go") // value: name - writeName(ctxt.Out, objabi.Version) // value: version - - writeName(ctxt.Out, "processed-by") // field name - writeUleb128(ctxt.Out, 1) // number of values - writeName(ctxt.Out, "Go cmd/compile") // value: name - writeName(ctxt.Out, objabi.Version) // value: version - - writeSecSize(ctxt, sizeOffset) -} - -var nameRegexp = regexp.MustCompile(`[^\w\.]`) - -// writeNameSec writes an optional section that assigns names to the functions declared by the "func" section. -// The names are only used by WebAssembly stack traces, debuggers and decompilers. -// TODO(neelance): add symbol table of DATA symbols -func writeNameSec(ctxt *ld.Link, firstFnIndex int, fns []*wasmFunc) { - sizeOffset := writeSecHeader(ctxt, sectionCustom) - writeName(ctxt.Out, "name") - - sizeOffset2 := writeSecHeader(ctxt, 0x01) // function names - writeUleb128(ctxt.Out, uint64(len(fns))) - for i, fn := range fns { - writeUleb128(ctxt.Out, uint64(firstFnIndex+i)) - writeName(ctxt.Out, fn.Name) - } - writeSecSize(ctxt, sizeOffset2) - - writeSecSize(ctxt, sizeOffset) -} - -type nameWriter interface { - io.ByteWriter - io.Writer -} - -func writeI32Const(w io.ByteWriter, v int32) { - w.WriteByte(0x41) // i32.const - writeSleb128(w, int64(v)) -} - -func writeI64Const(w io.ByteWriter, v int64) { - w.WriteByte(0x42) // i64.const - writeSleb128(w, v) -} - -func writeName(w nameWriter, name string) { - writeUleb128(w, uint64(len(name))) - w.Write([]byte(name)) -} - -func writeUleb128(w io.ByteWriter, v uint64) { - if v < 128 { - w.WriteByte(uint8(v)) - return - } - more := true - for more { - c := uint8(v & 0x7f) - v >>= 7 - more = v != 0 - if more { - c |= 0x80 - } - w.WriteByte(c) - } -} - -func writeUleb128FixedLength(w io.ByteWriter, v uint64, length int) { - for i := 0; i < length; i++ { - c := uint8(v & 0x7f) - v >>= 7 - if i < length-1 { - c |= 0x80 - } - w.WriteByte(c) - } - if v != 0 { - panic("writeUleb128FixedLength: length too small") - } -} - -func writeSleb128(w io.ByteWriter, v int64) { - more := true - for more { - c := uint8(v & 0x7f) - s := uint8(v & 0x40) - v >>= 7 - more = !((v == 0 && s == 0) || (v == -1 && s != 0)) - if more { - c |= 0x80 - } - w.WriteByte(c) - } -} diff --git a/src/cmd/oldlink/internal/wasm/obj.go b/src/cmd/oldlink/internal/wasm/obj.go deleted file mode 100644 index fdc9fb796a..0000000000 --- a/src/cmd/oldlink/internal/wasm/obj.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package wasm - -import ( - "cmd/internal/sys" - "cmd/oldlink/internal/ld" -) - -func Init() (*sys.Arch, ld.Arch) { - theArch := ld.Arch{ - Funcalign: 16, - Maxalign: 32, - Minalign: 1, - - Archinit: archinit, - AssignAddress: assignAddress, - Asmb: asmb, - Asmb2: asmb2, - Gentext: gentext, - } - - return sys.ArchWasm, theArch -} - -func archinit(ctxt *ld.Link) { - if *ld.FlagRound == -1 { - *ld.FlagRound = 4096 - } - if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 0 - } -} diff --git a/src/cmd/oldlink/internal/x86/asm.go b/src/cmd/oldlink/internal/x86/asm.go deleted file mode 100644 index e8e52f671f..0000000000 --- a/src/cmd/oldlink/internal/x86/asm.go +++ /dev/null @@ -1,699 +0,0 @@ -// Inferno utils/8l/asm.c -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package x86 - -import ( - "cmd/internal/objabi" - "cmd/internal/sys" - "cmd/oldlink/internal/ld" - "cmd/oldlink/internal/sym" - "debug/elf" - "log" -) - -// Append 4 bytes to s and create a R_CALL relocation targeting t to fill them in. -func addcall(ctxt *ld.Link, s *sym.Symbol, t *sym.Symbol) { - s.Attr |= sym.AttrReachable - i := s.Size - s.Size += 4 - s.Grow(s.Size) - r := s.AddRel() - r.Sym = t - r.Off = int32(i) - r.Type = objabi.R_CALL - r.Siz = 4 -} - -func gentext(ctxt *ld.Link) { - if ctxt.DynlinkingGo() { - // We need get_pc_thunk. - } else { - switch ctxt.BuildMode { - case ld.BuildModeCArchive: - if !ctxt.IsELF { - return - } - case ld.BuildModePIE, ld.BuildModeCShared, ld.BuildModePlugin: - // We need get_pc_thunk. - default: - return - } - } - - // Generate little thunks that load the PC of the next instruction into a register. - thunks := make([]*sym.Symbol, 0, 7+len(ctxt.Textp)) - for _, r := range [...]struct { - name string - num uint8 - }{ - {"ax", 0}, - {"cx", 1}, - {"dx", 2}, - {"bx", 3}, - // sp - {"bp", 5}, - {"si", 6}, - {"di", 7}, - } { - thunkfunc := ctxt.Syms.Lookup("__x86.get_pc_thunk."+r.name, 0) - thunkfunc.Type = sym.STEXT - thunkfunc.Attr |= sym.AttrLocal - thunkfunc.Attr |= sym.AttrReachable //TODO: remove? - o := func(op ...uint8) { - for _, op1 := range op { - thunkfunc.AddUint8(op1) - } - } - // 8b 04 24 mov (%esp),%eax - // Destination register is in bits 3-5 of the middle byte, so add that in. - o(0x8b, 0x04+r.num<<3, 0x24) - // c3 ret - o(0xc3) - - thunks = append(thunks, thunkfunc) - } - ctxt.Textp = append(thunks, ctxt.Textp...) // keep Textp in dependency order - - addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0) - if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin { - // we're linking a module containing the runtime -> no need for - // an init function - return - } - - addmoduledata.Attr |= sym.AttrReachable - - initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0) - initfunc.Type = sym.STEXT - initfunc.Attr |= sym.AttrLocal - initfunc.Attr |= sym.AttrReachable - o := func(op ...uint8) { - for _, op1 := range op { - initfunc.AddUint8(op1) - } - } - - // go.link.addmoduledata: - // 53 push %ebx - // e8 00 00 00 00 call __x86.get_pc_thunk.cx + R_CALL __x86.get_pc_thunk.cx - // 8d 81 00 00 00 00 lea 0x0(%ecx), %eax + R_PCREL ctxt.Moduledata - // 8d 99 00 00 00 00 lea 0x0(%ecx), %ebx + R_GOTPC _GLOBAL_OFFSET_TABLE_ - // e8 00 00 00 00 call runtime.addmoduledata@plt + R_CALL runtime.addmoduledata - // 5b pop %ebx - // c3 ret - - o(0x53) - - o(0xe8) - addcall(ctxt, initfunc, ctxt.Syms.Lookup("__x86.get_pc_thunk.cx", 0)) - - o(0x8d, 0x81) - initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 6) - - o(0x8d, 0x99) - i := initfunc.Size - initfunc.Size += 4 - initfunc.Grow(initfunc.Size) - r := initfunc.AddRel() - r.Sym = ctxt.Syms.Lookup("_GLOBAL_OFFSET_TABLE_", 0) - r.Off = int32(i) - r.Type = objabi.R_PCREL - r.Add = 12 - r.Siz = 4 - - o(0xe8) - addcall(ctxt, initfunc, addmoduledata) - - o(0x5b) - - o(0xc3) - - if ctxt.BuildMode == ld.BuildModePlugin { - ctxt.Textp = append(ctxt.Textp, addmoduledata) - } - ctxt.Textp = append(ctxt.Textp, initfunc) - initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0) - initarray_entry.Attr |= sym.AttrReachable - initarray_entry.Attr |= sym.AttrLocal - initarray_entry.Type = sym.SINITARR - initarray_entry.AddAddr(ctxt.Arch, initfunc) -} - -func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { - targ := r.Sym - - switch r.Type { - default: - if r.Type >= objabi.ElfRelocOffset { - ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type)) - return false - } - - // Handle relocations found in ELF object files. - case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name) - } - // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make - // sense and should be removed when someone has thought about it properly. - if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() { - ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) - } - r.Type = objabi.R_PCREL - r.Add += 4 - return true - - case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32): - r.Type = objabi.R_PCREL - r.Add += 4 - if targ.Type == sym.SDYNIMPORT { - addpltsym(ctxt, targ) - r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add += int64(targ.Plt()) - } - - return true - - case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32), - objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X): - if targ.Type != sym.SDYNIMPORT { - // have symbol - if r.Off >= 2 && s.P[r.Off-2] == 0x8b { - // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT. - s.P[r.Off-2] = 0x8d - - r.Type = objabi.R_GOTOFF - return true - } - - if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 { - // turn PUSHL of GOT entry into PUSHL of symbol itself. - // use unnecessary SS prefix to keep instruction same length. - s.P[r.Off-2] = 0x36 - - s.P[r.Off-1] = 0x68 - r.Type = objabi.R_ADDR - return true - } - - ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name) - return false - } - - addgotsym(ctxt, targ) - r.Type = objabi.R_CONST // write r->add during relocsym - r.Sym = nil - r.Add += int64(targ.Got()) - return true - - case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF): - r.Type = objabi.R_GOTOFF - return true - - case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC): - r.Type = objabi.R_PCREL - r.Sym = ctxt.Syms.Lookup(".got", 0) - r.Add += 4 - return true - - case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32): - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name) - } - r.Type = objabi.R_ADDR - return true - - case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0: - r.Type = objabi.R_ADDR - if targ.Type == sym.SDYNIMPORT { - ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name) - } - return true - - case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1: - if targ.Type == sym.SDYNIMPORT { - addpltsym(ctxt, targ) - r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(targ.Plt()) - r.Type = objabi.R_PCREL - return true - } - - r.Type = objabi.R_PCREL - return true - - case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL: - if targ.Type != sym.SDYNIMPORT { - // have symbol - // turn MOVL of GOT entry into LEAL of symbol itself - if r.Off < 2 || s.P[r.Off-2] != 0x8b { - ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name) - return false - } - - s.P[r.Off-2] = 0x8d - r.Type = objabi.R_PCREL - return true - } - - addgotsym(ctxt, targ) - r.Sym = ctxt.Syms.Lookup(".got", 0) - r.Add += int64(targ.Got()) - r.Type = objabi.R_PCREL - return true - } - - // Handle references to ELF symbols from our own object files. - if targ.Type != sym.SDYNIMPORT { - return true - } - switch r.Type { - case objabi.R_CALL, - objabi.R_PCREL: - if ctxt.LinkMode == ld.LinkExternal { - // External linker will do this relocation. - return true - } - addpltsym(ctxt, targ) - r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(targ.Plt()) - return true - - case objabi.R_ADDR: - if s.Type != sym.SDATA { - break - } - if ctxt.IsELF { - ld.Adddynsym(ctxt, targ) - rel := ctxt.Syms.Lookup(".rel", 0) - rel.AddAddrPlus(ctxt.Arch, s, int64(r.Off)) - rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32))) - r.Type = objabi.R_CONST // write r->add during relocsym - r.Sym = nil - return true - } - - if ctxt.HeadType == objabi.Hdarwin && s.Size == int64(ctxt.Arch.PtrSize) && r.Off == 0 { - // Mach-O relocations are a royal pain to lay out. - // They use a compact stateful bytecode representation - // that is too much bother to deal with. - // Instead, interpret the C declaration - // void *_Cvar_stderr = &stderr; - // as making _Cvar_stderr the name of a GOT entry - // for stderr. This is separate from the usual GOT entry, - // just in case the C code assigns to the variable, - // and of course it only works for single pointers, - // but we only need to support cgo and that's all it needs. - ld.Adddynsym(ctxt, targ) - - got := ctxt.Syms.Lookup(".got", 0) - s.Type = got.Type - s.Attr |= sym.AttrSubSymbol - s.Outer = got - s.Sub = got.Sub - got.Sub = s - s.Value = got.Size - got.AddUint32(ctxt.Arch, 0) - ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(targ.Dynid)) - r.Type = objabi.ElfRelocOffset // ignore during relocsym - return true - } - } - - return false -} - -func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { - ctxt.Out.Write32(uint32(sectoff)) - - elfsym := r.Xsym.ElfsymForReloc() - switch r.Type { - default: - return false - case objabi.R_ADDR: - if r.Siz == 4 { - ctxt.Out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8) - } else { - return false - } - case objabi.R_GOTPCREL: - if r.Siz == 4 { - ctxt.Out.Write32(uint32(elf.R_386_GOTPC)) - if r.Xsym.Name != "_GLOBAL_OFFSET_TABLE_" { - ctxt.Out.Write32(uint32(sectoff)) - ctxt.Out.Write32(uint32(elf.R_386_GOT32) | uint32(elfsym)<<8) - } - } else { - return false - } - case objabi.R_CALL: - if r.Siz == 4 { - if r.Xsym.Type == sym.SDYNIMPORT { - ctxt.Out.Write32(uint32(elf.R_386_PLT32) | uint32(elfsym)<<8) - } else { - ctxt.Out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8) - } - } else { - return false - } - case objabi.R_PCREL: - if r.Siz == 4 { - ctxt.Out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8) - } else { - return false - } - case objabi.R_TLS_LE: - if r.Siz == 4 { - ctxt.Out.Write32(uint32(elf.R_386_TLS_LE) | uint32(elfsym)<<8) - } else { - return false - } - case objabi.R_TLS_IE: - if r.Siz == 4 { - ctxt.Out.Write32(uint32(elf.R_386_GOTPC)) - ctxt.Out.Write32(uint32(sectoff)) - ctxt.Out.Write32(uint32(elf.R_386_TLS_GOTIE) | uint32(elfsym)<<8) - } else { - return false - } - } - - return true -} - -func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool { - return false -} - -func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool { - var v uint32 - - rs := r.Xsym - - if rs.Dynid < 0 { - ld.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type) - return false - } - - out.Write32(uint32(sectoff)) - out.Write32(uint32(rs.Dynid)) - - switch r.Type { - default: - return false - - case objabi.R_DWARFSECREF: - v = ld.IMAGE_REL_I386_SECREL - - case objabi.R_ADDR: - v = ld.IMAGE_REL_I386_DIR32 - - case objabi.R_CALL, - objabi.R_PCREL: - v = ld.IMAGE_REL_I386_REL32 - } - - out.Write16(uint16(v)) - - return true -} - -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { - if ctxt.LinkMode == ld.LinkExternal { - return val, false - } - switch r.Type { - case objabi.R_CONST: - return r.Add, true - case objabi.R_GOTOFF: - return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true - } - - return val, false -} - -func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { - log.Fatalf("unexpected relocation variant") - return t -} - -func elfsetupplt(ctxt *ld.Link) { - plt := ctxt.Syms.Lookup(".plt", 0) - got := ctxt.Syms.Lookup(".got.plt", 0) - if plt.Size == 0 { - // pushl got+4 - plt.AddUint8(0xff) - - plt.AddUint8(0x35) - plt.AddAddrPlus(ctxt.Arch, got, 4) - - // jmp *got+8 - plt.AddUint8(0xff) - - plt.AddUint8(0x25) - plt.AddAddrPlus(ctxt.Arch, got, 8) - - // zero pad - plt.AddUint32(ctxt.Arch, 0) - - // assume got->size == 0 too - got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0) - - got.AddUint32(ctxt.Arch, 0) - got.AddUint32(ctxt.Arch, 0) - } -} - -func addpltsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Plt() >= 0 { - return - } - - ld.Adddynsym(ctxt, s) - - if ctxt.IsELF { - plt := ctxt.Syms.Lookup(".plt", 0) - got := ctxt.Syms.Lookup(".got.plt", 0) - rel := ctxt.Syms.Lookup(".rel.plt", 0) - if plt.Size == 0 { - elfsetupplt(ctxt) - } - - // jmpq *got+size - plt.AddUint8(0xff) - - plt.AddUint8(0x25) - plt.AddAddrPlus(ctxt.Arch, got, got.Size) - - // add to got: pointer to current pos in plt - got.AddAddrPlus(ctxt.Arch, plt, plt.Size) - - // pushl $x - plt.AddUint8(0x68) - - plt.AddUint32(ctxt.Arch, uint32(rel.Size)) - - // jmp .plt - plt.AddUint8(0xe9) - - plt.AddUint32(ctxt.Arch, uint32(-(plt.Size + 4))) - - // rel - rel.AddAddrPlus(ctxt.Arch, got, got.Size-4) - - rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT))) - - s.SetPlt(int32(plt.Size - 16)) - } else if ctxt.HeadType == objabi.Hdarwin { - // Same laziness as in 6l. - - plt := ctxt.Syms.Lookup(".plt", 0) - - addgotsym(ctxt, s) - - ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid)) - - // jmpq *got+size(IP) - s.SetPlt(int32(plt.Size)) - - plt.AddUint8(0xff) - plt.AddUint8(0x25) - plt.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got())) - } else { - ld.Errorf(s, "addpltsym: unsupported binary format") - } -} - -func addgotsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Got() >= 0 { - return - } - - ld.Adddynsym(ctxt, s) - got := ctxt.Syms.Lookup(".got", 0) - s.SetGot(int32(got.Size)) - got.AddUint32(ctxt.Arch, 0) - - if ctxt.IsELF { - rel := ctxt.Syms.Lookup(".rel", 0) - rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got())) - rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT))) - } else if ctxt.HeadType == objabi.Hdarwin { - ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(s.Dynid)) - } else { - ld.Errorf(s, "addgotsym: unsupported binary format") - } -} - -func asmb(ctxt *ld.Link) { - if ctxt.IsELF { - ld.Asmbelfsetup() - } - - sect := ld.Segtext.Sections[0] - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - // 0xCC is INT $3 - breakpoint instruction - ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC}) - for _, sect = range ld.Segtext.Sections[1:] { - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) - } - - if ld.Segrodata.Filelen > 0 { - ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) - } - if ld.Segrelrodata.Filelen > 0 { - ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen)) - } - - ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) - - ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff)) - ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) -} - -func asmb2(ctxt *ld.Link) { - machlink := uint32(0) - if ctxt.HeadType == objabi.Hdarwin { - machlink = uint32(ld.Domacholink(ctxt)) - } - - ld.Symsize = 0 - ld.Spsize = 0 - ld.Lcsize = 0 - symo := uint32(0) - if !*ld.FlagS { - // TODO: rationalize - switch ctxt.HeadType { - default: - if ctxt.IsELF { - symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) - symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound))) - } - - case objabi.Hplan9: - symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) - - case objabi.Hdarwin: - symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink)) - - case objabi.Hwindows: - symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) - symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN)) - } - - ctxt.Out.SeekSet(int64(symo)) - switch ctxt.HeadType { - default: - if ctxt.IsELF { - ld.Asmelfsym(ctxt) - ctxt.Out.Flush() - ctxt.Out.Write(ld.Elfstrdat) - - if ctxt.LinkMode == ld.LinkExternal { - ld.Elfemitreloc(ctxt) - } - } - - case objabi.Hplan9: - ld.Asmplan9sym(ctxt) - ctxt.Out.Flush() - - sym := ctxt.Syms.Lookup("pclntab", 0) - if sym != nil { - ld.Lcsize = int32(len(sym.P)) - ctxt.Out.Write(sym.P) - ctxt.Out.Flush() - } - - case objabi.Hwindows: - // Do nothing - - case objabi.Hdarwin: - if ctxt.LinkMode == ld.LinkExternal { - ld.Machoemitreloc(ctxt) - } - } - } - - ctxt.Out.SeekSet(0) - switch ctxt.HeadType { - default: - case objabi.Hplan9: /* plan9 */ - magic := int32(4*11*11 + 7) - - ctxt.Out.Write32b(uint32(magic)) /* magic */ - ctxt.Out.Write32b(uint32(ld.Segtext.Filelen)) /* sizes */ - ctxt.Out.Write32b(uint32(ld.Segdata.Filelen)) - ctxt.Out.Write32b(uint32(ld.Segdata.Length - ld.Segdata.Filelen)) - ctxt.Out.Write32b(uint32(ld.Symsize)) /* nsyms */ - ctxt.Out.Write32b(uint32(ld.Entryvalue(ctxt))) /* va of entry */ - ctxt.Out.Write32b(uint32(ld.Spsize)) /* sp offsets */ - ctxt.Out.Write32b(uint32(ld.Lcsize)) /* line offsets */ - - case objabi.Hdarwin: - ld.Asmbmacho(ctxt) - - case objabi.Hlinux, - objabi.Hfreebsd, - objabi.Hnetbsd, - objabi.Hopenbsd: - ld.Asmbelf(ctxt, int64(symo)) - - case objabi.Hwindows: - ld.Asmbpe(ctxt) - } - - ctxt.Out.Flush() -} diff --git a/src/cmd/oldlink/internal/x86/l.go b/src/cmd/oldlink/internal/x86/l.go deleted file mode 100644 index 0f104eab57..0000000000 --- a/src/cmd/oldlink/internal/x86/l.go +++ /dev/null @@ -1,43 +0,0 @@ -// Inferno utils/8l/l.h -// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package x86 - -const ( - maxAlign = 32 // max data alignment - minAlign = 1 // min data alignment - funcAlign = 16 -) - -/* Used by ../internal/ld/dwarf.go */ -const ( - dwarfRegSP = 4 - dwarfRegLR = 8 -) diff --git a/src/cmd/oldlink/internal/x86/obj.go b/src/cmd/oldlink/internal/x86/obj.go deleted file mode 100644 index b78ccbaf99..0000000000 --- a/src/cmd/oldlink/internal/x86/obj.go +++ /dev/null @@ -1,113 +0,0 @@ -// 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 - } -} diff --git a/src/cmd/oldlink/main.go b/src/cmd/oldlink/main.go deleted file mode 100644 index be1d0fde3b..0000000000 --- a/src/cmd/oldlink/main.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// 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) -}