github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/newlink/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 }