mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
As it can't appear in user package paths. There is a hack for handling "go:buildid" and "type:*" on windows/386. Previously, windows/386 requires underscore prefix on external symbols, but that's only applied for SHOSTOBJ/SUNDEFEXT or cgo export symbols. "go.buildid" is STEXT, "type.*" is STYPE, thus they are not prefixed with underscore. In external linking mode, the external linker can't resolve them as external symbols. But we are lucky that they have "." in their name, so the external linker see them as Forwarder RVA exports. See: - https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-address-table - https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=ld/pe-dll.c;h=e7b82ba6ffadf74dc1b9ee71dc13d48336941e51;hb=HEAD#l972) This CL changes "." to ":" in symbols name, so theses symbols can not be found by external linker anymore. So a hacky way is adding the underscore prefix for these 2 symbols. I don't have enough knowledge to verify whether adding the underscore for all STEXT/STYPE symbols are fine, even if it could be, that would be done in future CL. Fixes #37762 Change-Id: I92eaaf24c0820926a36e0530fdb07b07af1fcc35 Reviewed-on: https://go-review.googlesource.com/c/go/+/317917 Reviewed-by: Than McIntosh <thanm@google.com> Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
455 lines
12 KiB
Go
455 lines
12 KiB
Go
// 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 (
|
|
"bytes"
|
|
"cmd/internal/goobj"
|
|
"cmd/internal/objabi"
|
|
"cmd/internal/sys"
|
|
"cmd/link/internal/sym"
|
|
"fmt"
|
|
"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 := uint32(len(ldr.objSyms))
|
|
st := loadState{l: ldr}
|
|
return st.addSym(name, 0, or, idx, nonPkgDef, &goobj.Sym{})
|
|
}
|
|
|
|
func mkLoader() *Loader {
|
|
edummy := func(str string, off int) {}
|
|
er := ErrorReporter{}
|
|
ldr := NewLoader(0, edummy, &er)
|
|
er.ldr = ldr
|
|
return ldr
|
|
}
|
|
|
|
func TestAddMaterializedSymbol(t *testing.T) {
|
|
ldr := mkLoader()
|
|
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
|
or := &dummyOreader
|
|
|
|
// Create some syms from a dummy object file symbol to get things going.
|
|
ts1 := addDummyObjSym(t, ldr, or, "type:uint8")
|
|
ts2 := addDummyObjSym(t, ldr, or, "mumble")
|
|
ts3 := addDummyObjSym(t, ldr, or, "type:string")
|
|
|
|
// Create some external symbols.
|
|
es1 := ldr.LookupOrCreateSym("extnew1", 0)
|
|
if es1 == 0 {
|
|
t.Fatalf("LookupOrCreateSym failed for extnew1")
|
|
}
|
|
es1x := ldr.LookupOrCreateSym("extnew1", 0)
|
|
if es1x != es1 {
|
|
t.Fatalf("LookupOrCreateSym lookup: expected %d got %d for second lookup", es1, es1x)
|
|
}
|
|
es2 := ldr.LookupOrCreateSym("go:info.type.uint8", 0)
|
|
if es2 == 0 {
|
|
t.Fatalf("LookupOrCreateSym failed for go.info.type.uint8")
|
|
}
|
|
// Create a nameless symbol
|
|
es3 := ldr.CreateStaticSym("")
|
|
if es3 == 0 {
|
|
t.Fatalf("CreateStaticSym failed for nameless sym")
|
|
}
|
|
|
|
// Grab symbol builder pointers
|
|
sb1 := ldr.MakeSymbolUpdater(es1)
|
|
sb2 := ldr.MakeSymbolUpdater(es2)
|
|
sb3 := ldr.MakeSymbolUpdater(es3)
|
|
|
|
// Suppose we create some more symbols, which triggers a grow.
|
|
// Make sure the symbol builder's payload pointer is valid,
|
|
// even across a grow.
|
|
for i := 0; i < 9999; i++ {
|
|
ldr.CreateStaticSym("dummy")
|
|
}
|
|
|
|
// Check get/set symbol type
|
|
es3typ := sb3.Type()
|
|
if es3typ != sym.Sxxx {
|
|
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)
|
|
}
|
|
es3typ = ldr.SymType(es3)
|
|
if es3typ != sym.SRODATA {
|
|
t.Errorf("SymType(es3): expected %v, got %v", 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")
|
|
}
|
|
|
|
// ... 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.LookupOrCreateSym(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")
|
|
}
|
|
}
|
|
|
|
sb1 = ldr.MakeSymbolUpdater(es1)
|
|
sb2 = ldr.MakeSymbolUpdater(es2)
|
|
|
|
// 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")
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
// Add some relocations to the new symbols.
|
|
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)
|
|
|
|
// 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{{r1, r2}, {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)
|
|
}
|
|
}
|
|
|
|
// ... 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.SymName(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)
|
|
}
|
|
}
|
|
|
|
func sameRelocSlice(s1 *Relocs, s2 []Reloc) bool {
|
|
if s1.Count() != len(s2) {
|
|
return false
|
|
}
|
|
for i := 0; i < s1.Count(); i++ {
|
|
r1 := s1.At(i)
|
|
r2 := &s2[i]
|
|
if r1.Sym() != r2.Sym() ||
|
|
r1.Type() != r2.Type() ||
|
|
r1.Off() != r2.Off() ||
|
|
r1.Add() != r2.Add() ||
|
|
r1.Siz() != r2.Siz() {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
type addFunc func(l *Loader, s Sym, s2 Sym) Sym
|
|
|
|
func mkReloc(l *Loader, typ objabi.RelocType, off int32, siz uint8, add int64, sym Sym) Reloc {
|
|
r := Reloc{&goobj.Reloc{}, l.extReader, l}
|
|
r.SetType(typ)
|
|
r.SetOff(off)
|
|
r.SetSiz(siz)
|
|
r.SetAdd(add)
|
|
r.SetSym(sym)
|
|
return r
|
|
}
|
|
|
|
func TestAddDataMethods(t *testing.T) {
|
|
ldr := mkLoader()
|
|
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
|
or := &dummyOreader
|
|
|
|
// Populate loader with some symbols.
|
|
addDummyObjSym(t, ldr, or, "type:uint8")
|
|
ldr.LookupOrCreateSym("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) Sym {
|
|
sb := l.MakeSymbolUpdater(s)
|
|
sb.AddUint8('a')
|
|
return s
|
|
},
|
|
expData: []byte{'a'},
|
|
expKind: sym.SDATA,
|
|
},
|
|
{
|
|
which: "AddUintXX",
|
|
addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
|
|
sb := l.MakeSymbolUpdater(s)
|
|
sb.AddUintXX(arch, 25185, 2)
|
|
return s
|
|
},
|
|
expData: []byte{'a', 'b'},
|
|
expKind: sym.SDATA,
|
|
},
|
|
{
|
|
which: "SetUint8",
|
|
addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
|
|
sb := l.MakeSymbolUpdater(s)
|
|
sb.AddUint8('a')
|
|
sb.AddUint8('b')
|
|
sb.SetUint8(arch, 1, 'c')
|
|
return s
|
|
},
|
|
expData: []byte{'a', 'c'},
|
|
expKind: sym.SDATA,
|
|
},
|
|
{
|
|
which: "AddString",
|
|
addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
|
|
sb := l.MakeSymbolUpdater(s)
|
|
sb.Addstring("hello")
|
|
return s
|
|
},
|
|
expData: []byte{'h', 'e', 'l', 'l', 'o', 0},
|
|
expKind: sym.SNOPTRDATA,
|
|
},
|
|
{
|
|
which: "AddAddrPlus",
|
|
addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
|
|
sb := l.MakeSymbolUpdater(s)
|
|
sb.AddAddrPlus(arch, s2, 3)
|
|
return s
|
|
},
|
|
expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
|
|
expKind: sym.SDATA,
|
|
expRel: []Reloc{mkReloc(ldr, objabi.R_ADDR, 0, 8, 3, 6)},
|
|
},
|
|
{
|
|
which: "AddAddrPlus4",
|
|
addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
|
|
sb := l.MakeSymbolUpdater(s)
|
|
sb.AddAddrPlus4(arch, s2, 3)
|
|
return s
|
|
},
|
|
expData: []byte{0, 0, 0, 0},
|
|
expKind: sym.SDATA,
|
|
expRel: []Reloc{mkReloc(ldr, objabi.R_ADDR, 0, 4, 3, 7)},
|
|
},
|
|
{
|
|
which: "AddCURelativeAddrPlus",
|
|
addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
|
|
sb := l.MakeSymbolUpdater(s)
|
|
sb.AddCURelativeAddrPlus(arch, s2, 7)
|
|
return s
|
|
},
|
|
expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
|
|
expKind: sym.SDATA,
|
|
expRel: []Reloc{mkReloc(ldr, objabi.R_ADDRCUOFF, 0, 8, 7, 8)},
|
|
},
|
|
}
|
|
|
|
var pmi Sym
|
|
for k, tp := range testpoints {
|
|
name := fmt.Sprintf("new%d", k+1)
|
|
mi := ldr.LookupOrCreateSym(name, 0)
|
|
if mi == 0 {
|
|
t.Fatalf("LookupOrCreateSym failed for '" + name + "'")
|
|
}
|
|
mi = 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))
|
|
}
|
|
relocs := ldr.Relocs(mi)
|
|
if !sameRelocSlice(&relocs, tp.expRel) {
|
|
t.Fatalf("testing Loader.%s: got relocslice %+v wanted %+v",
|
|
tp.which, relocs, tp.expRel)
|
|
}
|
|
pmi = mi
|
|
}
|
|
}
|
|
|
|
func TestOuterSub(t *testing.T) {
|
|
ldr := mkLoader()
|
|
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
|
or := &dummyOreader
|
|
|
|
// Populate loader with some symbols.
|
|
addDummyObjSym(t, ldr, or, "type:uint8")
|
|
es1 := ldr.LookupOrCreateSym("outer", 0)
|
|
ldr.MakeSymbolUpdater(es1).SetSize(101)
|
|
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)
|
|
|
|
// 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.AddInteriorSym(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.AddInteriorSym(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)
|
|
}
|
|
|
|
// Some more
|
|
ldr.AddInteriorSym(es1, es4)
|
|
ldr.AddInteriorSym(es1, es5)
|
|
ldr.AddInteriorSym(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)
|
|
}
|
|
}
|