mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
99 lines
2.6 KiB
Go
99 lines
2.6 KiB
Go
|
|
// 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 (
|
||
|
|
"encoding/binary"
|
||
|
|
"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) {
|
||
|
|
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.
|
||
|
|
seg := sym.Section.Segment
|
||
|
|
off := sym.Addr - seg.VirtAddr
|
||
|
|
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): These are the relocation types and should be
|
||
|
|
// loaded from debug/goobj. They are not in debug/goobj
|
||
|
|
// because they are different for each architecture.
|
||
|
|
// The symbol file format needs to be revised to use an
|
||
|
|
// architecture-independent set of numbers, and then
|
||
|
|
// those should be fetched from debug/goobj instead of
|
||
|
|
// defined here. These are the amd64 numbers.
|
||
|
|
const (
|
||
|
|
D_ADDR = 120
|
||
|
|
D_SIZE = 246
|
||
|
|
D_PCREL = 247
|
||
|
|
)
|
||
|
|
|
||
|
|
// 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 D_ADDR:
|
||
|
|
// ok
|
||
|
|
case D_PCREL:
|
||
|
|
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?
|
||
|
|
// TODO(rsc): Handle big-endian systems.
|
||
|
|
binary.LittleEndian.PutUint32(frag, uint32(val))
|
||
|
|
case 8:
|
||
|
|
binary.LittleEndian.PutUint64(frag, uint64(val))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|