Source file src/cmd/link/internal/loader/loader_test.go

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package loader
     6  
     7  import (
     8  	"bytes"
     9  	"cmd/internal/goobj"
    10  	"cmd/internal/objabi"
    11  	"cmd/internal/sys"
    12  	"cmd/link/internal/sym"
    13  	"fmt"
    14  	"testing"
    15  )
    16  
    17  // dummyAddSym adds the named symbol to the loader as if it had been
    18  // read from a Go object file. Note that it allocates a global
    19  // index without creating an associated object reader, so one can't
    20  // do anything interesting with this symbol (such as look at its
    21  // data or relocations).
    22  func addDummyObjSym(t *testing.T, ldr *Loader, or *oReader, name string) Sym {
    23  	idx := uint32(len(ldr.objSyms))
    24  	st := loadState{l: ldr}
    25  	return st.addSym(name, 0, or, idx, nonPkgDef, &goobj.Sym{})
    26  }
    27  
    28  func mkLoader() *Loader {
    29  	edummy := func(str string, off int) {}
    30  	er := ErrorReporter{}
    31  	ldr := NewLoader(0, edummy, &er)
    32  	er.ldr = ldr
    33  	return ldr
    34  }
    35  
    36  func TestAddMaterializedSymbol(t *testing.T) {
    37  	ldr := mkLoader()
    38  	dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
    39  	or := &dummyOreader
    40  
    41  	// Create some syms from a dummy object file symbol to get things going.
    42  	ts1 := addDummyObjSym(t, ldr, or, "type.uint8")
    43  	ts2 := addDummyObjSym(t, ldr, or, "mumble")
    44  	ts3 := addDummyObjSym(t, ldr, or, "type.string")
    45  
    46  	// Create some external symbols.
    47  	es1 := ldr.LookupOrCreateSym("extnew1", 0)
    48  	if es1 == 0 {
    49  		t.Fatalf("LookupOrCreateSym failed for extnew1")
    50  	}
    51  	es1x := ldr.LookupOrCreateSym("extnew1", 0)
    52  	if es1x != es1 {
    53  		t.Fatalf("LookupOrCreateSym lookup: expected %d got %d for second lookup", es1, es1x)
    54  	}
    55  	es2 := ldr.LookupOrCreateSym("go.info.type.uint8", 0)
    56  	if es2 == 0 {
    57  		t.Fatalf("LookupOrCreateSym failed for go.info.type.uint8")
    58  	}
    59  	// Create a nameless symbol
    60  	es3 := ldr.CreateStaticSym("")
    61  	if es3 == 0 {
    62  		t.Fatalf("CreateStaticSym failed for nameless sym")
    63  	}
    64  
    65  	// Grab symbol builder pointers
    66  	sb1 := ldr.MakeSymbolUpdater(es1)
    67  	sb2 := ldr.MakeSymbolUpdater(es2)
    68  	sb3 := ldr.MakeSymbolUpdater(es3)
    69  
    70  	// Suppose we create some more symbols, which triggers a grow.
    71  	// Make sure the symbol builder's payload pointer is valid,
    72  	// even across a grow.
    73  	for i := 0; i < 9999; i++ {
    74  		ldr.CreateStaticSym("dummy")
    75  	}
    76  
    77  	// Check get/set symbol type
    78  	es3typ := sb3.Type()
    79  	if es3typ != sym.Sxxx {
    80  		t.Errorf("SymType(es3): expected %v, got %v", sym.Sxxx, es3typ)
    81  	}
    82  	sb3.SetType(sym.SRODATA)
    83  	es3typ = sb3.Type()
    84  	if es3typ != sym.SRODATA {
    85  		t.Errorf("SymType(es3): expected %v, got %v", sym.SRODATA, es3typ)
    86  	}
    87  	es3typ = ldr.SymType(es3)
    88  	if es3typ != sym.SRODATA {
    89  		t.Errorf("SymType(es3): expected %v, got %v", sym.SRODATA, es3typ)
    90  	}
    91  
    92  	// New symbols should not initially be reachable.
    93  	if ldr.AttrReachable(es1) || ldr.AttrReachable(es2) || ldr.AttrReachable(es3) {
    94  		t.Errorf("newly materialized symbols should not be reachable")
    95  	}
    96  
    97  	// ... however it should be possible to set/unset their reachability.
    98  	ldr.SetAttrReachable(es3, true)
    99  	if !ldr.AttrReachable(es3) {
   100  		t.Errorf("expected reachable symbol after update")
   101  	}
   102  	ldr.SetAttrReachable(es3, false)
   103  	if ldr.AttrReachable(es3) {
   104  		t.Errorf("expected unreachable symbol after update")
   105  	}
   106  
   107  	// Test expansion of attr bitmaps
   108  	for idx := 0; idx < 36; idx++ {
   109  		es := ldr.LookupOrCreateSym(fmt.Sprintf("zext%d", idx), 0)
   110  		if ldr.AttrOnList(es) {
   111  			t.Errorf("expected OnList after creation")
   112  		}
   113  		ldr.SetAttrOnList(es, true)
   114  		if !ldr.AttrOnList(es) {
   115  			t.Errorf("expected !OnList after update")
   116  		}
   117  		if ldr.AttrDuplicateOK(es) {
   118  			t.Errorf("expected DupOK after creation")
   119  		}
   120  		ldr.SetAttrDuplicateOK(es, true)
   121  		if !ldr.AttrDuplicateOK(es) {
   122  			t.Errorf("expected !DupOK after update")
   123  		}
   124  	}
   125  
   126  	sb1 = ldr.MakeSymbolUpdater(es1)
   127  	sb2 = ldr.MakeSymbolUpdater(es2)
   128  
   129  	// Get/set a few other attributes
   130  	if ldr.AttrVisibilityHidden(es3) {
   131  		t.Errorf("expected initially not hidden")
   132  	}
   133  	ldr.SetAttrVisibilityHidden(es3, true)
   134  	if !ldr.AttrVisibilityHidden(es3) {
   135  		t.Errorf("expected hidden after update")
   136  	}
   137  
   138  	// Test get/set symbol value.
   139  	toTest := []Sym{ts2, es3}
   140  	for i, s := range toTest {
   141  		if v := ldr.SymValue(s); v != 0 {
   142  			t.Errorf("ldr.Value(%d): expected 0 got %d\n", s, v)
   143  		}
   144  		nv := int64(i + 101)
   145  		ldr.SetSymValue(s, nv)
   146  		if v := ldr.SymValue(s); v != nv {
   147  			t.Errorf("ldr.SetValue(%d,%d): expected %d got %d\n", s, nv, nv, v)
   148  		}
   149  	}
   150  
   151  	// Check/set alignment
   152  	es3al := ldr.SymAlign(es3)
   153  	if es3al != 0 {
   154  		t.Errorf("SymAlign(es3): expected 0, got %d", es3al)
   155  	}
   156  	ldr.SetSymAlign(es3, 128)
   157  	es3al = ldr.SymAlign(es3)
   158  	if es3al != 128 {
   159  		t.Errorf("SymAlign(es3): expected 128, got %d", es3al)
   160  	}
   161  
   162  	// Add some relocations to the new symbols.
   163  	r1, _ := sb1.AddRel(objabi.R_ADDR)
   164  	r1.SetOff(0)
   165  	r1.SetSiz(1)
   166  	r1.SetSym(ts1)
   167  	r2, _ := sb1.AddRel(objabi.R_CALL)
   168  	r2.SetOff(3)
   169  	r2.SetSiz(8)
   170  	r2.SetSym(ts2)
   171  	r3, _ := sb2.AddRel(objabi.R_USETYPE)
   172  	r3.SetOff(7)
   173  	r3.SetSiz(1)
   174  	r3.SetSym(ts3)
   175  
   176  	// Add some data to the symbols.
   177  	d1 := []byte{1, 2, 3}
   178  	d2 := []byte{4, 5, 6, 7}
   179  	sb1.AddBytes(d1)
   180  	sb2.AddBytes(d2)
   181  
   182  	// Now invoke the usual loader interfaces to make sure
   183  	// we're getting the right things back for these symbols.
   184  	// First relocations...
   185  	expRel := [][]Reloc{{r1, r2}, {r3}}
   186  	for k, sb := range []*SymbolBuilder{sb1, sb2} {
   187  		rsl := sb.Relocs()
   188  		exp := expRel[k]
   189  		if !sameRelocSlice(&rsl, exp) {
   190  			t.Errorf("expected relocs %v, got %v", exp, rsl)
   191  		}
   192  	}
   193  
   194  	// ... then data.
   195  	dat := sb2.Data()
   196  	if bytes.Compare(dat, d2) != 0 {
   197  		t.Errorf("expected es2 data %v, got %v", d2, dat)
   198  	}
   199  
   200  	// Nameless symbol should still be nameless.
   201  	es3name := ldr.RawSymName(es3)
   202  	if "" != es3name {
   203  		t.Errorf("expected es3 name of '', got '%s'", es3name)
   204  	}
   205  
   206  	// Read value of materialized symbol.
   207  	es1val := sb1.Value()
   208  	if 0 != es1val {
   209  		t.Errorf("expected es1 value of 0, got %v", es1val)
   210  	}
   211  
   212  	// Test other misc methods
   213  	irm := ldr.IsReflectMethod(es1)
   214  	if 0 != es1val {
   215  		t.Errorf("expected IsReflectMethod(es1) value of 0, got %v", irm)
   216  	}
   217  }
   218  
   219  func sameRelocSlice(s1 *Relocs, s2 []Reloc) bool {
   220  	if s1.Count() != len(s2) {
   221  		return false
   222  	}
   223  	for i := 0; i < s1.Count(); i++ {
   224  		r1 := s1.At(i)
   225  		r2 := &s2[i]
   226  		if r1.Sym() != r2.Sym() ||
   227  			r1.Type() != r2.Type() ||
   228  			r1.Off() != r2.Off() ||
   229  			r1.Add() != r2.Add() ||
   230  			r1.Siz() != r2.Siz() {
   231  			return false
   232  		}
   233  	}
   234  	return true
   235  }
   236  
   237  type addFunc func(l *Loader, s Sym, s2 Sym) Sym
   238  
   239  func mkReloc(l *Loader, typ objabi.RelocType, off int32, siz uint8, add int64, sym Sym) Reloc {
   240  	r := Reloc{&goobj.Reloc{}, l.extReader, l}
   241  	r.SetType(typ)
   242  	r.SetOff(off)
   243  	r.SetSiz(siz)
   244  	r.SetAdd(add)
   245  	r.SetSym(sym)
   246  	return r
   247  }
   248  
   249  func TestAddDataMethods(t *testing.T) {
   250  	ldr := mkLoader()
   251  	dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
   252  	or := &dummyOreader
   253  
   254  	// Populate loader with some symbols.
   255  	addDummyObjSym(t, ldr, or, "type.uint8")
   256  	ldr.LookupOrCreateSym("hello", 0)
   257  
   258  	arch := sys.ArchAMD64
   259  	var testpoints = []struct {
   260  		which       string
   261  		addDataFunc addFunc
   262  		expData     []byte
   263  		expKind     sym.SymKind
   264  		expRel      []Reloc
   265  	}{
   266  		{
   267  			which: "AddUint8",
   268  			addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
   269  				sb := l.MakeSymbolUpdater(s)
   270  				sb.AddUint8('a')
   271  				return s
   272  			},
   273  			expData: []byte{'a'},
   274  			expKind: sym.SDATA,
   275  		},
   276  		{
   277  			which: "AddUintXX",
   278  			addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
   279  				sb := l.MakeSymbolUpdater(s)
   280  				sb.AddUintXX(arch, 25185, 2)
   281  				return s
   282  			},
   283  			expData: []byte{'a', 'b'},
   284  			expKind: sym.SDATA,
   285  		},
   286  		{
   287  			which: "SetUint8",
   288  			addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
   289  				sb := l.MakeSymbolUpdater(s)
   290  				sb.AddUint8('a')
   291  				sb.AddUint8('b')
   292  				sb.SetUint8(arch, 1, 'c')
   293  				return s
   294  			},
   295  			expData: []byte{'a', 'c'},
   296  			expKind: sym.SDATA,
   297  		},
   298  		{
   299  			which: "AddString",
   300  			addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
   301  				sb := l.MakeSymbolUpdater(s)
   302  				sb.Addstring("hello")
   303  				return s
   304  			},
   305  			expData: []byte{'h', 'e', 'l', 'l', 'o', 0},
   306  			expKind: sym.SNOPTRDATA,
   307  		},
   308  		{
   309  			which: "AddAddrPlus",
   310  			addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
   311  				sb := l.MakeSymbolUpdater(s)
   312  				sb.AddAddrPlus(arch, s2, 3)
   313  				return s
   314  			},
   315  			expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
   316  			expKind: sym.SDATA,
   317  			expRel:  []Reloc{mkReloc(ldr, objabi.R_ADDR, 0, 8, 3, 6)},
   318  		},
   319  		{
   320  			which: "AddAddrPlus4",
   321  			addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
   322  				sb := l.MakeSymbolUpdater(s)
   323  				sb.AddAddrPlus4(arch, s2, 3)
   324  				return s
   325  			},
   326  			expData: []byte{0, 0, 0, 0},
   327  			expKind: sym.SDATA,
   328  			expRel:  []Reloc{mkReloc(ldr, objabi.R_ADDR, 0, 4, 3, 7)},
   329  		},
   330  		{
   331  			which: "AddCURelativeAddrPlus",
   332  			addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
   333  				sb := l.MakeSymbolUpdater(s)
   334  				sb.AddCURelativeAddrPlus(arch, s2, 7)
   335  				return s
   336  			},
   337  			expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
   338  			expKind: sym.SDATA,
   339  			expRel:  []Reloc{mkReloc(ldr, objabi.R_ADDRCUOFF, 0, 8, 7, 8)},
   340  		},
   341  	}
   342  
   343  	var pmi Sym
   344  	for k, tp := range testpoints {
   345  		name := fmt.Sprintf("new%d", k+1)
   346  		mi := ldr.LookupOrCreateSym(name, 0)
   347  		if mi == 0 {
   348  			t.Fatalf("LookupOrCreateSym failed for '" + name + "'")
   349  		}
   350  		mi = tp.addDataFunc(ldr, mi, pmi)
   351  		if ldr.SymType(mi) != tp.expKind {
   352  			t.Errorf("testing Loader.%s: expected kind %s got %s",
   353  				tp.which, tp.expKind, ldr.SymType(mi))
   354  		}
   355  		if bytes.Compare(ldr.Data(mi), tp.expData) != 0 {
   356  			t.Errorf("testing Loader.%s: expected data %v got %v",
   357  				tp.which, tp.expData, ldr.Data(mi))
   358  		}
   359  		relocs := ldr.Relocs(mi)
   360  		if !sameRelocSlice(&relocs, tp.expRel) {
   361  			t.Fatalf("testing Loader.%s: got relocslice %+v wanted %+v",
   362  				tp.which, relocs, tp.expRel)
   363  		}
   364  		pmi = mi
   365  	}
   366  }
   367  
   368  func TestOuterSub(t *testing.T) {
   369  	ldr := mkLoader()
   370  	dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
   371  	or := &dummyOreader
   372  
   373  	// Populate loader with some symbols.
   374  	addDummyObjSym(t, ldr, or, "type.uint8")
   375  	es1 := ldr.LookupOrCreateSym("outer", 0)
   376  	ldr.MakeSymbolUpdater(es1).SetSize(101)
   377  	es2 := ldr.LookupOrCreateSym("sub1", 0)
   378  	es3 := ldr.LookupOrCreateSym("sub2", 0)
   379  	es4 := ldr.LookupOrCreateSym("sub3", 0)
   380  	es5 := ldr.LookupOrCreateSym("sub4", 0)
   381  	es6 := ldr.LookupOrCreateSym("sub5", 0)
   382  
   383  	// Should not have an outer sym initially
   384  	if ldr.OuterSym(es1) != 0 {
   385  		t.Errorf("es1 outer sym set ")
   386  	}
   387  	if ldr.SubSym(es2) != 0 {
   388  		t.Errorf("es2 outer sym set ")
   389  	}
   390  
   391  	// Establish first outer/sub relationship
   392  	ldr.AddInteriorSym(es1, es2)
   393  	if ldr.OuterSym(es1) != 0 {
   394  		t.Errorf("ldr.OuterSym(es1) got %d wanted %d", ldr.OuterSym(es1), 0)
   395  	}
   396  	if ldr.OuterSym(es2) != es1 {
   397  		t.Errorf("ldr.OuterSym(es2) got %d wanted %d", ldr.OuterSym(es2), es1)
   398  	}
   399  	if ldr.SubSym(es1) != es2 {
   400  		t.Errorf("ldr.SubSym(es1) got %d wanted %d", ldr.SubSym(es1), es2)
   401  	}
   402  	if ldr.SubSym(es2) != 0 {
   403  		t.Errorf("ldr.SubSym(es2) got %d wanted %d", ldr.SubSym(es2), 0)
   404  	}
   405  
   406  	// Establish second outer/sub relationship
   407  	ldr.AddInteriorSym(es1, es3)
   408  	if ldr.OuterSym(es1) != 0 {
   409  		t.Errorf("ldr.OuterSym(es1) got %d wanted %d", ldr.OuterSym(es1), 0)
   410  	}
   411  	if ldr.OuterSym(es2) != es1 {
   412  		t.Errorf("ldr.OuterSym(es2) got %d wanted %d", ldr.OuterSym(es2), es1)
   413  	}
   414  	if ldr.OuterSym(es3) != es1 {
   415  		t.Errorf("ldr.OuterSym(es3) got %d wanted %d", ldr.OuterSym(es3), es1)
   416  	}
   417  	if ldr.SubSym(es1) != es3 {
   418  		t.Errorf("ldr.SubSym(es1) got %d wanted %d", ldr.SubSym(es1), es3)
   419  	}
   420  	if ldr.SubSym(es3) != es2 {
   421  		t.Errorf("ldr.SubSym(es3) got %d wanted %d", ldr.SubSym(es3), es2)
   422  	}
   423  
   424  	// Some more
   425  	ldr.AddInteriorSym(es1, es4)
   426  	ldr.AddInteriorSym(es1, es5)
   427  	ldr.AddInteriorSym(es1, es6)
   428  
   429  	// Set values.
   430  	ldr.SetSymValue(es2, 7)
   431  	ldr.SetSymValue(es3, 1)
   432  	ldr.SetSymValue(es4, 13)
   433  	ldr.SetSymValue(es5, 101)
   434  	ldr.SetSymValue(es6, 3)
   435  
   436  	// Sort
   437  	news := ldr.SortSub(es1)
   438  	if news != es3 {
   439  		t.Errorf("ldr.SortSub leader got %d wanted %d", news, es3)
   440  	}
   441  	pv := int64(-1)
   442  	count := 0
   443  	for ss := ldr.SubSym(es1); ss != 0; ss = ldr.SubSym(ss) {
   444  		v := ldr.SymValue(ss)
   445  		if v <= pv {
   446  			t.Errorf("ldr.SortSub sortfail at %d: val %d >= prev val %d",
   447  				ss, v, pv)
   448  		}
   449  		pv = v
   450  		count++
   451  	}
   452  	if count != 5 {
   453  		t.Errorf("expected %d in sub list got %d", 5, count)
   454  	}
   455  }
   456  

View as plain text