github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/ld/objfile.go (about)

     1  // Copyright 2013 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ld
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"log"
    11  	"strconv"
    12  	"strings"
    13  )
    14  
    15  const (
    16  	startmagic = "\x00\x00go13ld"
    17  	endmagic   = "\xff\xffgo13ld"
    18  )
    19  
    20  func ldobjfile(ctxt *Link, f *Biobuf, pkg string, length int64, pn string) {
    21  	start := Boffset(f)
    22  	ctxt.Version++
    23  	var buf [8]uint8
    24  	Bread(f, buf[:])
    25  	if string(buf[:]) != startmagic {
    26  		log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
    27  	}
    28  	c := Bgetc(f)
    29  	if c != 1 {
    30  		log.Fatalf("%s: invalid file version number %d", pn, c)
    31  	}
    32  
    33  	var lib string
    34  	for {
    35  		lib = rdstring(f)
    36  		if lib == "" {
    37  			break
    38  		}
    39  		addlib(ctxt, pkg, pn, lib)
    40  	}
    41  
    42  	for {
    43  		c = Bgetc(f)
    44  		Bungetc(f)
    45  		if c == 0xff {
    46  			break
    47  		}
    48  		readsym(ctxt, f, pkg, pn)
    49  	}
    50  
    51  	buf = [8]uint8{}
    52  	Bread(f, buf[:])
    53  	if string(buf[:]) != endmagic {
    54  		log.Fatalf("%s: invalid file end", pn)
    55  	}
    56  
    57  	if Boffset(f) != start+length {
    58  		log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(Boffset(f)), int64(start+length))
    59  	}
    60  }
    61  
    62  var readsym_ndup int
    63  
    64  func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) {
    65  	if Bgetc(f) != 0xfe {
    66  		log.Fatalf("readsym out of sync")
    67  	}
    68  	t := int(rdint(f))
    69  	name := expandpkg(rdstring(f), pkg)
    70  	v := int(rdint(f))
    71  	if v != 0 && v != 1 {
    72  		log.Fatalf("invalid symbol version %d", v)
    73  	}
    74  	dupok := int(rdint(f))
    75  	dupok &= 1
    76  	size := int(rdint(f))
    77  	typ := rdsym(ctxt, f, pkg)
    78  	var data []byte
    79  	rddata(f, &data)
    80  	nreloc := int(rdint(f))
    81  
    82  	if v != 0 {
    83  		v = ctxt.Version
    84  	}
    85  	s := Linklookup(ctxt, name, v)
    86  	var dup *LSym
    87  	if s.Type != 0 && s.Type != SXREF {
    88  		if (t == SDATA || t == SBSS || t == SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
    89  			if s.Size < int64(size) {
    90  				s.Size = int64(size)
    91  			}
    92  			if typ != nil && s.Gotype == nil {
    93  				s.Gotype = typ
    94  			}
    95  			return
    96  		}
    97  
    98  		if (s.Type == SDATA || s.Type == SBSS || s.Type == SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
    99  			goto overwrite
   100  		}
   101  		if s.Type != SBSS && s.Type != SNOPTRBSS && dupok == 0 && s.Dupok == 0 {
   102  			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
   103  		}
   104  		if len(s.P) > 0 {
   105  			dup = s
   106  			s = linknewsym(ctxt, ".dup", readsym_ndup)
   107  			readsym_ndup++ // scratch
   108  		}
   109  	}
   110  
   111  overwrite:
   112  	s.File = pkg
   113  	s.Dupok = uint8(dupok)
   114  	if t == SXREF {
   115  		log.Fatalf("bad sxref")
   116  	}
   117  	if t == 0 {
   118  		log.Fatalf("missing type for %s in %s", name, pn)
   119  	}
   120  	if t == SBSS && (s.Type == SRODATA || s.Type == SNOPTRBSS) {
   121  		t = int(s.Type)
   122  	}
   123  	s.Type = int16(t)
   124  	if s.Size < int64(size) {
   125  		s.Size = int64(size)
   126  	}
   127  	if typ != nil { // if bss sym defined multiple times, take type from any one def
   128  		s.Gotype = typ
   129  	}
   130  	if dup != nil && typ != nil {
   131  		dup.Gotype = typ
   132  	}
   133  	s.P = data
   134  	s.P = s.P[:len(data)]
   135  	if nreloc > 0 {
   136  		s.R = make([]Reloc, nreloc)
   137  		s.R = s.R[:nreloc]
   138  		var r *Reloc
   139  		for i := 0; i < nreloc; i++ {
   140  			r = &s.R[i]
   141  			r.Off = int32(rdint(f))
   142  			r.Siz = uint8(rdint(f))
   143  			r.Type = int32(rdint(f))
   144  			r.Add = rdint(f)
   145  			r.Xadd = rdint(f)
   146  			r.Sym = rdsym(ctxt, f, pkg)
   147  			r.Xsym = rdsym(ctxt, f, pkg)
   148  		}
   149  	}
   150  
   151  	if len(s.P) > 0 && dup != nil && len(dup.P) > 0 && strings.HasPrefix(s.Name, "gclocals·") {
   152  		// content-addressed garbage collection liveness bitmap symbol.
   153  		// double check for hash collisions.
   154  		if !bytes.Equal(s.P, dup.P) {
   155  			log.Fatalf("dupok hash collision for %s in %s and %s", s.Name, s.File, pn)
   156  		}
   157  	}
   158  
   159  	if s.Type == STEXT {
   160  		s.Args = int32(rdint(f))
   161  		s.Locals = int32(rdint(f))
   162  		s.Nosplit = uint8(rdint(f))
   163  		v := int(rdint(f))
   164  		s.Leaf = uint8(v & 1)
   165  		s.Cfunc = uint8(v & 2)
   166  		n := int(rdint(f))
   167  		var a *Auto
   168  		for i := 0; i < n; i++ {
   169  			a = new(Auto)
   170  			a.Asym = rdsym(ctxt, f, pkg)
   171  			a.Aoffset = int32(rdint(f))
   172  			a.Name = int16(rdint(f))
   173  			a.Gotype = rdsym(ctxt, f, pkg)
   174  			a.Link = s.Autom
   175  			s.Autom = a
   176  		}
   177  
   178  		s.Pcln = new(Pcln)
   179  		pc := s.Pcln
   180  		rddata(f, &pc.Pcsp.P)
   181  		rddata(f, &pc.Pcfile.P)
   182  		rddata(f, &pc.Pcline.P)
   183  		n = int(rdint(f))
   184  		pc.Pcdata = make([]Pcdata, n)
   185  		pc.Npcdata = n
   186  		for i := 0; i < n; i++ {
   187  			rddata(f, &pc.Pcdata[i].P)
   188  		}
   189  		n = int(rdint(f))
   190  		pc.Funcdata = make([]*LSym, n)
   191  		pc.Funcdataoff = make([]int64, n)
   192  		pc.Nfuncdata = n
   193  		for i := 0; i < n; i++ {
   194  			pc.Funcdata[i] = rdsym(ctxt, f, pkg)
   195  		}
   196  		for i := 0; i < n; i++ {
   197  			pc.Funcdataoff[i] = rdint(f)
   198  		}
   199  		n = int(rdint(f))
   200  		pc.File = make([]*LSym, n)
   201  		pc.Nfile = n
   202  		for i := 0; i < n; i++ {
   203  			pc.File[i] = rdsym(ctxt, f, pkg)
   204  		}
   205  
   206  		if dup == nil {
   207  			if s.Onlist != 0 {
   208  				log.Fatalf("symbol %s listed multiple times", s.Name)
   209  			}
   210  			s.Onlist = 1
   211  			if ctxt.Etextp != nil {
   212  				ctxt.Etextp.Next = s
   213  			} else {
   214  				ctxt.Textp = s
   215  			}
   216  			ctxt.Etextp = s
   217  		}
   218  	}
   219  
   220  	if ctxt.Debugasm != 0 {
   221  		fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
   222  		if s.Version != 0 {
   223  			fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
   224  		}
   225  		if s.Type != 0 {
   226  			fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
   227  		}
   228  		if s.Dupok != 0 {
   229  			fmt.Fprintf(ctxt.Bso, "dupok ")
   230  		}
   231  		if s.Cfunc != 0 {
   232  			fmt.Fprintf(ctxt.Bso, "cfunc ")
   233  		}
   234  		if s.Nosplit != 0 {
   235  			fmt.Fprintf(ctxt.Bso, "nosplit ")
   236  		}
   237  		fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
   238  		if s.Type == STEXT {
   239  			fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
   240  		}
   241  		fmt.Fprintf(ctxt.Bso, "\n")
   242  		var c int
   243  		var j int
   244  		for i := 0; i < len(s.P); {
   245  			fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
   246  			for j = i; j < i+16 && j < len(s.P); j++ {
   247  				fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
   248  			}
   249  			for ; j < i+16; j++ {
   250  				fmt.Fprintf(ctxt.Bso, "   ")
   251  			}
   252  			fmt.Fprintf(ctxt.Bso, "  ")
   253  			for j = i; j < i+16 && j < len(s.P); j++ {
   254  				c = int(s.P[j])
   255  				if ' ' <= c && c <= 0x7e {
   256  					fmt.Fprintf(ctxt.Bso, "%c", c)
   257  				} else {
   258  					fmt.Fprintf(ctxt.Bso, ".")
   259  				}
   260  			}
   261  
   262  			fmt.Fprintf(ctxt.Bso, "\n")
   263  			i += 16
   264  		}
   265  
   266  		var r *Reloc
   267  		for i := 0; i < len(s.R); i++ {
   268  			r = &s.R[i]
   269  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, r.Sym.Name, int64(r.Add))
   270  		}
   271  	}
   272  }
   273  
   274  func rdint(f *Biobuf) int64 {
   275  	var c int
   276  
   277  	uv := uint64(0)
   278  	for shift := 0; ; shift += 7 {
   279  		if shift >= 64 {
   280  			log.Fatalf("corrupt input")
   281  		}
   282  		c = Bgetc(f)
   283  		uv |= uint64(c&0x7F) << uint(shift)
   284  		if c&0x80 == 0 {
   285  			break
   286  		}
   287  	}
   288  
   289  	return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
   290  }
   291  
   292  func rdstring(f *Biobuf) string {
   293  	n := rdint(f)
   294  	p := make([]byte, n)
   295  	Bread(f, p)
   296  	return string(p)
   297  }
   298  
   299  func rddata(f *Biobuf, pp *[]byte) {
   300  	n := rdint(f)
   301  	*pp = make([]byte, n)
   302  	Bread(f, *pp)
   303  }
   304  
   305  var symbuf []byte
   306  
   307  func rdsym(ctxt *Link, f *Biobuf, pkg string) *LSym {
   308  	n := int(rdint(f))
   309  	if n == 0 {
   310  		rdint(f)
   311  		return nil
   312  	}
   313  
   314  	if len(symbuf) < n {
   315  		symbuf = make([]byte, n)
   316  	}
   317  	Bread(f, symbuf[:n])
   318  	p := string(symbuf[:n])
   319  	v := int(rdint(f))
   320  	if v != 0 {
   321  		v = ctxt.Version
   322  	}
   323  	s := Linklookup(ctxt, expandpkg(p, pkg), v)
   324  
   325  	if v == 0 && s.Name[0] == '$' && s.Type == 0 {
   326  		if strings.HasPrefix(s.Name, "$f32.") {
   327  			x, _ := strconv.ParseUint(s.Name[5:], 16, 32)
   328  			i32 := int32(x)
   329  			s.Type = SRODATA
   330  			s.Local = true
   331  			Adduint32(ctxt, s, uint32(i32))
   332  			s.Reachable = false
   333  		} else if strings.HasPrefix(s.Name, "$f64.") || strings.HasPrefix(s.Name, "$i64.") {
   334  			x, _ := strconv.ParseUint(s.Name[5:], 16, 64)
   335  			i64 := int64(x)
   336  			s.Type = SRODATA
   337  			s.Local = true
   338  			Adduint64(ctxt, s, uint64(i64))
   339  			s.Reachable = false
   340  		}
   341  	}
   342  
   343  	return s
   344  }