github.com/zach-klippenstein/go@v0.0.0-20150108044943-fcfbeb3adf58/src/cmd/link/layout.go (about)

     1  // Copyright 2014 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Executable image layout - address assignment.
     6  
     7  package main
     8  
     9  import (
    10  	"cmd/internal/goobj"
    11  )
    12  
    13  // A layoutSection describes a single section to add to the
    14  // final executable. Go binaries only have a fixed set of possible
    15  // sections, and the symbol kind determines the section.
    16  type layoutSection struct {
    17  	Segment string
    18  	Section string
    19  	Kind    goobj.SymKind
    20  	Index   int
    21  }
    22  
    23  // layout defines the layout of the generated Go executable.
    24  // The order of entries here is the order in the executable.
    25  // Entries with the same Segment name must be contiguous.
    26  var layout = []layoutSection{
    27  	{Segment: "text", Section: "text", Kind: goobj.STEXT},
    28  	{Segment: "rodata", Section: "rodata", Kind: goobj.SRODATA},
    29  	{Segment: "rodata", Section: "functab", Kind: goobj.SPCLNTAB},
    30  	{Segment: "rodata", Section: "typelink", Kind: goobj.STYPELINK},
    31  	{Segment: "data", Section: "noptrdata", Kind: goobj.SNOPTRDATA},
    32  	{Segment: "data", Section: "data", Kind: goobj.SDATA},
    33  	{Segment: "data", Section: "bss", Kind: goobj.SBSS},
    34  	{Segment: "data", Section: "noptrbss", Kind: goobj.SNOPTRBSS},
    35  
    36  	// Later:
    37  	//	{"rodata", "type", goobj.STYPE},
    38  	//	{"rodata", "string", goobj.SSTRING},
    39  	//	{"rodata", "gostring", goobj.SGOSTRING},
    40  	//	{"rodata", "gofunc", goobj.SGOFUNC},
    41  }
    42  
    43  // layoutByKind maps from SymKind to an entry in layout.
    44  var layoutByKind []*layoutSection
    45  
    46  func init() {
    47  	// Build index from symbol type to layout entry.
    48  	max := 0
    49  	for _, sect := range layout {
    50  		if max <= int(sect.Kind) {
    51  			max = int(sect.Kind) + 1
    52  		}
    53  	}
    54  	layoutByKind = make([]*layoutSection, max)
    55  	for i := range layout {
    56  		sect := &layout[i]
    57  		layoutByKind[sect.Kind] = sect
    58  		sect.Index = i
    59  	}
    60  }
    61  
    62  // layout arranges symbols into sections and sections into segments,
    63  // and then it assigns addresses to segments, sections, and symbols.
    64  func (p *Prog) layout() {
    65  	sections := make([]*Section, len(layout))
    66  
    67  	// Assign symbols to sections using index, creating sections as needed.
    68  	// Could keep sections separated by type during input instead.
    69  	for _, sym := range p.SymOrder {
    70  		kind := sym.Kind
    71  		if kind < 0 || int(kind) >= len(layoutByKind) || layoutByKind[kind] == nil {
    72  			p.errorf("%s: unexpected symbol kind %v", sym.SymID, kind)
    73  			continue
    74  		}
    75  		lsect := layoutByKind[kind]
    76  		sect := sections[lsect.Index]
    77  		if sect == nil {
    78  			sect = &Section{
    79  				Name:  lsect.Section,
    80  				Align: 1,
    81  			}
    82  			sections[lsect.Index] = sect
    83  		}
    84  		if sym.Data.Size > 0 || len(sym.Bytes) > 0 {
    85  			sect.InFile = true
    86  		}
    87  		sym.Section = sect
    88  		sect.Syms = append(sect.Syms, sym)
    89  
    90  		// TODO(rsc): Incorporate alignment information.
    91  		// First that information needs to be added to the object files.
    92  		//
    93  		// if sect.Align < Addr(sym.Align) {
    94  		//	sect.Align = Addr(sym.Align)
    95  		// }
    96  	}
    97  
    98  	// Assign sections to segments, creating segments as needed.
    99  	var seg *Segment
   100  	for i, sect := range sections {
   101  		if sect == nil {
   102  			continue
   103  		}
   104  		segName := layout[i].Segment
   105  
   106  		// Special case: Mach-O does not support "rodata" segment,
   107  		// so store read-only data in text segment.
   108  		if p.GOOS == "darwin" && segName == "rodata" {
   109  			segName = "text"
   110  		}
   111  
   112  		if seg == nil || seg.Name != segName {
   113  			seg = &Segment{
   114  				Name: segName,
   115  			}
   116  			p.Segments = append(p.Segments, seg)
   117  		}
   118  		sect.Segment = seg
   119  		seg.Sections = append(seg.Sections, sect)
   120  	}
   121  
   122  	// Assign addresses.
   123  
   124  	// TODO(rsc): This choice needs to be informed by both
   125  	// the formatter and the target architecture.
   126  	// And maybe eventually a command line flag (sigh).
   127  	const segAlign = 4096
   128  
   129  	// TODO(rsc): Use a larger amount on most systems, which will let the
   130  	// compiler eliminate more nil checks.
   131  	if p.UnmappedSize == 0 {
   132  		p.UnmappedSize = segAlign
   133  	}
   134  
   135  	// TODO(rsc): addr := Addr(0) when generating a shared library or PIE.
   136  	addr := p.UnmappedSize
   137  
   138  	// Account for initial file header.
   139  	hdrVirt, hdrFile := p.formatter.headerSize(p)
   140  	addr += hdrVirt
   141  
   142  	// Assign addresses to segments, sections, symbols.
   143  	// Assign sizes to segments, sections.
   144  	startVirt := addr
   145  	startFile := hdrFile
   146  	for _, seg := range p.Segments {
   147  		addr = round(addr, segAlign)
   148  		seg.VirtAddr = addr
   149  		seg.FileOffset = startFile + seg.VirtAddr - startVirt
   150  		for _, sect := range seg.Sections {
   151  			addr = round(addr, sect.Align)
   152  			sect.VirtAddr = addr
   153  			for _, sym := range sect.Syms {
   154  				// TODO(rsc): Respect alignment once we have that information.
   155  				sym.Addr = addr
   156  				addr += Addr(sym.Size)
   157  			}
   158  			sect.Size = addr - sect.VirtAddr
   159  			if sect.InFile {
   160  				seg.FileSize = addr - seg.VirtAddr
   161  			}
   162  		}
   163  		seg.VirtSize = addr - seg.VirtAddr
   164  	}
   165  
   166  	// Define symbols for section names.
   167  	var progEnd Addr
   168  	for i, sect := range sections {
   169  		name := layout[i].Section
   170  		var start, end Addr
   171  		if sect != nil {
   172  			start = sect.VirtAddr
   173  			end = sect.VirtAddr + sect.Size
   174  		}
   175  		p.defineConst("runtime."+name, start)
   176  		p.defineConst("runtime.e"+name, end)
   177  		progEnd = end
   178  	}
   179  	p.defineConst("runtime.end", progEnd)
   180  }