summaryrefslogtreecommitdiff
path: root/src/cmd/link/prog.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/prog.go')
-rw-r--r--src/cmd/link/prog.go182
1 files changed, 182 insertions, 0 deletions
diff --git a/src/cmd/link/prog.go b/src/cmd/link/prog.go
new file mode 100644
index 0000000000..ec98e863f2
--- /dev/null
+++ b/src/cmd/link/prog.go
@@ -0,0 +1,182 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "debug/goobj"
+ "fmt"
+ "go/build"
+ "io"
+ "os"
+)
+
+// A Prog holds state for constructing an executable (program) image.
+//
+// The usual sequence of operations on a Prog is:
+//
+// p.init()
+// p.scan(file)
+// p.dead()
+// p.runtime()
+// p.layout()
+// p.load()
+// p.debug()
+// p.write(w)
+//
+// p.init is in this file. The rest of the methods are in files
+// named for the method. The convenience method p.link runs
+// this sequence.
+//
+type Prog struct {
+ // Context
+ GOOS string // target operating system
+ GOARCH string // target architecture
+ Format string // desired file format ("elf", "macho", ...)
+ formatter formatter
+ Error func(string) // called to report an error (if set)
+ NumError int // number of errors printed
+
+ // Input
+ Packages map[string]*Package // loaded packages, by import path
+ Syms map[goobj.SymID]*Sym // defined symbols, by symbol ID
+ Missing map[goobj.SymID]bool // missing symbols, by symbol ID
+ MaxVersion int // max SymID.Version, for generating fresh symbol IDs
+
+ // Output
+ UnmappedSize Addr // size of unmapped region at address 0
+ HeaderSize Addr // size of object file header
+ Entry Addr // virtual address where execution begins
+ Segments []*Segment // loaded memory segments
+}
+
+// startSymID is the symbol where program execution begins.
+var startSymID = goobj.SymID{Name: "_rt0_go"}
+
+// A formatter takes care of the details of generating a particular
+// kind of executable file.
+type formatter interface {
+ // headerSize returns the footprint of the header for p
+ // in both virtual address space and file bytes.
+ // The footprint does not include any bytes stored at the
+ // end of the file.
+ headerSize(p *Prog) (virt, file Addr)
+
+ // write writes the executable file for p to w.
+ write(w io.Writer, p *Prog)
+}
+
+// An Addr represents a virtual memory address, a file address, or a size.
+// It must be a uint64, not a uintptr, so that a 32-bit linker can still generate a 64-bit binary.
+// It must be unsigned in order to link programs placed at very large start addresses.
+// Math involving Addrs must be checked carefully not to require negative numbers.
+type Addr uint64
+
+// A Package is a Go package loaded from a file.
+type Package struct {
+ *goobj.Package // table of contents
+ File string // file name for reopening
+ Syms []*Sym // symbols defined by this package
+}
+
+// A Sym is a symbol defined in a loaded package.
+type Sym struct {
+ *goobj.Sym // symbol metadata from package file
+ Package *Package // package defining symbol
+ Section *Section // section where symbol is placed in output program
+ Addr Addr // virtual address of symbol in output program
+}
+
+// A Segment is a loaded memory segment.
+// A Prog is expected to have segments named "text" and optionally "data",
+// in that order, before any other segments.
+type Segment struct {
+ Name string // name of segment: "text", "data", ...
+ VirtAddr Addr // virtual memory address of segment base
+ VirtSize Addr // size of segment in memory
+ FileOffset Addr // file offset of segment base
+ FileSize Addr // size of segment in file; can be less than VirtSize
+ Sections []*Section // sections inside segment
+ Data []byte // raw data of segment image
+}
+
+// A Section is part of a loaded memory segment.
+type Section struct {
+ Name string // name of section: "text", "rodata", "noptrbss", and so on
+ VirtAddr Addr // virtual memory address of section base
+ Size Addr // size of section in memory
+ Align Addr // required alignment
+ InFile bool // section has image data in file (like data, unlike bss)
+ Syms []*Sym // symbols stored in section
+ Segment *Segment // segment containing section
+}
+
+func (p *Prog) errorf(format string, args ...interface{}) {
+ if p.Error != nil {
+ p.Error(fmt.Sprintf(format, args...))
+ } else {
+ fmt.Fprintf(os.Stderr, format+"\n", args...)
+ }
+ p.NumError++
+}
+
+// link is the one-stop convenience method for running a link.
+// It writes to w the object file generated from using mainFile as the main package.
+func (p *Prog) link(w io.Writer, mainFile string) {
+ p.init()
+ p.scan(mainFile)
+ if p.NumError > 0 {
+ return
+ }
+ p.dead()
+ p.runtime()
+ p.layout()
+ if p.NumError > 0 {
+ return
+ }
+ p.load()
+ if p.NumError > 0 {
+ return
+ }
+ p.debug()
+ if p.NumError > 0 {
+ return
+ }
+ p.write(w)
+}
+
+// init initializes p for use by the other methods.
+func (p *Prog) init() {
+ // Set default context if not overridden.
+ if p.GOOS == "" {
+ p.GOOS = build.Default.GOOS
+ }
+ if p.GOARCH == "" {
+ p.GOARCH = build.Default.GOARCH
+ }
+ if p.Format == "" {
+ p.Format = goosFormat[p.GOOS]
+ if p.Format == "" {
+ p.errorf("no default file format for GOOS %q", p.GOOS)
+ return
+ }
+ }
+
+ // Derive internal context.
+ p.formatter = formatters[p.Format]
+ if p.formatter == nil {
+ p.errorf("unknown output file format %q", p.Format)
+ return
+ }
+}
+
+// goosFormat records the default format for each known GOOS value.
+var goosFormat = map[string]string{
+ "darwin": "darwin",
+}
+
+// formatters records the format implementation for each known format value.
+var formatters = map[string]formatter{
+ "darwin": machoFormat{},
+}