]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.cc] cmd/objwriter: implement using cmd/internal/obj
authorRuss Cox <rsc@golang.org>
Mon, 19 Jan 2015 19:41:34 +0000 (14:41 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 21 Jan 2015 03:02:35 +0000 (03:02 +0000)
New code but nothing interesting.
It's nearly all parsing code for the format written by liblink.
The interesting part is the call to obj.Writeobjdirect, which
is the Go translation of the C liblink writeobjdirect function.

Change-Id: I2e9e755e7a3c999302e2ef2c7475c0af9c5acdd2
Reviewed-on: https://go-review.googlesource.com/3047
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/objwriter/main.go

index 25a9def876f4f01de9f28ff0403cb1754dc631f6..27c2fb7636f10dabe43d6c707960bbea0c3555ad 100644 (file)
 // used otherwise.
 package main
 
-import "cmd/internal/obj"
 import (
+       "bufio"
+       "bytes"
+       "flag"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "log"
+       "math"
+       "os"
+       "runtime/pprof"
+       "strconv"
+       "strings"
+
+       "cmd/internal/obj"
+       "cmd/internal/obj/arm"
+       "cmd/internal/obj/i386"
+       "cmd/internal/obj/ppc64"
        "cmd/internal/obj/x86"
 )
 
-// TODO(rsc): Implement.
-// For now we just check that the objwriter binary is available to be run.
+var arch *obj.LinkArch
+var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
+var memprofile = flag.String("memprofile", "", "write memory profile to this file")
 
 func main() {
-       _ = obj.Exported
-       _ = x86.Exported
+       log.SetPrefix("goobj: ")
+       log.SetFlags(0)
+       flag.Parse()
+
+       if flag.NArg() == 1 && flag.Arg(0) == "ping" {
+               // old invocation from liblink, just testing that objwriter exists
+               return
+       }
+
+       if flag.NArg() != 4 {
+               fmt.Fprintf(os.Stderr, "usage: goobj infile objfile offset goarch\n")
+               os.Exit(2)
+       }
+
+       if *cpuprofile != "" {
+               f, err := os.Create(*cpuprofile)
+               if err != nil {
+                       log.Fatal(err)
+               }
+               pprof.StartCPUProfile(f)
+               defer pprof.StopCPUProfile()
+       }
+       if *memprofile != "" {
+               f, err := os.Create(*memprofile)
+               if err != nil {
+                       log.Fatal(err)
+               }
+               defer pprof.WriteHeapProfile(f)
+       }
+
+       switch flag.Arg(3) {
+       case "amd64":
+               arch = &x86.Linkamd64
+       case "amd64p32":
+               arch = &x86.Linkamd64p32
+       case "386":
+               // TODO(rsc): Move Link386 to package x86.
+               arch = &i386.Link386
+       case "arm":
+               arch = &arm.Linkarm
+       case "ppc64":
+               arch = &ppc64.Linkppc64
+       case "ppc64le":
+               arch = &ppc64.Linkppc64le
+       }
+
+       input()
+}
+
+const (
+       // must match liblink/objfilego.c
+       TypeEnd = iota
+       TypeCtxt
+       TypePlist
+       TypeSym
+       TypeProg
+       TypeAddr
+       TypeHist
+)
+
+var (
+       ctxt   *obj.Link
+       plists = map[int64]*obj.Plist{}
+       syms   = map[int64]*obj.LSym{}
+       progs  = map[int64]*obj.Prog{}
+       hists  = map[int64]*obj.Hist{}
+       undef  = map[interface{}]bool{}
+)
+
+func input() {
+       args := flag.Args()
+       ctxt = obj.Linknew(arch)
+       ctxt.Debugasm = 1
+       ctxt.Bso = obj.Binitw(os.Stdout)
+       defer obj.Bflush(ctxt.Bso)
+       ctxt.Diag = log.Fatalf
+       f, err := os.Open(args[0])
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       b := bufio.NewReaderSize(f, 1<<20)
+       if v := rdint(b); v != TypeCtxt {
+               log.Fatalf("invalid input - missing ctxt - got %d", v)
+       }
+       name := rdstring(b)
+       if name != ctxt.Arch.Name {
+               log.Fatalf("bad arch %s - want %s", name, ctxt.Arch.Name)
+       }
+
+       ctxt.Goarm = int32(rdint(b))
+       ctxt.Debugasm = int32(rdint(b))
+       ctxt.Trimpath = rdstring(b)
+       ctxt.Plist = rdplist(b)
+       ctxt.Plast = rdplist(b)
+       ctxt.Hist = rdhist(b)
+       ctxt.Ehist = rdhist(b)
+       for {
+               i := rdint(b)
+               if i < 0 {
+                       break
+               }
+               ctxt.Hash[i] = rdsym(b)
+       }
+       last := int64(TypeCtxt)
+
+Loop:
+       for {
+               t := rdint(b)
+               switch t {
+               default:
+                       log.Fatalf("unexpected input after type %d: %v", last, t)
+               case TypeEnd:
+                       break Loop
+               case TypePlist:
+                       readplist(b, rdplist(b))
+               case TypeSym:
+                       readsym(b, rdsym(b))
+               case TypeProg:
+                       readprog(b, rdprog(b))
+               case TypeHist:
+                       readhist(b, rdhist(b))
+               }
+               last = t
+       }
+
+       if len(undef) > 0 {
+               panic("missing definitions")
+       }
+
+       var buf bytes.Buffer
+       obuf := obj.Binitw(&buf)
+       obj.Writeobjdirect(ctxt, obuf)
+       obj.Bflush(obuf)
+
+       data, err := ioutil.ReadFile(args[1])
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       offset, err := strconv.Atoi(args[2])
+       if err != nil {
+               log.Fatalf("bad offset: %v", err)
+       }
+       if offset > len(data) {
+               log.Fatalf("offset too large: %v > %v", offset, len(data))
+       }
+
+       old := data[offset:]
+       if len(old) > 0 && !bytes.Equal(old, buf.Bytes()) {
+               out := strings.TrimSuffix(args[0], ".in") + ".out"
+               if err := ioutil.WriteFile(out, append(data[:offset:offset], buf.Bytes()...), 0666); err != nil {
+                       log.Fatal(err)
+               }
+               log.Fatalf("goobj produced different output:\n\toriginal: %s\n\tgoobj: %s", args[1], out)
+       }
+
+       if len(old) == 0 {
+               data = append(data, buf.Bytes()...)
+               if err := ioutil.WriteFile(args[1], data, 0666); err != nil {
+                       log.Fatal(err)
+               }
+       }
+}
+
+func rdstring(b *bufio.Reader) string {
+       v := rdint(b)
+       buf := make([]byte, v)
+       io.ReadFull(b, buf)
+       return string(buf)
+}
+
+func rdint(b *bufio.Reader) int64 {
+       var v uint64
+       shift := uint(0)
+       for {
+               b, err := b.ReadByte()
+               if err != nil {
+                       log.Fatal(err)
+               }
+               v |= uint64(b&0x7F) << shift
+               shift += 7
+               if b&0x80 == 0 {
+                       break
+               }
+       }
+       return int64(v>>1) ^ int64(v<<63)>>63
+}
+
+func rdplist(b *bufio.Reader) *obj.Plist {
+       id := rdint(b)
+       if id == 0 {
+               return nil
+       }
+       pl := plists[id]
+       if pl == nil {
+               pl = new(obj.Plist)
+               plists[id] = pl
+               undef[pl] = true
+       }
+       return pl
+}
+
+func rdsym(b *bufio.Reader) *obj.LSym {
+       id := rdint(b)
+       if id == 0 {
+               return nil
+       }
+       sym := syms[id]
+       if sym == nil {
+               sym = new(obj.LSym)
+               syms[id] = sym
+               undef[sym] = true
+       }
+       return sym
+}
+
+func rdprog(b *bufio.Reader) *obj.Prog {
+       id := rdint(b)
+       if id == 0 {
+               return nil
+       }
+       prog := progs[id]
+       if prog == nil {
+               prog = new(obj.Prog)
+               prog.Ctxt = ctxt
+               progs[id] = prog
+               undef[prog] = true
+       }
+       return prog
+}
+
+func rdhist(b *bufio.Reader) *obj.Hist {
+       id := rdint(b)
+       if id == 0 {
+               return nil
+       }
+       h := hists[id]
+       if h == nil {
+               h = new(obj.Hist)
+               hists[id] = h
+               undef[h] = true
+       }
+       return h
+}
+
+func readplist(b *bufio.Reader, pl *obj.Plist) {
+       if !undef[pl] {
+               panic("double-def")
+       }
+       delete(undef, pl)
+       pl.Recur = int(rdint(b))
+       pl.Name = rdsym(b)
+       pl.Firstpc = rdprog(b)
+       pl.Link = rdplist(b)
+}
+
+func readsym(b *bufio.Reader, s *obj.LSym) {
+       if !undef[s] {
+               panic("double-def")
+       }
+       delete(undef, s)
+       s.Name = rdstring(b)
+       s.Extname = rdstring(b)
+       s.Type_ = int16(rdint(b))
+       s.Version = int16(rdint(b))
+       s.Dupok = uint8(rdint(b))
+       s.External = uint8(rdint(b))
+       s.Nosplit = uint8(rdint(b))
+       s.Reachable = uint8(rdint(b))
+       s.Cgoexport = uint8(rdint(b))
+       s.Special = uint8(rdint(b))
+       s.Stkcheck = uint8(rdint(b))
+       s.Hide = uint8(rdint(b))
+       s.Leaf = uint8(rdint(b))
+       s.Fnptr = uint8(rdint(b))
+       s.Seenglobl = uint8(rdint(b))
+       s.Onlist = uint8(rdint(b))
+       s.Symid = int16(rdint(b))
+       s.Dynid = int32(rdint(b))
+       s.Sig = int32(rdint(b))
+       s.Plt = int32(rdint(b))
+       s.Got = int32(rdint(b))
+       s.Align = int32(rdint(b))
+       s.Elfsym = int32(rdint(b))
+       s.Args = int32(rdint(b))
+       s.Locals = int32(rdint(b))
+       s.Value = rdint(b)
+       s.Size = rdint(b)
+       s.Hash = rdsym(b)
+       s.Allsym = rdsym(b)
+       s.Next = rdsym(b)
+       s.Sub = rdsym(b)
+       s.Outer = rdsym(b)
+       s.Gotype = rdsym(b)
+       s.Reachparent = rdsym(b)
+       s.Queue = rdsym(b)
+       s.File = rdstring(b)
+       s.Dynimplib = rdstring(b)
+       s.Dynimpvers = rdstring(b)
+       s.Text = rdprog(b)
+       s.Etext = rdprog(b)
+       n := int(rdint(b))
+       if n > 0 {
+               s.P = make([]byte, n)
+               io.ReadFull(b, s.P)
+       }
+       s.R = make([]obj.Reloc, int(rdint(b)))
+       for i := range s.R {
+               r := &s.R[i]
+               r.Off = int32(rdint(b))
+               r.Siz = uint8(rdint(b))
+               r.Done = uint8(rdint(b))
+               r.Type_ = int32(rdint(b))
+               r.Add = rdint(b)
+               r.Xadd = rdint(b)
+               r.Sym = rdsym(b)
+               r.Xsym = rdsym(b)
+       }
+}
+
+func readprog(b *bufio.Reader, p *obj.Prog) {
+       if !undef[p] {
+               panic("double-def")
+       }
+       delete(undef, p)
+       p.Pc = rdint(b)
+       p.Lineno = int32(rdint(b))
+       p.Link = rdprog(b)
+       p.As = int16(rdint(b))
+       p.Reg = uint8(rdint(b))
+       p.Scond = uint8(rdint(b))
+       p.Width = int8(rdint(b))
+       readaddr(b, &p.From)
+       readaddr(b, &p.From3)
+       readaddr(b, &p.To)
+}
+
+func readaddr(b *bufio.Reader, a *obj.Addr) {
+       if rdint(b) != TypeAddr {
+               log.Fatal("out of sync")
+       }
+       a.Offset = rdint(b)
+       a.U.Dval = rdfloat(b)
+       buf := make([]byte, 8)
+       io.ReadFull(b, buf)
+       a.U.Sval = string(buf)
+       a.U.Branch = rdprog(b)
+       a.Sym = rdsym(b)
+       a.Gotype = rdsym(b)
+       a.Type_ = int16(rdint(b))
+       a.Index = uint8(rdint(b))
+       a.Scale = int8(rdint(b))
+       a.Reg = int8(rdint(b))
+       a.Name = int8(rdint(b))
+       a.Class = int8(rdint(b))
+       a.Etype = uint8(rdint(b))
+       a.Offset2 = int32(rdint(b))
+       a.Width = rdint(b)
+}
+
+func readhist(b *bufio.Reader, h *obj.Hist) {
+       if !undef[h] {
+               panic("double-def")
+       }
+       delete(undef, h)
+       h.Link = rdhist(b)
+       h.Name = rdstring(b)
+       h.Line = int32(rdint(b))
+       h.Offset = int32(rdint(b))
+}
+
+func rdfloat(b *bufio.Reader) float64 {
+       return math.Float64frombits(uint64(rdint(b)))
 }