|  | // 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)) | 
|  | } | 
|  | } | 
|  | } |