123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755 |
- // 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.
- // Writing Go object files.
- package obj
- import (
- "bytes"
- "github.com/twitchyliquid64/golang-asm/bio"
- "github.com/twitchyliquid64/golang-asm/goobj"
- "github.com/twitchyliquid64/golang-asm/objabi"
- "github.com/twitchyliquid64/golang-asm/sys"
- "crypto/sha1"
- "encoding/binary"
- "fmt"
- "io"
- "path/filepath"
- "sort"
- "strings"
- )
- // Entry point of writing new object file.
- func WriteObjFile(ctxt *Link, b *bio.Writer) {
- debugAsmEmit(ctxt)
- genFuncInfoSyms(ctxt)
- w := writer{
- Writer: goobj.NewWriter(b),
- ctxt: ctxt,
- pkgpath: objabi.PathToPrefix(ctxt.Pkgpath),
- }
- start := b.Offset()
- w.init()
- // Header
- // We just reserve the space. We'll fill in the offsets later.
- flags := uint32(0)
- if ctxt.Flag_shared {
- flags |= goobj.ObjFlagShared
- }
- if w.pkgpath == "" {
- flags |= goobj.ObjFlagNeedNameExpansion
- }
- if ctxt.IsAsm {
- flags |= goobj.ObjFlagFromAssembly
- }
- h := goobj.Header{
- Magic: goobj.Magic,
- Fingerprint: ctxt.Fingerprint,
- Flags: flags,
- }
- h.Write(w.Writer)
- // String table
- w.StringTable()
- // Autolib
- h.Offsets[goobj.BlkAutolib] = w.Offset()
- for i := range ctxt.Imports {
- ctxt.Imports[i].Write(w.Writer)
- }
- // Package references
- h.Offsets[goobj.BlkPkgIdx] = w.Offset()
- for _, pkg := range w.pkglist {
- w.StringRef(pkg)
- }
- // File table (for DWARF and pcln generation).
- h.Offsets[goobj.BlkFile] = w.Offset()
- for _, f := range ctxt.PosTable.FileTable() {
- w.StringRef(filepath.ToSlash(f))
- }
- // Symbol definitions
- h.Offsets[goobj.BlkSymdef] = w.Offset()
- for _, s := range ctxt.defs {
- w.Sym(s)
- }
- // Short hashed symbol definitions
- h.Offsets[goobj.BlkHashed64def] = w.Offset()
- for _, s := range ctxt.hashed64defs {
- w.Sym(s)
- }
- // Hashed symbol definitions
- h.Offsets[goobj.BlkHasheddef] = w.Offset()
- for _, s := range ctxt.hasheddefs {
- w.Sym(s)
- }
- // Non-pkg symbol definitions
- h.Offsets[goobj.BlkNonpkgdef] = w.Offset()
- for _, s := range ctxt.nonpkgdefs {
- w.Sym(s)
- }
- // Non-pkg symbol references
- h.Offsets[goobj.BlkNonpkgref] = w.Offset()
- for _, s := range ctxt.nonpkgrefs {
- w.Sym(s)
- }
- // Referenced package symbol flags
- h.Offsets[goobj.BlkRefFlags] = w.Offset()
- w.refFlags()
- // Hashes
- h.Offsets[goobj.BlkHash64] = w.Offset()
- for _, s := range ctxt.hashed64defs {
- w.Hash64(s)
- }
- h.Offsets[goobj.BlkHash] = w.Offset()
- for _, s := range ctxt.hasheddefs {
- w.Hash(s)
- }
- // TODO: hashedrefs unused/unsupported for now
- // Reloc indexes
- h.Offsets[goobj.BlkRelocIdx] = w.Offset()
- nreloc := uint32(0)
- lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs}
- for _, list := range lists {
- for _, s := range list {
- w.Uint32(nreloc)
- nreloc += uint32(len(s.R))
- }
- }
- w.Uint32(nreloc)
- // Symbol Info indexes
- h.Offsets[goobj.BlkAuxIdx] = w.Offset()
- naux := uint32(0)
- for _, list := range lists {
- for _, s := range list {
- w.Uint32(naux)
- naux += uint32(nAuxSym(s))
- }
- }
- w.Uint32(naux)
- // Data indexes
- h.Offsets[goobj.BlkDataIdx] = w.Offset()
- dataOff := uint32(0)
- for _, list := range lists {
- for _, s := range list {
- w.Uint32(dataOff)
- dataOff += uint32(len(s.P))
- }
- }
- w.Uint32(dataOff)
- // Relocs
- h.Offsets[goobj.BlkReloc] = w.Offset()
- for _, list := range lists {
- for _, s := range list {
- for i := range s.R {
- w.Reloc(&s.R[i])
- }
- }
- }
- // Aux symbol info
- h.Offsets[goobj.BlkAux] = w.Offset()
- for _, list := range lists {
- for _, s := range list {
- w.Aux(s)
- }
- }
- // Data
- h.Offsets[goobj.BlkData] = w.Offset()
- for _, list := range lists {
- for _, s := range list {
- w.Bytes(s.P)
- }
- }
- // Pcdata
- h.Offsets[goobj.BlkPcdata] = w.Offset()
- for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
- if s.Func != nil {
- pc := &s.Func.Pcln
- w.Bytes(pc.Pcsp.P)
- w.Bytes(pc.Pcfile.P)
- w.Bytes(pc.Pcline.P)
- w.Bytes(pc.Pcinline.P)
- for i := range pc.Pcdata {
- w.Bytes(pc.Pcdata[i].P)
- }
- }
- }
- // Blocks used only by tools (objdump, nm).
- // Referenced symbol names from other packages
- h.Offsets[goobj.BlkRefName] = w.Offset()
- w.refNames()
- h.Offsets[goobj.BlkEnd] = w.Offset()
- // Fix up block offsets in the header
- end := start + int64(w.Offset())
- b.MustSeek(start, 0)
- h.Write(w.Writer)
- b.MustSeek(end, 0)
- }
- type writer struct {
- *goobj.Writer
- ctxt *Link
- pkgpath string // the package import path (escaped), "" if unknown
- pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
- }
- // prepare package index list
- func (w *writer) init() {
- w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
- w.pkglist[0] = "" // dummy invalid package for index 0
- for pkg, i := range w.ctxt.pkgIdx {
- w.pkglist[i] = pkg
- }
- }
- func (w *writer) StringTable() {
- w.AddString("")
- for _, p := range w.ctxt.Imports {
- w.AddString(p.Pkg)
- }
- for _, pkg := range w.pkglist {
- w.AddString(pkg)
- }
- w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
- // TODO: this includes references of indexed symbols from other packages,
- // for which the linker doesn't need the name. Consider moving them to
- // a separate block (for tools only).
- if w.pkgpath != "" {
- s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
- }
- // Don't put names of builtins into the string table (to save
- // space).
- if s.PkgIdx == goobj.PkgIdxBuiltin {
- return
- }
- w.AddString(s.Name)
- })
- // All filenames are in the postable.
- for _, f := range w.ctxt.PosTable.FileTable() {
- w.AddString(filepath.ToSlash(f))
- }
- }
- func (w *writer) Sym(s *LSym) {
- abi := uint16(s.ABI())
- if s.Static() {
- abi = goobj.SymABIstatic
- }
- flag := uint8(0)
- if s.DuplicateOK() {
- flag |= goobj.SymFlagDupok
- }
- if s.Local() {
- flag |= goobj.SymFlagLocal
- }
- if s.MakeTypelink() {
- flag |= goobj.SymFlagTypelink
- }
- if s.Leaf() {
- flag |= goobj.SymFlagLeaf
- }
- if s.NoSplit() {
- flag |= goobj.SymFlagNoSplit
- }
- if s.ReflectMethod() {
- flag |= goobj.SymFlagReflectMethod
- }
- if s.TopFrame() {
- flag |= goobj.SymFlagTopFrame
- }
- if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
- flag |= goobj.SymFlagGoType
- }
- flag2 := uint8(0)
- if s.UsedInIface() {
- flag2 |= goobj.SymFlagUsedInIface
- }
- if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
- flag2 |= goobj.SymFlagItab
- }
- name := s.Name
- if strings.HasPrefix(name, "gofile..") {
- name = filepath.ToSlash(name)
- }
- var align uint32
- if s.Func != nil {
- align = uint32(s.Func.Align)
- }
- if s.ContentAddressable() {
- // We generally assume data symbols are natually aligned,
- // except for strings. If we dedup a string symbol and a
- // non-string symbol with the same content, we should keep
- // the largest alignment.
- // TODO: maybe the compiler could set the alignment for all
- // data symbols more carefully.
- if s.Size != 0 && !strings.HasPrefix(s.Name, "go.string.") {
- switch {
- case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
- align = 8
- case s.Size%4 == 0:
- align = 4
- case s.Size%2 == 0:
- align = 2
- }
- // don't bother setting align to 1.
- }
- }
- var o goobj.Sym
- o.SetName(name, w.Writer)
- o.SetABI(abi)
- o.SetType(uint8(s.Type))
- o.SetFlag(flag)
- o.SetFlag2(flag2)
- o.SetSiz(uint32(s.Size))
- o.SetAlign(align)
- o.Write(w.Writer)
- }
- func (w *writer) Hash64(s *LSym) {
- if !s.ContentAddressable() || len(s.R) != 0 {
- panic("Hash of non-content-addresable symbol")
- }
- b := contentHash64(s)
- w.Bytes(b[:])
- }
- func (w *writer) Hash(s *LSym) {
- if !s.ContentAddressable() {
- panic("Hash of non-content-addresable symbol")
- }
- b := w.contentHash(s)
- w.Bytes(b[:])
- }
- func contentHash64(s *LSym) goobj.Hash64Type {
- var b goobj.Hash64Type
- copy(b[:], s.P)
- return b
- }
- // Compute the content hash for a content-addressable symbol.
- // We build a content hash based on its content and relocations.
- // Depending on the category of the referenced symbol, we choose
- // different hash algorithms such that the hash is globally
- // consistent.
- // - For referenced content-addressable symbol, its content hash
- // is globally consistent.
- // - For package symbol and builtin symbol, its local index is
- // globally consistent.
- // - For non-package symbol, its fully-expanded name is globally
- // consistent. For now, we require we know the current package
- // path so we can always expand symbol names. (Otherwise,
- // symbols with relocations are not considered hashable.)
- //
- // For now, we assume there is no circular dependencies among
- // hashed symbols.
- func (w *writer) contentHash(s *LSym) goobj.HashType {
- h := sha1.New()
- // The compiler trims trailing zeros _sometimes_. We just do
- // it always.
- h.Write(bytes.TrimRight(s.P, "\x00"))
- var tmp [14]byte
- for i := range s.R {
- r := &s.R[i]
- binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
- tmp[4] = r.Siz
- tmp[5] = uint8(r.Type)
- binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
- h.Write(tmp[:])
- rs := r.Sym
- switch rs.PkgIdx {
- case goobj.PkgIdxHashed64:
- h.Write([]byte{0})
- t := contentHash64(rs)
- h.Write(t[:])
- case goobj.PkgIdxHashed:
- h.Write([]byte{1})
- t := w.contentHash(rs)
- h.Write(t[:])
- case goobj.PkgIdxNone:
- h.Write([]byte{2})
- io.WriteString(h, rs.Name) // name is already expanded at this point
- case goobj.PkgIdxBuiltin:
- h.Write([]byte{3})
- binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
- h.Write(tmp[:4])
- case goobj.PkgIdxSelf:
- io.WriteString(h, w.pkgpath)
- binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
- h.Write(tmp[:4])
- default:
- io.WriteString(h, rs.Pkg)
- binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
- h.Write(tmp[:4])
- }
- }
- var b goobj.HashType
- copy(b[:], h.Sum(nil))
- return b
- }
- func makeSymRef(s *LSym) goobj.SymRef {
- if s == nil {
- return goobj.SymRef{}
- }
- if s.PkgIdx == 0 || !s.Indexed() {
- fmt.Printf("unindexed symbol reference: %v\n", s)
- panic("unindexed symbol reference")
- }
- return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
- }
- func (w *writer) Reloc(r *Reloc) {
- var o goobj.Reloc
- o.SetOff(r.Off)
- o.SetSiz(r.Siz)
- o.SetType(uint8(r.Type))
- o.SetAdd(r.Add)
- o.SetSym(makeSymRef(r.Sym))
- o.Write(w.Writer)
- }
- func (w *writer) aux1(typ uint8, rs *LSym) {
- var o goobj.Aux
- o.SetType(typ)
- o.SetSym(makeSymRef(rs))
- o.Write(w.Writer)
- }
- func (w *writer) Aux(s *LSym) {
- if s.Gotype != nil {
- w.aux1(goobj.AuxGotype, s.Gotype)
- }
- if s.Func != nil {
- w.aux1(goobj.AuxFuncInfo, s.Func.FuncInfoSym)
- for _, d := range s.Func.Pcln.Funcdata {
- w.aux1(goobj.AuxFuncdata, d)
- }
- if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
- w.aux1(goobj.AuxDwarfInfo, s.Func.dwarfInfoSym)
- }
- if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
- w.aux1(goobj.AuxDwarfLoc, s.Func.dwarfLocSym)
- }
- if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
- w.aux1(goobj.AuxDwarfRanges, s.Func.dwarfRangesSym)
- }
- if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
- w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
- }
- }
- }
- // Emits flags of referenced indexed symbols.
- func (w *writer) refFlags() {
- seen := make(map[*LSym]bool)
- w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
- switch rs.PkgIdx {
- case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
- return
- case goobj.PkgIdxInvalid:
- panic("unindexed symbol reference")
- }
- if seen[rs] {
- return
- }
- seen[rs] = true
- symref := makeSymRef(rs)
- flag2 := uint8(0)
- if rs.UsedInIface() {
- flag2 |= goobj.SymFlagUsedInIface
- }
- if flag2 == 0 {
- return // no need to write zero flags
- }
- var o goobj.RefFlags
- o.SetSym(symref)
- o.SetFlag2(flag2)
- o.Write(w.Writer)
- })
- }
- // Emits names of referenced indexed symbols, used by tools (objdump, nm)
- // only.
- func (w *writer) refNames() {
- seen := make(map[*LSym]bool)
- w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
- switch rs.PkgIdx {
- case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
- return
- case goobj.PkgIdxInvalid:
- panic("unindexed symbol reference")
- }
- if seen[rs] {
- return
- }
- seen[rs] = true
- symref := makeSymRef(rs)
- var o goobj.RefName
- o.SetSym(symref)
- o.SetName(rs.Name, w.Writer)
- o.Write(w.Writer)
- })
- // TODO: output in sorted order?
- // Currently tools (cmd/internal/goobj package) doesn't use mmap,
- // and it just read it into a map in memory upfront. If it uses
- // mmap, if the output is sorted, it probably could avoid reading
- // into memory and just do lookups in the mmap'd object file.
- }
- // return the number of aux symbols s have.
- func nAuxSym(s *LSym) int {
- n := 0
- if s.Gotype != nil {
- n++
- }
- if s.Func != nil {
- // FuncInfo is an aux symbol, each Funcdata is an aux symbol
- n += 1 + len(s.Func.Pcln.Funcdata)
- if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
- n++
- }
- if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
- n++
- }
- if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
- n++
- }
- if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
- n++
- }
- }
- return n
- }
- // generate symbols for FuncInfo.
- func genFuncInfoSyms(ctxt *Link) {
- infosyms := make([]*LSym, 0, len(ctxt.Text))
- var pcdataoff uint32
- var b bytes.Buffer
- symidx := int32(len(ctxt.defs))
- for _, s := range ctxt.Text {
- if s.Func == nil {
- continue
- }
- o := goobj.FuncInfo{
- Args: uint32(s.Func.Args),
- Locals: uint32(s.Func.Locals),
- FuncID: objabi.FuncID(s.Func.FuncID),
- }
- pc := &s.Func.Pcln
- o.Pcsp = pcdataoff
- pcdataoff += uint32(len(pc.Pcsp.P))
- o.Pcfile = pcdataoff
- pcdataoff += uint32(len(pc.Pcfile.P))
- o.Pcline = pcdataoff
- pcdataoff += uint32(len(pc.Pcline.P))
- o.Pcinline = pcdataoff
- pcdataoff += uint32(len(pc.Pcinline.P))
- o.Pcdata = make([]uint32, len(pc.Pcdata))
- for i, pcd := range pc.Pcdata {
- o.Pcdata[i] = pcdataoff
- pcdataoff += uint32(len(pcd.P))
- }
- o.PcdataEnd = pcdataoff
- o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
- for i, x := range pc.Funcdataoff {
- o.Funcdataoff[i] = uint32(x)
- }
- i := 0
- o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
- for f := range pc.UsedFiles {
- o.File[i] = f
- i++
- }
- sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
- o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
- for i, inl := range pc.InlTree.nodes {
- f, l := getFileIndexAndLine(ctxt, inl.Pos)
- o.InlTree[i] = goobj.InlTreeNode{
- Parent: int32(inl.Parent),
- File: goobj.CUFileIndex(f),
- Line: l,
- Func: makeSymRef(inl.Func),
- ParentPC: inl.ParentPC,
- }
- }
- o.Write(&b)
- isym := &LSym{
- Type: objabi.SDATA, // for now, I don't think it matters
- PkgIdx: goobj.PkgIdxSelf,
- SymIdx: symidx,
- P: append([]byte(nil), b.Bytes()...),
- }
- isym.Set(AttrIndexed, true)
- symidx++
- infosyms = append(infosyms, isym)
- s.Func.FuncInfoSym = isym
- b.Reset()
- dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym, s.Func.dwarfInfoSym}
- for _, s := range dwsyms {
- if s == nil || s.Size == 0 {
- continue
- }
- s.PkgIdx = goobj.PkgIdxSelf
- s.SymIdx = symidx
- s.Set(AttrIndexed, true)
- symidx++
- infosyms = append(infosyms, s)
- }
- }
- ctxt.defs = append(ctxt.defs, infosyms...)
- }
- // debugDumpAux is a dumper for selected aux symbols.
- func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
- // Most aux symbols (ex: funcdata) are not interesting--
- // pick out just the DWARF ones for now.
- if aux.Type != objabi.SDWARFLOC &&
- aux.Type != objabi.SDWARFFCN &&
- aux.Type != objabi.SDWARFABSFCN &&
- aux.Type != objabi.SDWARFLINES &&
- aux.Type != objabi.SDWARFRANGE {
- return
- }
- ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
- }
- func debugAsmEmit(ctxt *Link) {
- if ctxt.Debugasm > 0 {
- ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
- if ctxt.Debugasm > 1 {
- fn := func(par *LSym, aux *LSym) {
- writeAuxSymDebug(ctxt, par, aux)
- }
- ctxt.traverseAuxSyms(traverseAux, fn)
- }
- }
- }
- func (ctxt *Link) writeSymDebug(s *LSym) {
- ctxt.writeSymDebugNamed(s, s.Name)
- }
- func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
- ver := ""
- if ctxt.Debugasm > 1 {
- ver = fmt.Sprintf("<%d>", s.ABI())
- }
- fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
- if s.Type != 0 {
- fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
- }
- if s.Static() {
- fmt.Fprint(ctxt.Bso, "static ")
- }
- if s.DuplicateOK() {
- fmt.Fprintf(ctxt.Bso, "dupok ")
- }
- if s.CFunc() {
- fmt.Fprintf(ctxt.Bso, "cfunc ")
- }
- if s.NoSplit() {
- fmt.Fprintf(ctxt.Bso, "nosplit ")
- }
- if s.TopFrame() {
- fmt.Fprintf(ctxt.Bso, "topframe ")
- }
- fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
- if s.Type == objabi.STEXT {
- fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(s.Func.Args), uint64(s.Func.Locals), uint64(s.Func.FuncID))
- if s.Leaf() {
- fmt.Fprintf(ctxt.Bso, " leaf")
- }
- }
- fmt.Fprintf(ctxt.Bso, "\n")
- if s.Type == objabi.STEXT {
- for p := s.Func.Text; p != nil; p = p.Link {
- fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
- if ctxt.Debugasm > 1 {
- io.WriteString(ctxt.Bso, p.String())
- } else {
- p.InnermostString(ctxt.Bso)
- }
- fmt.Fprintln(ctxt.Bso)
- }
- }
- for i := 0; i < len(s.P); i += 16 {
- fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
- j := i
- for ; j < i+16 && j < len(s.P); j++ {
- fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
- }
- for ; j < i+16; j++ {
- fmt.Fprintf(ctxt.Bso, " ")
- }
- fmt.Fprintf(ctxt.Bso, " ")
- for j = i; j < i+16 && j < len(s.P); j++ {
- c := int(s.P[j])
- b := byte('.')
- if ' ' <= c && c <= 0x7e {
- b = byte(c)
- }
- ctxt.Bso.WriteByte(b)
- }
- fmt.Fprintf(ctxt.Bso, "\n")
- }
- sort.Sort(relocByOff(s.R)) // generate stable output
- for _, r := range s.R {
- name := ""
- ver := ""
- if r.Sym != nil {
- name = r.Sym.Name
- if ctxt.Debugasm > 1 {
- ver = fmt.Sprintf("<%d>", s.ABI())
- }
- } else if r.Type == objabi.R_TLS_LE {
- name = "TLS"
- }
- if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
- fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%x\n", int(r.Off), r.Siz, r.Type, name, ver, uint64(r.Add))
- } else {
- fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
- }
- }
- }
- // relocByOff sorts relocations by their offsets.
- type relocByOff []Reloc
- func (x relocByOff) Len() int { return len(x) }
- func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
- func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|