github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/newlink/load.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Loading of code and data fragments from package files into final image. 6 7 package main 8 9 import ( 10 "cmd/internal/obj" 11 "os" 12 ) 13 14 // load allocates segment images, populates them with data 15 // read from package files, and applies relocations to the data. 16 func (p *Prog) load() { 17 // TODO(rsc): mmap the output file and store the data directly. 18 // That will make writing the output file more efficient. 19 for _, seg := range p.Segments { 20 seg.Data = make([]byte, seg.FileSize) 21 } 22 for _, pkg := range p.Packages { 23 p.loadPackage(pkg) 24 } 25 } 26 27 // loadPackage loads and relocates data for all the 28 // symbols needed in the given package. 29 func (p *Prog) loadPackage(pkg *Package) { 30 if pkg.File == "" { 31 // This "package" contains internally generated symbols only. 32 // All such symbols have a sym.Bytes field holding the actual data 33 // (if any), plus relocations. 34 for _, sym := range pkg.Syms { 35 if sym.Bytes == nil { 36 continue 37 } 38 seg := sym.Section.Segment 39 off := sym.Addr - seg.VirtAddr 40 data := seg.Data[off : off+Addr(sym.Size)] 41 copy(data, sym.Bytes) 42 p.relocateSym(sym, data) 43 } 44 return 45 } 46 47 // Package stored in file. 48 f, err := os.Open(pkg.File) 49 if err != nil { 50 p.errorf("%v", err) 51 return 52 } 53 defer f.Close() 54 55 // TODO(rsc): Mmap file into memory. 56 57 for _, sym := range pkg.Syms { 58 if sym.Data.Size == 0 { 59 continue 60 } 61 // TODO(rsc): If not using mmap, at least coalesce nearby reads. 62 if sym.Section == nil { 63 p.errorf("internal error: missing section for %s", sym.Name) 64 } 65 seg := sym.Section.Segment 66 off := sym.Addr - seg.VirtAddr 67 if off >= Addr(len(seg.Data)) || off+Addr(sym.Data.Size) > Addr(len(seg.Data)) { 68 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) 69 } 70 data := seg.Data[off : off+Addr(sym.Data.Size)] 71 _, err := f.ReadAt(data, sym.Data.Offset) 72 if err != nil { 73 p.errorf("reading %v: %v", sym.SymID, err) 74 } 75 p.relocateSym(sym, data) 76 } 77 } 78 79 // relocateSym applies relocations to sym's data. 80 func (p *Prog) relocateSym(sym *Sym, data []byte) { 81 for i := range sym.Reloc { 82 r := &sym.Reloc[i] 83 targ := p.Syms[r.Sym] 84 if targ == nil { 85 p.errorf("%v: reference to undefined symbol %v", sym, r.Sym) 86 continue 87 } 88 val := targ.Addr + Addr(r.Add) 89 switch r.Type { 90 default: 91 p.errorf("%v: unknown relocation type %d", sym, r.Type) 92 case obj.R_ADDR, obj.R_CALLIND: 93 // ok 94 case obj.R_PCREL, obj.R_CALL: 95 val -= sym.Addr + Addr(r.Offset+r.Size) 96 } 97 frag := data[r.Offset : r.Offset+r.Size] 98 switch r.Size { 99 default: 100 p.errorf("%v: unknown relocation size %d", sym, r.Size) 101 case 4: 102 // TODO(rsc): Check for overflow? 103 p.byteorder.PutUint32(frag, uint32(val)) 104 case 8: 105 p.byteorder.PutUint64(frag, uint64(val)) 106 } 107 } 108 }