summaryrefslogtreecommitdiff
path: root/src/cmd/link/prog.go
blob: 77fb1ece5b1685c09358973870dadf7001830621 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// 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 (
	"cmd/internal/goobj"
	"encoding/binary"
	"fmt"
	"go/build"
	"io"
	"os"
	"runtime"
)

// 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", ...)
	Error    func(string) // called to report an error (if set)
	NumError int          // number of errors printed
	StartSym string

	// Derived context
	arch
	formatter   formatter
	startSym    goobj.SymID
	pkgdir      string
	omitRuntime bool // do not load runtime package

	// 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
	Dead       map[goobj.SymID]bool // symbols removed as dead
	SymOrder   []*Sym               // order syms were scanned
	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
}

// An arch describes architecture-dependent settings.
type arch struct {
	byteorder binary.ByteOrder
	ptrsize   int
	pcquantum int
}

// 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
	Bytes      []byte   // symbol data, for internally defined symbols
}

// 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.autoData()
	p.layout()
	p.autoConst()
	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
		}
	}
	if p.StartSym == "" {
		p.StartSym = fmt.Sprintf("_rt0_%s_%s", p.GOARCH, p.GOOS)
	}

	// Derive internal context.
	p.formatter = formatters[p.Format]
	if p.formatter == nil {
		p.errorf("unknown output file format %q", p.Format)
		return
	}
	p.startSym = goobj.SymID{Name: p.StartSym}
	arch, ok := arches[p.GOARCH]
	if !ok {
		p.errorf("unknown GOOS %q", p.GOOS)
		return
	}
	p.arch = arch

	p.pkgdir = fmt.Sprintf("%s/pkg/%s_%s", runtime.GOROOT(), p.GOOS, p.GOARCH)
}

// 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{},
}

var arches = map[string]arch{
	"amd64": {
		byteorder: binary.LittleEndian,
		ptrsize:   8,
		pcquantum: 1,
	},
}