if ctxt.IsELF {
ctxt.Out.SeekSet(symo)
ld.Asmelfsym(ctxt)
+ ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
if ctxt.LinkMode == ld.LinkExternal {
case objabi.Hplan9:
ld.Asmplan9sym(ctxt)
+ ctxt.Out.Flush()
sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
ctxt.Out.Write(sym.P)
+ ctxt.Out.Flush()
}
case objabi.Hwindows:
case objabi.Hwindows:
ld.Asmbpe(ctxt)
}
+
+ ctxt.Out.Flush()
}
func tlsIEtoLE(s *sym.Symbol, off, size int) {
default:
if ctxt.IsELF {
ld.Asmelfsym(ctxt)
+ ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
if ctxt.LinkMode == ld.LinkExternal {
case objabi.Hplan9:
ld.Asmplan9sym(ctxt)
+ ctxt.Out.Flush()
sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
ctxt.Out.Write(sym.P)
+ ctxt.Out.Flush()
}
case objabi.Hwindows:
ld.Asmbpe(ctxt)
}
+ ctxt.Out.Flush()
if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
default:
if ctxt.IsELF {
ld.Asmelfsym(ctxt)
+ ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
if ctxt.LinkMode == ld.LinkExternal {
case objabi.Hplan9:
ld.Asmplan9sym(ctxt)
+ ctxt.Out.Flush()
sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
ctxt.Out.Write(sym.P)
+ ctxt.Out.Flush()
}
case objabi.Hdarwin:
ld.Asmbmacho(ctxt)
}
+ ctxt.Out.Flush()
if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
package ld
import (
+ "bufio"
"bytes"
"cmd/internal/gcprog"
"cmd/internal/objabi"
// Used only on Wasm for now.
func DatblkBytes(ctxt *Link, addr int64, size int64) []byte {
- buf := make([]byte, size)
- out := &OutBuf{heap: buf}
+ buf := bytes.NewBuffer(make([]byte, 0, size))
+ out := &OutBuf{w: bufio.NewWriter(buf)}
writeDatblkToOutBuf(ctxt, out, addr, size)
- return buf
+ out.Flush()
+ return buf.Bytes()
}
func writeDatblkToOutBuf(ctxt *Link, out *OutBuf, addr int64, size int64) {
// for which we have computed the size and offset, in a
// mmap'd region. The second part writes more content, for
// which we don't know the size.
+ var outputMmapped bool
if ctxt.Arch.Family != sys.Wasm {
// Don't mmap if we're building for Wasm. Wasm file
// layout is very different so filesize is meaningless.
- if err := ctxt.Out.Mmap(filesize); err != nil {
- ctxt.Errorf(0, "error mapping file: %v", err)
- }
+ err := ctxt.Out.Mmap(filesize)
+ outputMmapped = err == nil
+ }
+ if outputMmapped {
+ // Asmb will redirect symbols to the output file mmap, and relocations
+ // will be applied directly there.
+ bench.Start("Asmb")
+ thearch.Asmb(ctxt)
+ bench.Start("reloc")
+ ctxt.reloc()
+ } else {
+ // If we don't mmap, we need to apply relocations before
+ // writing out.
+ bench.Start("reloc")
+ ctxt.reloc()
+ bench.Start("Asmb")
+ thearch.Asmb(ctxt)
}
-
- // Asmb will redirect symbols to the output file mmap, and relocations
- // will be applied directly there.
- bench.Start("Asmb")
- thearch.Asmb(ctxt)
- bench.Start("reloc")
- ctxt.reloc()
bench.Start("Asmb2")
thearch.Asmb2(ctxt)
- bench.Start("Munmap")
- ctxt.Out.Close() // Close handles Munmapping if necessary.
+ if outputMmapped {
+ bench.Start("Munmap")
+ ctxt.Out.Munmap()
+ }
bench.Start("undef")
ctxt.undef()
package ld
import (
+ "bufio"
"cmd/internal/sys"
"cmd/link/internal/sym"
"encoding/binary"
buf []byte // backing store of mmap'd output file
heap []byte // backing store for non-mmapped data
+ w *bufio.Writer
name string
f *os.File
encbuf [8]byte // temp buffer used by WriteN methods
}
out.off = 0
out.name = name
+ out.w = bufio.NewWriter(f)
out.f = f
return nil
}
if out.isView {
return viewCloseError
}
- if out.isMmapped() {
- return out.Munmap()
- }
+ out.Flush()
if out.f == nil {
return nil
}
- if len(out.heap) != 0 {
- if _, err := out.f.Write(out.heap); err != nil {
- return err
- }
- }
if err := out.f.Close(); err != nil {
return err
}
// writing. When the mmapped section is full, we switch over the heap memory
// for writing.
func (out *OutBuf) writeLoc(lenToWrite int64) (int64, []byte) {
+ if !out.isMmapped() {
+ panic("shouldn't happen")
+ }
+
// See if we have enough space in the mmaped area.
bufLen := int64(len(out.buf))
if out.off+lenToWrite <= bufLen {
}
func (out *OutBuf) SeekSet(p int64) {
+ if p == out.off {
+ return
+ }
+ if !out.isMmapped() {
+ out.Flush()
+ if _, err := out.f.Seek(p, 0); err != nil {
+ Exitf("seeking to %d in %s: %v", p, out.name, err)
+ }
+ }
out.off = p
}
}
// Write writes the contents of v to the buffer.
+//
+// As Write is backed by a bufio.Writer, callers do not have
+// to explicitly handle the returned error as long as Flush is
+// eventually called.
func (out *OutBuf) Write(v []byte) (int, error) {
- n := len(v)
- pos, buf := out.writeLoc(int64(n))
- copy(buf[pos:], v)
+ if out.isMmapped() {
+ n := len(v)
+ pos, buf := out.writeLoc(int64(n))
+ copy(buf[pos:], v)
+ out.off += int64(n)
+ return n, nil
+ }
+ n, err := out.w.Write(v)
out.off += int64(n)
- return n, nil
+ return n, err
}
func (out *OutBuf) Write8(v uint8) {
- pos, buf := out.writeLoc(1)
- buf[pos] = v
- out.off++
+ if out.isMmapped() {
+ pos, buf := out.writeLoc(1)
+ buf[pos] = v
+ out.off++
+ return
+ }
+ if err := out.w.WriteByte(v); err == nil {
+ out.off++
+ }
}
// WriteByte is an alias for Write8 to fulfill the io.ByteWriter interface.
}
func (out *OutBuf) WriteString(s string) {
- pos, buf := out.writeLoc(int64(len(s)))
- n := copy(buf[pos:], s)
- if n != len(s) {
- log.Fatalf("WriteString truncated. buffer size: %d, offset: %d, len(s)=%d", len(out.buf), out.off, len(s))
+ if out.isMmapped() {
+ pos, buf := out.writeLoc(int64(len(s)))
+ n := copy(buf[pos:], s)
+ if n != len(s) {
+ log.Fatalf("WriteString truncated. buffer size: %d, offset: %d, len(s)=%d", len(out.buf), out.off, len(s))
+ }
+ out.off += int64(n)
+ return
}
+ n, _ := out.w.WriteString(s)
out.off += int64(n)
}
// edit to the symbol content.
// If the output file is not Mmap'd, just writes the content.
func (out *OutBuf) WriteSym(s *sym.Symbol) {
- n := int64(len(s.P))
- pos, buf := out.writeLoc(n)
- copy(buf[pos:], s.P)
- out.off += n
- s.P = buf[pos : pos+n]
- s.Attr.Set(sym.AttrReadOnly, false)
+ // NB: We inline the Write call for speediness.
+ if out.isMmapped() {
+ n := int64(len(s.P))
+ pos, buf := out.writeLoc(n)
+ copy(buf[pos:], s.P)
+ out.off += n
+ s.P = buf[pos : pos+n]
+ s.Attr.Set(sym.AttrReadOnly, false)
+ } else {
+ n, _ := out.w.Write(s.P)
+ out.off += int64(n)
+ }
+}
+
+func (out *OutBuf) Flush() {
+ var err error
+ if out.w != nil {
+ err = out.w.Flush()
+ }
+ if err != nil {
+ Exitf("flushing %s: %v", out.name, err)
+ }
}
{100, 100, 0, 100, 100, 0, true},
{10, 10, 0, 100, 100, 0, true},
{10, 20, 10, 100, 110, 10, true},
- {0, 0, 0, 100, 100, 0, true},
}
for i, test := range tests {
}
f.loaderSize = off + uint64(stlen)
+ ctxt.Out.Flush()
/* again for printing */
if !*flagA {
// write string table
xfile.stringTable.write(ctxt.Out)
+ ctxt.Out.Flush()
+
// write headers
xcoffwrite(ctxt)
}
ctxt.Out.SeekSet(int64(symo))
ld.Asmelfsym(ctxt)
+ ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
if ctxt.LinkMode == ld.LinkExternal {
ld.Asmbelf(ctxt, int64(symo))
}
+ ctxt.Out.Flush()
if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
default:
if ctxt.IsELF {
ld.Asmelfsym(ctxt)
+ ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
if ctxt.LinkMode == ld.LinkExternal {
case objabi.Hplan9:
ld.Asmplan9sym(ctxt)
+ ctxt.Out.Flush()
sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
ctxt.Out.Write(sym.P)
+ ctxt.Out.Flush()
}
}
}
ld.Asmbelf(ctxt, int64(symo))
}
+ ctxt.Out.Flush()
if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
default:
if ctxt.IsELF {
ld.Asmelfsym(ctxt)
+ ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
if ctxt.LinkMode == ld.LinkExternal {
case objabi.Hplan9:
ld.Asmplan9sym(ctxt)
+ ctxt.Out.Flush()
sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
ctxt.Out.Write(sym.P)
+ ctxt.Out.Flush()
}
case objabi.Haix:
// symtab must be added once sections have been created in ld.Asmbxcoff
+ ctxt.Out.Flush()
}
}
ld.Asmbxcoff(ctxt, int64(fileoff))
}
+ ctxt.Out.Flush()
if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
ctxt.Out.SeekSet(int64(symo))
ld.Asmelfsym(ctxt)
+ ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
if ctxt.LinkMode == ld.LinkExternal {
default:
ld.Errorf(nil, "unsupported operating system")
}
+ ctxt.Out.Flush()
if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
ctxt.Out.SeekSet(int64(symo))
ld.Asmelfsym(ctxt)
+ ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
if ctxt.LinkMode == ld.LinkExternal {
ld.Asmbelf(ctxt, int64(symo))
}
+ ctxt.Out.Flush()
if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
if !*ld.FlagS {
writeNameSec(ctxt, len(hostImports), fns)
}
+
+ ctxt.Out.Flush()
}
func lookupType(sig *wasmFuncType, types *[]*wasmFuncType) uint32 {
default:
if ctxt.IsELF {
ld.Asmelfsym(ctxt)
+ ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
if ctxt.LinkMode == ld.LinkExternal {
case objabi.Hplan9:
ld.Asmplan9sym(ctxt)
+ ctxt.Out.Flush()
sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
ctxt.Out.Write(sym.P)
+ ctxt.Out.Flush()
}
case objabi.Hwindows:
case objabi.Hwindows:
ld.Asmbpe(ctxt)
}
+
+ ctxt.Out.Flush()
}