aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/newlink/load.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/newlink/load.go')
-rw-r--r--src/cmd/newlink/load.go108
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))
+ }
+ }
+}