mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
In preparation for making the current linker cmd/link. If cmd/newlink is ever completed, it can be moved back. See golang-dev thread titled "go tool compile, etc" for background. Change-Id: I4029580f470038240c5181a37ea4202ba971f9ef Reviewed-on: https://go-review.googlesource.com/10286 Reviewed-by: Rob Pike <r@golang.org>
108 lines
2.9 KiB
Go
108 lines
2.9 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 (
|
|
"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))
|
|
}
|
|
}
|
|
}
|