]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/internal/goobj2, cmd/link: experiment another way of accessing relocations
authorCherry Zhang <cherryyz@google.com>
Thu, 5 Mar 2020 16:29:24 +0000 (11:29 -0500)
committerCherry Zhang <cherryyz@google.com>
Fri, 13 Mar 2020 01:04:29 +0000 (01:04 +0000)
Use a different mechanism to access relocations from the object
files, and use it in the stack bounds check pass. This shows some
speedup.

(linking cmd/compile)
Dostkcheck     76.9ms ± 1%    55.1ms ± 1%  -28.36%  (p=0.008 n=5+5)

Change-Id: I2ac42da515dccd64719fb557ffff6cdc69e4319b
Reviewed-on: https://go-review.googlesource.com/c/go/+/222240
Run-TryBot: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/internal/goobj2/objfile.go
src/cmd/internal/goobj2/objfile_test.go [new file with mode: 0644]
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/loader/loader.go

index 8049ca7f31b7ff83b1de9f4b507fba47db1e535b..6d9b0f9e8d83f856eb6fbb93ad44bc37b9596263 100644 (file)
@@ -307,6 +307,20 @@ func (r *Reloc) Size() int {
        return 4 + 1 + 1 + 8 + r.Sym.Size()
 }
 
+// XXX experiment with another way of accessing relocations.
+
+const RelocSize = 22 // TODO: is it possible to not hard-code this?
+
+type Reloc2 [RelocSize]byte
+
+func (r *Reloc2) Off() int32  { return int32(binary.LittleEndian.Uint32(r[:])) }
+func (r *Reloc2) Siz() uint8  { return r[4] }
+func (r *Reloc2) Type() uint8 { return r[5] }
+func (r *Reloc2) Add() int64  { return int64(binary.LittleEndian.Uint64(r[6:])) }
+func (r *Reloc2) Sym() SymRef {
+       return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])}
+}
+
 // Aux symbol info.
 type Aux struct {
        Type uint8
@@ -566,6 +580,12 @@ func (r *Reader) RelocOff(i int, j int) uint32 {
        return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(relocsiz)
 }
 
+// Reloc2 returns a pointer to the j-th relocation of the i-th symbol.
+func (r *Reader) Reloc2(i int, j int) *Reloc2 {
+       off := r.RelocOff(i, j)
+       return (*Reloc2)(unsafe.Pointer(&r.b[off]))
+}
+
 // NAux returns the number of aux symbols of the i-th symbol.
 func (r *Reader) NAux(i int) int {
        auxIdxOff := r.h.Offsets[BlkAuxIdx] + uint32(i*4)
diff --git a/src/cmd/internal/goobj2/objfile_test.go b/src/cmd/internal/goobj2/objfile_test.go
new file mode 100644 (file)
index 0000000..eea97d4
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2020 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 goobj2
+
+import (
+       "bufio"
+       "bytes"
+       "cmd/internal/bio"
+       "testing"
+)
+
+func dummyWriter() *Writer {
+       var buf bytes.Buffer
+       wr := &bio.Writer{Writer: bufio.NewWriter(&buf)} // hacky: no file, so cannot seek
+       return NewWriter(wr)
+}
+
+func TestSize(t *testing.T) {
+       // This test checks that hard-coded sizes match the actual sizes
+       // in the object file format.
+       w := dummyWriter()
+       (&Reloc{}).Write(w)
+       off := w.off
+       if sz := uint32(RelocSize); off != sz {
+               t.Errorf("size mismatch: %d bytes written, but size=%d", off, sz)
+       }
+}
index 6f222ce10c8790a6ff2427d5ebe25d3364b6a8cc..d7d52a579b1676ac6fef6d18c0237fc754496106 100644 (file)
@@ -2266,14 +2266,15 @@ func (sc *stkChk) check(up *chain, depth int) int {
 
                // Process calls in this span.
                for i := 0; i < relocs.Count; i++ {
-                       r := relocs.At(i)
-                       if uint32(r.Off) >= pcsp.NextPC {
+                       r := relocs.At2(i)
+                       if uint32(r.Off()) >= pcsp.NextPC {
                                break
                        }
+                       t := r.Type()
                        switch {
-                       case r.Type.IsDirectCall():
+                       case t.IsDirectCall():
                                ch.limit = int(int32(limit) - pcsp.Value - int32(callsize(ctxt)))
-                               ch.sym = r.Sym
+                               ch.sym = r.Sym()
                                if sc.check(&ch, depth+1) < 0 {
                                        return -1
                                }
@@ -2282,7 +2283,7 @@ func (sc *stkChk) check(up *chain, depth int) int {
                        // so we have to make sure it can call morestack.
                        // Arrange the data structures to report both calls, so that
                        // if there is an error, stkprint shows all the steps involved.
-                       case r.Type == objabi.R_CALLIND:
+                       case t == objabi.R_CALLIND:
                                ch.limit = int(int32(limit) - pcsp.Value - int32(callsize(ctxt)))
                                ch.sym = 0
                                ch1.limit = ch.limit - callsize(ctxt) // for morestack in called prologue
index 5d29aa59a655b809730bc46ca5ebb5db36e9694a..979d94402ee150e2cb2176f376cad10cd28c8329 100644 (file)
@@ -49,6 +49,17 @@ type Reloc struct {
        Sym  Sym              // global index of symbol the reloc addresses
 }
 
+// Reloc2 holds a "handle" to access a relocation record from an
+// object file.
+type Reloc2 struct {
+       *goobj2.Reloc2
+       r *oReader
+       l *Loader
+}
+
+func (rel Reloc2) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc2.Type()) }
+func (rel Reloc2) Sym() Sym               { return rel.l.resolve(rel.r, rel.Reloc2.Sym()) }
+
 // oReader is a wrapper type of obj.Reader, along with some
 // extra information.
 // TODO: rename to objReader once the old one is gone?
@@ -1435,6 +1446,16 @@ func (relocs *Relocs) At(j int) Reloc {
        }
 }
 
+func (relocs *Relocs) At2(j int) Reloc2 {
+       if relocs.l.isExtReader(relocs.r) {
+               // TODO: implement this. How? Maybe we can construct the reloc
+               // data for external symbols in the same byte form as the one
+               // in the object file?
+               panic("not implemented")
+       }
+       return Reloc2{relocs.r.Reloc2(relocs.li, j), relocs.r, relocs.l}
+}
+
 // ReadAll method reads all relocations for a symbol into the
 // specified slice. If the slice capacity is not large enough, a new
 // larger slice will be allocated. Final slice is returned.