// 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. // Loading of code and data fragments from package files into final image. package main import "os" // load allocates segment images, populates them with data // read from package files, and applies relocations to the data. func (p *Prog) load() { // TODO(rsc): mmap the output file and store the data directly. // That will make writing the output file more efficient. for _, seg := range p.Segments { seg.Data = make([]byte, seg.FileSize) } for _, pkg := range p.Packages { p.loadPackage(pkg) } } // loadPackage loads and relocates data for all the // symbols needed in the given package. func (p *Prog) loadPackage(pkg *Package) { if pkg.File == "" { // This "package" contains internally generated symbols only. // All such symbols have a sym.Bytes field holding the actual data // (if any), plus relocations. for _, sym := range pkg.Syms { if sym.Bytes == nil { continue } seg := sym.Section.Segment off := sym.Addr - seg.VirtAddr data := seg.Data[off : off+Addr(sym.Size)] copy(data, sym.Bytes) p.relocateSym(sym, data) } return } // Package stored in file. f, err := os.Open(pkg.File) if err != nil { p.errorf("%v", err) return } defer f.Close() // TODO(rsc): Mmap file into memory. for _, sym := range pkg.Syms { if sym.Data.Size == 0 { continue } // TODO(rsc): If not using mmap, at least coalesce nearby reads. if sym.Section == nil { p.errorf("internal error: missing section for %s", sym.Name) } seg := sym.Section.Segment off := sym.Addr - seg.VirtAddr if off >= Addr(len(seg.Data)) || off+Addr(sym.Data.Size) > Addr(len(seg.Data)) { p.errorf("internal error: allocated space for %s too small: %d bytes for %d+%d (%d)", sym, len(seg.Data), off, sym.Data.Size, sym.Size) } data := seg.Data[off : off+Addr(sym.Data.Size)] _, err := f.ReadAt(data, sym.Data.Offset) if err != nil { p.errorf("reading %v: %v", sym.SymID, err) } p.relocateSym(sym, data) } } // TODO(rsc): Define full enumeration for relocation types. const ( R_ADDR = 1 R_SIZE = 2 R_CALL = 3 R_CALLARM = 4 R_CALLIND = 5 R_CONST = 6 R_PCREL = 7 ) // relocateSym applies relocations to sym's data. func (p *Prog) relocateSym(sym *Sym, data []byte) { for i := range sym.Reloc { r := &sym.Reloc[i] targ := p.Syms[r.Sym] if targ == nil { p.errorf("%v: reference to undefined symbol %v", sym, r.Sym) continue } val := targ.Addr + Addr(r.Add) switch r.Type { default: p.errorf("%v: unknown relocation type %d", sym, r.Type) case R_ADDR, R_CALLIND: // ok case R_PCREL, R_CALL: val -= sym.Addr + Addr(r.Offset+r.Size) } frag := data[r.Offset : r.Offset+r.Size] switch r.Size { default: p.errorf("%v: unknown relocation size %d", sym, r.Size) case 4: // TODO(rsc): Check for overflow? p.byteorder.PutUint32(frag, uint32(val)) case 8: p.byteorder.PutUint64(frag, uint64(val)) } } }