From: Cherry Zhang Date: Wed, 11 Sep 2019 19:57:39 +0000 (-0400) Subject: [dev.link] cmd/internal/goobj: support parsing new object file X-Git-Tag: go1.14beta1~292^2^2~79 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=d79380026cd9f3a65e4896e77a7f3fbe1a954934;p=gostls13.git [dev.link] cmd/internal/goobj: support parsing new object file Add support of parsing new object file format. We use the new parser if the magic string matches the new one, otherwise use the old one. The parsed data are still filled into the current goobj API. In the future we may consider to change the goobj API to a close match of the object file data. Now objdump and nm commands support new object file format. For a reference to a symbol defined in another package, with the new object file format we don't know its name. Write it as pkg.<#nn> for now, where nn is its symbol index. Change-Id: I06d05b2ca834ba36980da3c5d76aee16c3b0a483 Reviewed-on: https://go-review.googlesource.com/c/go/+/196031 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Than McIntosh --- diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go index 0c70b8cd9f..2a3afffeb0 100644 --- a/src/cmd/internal/goobj/read.go +++ b/src/cmd/internal/goobj/read.go @@ -503,6 +503,11 @@ func (r *objReader) parseObject(prefix []byte) error { // TODO: extract OS + build ID if/when we need it r.readFull(r.tmp[:8]) + if bytes.Equal(r.tmp[:8], []byte("\x00go114LD")) { + r.offset -= 8 + r.readNew() + return nil + } if !bytes.Equal(r.tmp[:8], []byte("\x00go114ld")) { return r.error(errCorruptObject) } diff --git a/src/cmd/internal/goobj/readnew.go b/src/cmd/internal/goobj/readnew.go new file mode 100644 index 0000000000..442784de3a --- /dev/null +++ b/src/cmd/internal/goobj/readnew.go @@ -0,0 +1,163 @@ +// 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 goobj + +import ( + "cmd/internal/goobj2" + "cmd/internal/objabi" + "fmt" +) + +// Read object file in new format. For now we still fill +// the data to the current goobj API. +func (r *objReader) readNew() { + start := uint32(r.offset) + rr := goobj2.NewReader(r.f, start) + if rr == nil { + panic("cannot read object file") + } + + // Imports + pkglist := rr.Pkglist() + r.p.Imports = pkglist[1:] // index 0 is a dummy invalid package + + abiToVer := func(abi uint16) int64 { + var vers int64 + if abi == goobj2.SymABIstatic { + // Static symbol + vers = r.p.MaxVersion + } + return vers + } + + resolveSymRef := func(s goobj2.SymRef) SymID { + var i int + switch p := s.PkgIdx; p { + case goobj2.PkgIdxInvalid: + if s.SymIdx != 0 { + panic("bad sym ref") + } + return SymID{} + case goobj2.PkgIdxNone: + i = int(s.SymIdx) + rr.NSym() + case goobj2.PkgIdxBuiltin: + panic("PkgIdxBuiltin is unused") + case goobj2.PkgIdxSelf: + i = int(s.SymIdx) + default: + pkg := pkglist[p] + return SymID{fmt.Sprintf("%s.<#%d>", pkg, s.SymIdx), 0} + } + sym := goobj2.Sym{} + sym.Read(rr, rr.SymOff(i)) + return SymID{sym.Name, abiToVer(sym.ABI)} + } + + // Read things for the current goobj API for now. + + // Symbols + pcdataBase := start + rr.PcdataBase() + n := rr.NSym() + rr.NNonpkgdef() + rr.NNonpkgref() + ndef := rr.NSym() + rr.NNonpkgdef() + for i := 0; i < n; i++ { + osym := goobj2.Sym{} + osym.Read(rr, rr.SymOff(i)) + if osym.Name == "" { + continue // not a real symbol + } + symID := SymID{Name: osym.Name, Version: abiToVer(osym.ABI)} + r.p.SymRefs = append(r.p.SymRefs, symID) + + if i >= ndef { + continue // not a defined symbol from here + } + + // Symbol data + dataOff := rr.DataOff(i) + siz := int64(rr.DataSize(i)) + + sym := Sym{ + SymID: symID, + Kind: objabi.SymKind(osym.Type), + DupOK: osym.Flag&goobj2.SymFlagDupok != 0, + Size: int64(osym.Siz), + Data: Data{int64(start + dataOff), siz}, + } + r.p.Syms = append(r.p.Syms, &sym) + + // Reloc + nreloc := rr.NReloc(i) + sym.Reloc = make([]Reloc, nreloc) + for j := 0; j < nreloc; j++ { + rel := goobj2.Reloc{} + rel.Read(rr, rr.RelocOff(i, j)) + sym.Reloc[j] = Reloc{ + Offset: int64(rel.Off), + Size: int64(rel.Siz), + Type: objabi.RelocType(rel.Type), + Add: rel.Add, + Sym: resolveSymRef(rel.Sym), + } + } + + // Aux symbol info + isym := -1 + funcdata := make([]goobj2.SymRef, 0, 4) + naux := rr.NAux(i) + for j := 0; j < naux; j++ { + a := goobj2.Aux{} + a.Read(rr, rr.AuxOff(i, j)) + switch a.Type { + case goobj2.AuxGotype: + sym.Type = resolveSymRef(a.Sym) + case goobj2.AuxFuncInfo: + if a.Sym.PkgIdx != goobj2.PkgIdxSelf { + panic("funcinfo symbol not defined in current package") + } + isym = int(a.Sym.SymIdx) + case goobj2.AuxFuncdata: + funcdata = append(funcdata, a.Sym) + default: + panic("unknown aux type") + } + } + + // Symbol Info + if isym == -1 { + continue + } + b := rr.BytesAt(rr.DataOff(isym), rr.DataSize(isym)) + info := goobj2.FuncInfo{} + info.Read(b) + + info.Pcdata = append(info.Pcdata, info.PcdataEnd) // for the ease of knowing where it ends + f := &Func{ + Args: int64(info.Args), + Frame: int64(info.Locals), + NoSplit: info.NoSplit != 0, + Leaf: info.Flags&goobj2.FuncFlagLeaf != 0, + TopFrame: info.Flags&goobj2.FuncFlagTopFrame != 0, + PCSP: Data{int64(pcdataBase + info.Pcsp), int64(info.Pcfile - info.Pcsp)}, + PCFile: Data{int64(pcdataBase + info.Pcfile), int64(info.Pcline - info.Pcfile)}, + PCLine: Data{int64(pcdataBase + info.Pcline), int64(info.Pcinline - info.Pcline)}, + PCInline: Data{int64(pcdataBase + info.Pcinline), int64(info.Pcdata[0] - info.Pcinline)}, + PCData: make([]Data, len(info.Pcdata)-1), // -1 as we appended one above + FuncData: make([]FuncData, len(info.Funcdataoff)), + File: make([]string, len(info.File)), + } + sym.Func = f + for k := range f.PCData { + f.PCData[k] = Data{int64(pcdataBase + info.Pcdata[k]), int64(info.Pcdata[k+1] - info.Pcdata[k])} + } + for k := range f.FuncData { + symID := resolveSymRef(funcdata[k]) + f.FuncData[k] = FuncData{symID, int64(info.Funcdataoff[k])} + } + for k := range f.File { + symID := resolveSymRef(info.File[k]) + f.File[k] = symID.Name + } + } +}