diff options
Diffstat (limited to 'src/cmd/newlink/layout.go')
| -rw-r--r-- | src/cmd/newlink/layout.go | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/cmd/newlink/layout.go b/src/cmd/newlink/layout.go new file mode 100644 index 0000000000..d5c291e255 --- /dev/null +++ b/src/cmd/newlink/layout.go @@ -0,0 +1,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) +} |
