diff options
Diffstat (limited to 'src/cmd/oldlink/internal/ld/outbuf.go')
-rw-r--r-- | src/cmd/oldlink/internal/ld/outbuf.go | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/cmd/oldlink/internal/ld/outbuf.go b/src/cmd/oldlink/internal/ld/outbuf.go new file mode 100644 index 0000000000..596d2395c8 --- /dev/null +++ b/src/cmd/oldlink/internal/ld/outbuf.go @@ -0,0 +1,177 @@ +// Copyright 2017 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. + +package ld + +import ( + "bufio" + "cmd/internal/sys" + "cmd/oldlink/internal/sym" + "encoding/binary" + "log" + "os" +) + +// OutBuf is a buffered file writer. +// +// It is simlar to the Writer in cmd/internal/bio with a few small differences. +// +// First, it tracks the output architecture and uses it to provide +// endian helpers. +// +// Second, it provides a very cheap offset counter that doesn't require +// any system calls to read the value. +// +// It also mmaps the output file (if available). The intended usage is: +// - Mmap the output file +// - Write the content +// - possibly apply any edits in the output buffer +// - Munmap the output file +// - possibly write more content to the file, which will not be edited later. +type OutBuf struct { + arch *sys.Arch + off int64 + w *bufio.Writer + buf []byte // backing store of mmap'd output file + f *os.File + encbuf [8]byte // temp buffer used by WriteN methods +} + +func (out *OutBuf) SeekSet(p int64) { + if p == out.off { + return + } + if out.buf == nil { + out.Flush() + if _, err := out.f.Seek(p, 0); err != nil { + Exitf("seeking to %d in %s: %v", p, out.f.Name(), err) + } + } + out.off = p +} + +func (out *OutBuf) Offset() int64 { + return out.off +} + +// 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) { + if out.buf != nil { + n := copy(out.buf[out.off:], v) + out.off += int64(n) + return n, nil + } + n, err := out.w.Write(v) + out.off += int64(n) + return n, err +} + +func (out *OutBuf) Write8(v uint8) { + if out.buf != nil { + out.buf[out.off] = 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) WriteByte(v byte) error { + out.Write8(v) + return nil +} + +func (out *OutBuf) Write16(v uint16) { + out.arch.ByteOrder.PutUint16(out.encbuf[:], v) + out.Write(out.encbuf[:2]) +} + +func (out *OutBuf) Write32(v uint32) { + out.arch.ByteOrder.PutUint32(out.encbuf[:], v) + out.Write(out.encbuf[:4]) +} + +func (out *OutBuf) Write32b(v uint32) { + binary.BigEndian.PutUint32(out.encbuf[:], v) + out.Write(out.encbuf[:4]) +} + +func (out *OutBuf) Write64(v uint64) { + out.arch.ByteOrder.PutUint64(out.encbuf[:], v) + out.Write(out.encbuf[:8]) +} + +func (out *OutBuf) Write64b(v uint64) { + binary.BigEndian.PutUint64(out.encbuf[:], v) + out.Write(out.encbuf[:8]) +} + +func (out *OutBuf) WriteString(s string) { + if out.buf != nil { + n := copy(out.buf[out.off:], 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) +} + +// WriteStringN writes the first n bytes of s. +// If n is larger than len(s) then it is padded with zero bytes. +func (out *OutBuf) WriteStringN(s string, n int) { + out.WriteStringPad(s, n, zeros[:]) +} + +// WriteStringPad writes the first n bytes of s. +// If n is larger than len(s) then it is padded with the bytes in pad (repeated as needed). +func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) { + if len(s) >= n { + out.WriteString(s[:n]) + } else { + out.WriteString(s) + n -= len(s) + for n > len(pad) { + out.Write(pad) + n -= len(pad) + + } + out.Write(pad[:n]) + } +} + +// WriteSym writes the content of a Symbol, then changes the Symbol's content +// to point to the output buffer that we just wrote, so we can apply further +// edit to the symbol content. +// If the output file is not Mmap'd, just writes the content. +func (out *OutBuf) WriteSym(s *sym.Symbol) { + if out.buf != nil { + start := out.off + out.Write(s.P) + s.P = out.buf[start:out.off] + s.Attr.Set(sym.AttrReadOnly, false) + } else { + out.Write(s.P) + } +} + +func (out *OutBuf) Flush() { + var err error + if out.buf != nil { + err = out.Msync() + } else { + err = out.w.Flush() + } + if err != nil { + Exitf("flushing %s: %v", out.f.Name(), err) + } +} |