2019-12-11 13:39:39 -05:00
|
|
|
// 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 (
|
2019-12-11 14:36:17 -05:00
|
|
|
"bytes"
|
2020-07-12 17:57:11 -04:00
|
|
|
"cmd/internal/goobj2"
|
2019-12-11 14:36:17 -05:00
|
|
|
"cmd/internal/objabi"
|
|
|
|
|
"cmd/internal/sys"
|
2019-12-11 13:39:39 -05:00
|
|
|
"cmd/link/internal/sym"
|
2019-12-11 14:05:14 -05:00
|
|
|
"fmt"
|
2019-12-11 13:39:39 -05:00
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// dummyAddSym adds the named symbol to the loader as if it had been
|
|
|
|
|
// read from a Go object file. Note that it allocates a global
|
|
|
|
|
// index without creating an associated object reader, so one can't
|
|
|
|
|
// do anything interesting with this symbol (such as look at its
|
|
|
|
|
// data or relocations).
|
|
|
|
|
func addDummyObjSym(t *testing.T, ldr *Loader, or *oReader, name string) Sym {
|
2020-05-12 20:08:27 -04:00
|
|
|
idx := uint32(len(ldr.objSyms))
|
2020-07-29 19:44:49 -04:00
|
|
|
st := loadState{l: ldr}
|
|
|
|
|
return st.addSym(name, 0, or, idx, nonPkgDef, &goobj2.Sym{})
|
2019-12-11 13:39:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-04-22 15:16:06 -04:00
|
|
|
func mkLoader() *Loader {
|
2020-05-12 17:16:51 -04:00
|
|
|
edummy := func(str string, off int) {}
|
2020-04-22 15:16:06 -04:00
|
|
|
er := ErrorReporter{}
|
|
|
|
|
ldr := NewLoader(0, edummy, &er)
|
|
|
|
|
er.ldr = ldr
|
|
|
|
|
return ldr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestAddMaterializedSymbol(t *testing.T) {
|
|
|
|
|
ldr := mkLoader()
|
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
|
|
|
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
2019-12-11 13:39:39 -05:00
|
|
|
or := &dummyOreader
|
|
|
|
|
|
|
|
|
|
// Create some syms from a dummy object file symbol to get things going.
|
2019-12-11 14:36:17 -05:00
|
|
|
ts1 := addDummyObjSym(t, ldr, or, "type.uint8")
|
2019-12-13 11:51:15 -05:00
|
|
|
ts2 := addDummyObjSym(t, ldr, or, "mumble")
|
2019-12-11 14:36:17 -05:00
|
|
|
ts3 := addDummyObjSym(t, ldr, or, "type.string")
|
2019-12-11 13:39:39 -05:00
|
|
|
|
|
|
|
|
// Create some external symbols.
|
2020-03-16 15:04:00 -04:00
|
|
|
es1 := ldr.LookupOrCreateSym("extnew1", 0)
|
2019-12-11 13:39:39 -05:00
|
|
|
if es1 == 0 {
|
2020-03-16 15:04:00 -04:00
|
|
|
t.Fatalf("LookupOrCreateSym failed for extnew1")
|
2019-12-11 13:39:39 -05:00
|
|
|
}
|
2020-03-16 15:04:00 -04:00
|
|
|
es1x := ldr.LookupOrCreateSym("extnew1", 0)
|
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
|
|
|
if es1x != es1 {
|
2020-03-16 15:04:00 -04:00
|
|
|
t.Fatalf("LookupOrCreateSym lookup: expected %d got %d for second lookup", es1, es1x)
|
2019-12-11 13:39:39 -05:00
|
|
|
}
|
2020-03-16 15:04:00 -04:00
|
|
|
es2 := ldr.LookupOrCreateSym("go.info.type.uint8", 0)
|
2019-12-11 13:39:39 -05:00
|
|
|
if es2 == 0 {
|
2020-03-16 15:04:00 -04:00
|
|
|
t.Fatalf("LookupOrCreateSym failed for go.info.type.uint8")
|
2019-12-11 13:39:39 -05:00
|
|
|
}
|
|
|
|
|
// Create a nameless symbol
|
2020-03-24 12:08:36 -04:00
|
|
|
es3 := ldr.CreateStaticSym("")
|
2019-12-11 13:39:39 -05:00
|
|
|
if es3 == 0 {
|
2020-03-24 12:08:36 -04:00
|
|
|
t.Fatalf("CreateStaticSym failed for nameless sym")
|
2019-12-11 13:39:39 -05:00
|
|
|
}
|
2019-12-11 14:05:14 -05:00
|
|
|
|
2019-12-11 14:36:17 -05:00
|
|
|
// Grab symbol builder pointers
|
2020-02-12 17:23:47 -05:00
|
|
|
sb1 := ldr.MakeSymbolUpdater(es1)
|
|
|
|
|
sb2 := ldr.MakeSymbolUpdater(es2)
|
|
|
|
|
sb3 := ldr.MakeSymbolUpdater(es3)
|
2019-12-11 14:36:17 -05:00
|
|
|
|
2020-01-29 22:10:51 -05:00
|
|
|
// Suppose we create some more symbols, which triggers a grow.
|
|
|
|
|
// Make sure the symbol builder's payload pointer is valid,
|
|
|
|
|
// even across a grow.
|
2020-05-14 16:05:29 -04:00
|
|
|
for i := 0; i < 9999; i++ {
|
|
|
|
|
ldr.CreateStaticSym("dummy")
|
|
|
|
|
}
|
2020-01-29 22:10:51 -05:00
|
|
|
|
2019-12-11 14:36:17 -05:00
|
|
|
// Check get/set symbol type
|
|
|
|
|
es3typ := sb3.Type()
|
|
|
|
|
if es3typ != sym.Sxxx {
|
2020-01-29 22:10:51 -05:00
|
|
|
t.Errorf("SymType(es3): expected %v, got %v", sym.Sxxx, es3typ)
|
|
|
|
|
}
|
|
|
|
|
sb3.SetType(sym.SRODATA)
|
|
|
|
|
es3typ = sb3.Type()
|
|
|
|
|
if es3typ != sym.SRODATA {
|
|
|
|
|
t.Errorf("SymType(es3): expected %v, got %v", sym.SRODATA, es3typ)
|
2019-12-11 14:36:17 -05:00
|
|
|
}
|
2020-01-29 22:10:51 -05:00
|
|
|
es3typ = ldr.SymType(es3)
|
2019-12-11 14:36:17 -05:00
|
|
|
if es3typ != sym.SRODATA {
|
2020-01-29 22:10:51 -05:00
|
|
|
t.Errorf("SymType(es3): expected %v, got %v", sym.SRODATA, es3typ)
|
2019-12-11 14:36:17 -05:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 14:05:14 -05:00
|
|
|
// 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")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ... however it should be possible to set/unset their reachability.
|
|
|
|
|
ldr.SetAttrReachable(es3, true)
|
|
|
|
|
if !ldr.AttrReachable(es3) {
|
|
|
|
|
t.Errorf("expected reachable symbol after update")
|
|
|
|
|
}
|
|
|
|
|
ldr.SetAttrReachable(es3, false)
|
|
|
|
|
if ldr.AttrReachable(es3) {
|
|
|
|
|
t.Errorf("expected unreachable symbol after update")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test expansion of attr bitmaps
|
|
|
|
|
for idx := 0; idx < 36; idx++ {
|
2020-03-16 15:04:00 -04:00
|
|
|
es := ldr.LookupOrCreateSym(fmt.Sprintf("zext%d", idx), 0)
|
2019-12-11 14:05:14 -05:00
|
|
|
if ldr.AttrOnList(es) {
|
|
|
|
|
t.Errorf("expected OnList after creation")
|
|
|
|
|
}
|
|
|
|
|
ldr.SetAttrOnList(es, true)
|
|
|
|
|
if !ldr.AttrOnList(es) {
|
|
|
|
|
t.Errorf("expected !OnList after update")
|
|
|
|
|
}
|
|
|
|
|
if ldr.AttrDuplicateOK(es) {
|
|
|
|
|
t.Errorf("expected DupOK after creation")
|
|
|
|
|
}
|
|
|
|
|
ldr.SetAttrDuplicateOK(es, true)
|
|
|
|
|
if !ldr.AttrDuplicateOK(es) {
|
|
|
|
|
t.Errorf("expected !DupOK after update")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-12 17:23:47 -05:00
|
|
|
sb1 = ldr.MakeSymbolUpdater(es1)
|
|
|
|
|
sb2 = ldr.MakeSymbolUpdater(es2)
|
2019-12-11 14:36:17 -05:00
|
|
|
|
2019-12-11 14:05:14 -05:00
|
|
|
// Get/set a few other attributes
|
|
|
|
|
if ldr.AttrVisibilityHidden(es3) {
|
|
|
|
|
t.Errorf("expected initially not hidden")
|
|
|
|
|
}
|
|
|
|
|
ldr.SetAttrVisibilityHidden(es3, true)
|
|
|
|
|
if !ldr.AttrVisibilityHidden(es3) {
|
|
|
|
|
t.Errorf("expected hidden after update")
|
|
|
|
|
}
|
2019-12-13 11:51:15 -05:00
|
|
|
|
|
|
|
|
// Test get/set symbol value.
|
|
|
|
|
toTest := []Sym{ts2, es3}
|
|
|
|
|
for i, s := range toTest {
|
|
|
|
|
if v := ldr.SymValue(s); v != 0 {
|
|
|
|
|
t.Errorf("ldr.Value(%d): expected 0 got %d\n", s, v)
|
|
|
|
|
}
|
|
|
|
|
nv := int64(i + 101)
|
|
|
|
|
ldr.SetSymValue(s, nv)
|
|
|
|
|
if v := ldr.SymValue(s); v != nv {
|
|
|
|
|
t.Errorf("ldr.SetValue(%d,%d): expected %d got %d\n", s, nv, nv, v)
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-11 14:24:19 -05:00
|
|
|
|
|
|
|
|
// Check/set alignment
|
|
|
|
|
es3al := ldr.SymAlign(es3)
|
|
|
|
|
if es3al != 0 {
|
|
|
|
|
t.Errorf("SymAlign(es3): expected 0, got %d", es3al)
|
|
|
|
|
}
|
|
|
|
|
ldr.SetSymAlign(es3, 128)
|
|
|
|
|
es3al = ldr.SymAlign(es3)
|
|
|
|
|
if es3al != 128 {
|
|
|
|
|
t.Errorf("SymAlign(es3): expected 128, got %d", es3al)
|
|
|
|
|
}
|
2019-12-11 14:36:17 -05:00
|
|
|
|
|
|
|
|
// Add some relocations to the new symbols.
|
2020-07-29 13:20:56 -04:00
|
|
|
r1, _ := sb1.AddRel(objabi.R_ADDR)
|
|
|
|
|
r1.SetOff(0)
|
|
|
|
|
r1.SetSiz(1)
|
|
|
|
|
r1.SetSym(ts1)
|
|
|
|
|
r2, _ := sb1.AddRel(objabi.R_CALL)
|
|
|
|
|
r2.SetOff(3)
|
|
|
|
|
r2.SetSiz(8)
|
|
|
|
|
r2.SetSym(ts2)
|
|
|
|
|
r3, _ := sb2.AddRel(objabi.R_USETYPE)
|
|
|
|
|
r3.SetOff(7)
|
|
|
|
|
r3.SetSiz(1)
|
|
|
|
|
r3.SetSym(ts3)
|
2019-12-11 14:36:17 -05:00
|
|
|
|
|
|
|
|
// 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...
|
2020-07-29 13:26:50 -04:00
|
|
|
expRel := [][]Reloc{{r1, r2}, {r3}}
|
2019-12-11 14:36:17 -05:00
|
|
|
for k, sb := range []*SymbolBuilder{sb1, sb2} {
|
|
|
|
|
rsl := sb.Relocs()
|
|
|
|
|
exp := expRel[k]
|
2020-03-28 16:46:47 -04:00
|
|
|
if !sameRelocSlice(&rsl, exp) {
|
2019-12-11 14:36:17 -05:00
|
|
|
t.Errorf("expected relocs %v, got %v", exp, rsl)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ... 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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-29 13:26:50 -04:00
|
|
|
func sameRelocSlice(s1 *Relocs, s2 []Reloc) bool {
|
2020-03-30 10:04:00 -04:00
|
|
|
if s1.Count() != len(s2) {
|
2019-12-11 14:36:17 -05:00
|
|
|
return false
|
|
|
|
|
}
|
2020-03-30 10:04:00 -04:00
|
|
|
for i := 0; i < s1.Count(); i++ {
|
2020-07-29 13:26:50 -04:00
|
|
|
r1 := s1.At(i)
|
2020-03-28 16:46:47 -04:00
|
|
|
r2 := &s2[i]
|
2020-07-29 13:20:56 -04:00
|
|
|
if r1.Sym() != r2.Sym() ||
|
|
|
|
|
r1.Type() != r2.Type() ||
|
|
|
|
|
r1.Off() != r2.Off() ||
|
|
|
|
|
r1.Add() != r2.Add() ||
|
|
|
|
|
r1.Siz() != r2.Siz() {
|
2019-12-11 14:36:17 -05:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-16 14:14:29 -05:00
|
|
|
type addFunc func(l *Loader, s Sym, s2 Sym) Sym
|
2019-12-11 14:36:17 -05:00
|
|
|
|
2020-07-29 13:26:50 -04:00
|
|
|
func mkReloc(l *Loader, typ objabi.RelocType, off int32, siz uint8, add int64, sym Sym) Reloc {
|
|
|
|
|
r := Reloc{&goobj2.Reloc{}, l.extReader, l, typ}
|
2020-07-29 13:20:56 -04:00
|
|
|
r.SetOff(off)
|
|
|
|
|
r.SetSiz(siz)
|
|
|
|
|
r.SetAdd(add)
|
|
|
|
|
r.SetSym(sym)
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 14:36:17 -05:00
|
|
|
func TestAddDataMethods(t *testing.T) {
|
2020-04-22 15:16:06 -04:00
|
|
|
ldr := mkLoader()
|
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
|
|
|
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
2019-12-11 14:36:17 -05:00
|
|
|
or := &dummyOreader
|
|
|
|
|
|
|
|
|
|
// Populate loader with some symbols.
|
|
|
|
|
addDummyObjSym(t, ldr, or, "type.uint8")
|
2020-03-16 15:04:00 -04:00
|
|
|
ldr.LookupOrCreateSym("hello", 0)
|
2019-12-11 14:36:17 -05:00
|
|
|
|
|
|
|
|
arch := sys.ArchAMD64
|
|
|
|
|
var testpoints = []struct {
|
|
|
|
|
which string
|
|
|
|
|
addDataFunc addFunc
|
|
|
|
|
expData []byte
|
|
|
|
|
expKind sym.SymKind
|
2020-07-29 13:26:50 -04:00
|
|
|
expRel []Reloc
|
2019-12-11 14:36:17 -05:00
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
which: "AddUint8",
|
2019-12-16 14:14:29 -05:00
|
|
|
addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
|
2020-02-12 17:23:47 -05:00
|
|
|
sb := l.MakeSymbolUpdater(s)
|
2019-12-11 14:36:17 -05:00
|
|
|
sb.AddUint8('a')
|
2020-02-12 17:23:47 -05:00
|
|
|
return s
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
expData: []byte{'a'},
|
|
|
|
|
expKind: sym.SDATA,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
which: "AddUintXX",
|
2019-12-16 14:14:29 -05:00
|
|
|
addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
|
2020-02-12 17:23:47 -05:00
|
|
|
sb := l.MakeSymbolUpdater(s)
|
2019-12-11 14:36:17 -05:00
|
|
|
sb.AddUintXX(arch, 25185, 2)
|
2020-02-12 17:23:47 -05:00
|
|
|
return s
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
expData: []byte{'a', 'b'},
|
|
|
|
|
expKind: sym.SDATA,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
which: "SetUint8",
|
2019-12-16 14:14:29 -05:00
|
|
|
addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
|
2020-02-12 17:23:47 -05:00
|
|
|
sb := l.MakeSymbolUpdater(s)
|
2019-12-11 14:36:17 -05:00
|
|
|
sb.AddUint8('a')
|
|
|
|
|
sb.AddUint8('b')
|
|
|
|
|
sb.SetUint8(arch, 1, 'c')
|
2020-02-12 17:23:47 -05:00
|
|
|
return s
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
expData: []byte{'a', 'c'},
|
|
|
|
|
expKind: sym.SDATA,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
which: "AddString",
|
2019-12-16 14:14:29 -05:00
|
|
|
addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
|
2020-02-12 17:23:47 -05:00
|
|
|
sb := l.MakeSymbolUpdater(s)
|
2019-12-11 14:36:17 -05:00
|
|
|
sb.Addstring("hello")
|
2020-02-12 17:23:47 -05:00
|
|
|
return s
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
expData: []byte{'h', 'e', 'l', 'l', 'o', 0},
|
|
|
|
|
expKind: sym.SNOPTRDATA,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
which: "AddAddrPlus",
|
2019-12-16 14:14:29 -05:00
|
|
|
addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
|
2020-02-12 17:23:47 -05:00
|
|
|
sb := l.MakeSymbolUpdater(s)
|
2019-12-11 14:36:17 -05:00
|
|
|
sb.AddAddrPlus(arch, s2, 3)
|
2020-02-12 17:23:47 -05:00
|
|
|
return s
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
expKind: sym.SDATA,
|
2020-07-29 13:26:50 -04:00
|
|
|
expRel: []Reloc{mkReloc(ldr, objabi.R_ADDR, 0, 8, 3, 6)},
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
which: "AddAddrPlus4",
|
2019-12-16 14:14:29 -05:00
|
|
|
addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
|
2020-02-12 17:23:47 -05:00
|
|
|
sb := l.MakeSymbolUpdater(s)
|
2019-12-11 14:36:17 -05:00
|
|
|
sb.AddAddrPlus4(arch, s2, 3)
|
2020-02-12 17:23:47 -05:00
|
|
|
return s
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
expData: []byte{0, 0, 0, 0},
|
|
|
|
|
expKind: sym.SDATA,
|
2020-07-29 13:26:50 -04:00
|
|
|
expRel: []Reloc{mkReloc(ldr, objabi.R_ADDR, 0, 4, 3, 7)},
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
which: "AddCURelativeAddrPlus",
|
2019-12-16 14:14:29 -05:00
|
|
|
addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
|
2020-02-12 17:23:47 -05:00
|
|
|
sb := l.MakeSymbolUpdater(s)
|
2019-12-11 14:36:17 -05:00
|
|
|
sb.AddCURelativeAddrPlus(arch, s2, 7)
|
2020-02-12 17:23:47 -05:00
|
|
|
return s
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
expKind: sym.SDATA,
|
2020-07-29 13:26:50 -04:00
|
|
|
expRel: []Reloc{mkReloc(ldr, objabi.R_ADDRCUOFF, 0, 8, 7, 8)},
|
2019-12-11 14:36:17 -05:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var pmi Sym
|
|
|
|
|
for k, tp := range testpoints {
|
|
|
|
|
name := fmt.Sprintf("new%d", k+1)
|
2020-03-16 15:04:00 -04:00
|
|
|
mi := ldr.LookupOrCreateSym(name, 0)
|
2019-12-11 14:36:17 -05:00
|
|
|
if mi == 0 {
|
2020-03-16 15:04:00 -04:00
|
|
|
t.Fatalf("LookupOrCreateSym failed for '" + name + "'")
|
2019-12-11 14:36:17 -05:00
|
|
|
}
|
2019-12-16 14:14:29 -05:00
|
|
|
mi = tp.addDataFunc(ldr, mi, pmi)
|
2019-12-11 14:36:17 -05:00
|
|
|
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))
|
|
|
|
|
}
|
|
|
|
|
relocs := ldr.Relocs(mi)
|
2020-03-28 16:46:47 -04:00
|
|
|
if !sameRelocSlice(&relocs, tp.expRel) {
|
2019-12-11 14:36:17 -05:00
|
|
|
t.Fatalf("testing Loader.%s: got relocslice %+v wanted %+v",
|
2020-03-28 16:46:47 -04:00
|
|
|
tp.which, relocs, tp.expRel)
|
2019-12-11 14:36:17 -05:00
|
|
|
}
|
|
|
|
|
pmi = mi
|
|
|
|
|
}
|
2019-12-11 13:39:39 -05:00
|
|
|
}
|
2019-12-11 14:17:14 -05:00
|
|
|
|
|
|
|
|
func TestOuterSub(t *testing.T) {
|
2020-04-22 15:16:06 -04:00
|
|
|
ldr := mkLoader()
|
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
|
|
|
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
2019-12-11 14:17:14 -05:00
|
|
|
or := &dummyOreader
|
|
|
|
|
|
|
|
|
|
// Populate loader with some symbols.
|
|
|
|
|
addDummyObjSym(t, ldr, or, "type.uint8")
|
2020-03-16 15:04:00 -04:00
|
|
|
es1 := ldr.LookupOrCreateSym("outer", 0)
|
2020-06-30 11:30:28 -04:00
|
|
|
ldr.MakeSymbolUpdater(es1).SetSize(101)
|
2020-03-16 15:04:00 -04:00
|
|
|
es2 := ldr.LookupOrCreateSym("sub1", 0)
|
|
|
|
|
es3 := ldr.LookupOrCreateSym("sub2", 0)
|
|
|
|
|
es4 := ldr.LookupOrCreateSym("sub3", 0)
|
|
|
|
|
es5 := ldr.LookupOrCreateSym("sub4", 0)
|
|
|
|
|
es6 := ldr.LookupOrCreateSym("sub5", 0)
|
2019-12-11 14:17:14 -05:00
|
|
|
|
|
|
|
|
// Should not have an outer sym initially
|
|
|
|
|
if ldr.OuterSym(es1) != 0 {
|
|
|
|
|
t.Errorf("es1 outer sym set ")
|
|
|
|
|
}
|
|
|
|
|
if ldr.SubSym(es2) != 0 {
|
|
|
|
|
t.Errorf("es2 outer sym set ")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Establish first outer/sub relationship
|
2020-06-30 11:30:28 -04:00
|
|
|
ldr.AddInteriorSym(es1, es2)
|
2019-12-11 14:17:14 -05:00
|
|
|
if ldr.OuterSym(es1) != 0 {
|
|
|
|
|
t.Errorf("ldr.OuterSym(es1) got %d wanted %d", ldr.OuterSym(es1), 0)
|
|
|
|
|
}
|
|
|
|
|
if ldr.OuterSym(es2) != es1 {
|
|
|
|
|
t.Errorf("ldr.OuterSym(es2) got %d wanted %d", ldr.OuterSym(es2), es1)
|
|
|
|
|
}
|
|
|
|
|
if ldr.SubSym(es1) != es2 {
|
|
|
|
|
t.Errorf("ldr.SubSym(es1) got %d wanted %d", ldr.SubSym(es1), es2)
|
|
|
|
|
}
|
|
|
|
|
if ldr.SubSym(es2) != 0 {
|
|
|
|
|
t.Errorf("ldr.SubSym(es2) got %d wanted %d", ldr.SubSym(es2), 0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Establish second outer/sub relationship
|
2020-06-30 11:30:28 -04:00
|
|
|
ldr.AddInteriorSym(es1, es3)
|
2019-12-11 14:17:14 -05:00
|
|
|
if ldr.OuterSym(es1) != 0 {
|
|
|
|
|
t.Errorf("ldr.OuterSym(es1) got %d wanted %d", ldr.OuterSym(es1), 0)
|
|
|
|
|
}
|
|
|
|
|
if ldr.OuterSym(es2) != es1 {
|
|
|
|
|
t.Errorf("ldr.OuterSym(es2) got %d wanted %d", ldr.OuterSym(es2), es1)
|
|
|
|
|
}
|
|
|
|
|
if ldr.OuterSym(es3) != es1 {
|
|
|
|
|
t.Errorf("ldr.OuterSym(es3) got %d wanted %d", ldr.OuterSym(es3), es1)
|
|
|
|
|
}
|
|
|
|
|
if ldr.SubSym(es1) != es3 {
|
|
|
|
|
t.Errorf("ldr.SubSym(es1) got %d wanted %d", ldr.SubSym(es1), es3)
|
|
|
|
|
}
|
|
|
|
|
if ldr.SubSym(es3) != es2 {
|
|
|
|
|
t.Errorf("ldr.SubSym(es3) got %d wanted %d", ldr.SubSym(es3), es2)
|
|
|
|
|
}
|
2019-12-12 11:28:07 -05:00
|
|
|
|
|
|
|
|
// Some more
|
2020-06-30 11:30:28 -04:00
|
|
|
ldr.AddInteriorSym(es1, es4)
|
|
|
|
|
ldr.AddInteriorSym(es1, es5)
|
|
|
|
|
ldr.AddInteriorSym(es1, es6)
|
2019-12-12 11:28:07 -05:00
|
|
|
|
|
|
|
|
// Set values.
|
|
|
|
|
ldr.SetSymValue(es2, 7)
|
|
|
|
|
ldr.SetSymValue(es3, 1)
|
|
|
|
|
ldr.SetSymValue(es4, 13)
|
|
|
|
|
ldr.SetSymValue(es5, 101)
|
|
|
|
|
ldr.SetSymValue(es6, 3)
|
|
|
|
|
|
|
|
|
|
// Sort
|
|
|
|
|
news := ldr.SortSub(es1)
|
|
|
|
|
if news != es3 {
|
|
|
|
|
t.Errorf("ldr.SortSub leader got %d wanted %d", news, es3)
|
|
|
|
|
}
|
|
|
|
|
pv := int64(-1)
|
|
|
|
|
count := 0
|
|
|
|
|
for ss := ldr.SubSym(es1); ss != 0; ss = ldr.SubSym(ss) {
|
|
|
|
|
v := ldr.SymValue(ss)
|
|
|
|
|
if v <= pv {
|
|
|
|
|
t.Errorf("ldr.SortSub sortfail at %d: val %d >= prev val %d",
|
|
|
|
|
ss, v, pv)
|
|
|
|
|
}
|
|
|
|
|
pv = v
|
|
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
if count != 5 {
|
|
|
|
|
t.Errorf("expected %d in sub list got %d", 5, count)
|
|
|
|
|
}
|
2019-12-11 14:17:14 -05:00
|
|
|
}
|