mirror of
https://github.com/golang/go
synced 2024-10-05 18:31:28 -06:00
2a141dedc4
In preparation for making the current linker cmd/link. If cmd/newlink is ever completed, it can be moved back. See golang-dev thread titled "go tool compile, etc" for background. Change-Id: I4029580f470038240c5181a37ea4202ba971f9ef Reviewed-on: https://go-review.googlesource.com/10286 Reviewed-by: Rob Pike <r@golang.org>
181 lines
4.9 KiB
Go
181 lines
4.9 KiB
Go
// 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)
|
|
}
|