mirror of
https://github.com/golang/go
synced 2024-11-18 18:14:43 -07:00
[dev.cc] cmd/objwriter: implement using cmd/internal/obj
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>
This commit is contained in:
parent
d6f6e420fc
commit
35d3987dbc
@ -8,15 +8,404 @@
|
||||
// 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)))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user