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

View as plain text