summaryrefslogtreecommitdiff
path: root/src/cmd/link/layout.go
blob: d5c291e255370ff36ed1bb8eb45fa6e09545ecc0 (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
// 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.

// Executable image layout - address assignment.

package main

import (
	"cmd/internal/goobj"
)

// A layoutSection describes a single section to add to the
// final executable. Go binaries only have a fixed set of possible
// sections, and the symbol kind determines the section.
type layoutSection struct {
	Segment string
	Section string
	Kind    goobj.SymKind
	Index   int
}

// layout defines the layout of the generated Go executable.
// The order of entries here is the order in the executable.
// Entries with the same Segment name must be contiguous.
var layout = []layoutSection{
	{Segment: "text", Section: "text", Kind: goobj.STEXT},
	{Segment: "rodata", Section: "rodata", Kind: goobj.SRODATA},
	{Segment: "rodata", Section: "functab", Kind: goobj.SPCLNTAB},
	{Segment: "rodata", Section: "typelink", Kind: goobj.STYPELINK},
	{Segment: "data", Section: "noptrdata", Kind: goobj.SNOPTRDATA},
	{Segment: "data", Section: "data", Kind: goobj.SDATA},
	{Segment: "data", Section: "bss", Kind: goobj.SBSS},
	{Segment: "data", Section: "noptrbss", Kind: goobj.SNOPTRBSS},

	// Later:
	//	{"rodata", "type", goobj.STYPE},
	//	{"rodata", "string", goobj.SSTRING},
	//	{"rodata", "gostring", goobj.SGOSTRING},
	//	{"rodata", "gofunc", goobj.SGOFUNC},
}

// layoutByKind maps from SymKind to an entry in layout.
var layoutByKind []*layoutSection

func init() {
	// Build index from symbol type to layout entry.
	max := 0
	for _, sect := range layout {
		if max <= int(sect.Kind) {
			max = int(sect.Kind) + 1
		}
	}
	layoutByKind = make([]*layoutSection, max)
	for i := range layout {
		sect := &layout[i]
		layoutByKind[sect.Kind] = sect
		sect.Index = i
	}
}

// layout arranges symbols into sections and sections into segments,
// and then it assigns addresses to segments, sections, and symbols.
func (p *Prog) layout() {
	sections := make([]*Section, len(layout))

	// Assign symbols to sections using index, creating sections as needed.
	// Could keep sections separated by type during input instead.
	for _, sym := range p.SymOrder {
		kind := sym.Kind
		if kind < 0 || int(kind) >= len(layoutByKind) || layoutByKind[kind] == nil {
			p.errorf("%s: unexpected symbol kind %v", sym.SymID, kind)
			continue
		}
		lsect := layoutByKind[kind]
		sect := sections[lsect.Index]
		if sect == nil {
			sect = &Section{
				Name:  lsect.Section,
				Align: 1,
			}
			sections[lsect.Index] = sect
		}
		if sym.Data.Size > 0 || len(sym.Bytes) > 0 {
			sect.InFile = true
		}
		sym.Section = sect
		sect.Syms = append(sect.Syms, sym)

		// TODO(rsc): Incorporate alignment information.
		// First that information needs to be added to the object files.
		//
		// if sect.Align < Addr(sym.Align) {
		//	sect.Align = Addr(sym.Align)
		// }
	}

	// Assign sections to segments, creating segments as needed.
	var seg *Segment
	for i, sect := range sections {
		if sect == nil {
			continue
		}
		segName := layout[i].Segment

		// Special case: Mach-O does not support "rodata" segment,
		// so store read-only data in text segment.
		if p.GOOS == "darwin" && segName == "rodata" {
			segName = "text"
		}

		if seg == nil || seg.Name != segName {
			seg = &Segment{
				Name: segName,
			}
			p.Segments = append(p.Segments, seg)
		}
		sect.Segment = seg
		seg.Sections = append(seg.Sections, sect)
	}

	// Assign addresses.

	// TODO(rsc): This choice needs to be informed by both
	// the formatter and the target architecture.
	// And maybe eventually a command line flag (sigh).
	const segAlign = 4096

	// TODO(rsc): Use a larger amount on most systems, which will let the
	// compiler eliminate more nil checks.
	if p.UnmappedSize == 0 {
		p.UnmappedSize = segAlign
	}

	// TODO(rsc): addr := Addr(0) when generating a shared library or PIE.
	addr := p.UnmappedSize

	// Account for initial file header.
	hdrVirt, hdrFile := p.formatter.headerSize(p)
	addr += hdrVirt

	// Assign addresses to segments, sections, symbols.
	// Assign sizes to segments, sections.
	startVirt := addr
	startFile := hdrFile
	for _, seg := range p.Segments {
		addr = round(addr, segAlign)
		seg.VirtAddr = addr
		seg.FileOffset = startFile + seg.VirtAddr - startVirt
		for _, sect := range seg.Sections {
			addr = round(addr, sect.Align)
			sect.VirtAddr = addr
			for _, sym := range sect.Syms {
				// TODO(rsc): Respect alignment once we have that information.
				sym.Addr = addr
				addr += Addr(sym.Size)
			}
			sect.Size = addr - sect.VirtAddr
			if sect.InFile {
				seg.FileSize = addr - seg.VirtAddr
			}
		}
		seg.VirtSize = addr - seg.VirtAddr
	}

	// Define symbols for section names.
	var progEnd Addr
	for i, sect := range sections {
		name := layout[i].Section
		var start, end Addr
		if sect != nil {
			start = sect.VirtAddr
			end = sect.VirtAddr + sect.Size
		}
		p.defineConst("runtime."+name, start)
		p.defineConst("runtime.e"+name, end)
		progEnd = end
	}
	p.defineConst("runtime.end", progEnd)
}