Home | History | Annotate | Download | only in ld
      1 // Copyright 2017 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 package ld
      6 
      7 import (
      8 	"bufio"
      9 	"cmd/internal/sys"
     10 	"encoding/binary"
     11 	"os"
     12 )
     13 
     14 // OutBuf is a buffered file writer.
     15 //
     16 // It is simlar to the Writer in cmd/internal/bio with a few small differences.
     17 //
     18 // First, it tracks the output architecture and uses it to provide
     19 // endian helpers.
     20 //
     21 // Second, it provides a very cheap offset counter that doesn't require
     22 // any system calls to read the value.
     23 type OutBuf struct {
     24 	arch   *sys.Arch
     25 	off    int64
     26 	w      *bufio.Writer
     27 	f      *os.File
     28 	encbuf [8]byte // temp buffer used by WriteN methods
     29 }
     30 
     31 func (out *OutBuf) SeekSet(p int64) {
     32 	if p == out.off {
     33 		return
     34 	}
     35 	out.Flush()
     36 	if _, err := out.f.Seek(p, 0); err != nil {
     37 		Exitf("seeking to %d in %s: %v", p, out.f.Name(), err)
     38 	}
     39 	out.off = p
     40 }
     41 
     42 func (out *OutBuf) Offset() int64 {
     43 	return out.off
     44 }
     45 
     46 // Write writes the contents of v to the buffer.
     47 //
     48 // As Write is backed by a bufio.Writer, callers do not have
     49 // to explicitly handle the returned error as long as Flush is
     50 // eventually called.
     51 func (out *OutBuf) Write(v []byte) (int, error) {
     52 	n, err := out.w.Write(v)
     53 	out.off += int64(n)
     54 	return n, err
     55 }
     56 
     57 func (out *OutBuf) Write8(v uint8) {
     58 	if err := out.w.WriteByte(v); err == nil {
     59 		out.off++
     60 	}
     61 }
     62 
     63 func (out *OutBuf) Write16(v uint16) {
     64 	out.arch.ByteOrder.PutUint16(out.encbuf[:], v)
     65 	out.Write(out.encbuf[:2])
     66 }
     67 
     68 func (out *OutBuf) Write32(v uint32) {
     69 	out.arch.ByteOrder.PutUint32(out.encbuf[:], v)
     70 	out.Write(out.encbuf[:4])
     71 }
     72 
     73 func (out *OutBuf) Write32b(v uint32) {
     74 	binary.BigEndian.PutUint32(out.encbuf[:], v)
     75 	out.Write(out.encbuf[:4])
     76 }
     77 
     78 func (out *OutBuf) Write64(v uint64) {
     79 	out.arch.ByteOrder.PutUint64(out.encbuf[:], v)
     80 	out.Write(out.encbuf[:8])
     81 }
     82 
     83 func (out *OutBuf) Write64b(v uint64) {
     84 	binary.BigEndian.PutUint64(out.encbuf[:], v)
     85 	out.Write(out.encbuf[:8])
     86 }
     87 
     88 func (out *OutBuf) WriteString(s string) {
     89 	n, _ := out.w.WriteString(s)
     90 	out.off += int64(n)
     91 }
     92 
     93 // WriteStringN writes the first n bytes of s.
     94 // If n is larger than len(s) then it is padded with zero bytes.
     95 func (out *OutBuf) WriteStringN(s string, n int) {
     96 	out.WriteStringPad(s, n, zeros[:])
     97 }
     98 
     99 // WriteStringPad writes the first n bytes of s.
    100 // If n is larger than len(s) then it is padded with the bytes in pad (repeated as needed).
    101 func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) {
    102 	if len(s) >= n {
    103 		out.WriteString(s[:n])
    104 	} else {
    105 		out.WriteString(s)
    106 		n -= len(s)
    107 		for n > len(pad) {
    108 			out.Write(pad)
    109 			n -= len(pad)
    110 
    111 		}
    112 		out.Write(pad[:n])
    113 	}
    114 }
    115 
    116 func (out *OutBuf) Flush() {
    117 	if err := out.w.Flush(); err != nil {
    118 		Exitf("flushing %s: %v", out.f.Name(), err)
    119 	}
    120 }
    121