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