github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/ld/objfile.go (about)

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