| // 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 ( | |
| "debug/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(name, start) | |
| p.defineConst("e"+name, end) | |
| progEnd = end | |
| } | |
| p.defineConst("end", progEnd) | |
| } |