diff options
Diffstat (limited to 'src/cmd/newlink/load.go')
| -rw-r--r-- | src/cmd/newlink/load.go | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/cmd/newlink/load.go b/src/cmd/newlink/load.go new file mode 100644 index 0000000000..50602b82a1 --- /dev/null +++ b/src/cmd/newlink/load.go @@ -0,0 +1,108 @@ +// 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 ( + "cmd/internal/obj" + "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) + } +} + +// 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 obj.R_ADDR, obj.R_CALLIND: + // ok + case obj.R_PCREL, obj.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)) + } + } +} |
