github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/newlink/load.go (about)

     1  // Copyright 2014 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  // Loading of code and data fragments from package files into final image.
     6  
     7  package main
     8  
     9  import (
    10  	"cmd/internal/obj"
    11  	"os"
    12  )
    13  
    14  // load allocates segment images, populates them with data
    15  // read from package files, and applies relocations to the data.
    16  func (p *Prog) load() {
    17  	// TODO(rsc): mmap the output file and store the data directly.
    18  	// That will make writing the output file more efficient.
    19  	for _, seg := range p.Segments {
    20  		seg.Data = make([]byte, seg.FileSize)
    21  	}
    22  	for _, pkg := range p.Packages {
    23  		p.loadPackage(pkg)
    24  	}
    25  }
    26  
    27  // loadPackage loads and relocates data for all the
    28  // symbols needed in the given package.
    29  func (p *Prog) loadPackage(pkg *Package) {
    30  	if pkg.File == "" {
    31  		// This "package" contains internally generated symbols only.
    32  		// All such symbols have a sym.Bytes field holding the actual data
    33  		// (if any), plus relocations.
    34  		for _, sym := range pkg.Syms {
    35  			if sym.Bytes == nil {
    36  				continue
    37  			}
    38  			seg := sym.Section.Segment
    39  			off := sym.Addr - seg.VirtAddr
    40  			data := seg.Data[off : off+Addr(sym.Size)]
    41  			copy(data, sym.Bytes)
    42  			p.relocateSym(sym, data)
    43  		}
    44  		return
    45  	}
    46  
    47  	// Package stored in file.
    48  	f, err := os.Open(pkg.File)
    49  	if err != nil {
    50  		p.errorf("%v", err)
    51  		return
    52  	}
    53  	defer f.Close()
    54  
    55  	// TODO(rsc): Mmap file into memory.
    56  
    57  	for _, sym := range pkg.Syms {
    58  		if sym.Data.Size == 0 {
    59  			continue
    60  		}
    61  		// TODO(rsc): If not using mmap, at least coalesce nearby reads.
    62  		if sym.Section == nil {
    63  			p.errorf("internal error: missing section for %s", sym.Name)
    64  		}
    65  		seg := sym.Section.Segment
    66  		off := sym.Addr - seg.VirtAddr
    67  		if off >= Addr(len(seg.Data)) || off+Addr(sym.Data.Size) > Addr(len(seg.Data)) {
    68  			p.errorf("internal error: allocated space for %s too small: %d bytes for %d+%d (%d)", sym, len(seg.Data), off, sym.Data.Size, sym.Size)
    69  		}
    70  		data := seg.Data[off : off+Addr(sym.Data.Size)]
    71  		_, err := f.ReadAt(data, sym.Data.Offset)
    72  		if err != nil {
    73  			p.errorf("reading %v: %v", sym.SymID, err)
    74  		}
    75  		p.relocateSym(sym, data)
    76  	}
    77  }
    78  
    79  // relocateSym applies relocations to sym's data.
    80  func (p *Prog) relocateSym(sym *Sym, data []byte) {
    81  	for i := range sym.Reloc {
    82  		r := &sym.Reloc[i]
    83  		targ := p.Syms[r.Sym]
    84  		if targ == nil {
    85  			p.errorf("%v: reference to undefined symbol %v", sym, r.Sym)
    86  			continue
    87  		}
    88  		val := targ.Addr + Addr(r.Add)
    89  		switch r.Type {
    90  		default:
    91  			p.errorf("%v: unknown relocation type %d", sym, r.Type)
    92  		case obj.R_ADDR, obj.R_CALLIND:
    93  			// ok
    94  		case obj.R_PCREL, obj.R_CALL:
    95  			val -= sym.Addr + Addr(r.Offset+r.Size)
    96  		}
    97  		frag := data[r.Offset : r.Offset+r.Size]
    98  		switch r.Size {
    99  		default:
   100  			p.errorf("%v: unknown relocation size %d", sym, r.Size)
   101  		case 4:
   102  			// TODO(rsc): Check for overflow?
   103  			p.byteorder.PutUint32(frag, uint32(val))
   104  		case 8:
   105  			p.byteorder.PutUint64(frag, uint64(val))
   106  		}
   107  	}
   108  }