]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: add SymbolBuilder helper
authorThan McIntosh <thanm@google.com>
Wed, 11 Dec 2019 19:36:17 +0000 (14:36 -0500)
committerThan McIntosh <thanm@google.com>
Fri, 27 Dec 2019 15:05:39 +0000 (15:05 +0000)
Add SymbolBuilder helper type -- this type provides a set of methods
intended to make it easy to manipulate the content of a symbol (type,
relocations, data, etc).

Change-Id: I579bf8d04650e66d33a9780a6c2347a576c94c6f
Reviewed-on: https://go-review.googlesource.com/c/go/+/210178
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/loader/loader.go
src/cmd/link/internal/loader/loader_test.go
src/cmd/link/internal/loader/symbolbuilder.go [new file with mode: 0644]

index dc3f1692f75d404cd5bca29240a1baec485b22a3..a4af4f0dd2e241d808ac082107625dc6788b37dd 100644 (file)
@@ -388,7 +388,7 @@ func (ctxt *Link) loadlib() {
        default:
                log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
        }
-       ctxt.loader = loader.NewLoader(flags)
+       ctxt.loader = loader.NewLoader(flags, elfsetstring)
 
        ctxt.cgo_export_static = make(map[string]bool)
        ctxt.cgo_export_dynamic = make(map[string]bool)
index 029e10fedaa9b6ac76251caadec4950012038468..89e312e665680138c577a9a88354ca823461e752 100644 (file)
@@ -211,8 +211,12 @@ type Loader struct {
        flags uint32
 
        strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
+
+       elfsetstring elfsetstringFunc
 }
 
+type elfsetstringFunc func(s *sym.Symbol, str string, off int)
+
 // extSymPayload holds the payload (data + relocations) for linker-synthesized
 // external symbols (note that symbol value is stored in a separate slice).
 type extSymPayload struct {
@@ -229,7 +233,7 @@ const (
        FlagStrictDups = 1 << iota
 )
 
-func NewLoader(flags uint32) *Loader {
+func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
        nbuiltin := goobj2.NBuiltin()
        return &Loader{
                start:                make(map[*oReader]Sym),
@@ -252,6 +256,7 @@ func NewLoader(flags uint32) *Loader {
                extStaticSyms:        make(map[nameVer]Sym),
                builtinSyms:          make([]Sym, nbuiltin),
                flags:                flags,
+               elfsetstring:         elfsetstring,
        }
 }
 
@@ -392,6 +397,21 @@ func (l *Loader) getPayload(i Sym) *extSymPayload {
        return &l.payloads[pi]
 }
 
+func (ms *extSymPayload) Grow(siz int64) {
+       if int64(int(siz)) != siz {
+               log.Fatalf("symgrow size %d too long", siz)
+       }
+       if int64(len(ms.data)) >= siz {
+               return
+       }
+       if cap(ms.data) < int(siz) {
+               cl := len(ms.data)
+               ms.data = append(ms.data, make([]byte, int(siz)+1-cl)...)
+               ms.data = ms.data[0:cl]
+       }
+       ms.data = ms.data[:siz]
+}
+
 // Ensure Syms slice has enough space, as well as growing the
 // 'payloads' slice.
 func (l *Loader) growSyms(i int) {
index 92ade70b8f2c8f1abd2df2795a779b6ab5bfc360..9ed84ccc5ef4cca7096a7cbec6cd75e909361f0f 100644 (file)
@@ -5,6 +5,9 @@
 package loader
 
 import (
+       "bytes"
+       "cmd/internal/objabi"
+       "cmd/internal/sys"
        "cmd/link/internal/sym"
        "fmt"
        "testing"
@@ -26,14 +29,15 @@ func addDummyObjSym(t *testing.T, ldr *Loader, or *oReader, name string) Sym {
 }
 
 func TestAddMaterializedSymbol(t *testing.T) {
-       ldr := NewLoader(0)
+       edummy := func(s *sym.Symbol, str string, off int) {}
+       ldr := NewLoader(0, edummy)
        dummyOreader := oReader{version: -1}
        or := &dummyOreader
 
        // Create some syms from a dummy object file symbol to get things going.
-       addDummyObjSym(t, ldr, or, "type.uint8")
+       ts1 := addDummyObjSym(t, ldr, or, "type.uint8")
        ts2 := addDummyObjSym(t, ldr, or, "mumble")
-       addDummyObjSym(t, ldr, or, "type.string")
+       ts3 := addDummyObjSym(t, ldr, or, "type.string")
 
        // Create some external symbols.
        es1 := ldr.AddExtSym("extnew1", 0)
@@ -54,6 +58,22 @@ func TestAddMaterializedSymbol(t *testing.T) {
                t.Fatalf("CreateExtSym failed for nameless sym")
        }
 
+       // Grab symbol builder pointers
+       sb1 := ldr.MakeSymbolUpdater(es1)
+       sb2 := ldr.MakeSymbolUpdater(es2)
+       sb3 := ldr.MakeSymbolUpdater(es3)
+
+       // Check get/set symbol type
+       es3typ := sb3.Type()
+       if es3typ != sym.Sxxx {
+               t.Errorf("SymType(es3): expected %d, got %d", sym.Sxxx, es3typ)
+       }
+       sb2.SetType(sym.SRODATA)
+       es3typ = sb2.Type()
+       if es3typ != sym.SRODATA {
+               t.Errorf("SymType(es3): expected %d, got %d", sym.SRODATA, es3typ)
+       }
+
        // New symbols should not initially be reachable.
        if ldr.AttrReachable(es1) || ldr.AttrReachable(es2) || ldr.AttrReachable(es3) {
                t.Errorf("newly materialized symbols should not be reachable")
@@ -88,6 +108,9 @@ func TestAddMaterializedSymbol(t *testing.T) {
                }
        }
 
+       sb1 = ldr.MakeSymbolUpdater(es1)
+       sb2 = ldr.MakeSymbolUpdater(es2)
+
        // Get/set a few other attributes
        if ldr.AttrVisibilityHidden(es3) {
                t.Errorf("expected initially not hidden")
@@ -120,10 +143,202 @@ func TestAddMaterializedSymbol(t *testing.T) {
        if es3al != 128 {
                t.Errorf("SymAlign(es3): expected 128, got %d", es3al)
        }
+
+       // Add some relocations to the new symbols.
+       r1 := Reloc{0, 1, objabi.R_ADDR, 0, ts1}
+       r2 := Reloc{3, 8, objabi.R_CALL, 0, ts2}
+       r3 := Reloc{7, 1, objabi.R_USETYPE, 0, ts3}
+       sb1.AddReloc(r1)
+       sb1.AddReloc(r2)
+       sb2.AddReloc(r3)
+
+       // Add some data to the symbols.
+       d1 := []byte{1, 2, 3}
+       d2 := []byte{4, 5, 6, 7}
+       sb1.AddBytes(d1)
+       sb2.AddBytes(d2)
+
+       // Now invoke the usual loader interfaces to make sure
+       // we're getting the right things back for these symbols.
+       // First relocations...
+       expRel := [][]Reloc{[]Reloc{r1, r2}, []Reloc{r3}}
+       for k, sb := range []*SymbolBuilder{sb1, sb2} {
+               rsl := sb.Relocs()
+               exp := expRel[k]
+               if !sameRelocSlice(rsl, exp) {
+                       t.Errorf("expected relocs %v, got %v", exp, rsl)
+               }
+               relocs := ldr.Relocs(sb.Sym())
+               r0 := relocs.At(0)
+               if r0 != exp[0] {
+                       t.Errorf("expected reloc %v, got %v", exp[0], r0)
+               }
+       }
+
+       // ... then data.
+       dat := sb2.Data()
+       if bytes.Compare(dat, d2) != 0 {
+               t.Errorf("expected es2 data %v, got %v", d2, dat)
+       }
+
+       // Nameless symbol should still be nameless.
+       es3name := ldr.RawSymName(es3)
+       if "" != es3name {
+               t.Errorf("expected es3 name of '', got '%s'", es3name)
+       }
+
+       // Read value of materialized symbol.
+       es1val := sb1.Value()
+       if 0 != es1val {
+               t.Errorf("expected es1 value of 0, got %v", es1val)
+       }
+
+       // Test other misc methods
+       irm := ldr.IsReflectMethod(es1)
+       if 0 != es1val {
+               t.Errorf("expected IsReflectMethod(es1) value of 0, got %v", irm)
+       }
+
+       // Writing data to a materialized symbol should mark it reachable.
+       if !sb1.Reachable() || !sb2.Reachable() {
+               t.Fatalf("written-to materialized symbols should be reachable")
+       }
+}
+
+func sameRelocSlice(s1 []Reloc, s2 []Reloc) bool {
+       if len(s1) != len(s2) {
+               return false
+       }
+       for i := 0; i < len(s1); i++ {
+               if s1[i] != s2[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+type addFunc func(l *Loader, s Sym, s2 Sym)
+
+func TestAddDataMethods(t *testing.T) {
+       edummy := func(s *sym.Symbol, str string, off int) {}
+       ldr := NewLoader(0, edummy)
+       dummyOreader := oReader{version: -1}
+       or := &dummyOreader
+
+       // Populate loader with some symbols.
+       addDummyObjSym(t, ldr, or, "type.uint8")
+       ldr.AddExtSym("hello", 0)
+
+       arch := sys.ArchAMD64
+       var testpoints = []struct {
+               which       string
+               addDataFunc addFunc
+               expData     []byte
+               expKind     sym.SymKind
+               expRel      []Reloc
+       }{
+               {
+                       which: "AddUint8",
+                       addDataFunc: func(l *Loader, s Sym, _ Sym) {
+                               sb := l.MakeSymbolUpdater(s)
+                               sb.AddUint8('a')
+                       },
+                       expData: []byte{'a'},
+                       expKind: sym.SDATA,
+               },
+               {
+                       which: "AddUintXX",
+                       addDataFunc: func(l *Loader, s Sym, _ Sym) {
+                               sb := l.MakeSymbolUpdater(s)
+                               sb.AddUintXX(arch, 25185, 2)
+                       },
+                       expData: []byte{'a', 'b'},
+                       expKind: sym.SDATA,
+               },
+               {
+                       which: "SetUint8",
+                       addDataFunc: func(l *Loader, s Sym, _ Sym) {
+                               sb := l.MakeSymbolUpdater(s)
+                               sb.AddUint8('a')
+                               sb.AddUint8('b')
+                               sb.SetUint8(arch, 1, 'c')
+                       },
+                       expData: []byte{'a', 'c'},
+                       expKind: sym.SDATA,
+               },
+               {
+                       which: "AddString",
+                       addDataFunc: func(l *Loader, s Sym, _ Sym) {
+                               sb := l.MakeSymbolUpdater(s)
+                               sb.Addstring("hello")
+                       },
+                       expData: []byte{'h', 'e', 'l', 'l', 'o', 0},
+                       expKind: sym.SNOPTRDATA,
+               },
+               {
+                       which: "AddAddrPlus",
+                       addDataFunc: func(l *Loader, s Sym, s2 Sym) {
+                               sb := l.MakeSymbolUpdater(s)
+                               sb.AddAddrPlus(arch, s2, 3)
+                       },
+                       expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
+                       expKind: sym.SDATA,
+                       expRel:  []Reloc{Reloc{Type: objabi.R_ADDR, Size: 8, Add: 3, Sym: 6}},
+               },
+               {
+                       which: "AddAddrPlus4",
+                       addDataFunc: func(l *Loader, s Sym, s2 Sym) {
+                               sb := l.MakeSymbolUpdater(s)
+                               sb.AddAddrPlus4(arch, s2, 3)
+                       },
+                       expData: []byte{0, 0, 0, 0},
+                       expKind: sym.SDATA,
+                       expRel:  []Reloc{Reloc{Type: objabi.R_ADDR, Size: 4, Add: 3, Sym: 7}},
+               },
+               {
+                       which: "AddCURelativeAddrPlus",
+                       addDataFunc: func(l *Loader, s Sym, s2 Sym) {
+                               sb := l.MakeSymbolUpdater(s)
+                               sb.AddCURelativeAddrPlus(arch, s2, 7)
+                       },
+                       expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
+                       expKind: sym.SDATA,
+                       expRel:  []Reloc{Reloc{Type: objabi.R_ADDRCUOFF, Size: 8, Add: 7, Sym: 8}},
+               },
+       }
+
+       var pmi Sym
+       for k, tp := range testpoints {
+               name := fmt.Sprintf("new%d", k+1)
+               mi := ldr.AddExtSym(name, 0)
+               if mi == 0 {
+                       t.Fatalf("AddExtSym failed for '" + name + "'")
+               }
+               tp.addDataFunc(ldr, mi, pmi)
+               if ldr.SymType(mi) != tp.expKind {
+                       t.Errorf("testing Loader.%s: expected kind %s got %s",
+                               tp.which, tp.expKind, ldr.SymType(mi))
+               }
+               if bytes.Compare(ldr.Data(mi), tp.expData) != 0 {
+                       t.Errorf("testing Loader.%s: expected data %v got %v",
+                               tp.which, tp.expData, ldr.Data(mi))
+               }
+               if !ldr.AttrReachable(mi) {
+                       t.Fatalf("testing Loader.%s: sym updated should be reachable", tp.which)
+               }
+               relocs := ldr.Relocs(mi)
+               rsl := relocs.ReadAll(nil)
+               if !sameRelocSlice(rsl, tp.expRel) {
+                       t.Fatalf("testing Loader.%s: got relocslice %+v wanted %+v",
+                               tp.which, rsl, tp.expRel)
+               }
+               pmi = mi
+       }
 }
 
 func TestOuterSub(t *testing.T) {
-       ldr := NewLoader(0)
+       edummy := func(s *sym.Symbol, str string, off int) {}
+       ldr := NewLoader(0, edummy)
        dummyOreader := oReader{version: -1}
        or := &dummyOreader
 
diff --git a/src/cmd/link/internal/loader/symbolbuilder.go b/src/cmd/link/internal/loader/symbolbuilder.go
new file mode 100644 (file)
index 0000000..21ed30d
--- /dev/null
@@ -0,0 +1,250 @@
+// Copyright 2019 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 loader
+
+import (
+       "cmd/internal/objabi"
+       "cmd/internal/sys"
+       "cmd/link/internal/sym"
+)
+
+// SymbolBuilder is a helper designed to help with the construction
+// of new symbol contents.
+type SymbolBuilder struct {
+       *extSymPayload         // points to payload being updated
+       symIdx         Sym     // index of symbol being updated/constructed
+       l              *Loader // loader
+}
+
+// NewSymbolBuilder creates a symbol builder for use in constructing
+// an entirely new symbol.
+func (l *Loader) MakeSymbolBuilder(name string) *SymbolBuilder {
+       // for now assume that any new sym is intended to be static
+       symIdx := l.CreateExtSym(name)
+       if l.Syms[symIdx] != nil {
+               panic("can't build if sym.Symbol already present")
+       }
+       sb := &SymbolBuilder{l: l, symIdx: symIdx}
+       sb.extSymPayload = &l.payloads[symIdx-l.extStart]
+       return sb
+}
+
+// NewSymbolBuilder creates a symbol builder helper for an already-allocated
+// external symbol 'symIdx'.
+func (l *Loader) MakeSymbolUpdater(symIdx Sym) *SymbolBuilder {
+       if !l.IsExternal(symIdx) {
+               panic("can't build on non-external sym")
+       }
+       if l.Syms[symIdx] != nil {
+               panic("can't build if sym.Symbol already present")
+       }
+       sb := &SymbolBuilder{l: l, symIdx: symIdx}
+       sb.extSymPayload = &l.payloads[symIdx-l.extStart]
+       return sb
+}
+
+// Getters for properties of the symbol we're working on.
+
+func (sb *SymbolBuilder) Sym() Sym           { return sb.symIdx }
+func (sb *SymbolBuilder) Name() string       { return sb.name }
+func (sb *SymbolBuilder) Version() int       { return sb.ver }
+func (sb *SymbolBuilder) Type() sym.SymKind  { return sb.kind }
+func (sb *SymbolBuilder) Size() int64        { return sb.size }
+func (sb *SymbolBuilder) Data() []byte       { return sb.data }
+func (sb *SymbolBuilder) Value() int64       { return sb.l.SymValue(sb.symIdx) }
+func (sb *SymbolBuilder) Align() int32       { return sb.l.SymAlign(sb.symIdx) }
+func (sb *SymbolBuilder) Localentry() uint8  { return sb.l.SymLocalentry(sb.symIdx) }
+func (sb *SymbolBuilder) Extname() string    { return sb.l.SymExtname(sb.symIdx) }
+func (sb *SymbolBuilder) Dynimplib() string  { return sb.l.SymDynimplib(sb.symIdx) }
+func (sb *SymbolBuilder) Dynimpvers() string { return sb.l.SymDynimpvers(sb.symIdx) }
+
+// Setters for symbol properties.
+
+func (sb *SymbolBuilder) SetType(kind sym.SymKind)   { sb.kind = kind }
+func (sb *SymbolBuilder) SetSize(size int64)         { sb.size = size }
+func (sb *SymbolBuilder) SetData(data []byte)        { sb.data = data }
+func (sb *SymbolBuilder) SetValue(v int64)           { sb.l.SetSymValue(sb.symIdx, v) }
+func (sb *SymbolBuilder) SetAlign(align int32)       { sb.l.SetSymAlign(sb.symIdx, align) }
+func (sb *SymbolBuilder) SetLocalentry(value uint8)  { sb.l.SetSymLocalentry(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetExtname(value string)    { sb.l.SetSymExtname(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetDynimplib(value string)  { sb.l.SetSymDynimplib(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetDynimpvers(value string) { sb.l.SetSymDynimpvers(sb.symIdx, value) }
+
+func (sb *SymbolBuilder) AddBytes(data []byte) {
+       sb.setReachable()
+       if sb.kind == 0 {
+               sb.kind = sym.SDATA
+       }
+       sb.data = append(sb.data, data...)
+       sb.size = int64(len(sb.data))
+}
+
+func (sb *SymbolBuilder) Relocs() []Reloc {
+       return sb.relocs
+}
+
+func (sb *SymbolBuilder) SetRelocs(rslice []Reloc) {
+       sb.relocs = rslice
+}
+
+func (sb *SymbolBuilder) AddReloc(r Reloc) {
+       sb.relocs = append(sb.relocs, r)
+}
+
+func (sb *SymbolBuilder) Reachable() bool {
+       return sb.l.AttrReachable(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) setReachable() {
+       sb.l.SetAttrReachable(sb.symIdx, true)
+}
+
+func (sb *SymbolBuilder) Outer() Sym {
+       return sb.l.OuterSym(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) Sub() Sym {
+       return sb.l.SubSym(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) SortSub() {
+       sb.l.SortSub(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) PrependSub(sub Sym) {
+       sb.l.PrependSub(sb.symIdx, sub)
+}
+
+func (sb *SymbolBuilder) AddUint8(v uint8) int64 {
+       off := sb.size
+       if sb.kind == 0 {
+               sb.kind = sym.SDATA
+       }
+       sb.setReachable()
+       sb.size++
+       sb.data = append(sb.data, v)
+       return off
+}
+
+func (sb *SymbolBuilder) AddUintXX(arch *sys.Arch, v uint64, wid int) int64 {
+       off := sb.size
+       sb.setReachable()
+       sb.setUintXX(arch, off, v, int64(wid))
+       return off
+}
+
+func (sb *SymbolBuilder) setUintXX(arch *sys.Arch, off int64, v uint64, wid int64) int64 {
+       if sb.kind == 0 {
+               sb.kind = sym.SDATA
+       }
+       if sb.size < off+wid {
+               sb.size = off + wid
+               sb.Grow(sb.size)
+       }
+
+       switch wid {
+       case 1:
+               sb.data[off] = uint8(v)
+       case 2:
+               arch.ByteOrder.PutUint16(sb.data[off:], uint16(v))
+       case 4:
+               arch.ByteOrder.PutUint32(sb.data[off:], uint32(v))
+       case 8:
+               arch.ByteOrder.PutUint64(sb.data[off:], v)
+       }
+
+       return off + wid
+}
+
+func (sb *SymbolBuilder) AddUint16(arch *sys.Arch, v uint16) int64 {
+       return sb.AddUintXX(arch, uint64(v), 2)
+}
+
+func (sb *SymbolBuilder) AddUint32(arch *sys.Arch, v uint32) int64 {
+       return sb.AddUintXX(arch, uint64(v), 4)
+}
+
+func (sb *SymbolBuilder) AddUint64(arch *sys.Arch, v uint64) int64 {
+       return sb.AddUintXX(arch, v, 8)
+}
+
+func (sb *SymbolBuilder) AddUint(arch *sys.Arch, v uint64) int64 {
+       return sb.AddUintXX(arch, v, arch.PtrSize)
+}
+
+func (sb *SymbolBuilder) SetUint8(arch *sys.Arch, r int64, v uint8) int64 {
+       sb.setReachable()
+       return sb.setUintXX(arch, r, uint64(v), 1)
+}
+
+func (sb *SymbolBuilder) SetUint16(arch *sys.Arch, r int64, v uint16) int64 {
+       sb.setReachable()
+       return sb.setUintXX(arch, r, uint64(v), 2)
+}
+
+func (sb *SymbolBuilder) SetUint32(arch *sys.Arch, r int64, v uint32) int64 {
+       sb.setReachable()
+       return sb.setUintXX(arch, r, uint64(v), 4)
+}
+
+func (sb *SymbolBuilder) SetUint(arch *sys.Arch, r int64, v uint64) int64 {
+       sb.setReachable()
+       return sb.setUintXX(arch, r, v, int64(arch.PtrSize))
+}
+
+func (sb *SymbolBuilder) Addstring(str string) int64 {
+       sb.setReachable()
+       if sb.kind == 0 {
+               sb.kind = sym.SNOPTRDATA
+       }
+       r := sb.size
+       if sb.name == ".shstrtab" {
+               // FIXME: find a better mechanism for this
+               sb.l.elfsetstring(nil, str, int(r))
+       }
+       sb.data = append(sb.data, str...)
+       sb.data = append(sb.data, 0)
+       sb.size = int64(len(sb.data))
+       return r
+}
+
+func (sb *SymbolBuilder) addRel() *Reloc {
+       sb.relocs = append(sb.relocs, Reloc{})
+       return &sb.relocs[len(sb.relocs)-1]
+}
+
+func (sb *SymbolBuilder) addAddrPlus(tgt Sym, add int64, typ objabi.RelocType, rsize int) int64 {
+       if sb.kind == 0 {
+               sb.kind = sym.SDATA
+       }
+       i := sb.size
+
+       sb.size += int64(rsize)
+       sb.Grow(sb.size)
+
+       r := sb.addRel()
+       r.Sym = tgt
+       r.Off = int32(i)
+       r.Size = uint8(rsize)
+       r.Type = typ
+       r.Add = add
+
+       return i + int64(r.Size)
+}
+
+func (sb *SymbolBuilder) AddAddrPlus(arch *sys.Arch, tgt Sym, add int64) int64 {
+       sb.setReachable()
+       return sb.addAddrPlus(tgt, add, objabi.R_ADDR, arch.PtrSize)
+}
+
+func (sb *SymbolBuilder) AddAddrPlus4(arch *sys.Arch, tgt Sym, add int64) int64 {
+       sb.setReachable()
+       return sb.addAddrPlus(tgt, add, objabi.R_ADDR, 4)
+}
+
+func (sb *SymbolBuilder) AddCURelativeAddrPlus(arch *sys.Arch, tgt Sym, add int64) int64 {
+       sb.setReachable()
+       return sb.addAddrPlus(tgt, add, objabi.R_ADDRCUOFF, arch.PtrSize)
+}