]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: remove buffered file I/O from OutBuf
authorJeremy Faller <jeremy@golang.org>
Fri, 17 Apr 2020 20:07:45 +0000 (16:07 -0400)
committerJeremy Faller <jeremy@golang.org>
Mon, 20 Apr 2020 13:10:55 +0000 (13:10 +0000)
Recreation of CL 228317.

The problem with that original CL was a late requested change,
reordering reloc and asmb, resulting in symbols having stale pointers to
their data. I've fixed this by preallocating the heap variable in OutBuf
for platforms w/o mmap.

Change-Id: Icdb392ac2c8d6518830f4c84cf422e78b8ab68c7
Reviewed-on: https://go-review.googlesource.com/c/go/+/228782
Run-TryBot: Jeremy Faller <jeremy@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
16 files changed:
src/cmd/link/internal/amd64/asm.go
src/cmd/link/internal/arm/asm.go
src/cmd/link/internal/arm64/asm.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/main.go
src/cmd/link/internal/ld/outbuf.go
src/cmd/link/internal/ld/outbuf_nommap.go
src/cmd/link/internal/ld/outbuf_test.go
src/cmd/link/internal/ld/xcoff.go
src/cmd/link/internal/mips/asm.go
src/cmd/link/internal/mips64/asm.go
src/cmd/link/internal/ppc64/asm.go
src/cmd/link/internal/riscv64/asm.go
src/cmd/link/internal/s390x/asm.go
src/cmd/link/internal/wasm/asm.go
src/cmd/link/internal/x86/asm.go

index 5c4ffe19c256591adeb43b820a4a6eaadf999df3..d26a9a234cc3fd081b45c93376b0baa1c47d3ab3 100644 (file)
@@ -756,7 +756,6 @@ func asmb2(ctxt *ld.Link) {
                        if ctxt.IsELF {
                                ctxt.Out.SeekSet(symo)
                                ld.Asmelfsym(ctxt)
-                               ctxt.Out.Flush()
                                ctxt.Out.Write(ld.Elfstrdat)
 
                                if ctxt.LinkMode == ld.LinkExternal {
@@ -766,13 +765,11 @@ func asmb2(ctxt *ld.Link) {
 
                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:
@@ -817,8 +814,6 @@ func asmb2(ctxt *ld.Link) {
        case objabi.Hwindows:
                ld.Asmbpe(ctxt)
        }
-
-       ctxt.Out.Flush()
 }
 
 func tlsIEtoLE(s *sym.Symbol, off, size int) {
index f3d1262879a6edc876190254e7de6934a231b9f9..e9eea5ce2c9ec1c8819092e1e2b30a62c4f68b41 100644 (file)
@@ -816,7 +816,6 @@ func asmb2(ctxt *ld.Link) {
                default:
                        if ctxt.IsELF {
                                ld.Asmelfsym(ctxt)
-                               ctxt.Out.Flush()
                                ctxt.Out.Write(ld.Elfstrdat)
 
                                if ctxt.LinkMode == ld.LinkExternal {
@@ -826,13 +825,11 @@ func asmb2(ctxt *ld.Link) {
 
                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:
@@ -863,7 +860,6 @@ func asmb2(ctxt *ld.Link) {
                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)
index 053b8d119d99b6ace1692a688b7a2a27374530fa..46bda74c4c5118b3d4c8c36c6e07871a6015257c 100644 (file)
@@ -866,7 +866,6 @@ func asmb2(ctxt *ld.Link) {
                default:
                        if ctxt.IsELF {
                                ld.Asmelfsym(ctxt)
-                               ctxt.Out.Flush()
                                ctxt.Out.Write(ld.Elfstrdat)
 
                                if ctxt.LinkMode == ld.LinkExternal {
@@ -876,13 +875,11 @@ func asmb2(ctxt *ld.Link) {
 
                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:
@@ -915,7 +912,6 @@ func asmb2(ctxt *ld.Link) {
                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)
index 3979880cf4d7a7ad3e6ad69e75f3df3edc3e455c..36708ee5d1ebb16689f2185d8af085b38e042d6b 100644 (file)
@@ -32,7 +32,6 @@
 package ld
 
 import (
-       "bufio"
        "bytes"
        "cmd/internal/gcprog"
        "cmd/internal/objabi"
@@ -958,11 +957,10 @@ func Datblk(ctxt *Link, out *OutBuf, addr, size int64) {
 
 // Used only on Wasm for now.
 func DatblkBytes(ctxt *Link, addr int64, size int64) []byte {
-       buf := bytes.NewBuffer(make([]byte, 0, size))
-       out := &OutBuf{w: bufio.NewWriter(buf)}
+       buf := make([]byte, size)
+       out := &OutBuf{heap: buf}
        writeDatblkToOutBuf(ctxt, out, addr, size)
-       out.Flush()
-       return buf.Bytes()
+       return buf
 }
 
 func writeDatblkToOutBuf(ctxt *Link, out *OutBuf, addr int64, size int64) {
index dd089e6efa5ae19344f23b409f374d694923968b..4735b91b352cb4b3c858b384e3b2eee623c7e8a4 100644 (file)
@@ -319,14 +319,12 @@ func Main(arch *sys.Arch, theArch Arch) {
        // 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.
-               err := ctxt.Out.Mmap(filesize)
-               outputMmapped = err == nil
-       }
-       if outputMmapped {
+               if err := ctxt.Out.Mmap(filesize); err != nil {
+                       panic(err)
+               }
                // Asmb will redirect symbols to the output file mmap, and relocations
                // will be applied directly there.
                bench.Start("Asmb")
@@ -344,10 +342,8 @@ func Main(arch *sys.Arch, theArch Arch) {
        bench.Start("Asmb2")
        thearch.Asmb2(ctxt)
 
-       if outputMmapped {
-               bench.Start("Munmap")
-               ctxt.Out.Munmap()
-       }
+       bench.Start("Munmap")
+       ctxt.Out.Close() // Close handles Munmapping if necessary.
 
        bench.Start("undef")
        ctxt.undef()
index c36fc74a445dab6d811a8dbb889a5c8add57c5e3..f043168f1a2630275271cce8a2ace07b674b7681 100644 (file)
@@ -5,7 +5,6 @@
 package ld
 
 import (
-       "bufio"
        "cmd/internal/sys"
        "cmd/link/internal/sym"
        "encoding/binary"
@@ -61,7 +60,6 @@ type OutBuf struct {
        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
@@ -78,7 +76,6 @@ func (out *OutBuf) Open(name string) error {
        }
        out.off = 0
        out.name = name
-       out.w = bufio.NewWriter(f)
        out.f = f
        return nil
 }
@@ -92,13 +89,11 @@ func NewOutBuf(arch *sys.Arch) *OutBuf {
 var viewError = errors.New("output not mmapped")
 
 func (out *OutBuf) View(start uint64) (*OutBuf, error) {
-       if !out.isMmapped() {
-               return nil, viewError
-       }
        return &OutBuf{
                arch:   out.arch,
                name:   out.name,
                buf:    out.buf,
+               heap:   out.heap,
                off:    int64(start),
                isView: true,
        }, nil
@@ -110,10 +105,17 @@ func (out *OutBuf) Close() error {
        if out.isView {
                return viewCloseError
        }
-       out.Flush()
+       if out.isMmapped() {
+               return out.Munmap()
+       }
        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
        }
@@ -151,42 +153,28 @@ func (out *OutBuf) Munmap() error {
 // 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 {
                return out.off, out.buf
        }
 
-       // The heap variables aren't protected by a mutex. For now, just bomb if you
-       // try to use OutBuf in parallel. (Note this probably could be fixed.)
-       if out.isView {
-               panic("cannot write to heap in parallel")
-       }
-
        // Not enough space in the mmaped area, write to heap area instead.
        heapPos := out.off - bufLen
        heapLen := int64(len(out.heap))
        lenNeeded := heapPos + lenToWrite
        if lenNeeded > heapLen { // do we need to grow the heap storage?
+               // The heap variables aren't protected by a mutex. For now, just bomb if you
+               // try to use OutBuf in parallel. (Note this probably could be fixed.)
+               if out.isView {
+                       panic("cannot write to heap in parallel")
+               }
                out.heap = append(out.heap, make([]byte, lenNeeded-heapLen)...)
        }
        return heapPos, out.heap
 }
 
 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
 }
 
@@ -195,33 +183,18 @@ func (out *OutBuf) Offset() int64 {
 }
 
 // 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.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)
+       n := len(v)
+       pos, buf := out.writeLoc(int64(n))
+       copy(buf[pos:], v)
        out.off += int64(n)
-       return n, err
+       return n, nil
 }
 
 func (out *OutBuf) Write8(v uint8) {
-       if out.isMmapped() {
-               pos, buf := out.writeLoc(1)
-               buf[pos] = v
-               out.off++
-               return
-       }
-       if err := out.w.WriteByte(v); err == nil {
-               out.off++
-       }
+       pos, buf := out.writeLoc(1)
+       buf[pos] = v
+       out.off++
 }
 
 // WriteByte is an alias for Write8 to fulfill the io.ByteWriter interface.
@@ -256,16 +229,11 @@ func (out *OutBuf) Write64b(v uint64) {
 }
 
 func (out *OutBuf) WriteString(s string) {
-       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
+       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))
        }
-       n, _ := out.w.WriteString(s)
        out.off += int64(n)
 }
 
@@ -297,26 +265,10 @@ func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) {
 // edit to the symbol content.
 // If the output file is not Mmap'd, just writes the content.
 func (out *OutBuf) WriteSym(s *sym.Symbol) {
-       // 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)
-       }
+       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)
 }
index 0b0ed912802c0cf47e394bc0a6c34b9420c010b5..472fca22d742c92f4cb0a59bac7e3a06726f3199 100644 (file)
@@ -6,10 +6,11 @@
 
 package ld
 
-import "errors"
+func (out *OutBuf) Mmap(filesize uint64) error {
+       // We need space to put all the symbols before we apply relocations.
+       out.heap = make([]byte, filesize)
+       return nil
+}
 
-var errNotSupported = errors.New("mmap not supported")
-
-func (out *OutBuf) Mmap(filesize uint64) error { return errNotSupported }
-func (out *OutBuf) munmap()                    { panic("unreachable") }
-func (out *OutBuf) Msync() error               { panic("unreachable") }
+func (out *OutBuf) munmap()      { panic("unreachable") }
+func (out *OutBuf) Msync() error { panic("unreachable") }
index aae206f511a824d7bde953a7caf98c7e14d830bf..58f9b10cfa46485ba6305c12f9d30ad44fe7ba71 100644 (file)
@@ -50,6 +50,7 @@ func TestWriteLoc(t *testing.T) {
                {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 {
index 4ff123e8cd6c591bb0afc825676e5374fc8e044d..9fe3669eee2f32d997b3ddfd251011bc8818c9bc 100644 (file)
@@ -1389,7 +1389,6 @@ func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
        }
 
        f.loaderSize = off + uint64(stlen)
-       ctxt.Out.Flush()
 
        /* again for printing */
        if !*flagA {
@@ -1559,8 +1558,6 @@ func Asmbxcoff(ctxt *Link, fileoff int64) {
        // write string table
        xfile.stringTable.write(ctxt.Out)
 
-       ctxt.Out.Flush()
-
        // write headers
        xcoffwrite(ctxt)
 }
index b50112ad750ffa83567d421af2ba2df86c054077..21a57ccbb0d182345685c87985c74272813bc123 100644 (file)
@@ -204,7 +204,6 @@ func asmb2(ctxt *ld.Link) {
 
                ctxt.Out.SeekSet(int64(symo))
                ld.Asmelfsym(ctxt)
-               ctxt.Out.Flush()
                ctxt.Out.Write(ld.Elfstrdat)
 
                if ctxt.LinkMode == ld.LinkExternal {
@@ -220,7 +219,6 @@ func asmb2(ctxt *ld.Link) {
                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)
index 1b2914eea398f5af4516360f062f6eb299201149..0a2a3c11f3eff41195fac9ef1b7c339957964853 100644 (file)
@@ -223,7 +223,6 @@ func asmb2(ctxt *ld.Link) {
                default:
                        if ctxt.IsELF {
                                ld.Asmelfsym(ctxt)
-                               ctxt.Out.Flush()
                                ctxt.Out.Write(ld.Elfstrdat)
 
                                if ctxt.LinkMode == ld.LinkExternal {
@@ -233,13 +232,11 @@ func asmb2(ctxt *ld.Link) {
 
                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()
                        }
                }
        }
@@ -268,7 +265,6 @@ func asmb2(ctxt *ld.Link) {
                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)
index d86738538d9cdca71e03656a6d1093995d729094..0e3a69143225754eff3ffa24d9c6aac762ae26ae 100644 (file)
@@ -1130,7 +1130,6 @@ func asmb2(ctxt *ld.Link) {
                default:
                        if ctxt.IsELF {
                                ld.Asmelfsym(ctxt)
-                               ctxt.Out.Flush()
                                ctxt.Out.Write(ld.Elfstrdat)
 
                                if ctxt.LinkMode == ld.LinkExternal {
@@ -1140,18 +1139,15 @@ func asmb2(ctxt *ld.Link) {
 
                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()
                }
        }
 
@@ -1180,7 +1176,6 @@ func asmb2(ctxt *ld.Link) {
                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)
index db3b602b848af45aae392a07b7014435e1a363e9..51cc5980c89a75a76a93fb4aab1251a2252fa685 100644 (file)
@@ -142,7 +142,6 @@ func asmb2(ctxt *ld.Link) {
                ctxt.Out.SeekSet(int64(symo))
 
                ld.Asmelfsym(ctxt)
-               ctxt.Out.Flush()
                ctxt.Out.Write(ld.Elfstrdat)
 
                if ctxt.LinkMode == ld.LinkExternal {
@@ -157,7 +156,6 @@ func asmb2(ctxt *ld.Link) {
        default:
                ld.Errorf(nil, "unsupported operating system")
        }
-       ctxt.Out.Flush()
 
        if *ld.FlagC {
                fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
index 5d55a190726615e7489dcb78cd15bf47284a6145..9b6be28421f144d554e53a48d2bf4daa49b90250 100644 (file)
@@ -515,7 +515,6 @@ func asmb2(ctxt *ld.Link) {
 
                ctxt.Out.SeekSet(int64(symo))
                ld.Asmelfsym(ctxt)
-               ctxt.Out.Flush()
                ctxt.Out.Write(ld.Elfstrdat)
 
                if ctxt.LinkMode == ld.LinkExternal {
@@ -531,7 +530,6 @@ func asmb2(ctxt *ld.Link) {
                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)
index 550ed5bc3c43276bd94380ad61e969e9dfcc5028..7f8742d00823648701324e5eb06bb437db53c099 100644 (file)
@@ -187,8 +187,6 @@ func asmb2(ctxt *ld.Link) {
        if !*ld.FlagS {
                writeNameSec(ctxt, len(hostImports), fns)
        }
-
-       ctxt.Out.Flush()
 }
 
 func lookupType(sig *wasmFuncType, types *[]*wasmFuncType) uint32 {
index cbc79c987b9323654d180eb7c2f17c24c76ec868..7dcdda0fa80d4539a605acf60ba7b8d67bb63a58 100644 (file)
@@ -646,7 +646,6 @@ func asmb2(ctxt *ld.Link) {
                default:
                        if ctxt.IsELF {
                                ld.Asmelfsym(ctxt)
-                               ctxt.Out.Flush()
                                ctxt.Out.Write(ld.Elfstrdat)
 
                                if ctxt.LinkMode == ld.LinkExternal {
@@ -656,13 +655,11 @@ func asmb2(ctxt *ld.Link) {
 
                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:
@@ -702,6 +699,4 @@ func asmb2(ctxt *ld.Link) {
        case objabi.Hwindows:
                ld.Asmbpe(ctxt)
        }
-
-       ctxt.Out.Flush()
 }