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 (
|
|
|
|
|
"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 {
|
|
|
|
|
idx := ldr.max + 1
|
|
|
|
|
ldr.max++
|
|
|
|
|
if ok := ldr.AddSym(name, 0, idx, or, false, sym.SRODATA); !ok {
|
|
|
|
|
t.Errorf("AddrSym failed for '" + name + "'")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return idx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestAddMaterializedSymbol(t *testing.T) {
|
|
|
|
|
ldr := NewLoader(0)
|
|
|
|
|
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")
|
2019-12-13 11:51:15 -05:00
|
|
|
ts2 := addDummyObjSym(t, ldr, or, "mumble")
|
2019-12-11 13:39:39 -05:00
|
|
|
addDummyObjSym(t, ldr, or, "type.string")
|
|
|
|
|
|
|
|
|
|
// Create some external symbols.
|
|
|
|
|
es1 := ldr.AddExtSym("extnew1", 0)
|
|
|
|
|
if es1 == 0 {
|
|
|
|
|
t.Fatalf("AddExtSym failed for extnew1")
|
|
|
|
|
}
|
|
|
|
|
es1x := ldr.AddExtSym("extnew1", 0)
|
|
|
|
|
if es1x != 0 {
|
|
|
|
|
t.Fatalf("AddExtSym lookup: expected 0 got %d for second lookup", es1x)
|
|
|
|
|
}
|
|
|
|
|
es2 := ldr.AddExtSym("go.info.type.uint8", 0)
|
|
|
|
|
if es2 == 0 {
|
|
|
|
|
t.Fatalf("AddExtSym failed for go.info.type.uint8")
|
|
|
|
|
}
|
|
|
|
|
// Create a nameless symbol
|
|
|
|
|
es3 := ldr.CreateExtSym("")
|
|
|
|
|
if es3 == 0 {
|
|
|
|
|
t.Fatalf("CreateExtSym failed for nameless sym")
|
|
|
|
|
}
|
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++ {
|
|
|
|
|
es := ldr.AddExtSym(fmt.Sprintf("zext%d", idx), 0)
|
|
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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 13:39:39 -05:00
|
|
|
}
|
2019-12-11 14:17:14 -05:00
|
|
|
|
|
|
|
|
func TestOuterSub(t *testing.T) {
|
|
|
|
|
ldr := NewLoader(0)
|
|
|
|
|
dummyOreader := oReader{version: -1}
|
|
|
|
|
or := &dummyOreader
|
|
|
|
|
|
|
|
|
|
// Populate loader with some symbols.
|
|
|
|
|
addDummyObjSym(t, ldr, or, "type.uint8")
|
|
|
|
|
es1 := ldr.AddExtSym("outer", 0)
|
|
|
|
|
es2 := ldr.AddExtSym("sub1", 0)
|
|
|
|
|
es3 := ldr.AddExtSym("sub2", 0)
|
2019-12-12 11:28:07 -05:00
|
|
|
es4 := ldr.AddExtSym("sub3", 0)
|
|
|
|
|
es5 := ldr.AddExtSym("sub4", 0)
|
|
|
|
|
es6 := ldr.AddExtSym("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
|
|
|
|
|
ldr.PrependSub(es1, es2)
|
|
|
|
|
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
|
|
|
|
|
ldr.PrependSub(es1, es3)
|
|
|
|
|
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
|
|
|
|
|
ldr.PrependSub(es1, es4)
|
|
|
|
|
ldr.PrependSub(es1, es5)
|
|
|
|
|
ldr.PrependSub(es1, es6)
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|