github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/link/prog.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  package main
     6  
     7  import (
     8  	"cmd/internal/goobj"
     9  	"encoding/binary"
    10  	"fmt"
    11  	"go/build"
    12  	"io"
    13  	"os"
    14  	"runtime"
    15  )
    16  
    17  // A Prog holds state for constructing an executable (program) image.
    18  //
    19  // The usual sequence of operations on a Prog is:
    20  //
    21  //	p.init()
    22  //	p.scan(file)
    23  //	p.dead()
    24  //	p.runtime()
    25  //	p.layout()
    26  //	p.load()
    27  //	p.debug()
    28  //	p.write(w)
    29  //
    30  // p.init is in this file. The rest of the methods are in files
    31  // named for the method. The convenience method p.link runs
    32  // this sequence.
    33  //
    34  type Prog struct {
    35  	// Context
    36  	GOOS     string       // target operating system
    37  	GOARCH   string       // target architecture
    38  	Format   string       // desired file format ("elf", "macho", ...)
    39  	Error    func(string) // called to report an error (if set)
    40  	NumError int          // number of errors printed
    41  	StartSym string
    42  
    43  	// Derived context
    44  	arch
    45  	formatter   formatter
    46  	startSym    goobj.SymID
    47  	pkgdir      string
    48  	omitRuntime bool // do not load runtime package
    49  
    50  	// Input
    51  	Packages   map[string]*Package  // loaded packages, by import path
    52  	Syms       map[goobj.SymID]*Sym // defined symbols, by symbol ID
    53  	Missing    map[goobj.SymID]bool // missing symbols
    54  	Dead       map[goobj.SymID]bool // symbols removed as dead
    55  	SymOrder   []*Sym               // order syms were scanned
    56  	MaxVersion int                  // max SymID.Version, for generating fresh symbol IDs
    57  
    58  	// Output
    59  	UnmappedSize Addr       // size of unmapped region at address 0
    60  	HeaderSize   Addr       // size of object file header
    61  	Entry        Addr       // virtual address where execution begins
    62  	Segments     []*Segment // loaded memory segments
    63  }
    64  
    65  // An arch describes architecture-dependent settings.
    66  type arch struct {
    67  	byteorder binary.ByteOrder
    68  	ptrsize   int
    69  	pcquantum int
    70  }
    71  
    72  // A formatter takes care of the details of generating a particular
    73  // kind of executable file.
    74  type formatter interface {
    75  	// headerSize returns the footprint of the header for p
    76  	// in both virtual address space and file bytes.
    77  	// The footprint does not include any bytes stored at the
    78  	// end of the file.
    79  	headerSize(p *Prog) (virt, file Addr)
    80  
    81  	// write writes the executable file for p to w.
    82  	write(w io.Writer, p *Prog)
    83  }
    84  
    85  // An Addr represents a virtual memory address, a file address, or a size.
    86  // It must be a uint64, not a uintptr, so that a 32-bit linker can still generate a 64-bit binary.
    87  // It must be unsigned in order to link programs placed at very large start addresses.
    88  // Math involving Addrs must be checked carefully not to require negative numbers.
    89  type Addr uint64
    90  
    91  // A Package is a Go package loaded from a file.
    92  type Package struct {
    93  	*goobj.Package        // table of contents
    94  	File           string // file name for reopening
    95  	Syms           []*Sym // symbols defined by this package
    96  }
    97  
    98  // A Sym is a symbol defined in a loaded package.
    99  type Sym struct {
   100  	*goobj.Sym          // symbol metadata from package file
   101  	Package    *Package // package defining symbol
   102  	Section    *Section // section where symbol is placed in output program
   103  	Addr       Addr     // virtual address of symbol in output program
   104  	Bytes      []byte   // symbol data, for internally defined symbols
   105  }
   106  
   107  // A Segment is a loaded memory segment.
   108  // A Prog is expected to have segments named "text" and optionally "data",
   109  // in that order, before any other segments.
   110  type Segment struct {
   111  	Name       string     // name of segment: "text", "data", ...
   112  	VirtAddr   Addr       // virtual memory address of segment base
   113  	VirtSize   Addr       // size of segment in memory
   114  	FileOffset Addr       // file offset of segment base
   115  	FileSize   Addr       // size of segment in file; can be less than VirtSize
   116  	Sections   []*Section // sections inside segment
   117  	Data       []byte     // raw data of segment image
   118  }
   119  
   120  // A Section is part of a loaded memory segment.
   121  type Section struct {
   122  	Name     string   // name of section: "text", "rodata", "noptrbss", and so on
   123  	VirtAddr Addr     // virtual memory address of section base
   124  	Size     Addr     // size of section in memory
   125  	Align    Addr     // required alignment
   126  	InFile   bool     // section has image data in file (like data, unlike bss)
   127  	Syms     []*Sym   // symbols stored in section
   128  	Segment  *Segment // segment containing section
   129  }
   130  
   131  func (p *Prog) errorf(format string, args ...interface{}) {
   132  	if p.Error != nil {
   133  		p.Error(fmt.Sprintf(format, args...))
   134  	} else {
   135  		fmt.Fprintf(os.Stderr, format+"\n", args...)
   136  	}
   137  	p.NumError++
   138  }
   139  
   140  // link is the one-stop convenience method for running a link.
   141  // It writes to w the object file generated from using mainFile as the main package.
   142  func (p *Prog) link(w io.Writer, mainFile string) {
   143  	p.init()
   144  	p.scan(mainFile)
   145  	if p.NumError > 0 {
   146  		return
   147  	}
   148  	p.dead()
   149  	p.runtime()
   150  	p.autoData()
   151  	p.layout()
   152  	p.autoConst()
   153  	if p.NumError > 0 {
   154  		return
   155  	}
   156  	p.load()
   157  	if p.NumError > 0 {
   158  		return
   159  	}
   160  	p.debug()
   161  	if p.NumError > 0 {
   162  		return
   163  	}
   164  	p.write(w)
   165  }
   166  
   167  // init initializes p for use by the other methods.
   168  func (p *Prog) init() {
   169  	// Set default context if not overridden.
   170  	if p.GOOS == "" {
   171  		p.GOOS = build.Default.GOOS
   172  	}
   173  	if p.GOARCH == "" {
   174  		p.GOARCH = build.Default.GOARCH
   175  	}
   176  	if p.Format == "" {
   177  		p.Format = goosFormat[p.GOOS]
   178  		if p.Format == "" {
   179  			p.errorf("no default file format for GOOS %q", p.GOOS)
   180  			return
   181  		}
   182  	}
   183  	if p.StartSym == "" {
   184  		p.StartSym = fmt.Sprintf("_rt0_%s_%s", p.GOARCH, p.GOOS)
   185  	}
   186  
   187  	// Derive internal context.
   188  	p.formatter = formatters[p.Format]
   189  	if p.formatter == nil {
   190  		p.errorf("unknown output file format %q", p.Format)
   191  		return
   192  	}
   193  	p.startSym = goobj.SymID{Name: p.StartSym}
   194  	arch, ok := arches[p.GOARCH]
   195  	if !ok {
   196  		p.errorf("unknown GOOS %q", p.GOOS)
   197  		return
   198  	}
   199  	p.arch = arch
   200  
   201  	p.pkgdir = fmt.Sprintf("%s/pkg/%s_%s", runtime.GOROOT(), p.GOOS, p.GOARCH)
   202  }
   203  
   204  // goosFormat records the default format for each known GOOS value.
   205  var goosFormat = map[string]string{
   206  	"darwin": "darwin",
   207  }
   208  
   209  // formatters records the format implementation for each known format value.
   210  var formatters = map[string]formatter{
   211  	"darwin": machoFormat{},
   212  }
   213  
   214  var arches = map[string]arch{
   215  	"amd64": {
   216  		byteorder: binary.LittleEndian,
   217  		ptrsize:   8,
   218  		pcquantum: 1,
   219  	},
   220  }