aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/newlink/layout.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/newlink/layout.go')
-rw-r--r--src/cmd/newlink/layout.go180
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)
+}