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