This change rewrites and simplifies the relro handling.
We eliminate the separate relro SymKind values and the complex
shifting of symbol kinds. Instead, we put the possible relro data
into their own sections, and make those sections relro when appropriate.
We put type descriptors and their associated data into a
new .go.type section. As part of this we change the runtime.etypes
symbol to be the end of the new section, rather than the end of
rodata as it was before.
We put function descriptors into a new .go.func section.
Ordinary rodata relro stays in the .data.rel.ro section.
We stop making the typelink section relro, as it only contains
offsets and never has dynamic relocations.
We drop the typerel:* and go:funcdescrel symbols.
For #76038
Change-Id: I7aab7cfad3f2623ff06c09a70b756fe1e43f4169
Reviewed-on: https://go-review.googlesource.com/c/go/+/723580
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
ldr.SetAttrSpecial(types.Sym(), false)
etypes := ldr.CreateSymForUpdate("runtime.etypes", 0)
- etypes.SetType(sym.SFUNCTAB)
+ etypes.SetType(sym.STYPE)
ldr.SetAttrSpecial(etypes.Sym(), false)
if ctxt.HeadType == objabi.Haix {
// "read only" data with relocations needs to go in its own section
// when building a shared library. We do this by boosting objects of
- // type SXXX with relocations to type SXXXRELRO.
+ // type SRODATA with relocations to type SRODATARELRO.
ldr := target.loader
- for _, symnro := range sym.ReadOnly {
- symnrelro := sym.RelROMap[symnro]
-
- ro := []loader.Sym{}
- relro := state.data[symnrelro]
-
- for _, s := range state.data[symnro] {
- relocs := ldr.Relocs(s)
- isRelro := relocs.Count() > 0
- switch state.symType(s) {
- case sym.STYPE, sym.STYPERELRO, sym.SGOFUNCRELRO:
- // Symbols are not sorted yet, so it is possible
- // that an Outer symbol has been changed to a
- // relro Type before it reaches here.
- isRelro = true
- case sym.SFUNCTAB:
- if ldr.SymName(s) == "runtime.etypes" {
- // runtime.etypes must be at the end of
- // the relro data.
- isRelro = true
- }
- case sym.SGOFUNC, sym.SPCLNTAB:
- // The only SGOFUNC symbols that contain relocations are .stkobj,
- // and their relocations are of type objabi.R_ADDROFF,
- // which always get resolved during linking.
- isRelro = false
- }
- if isRelro {
- if symnrelro == sym.Sxxx {
- state.ctxt.Errorf(s, "cannot contain relocations (type %v)", symnro)
- }
- state.setSymType(s, symnrelro)
- if outer := ldr.OuterSym(s); outer != 0 {
- state.setSymType(outer, symnrelro)
- }
- relro = append(relro, s)
- } else {
- ro = append(ro, s)
+ ro := []loader.Sym{}
+ relro := state.data[sym.SRODATARELRO]
+ for _, s := range state.data[sym.SRODATA] {
+ relocs := ldr.Relocs(s)
+ if relocs.Count() == 0 {
+ ro = append(ro, s)
+ } else {
+ state.setSymType(s, sym.SRODATARELRO)
+ if outer := ldr.OuterSym(s); outer != 0 {
+ state.setSymType(outer, sym.SRODATARELRO)
}
+ relro = append(relro, s)
}
+ }
- // Check that we haven't made two symbols with the same .Outer into
- // different types (because references two symbols with non-nil Outer
- // become references to the outer symbol + offset it's vital that the
- // symbol and the outer end up in the same section).
- for _, s := range relro {
- if outer := ldr.OuterSym(s); outer != 0 {
- st := state.symType(s)
- ost := state.symType(outer)
- if st != ost {
- state.ctxt.Errorf(s, "inconsistent types for symbol and its Outer %s (%v != %v)",
- ldr.SymName(outer), st, ost)
- }
+ // Check that we haven't made two symbols with the same .Outer into
+ // different types (because references two symbols with non-nil Outer
+ // become references to the outer symbol + offset it's vital that the
+ // symbol and the outer end up in the same section).
+ for _, s := range relro {
+ if outer := ldr.OuterSym(s); outer != 0 {
+ st := state.symType(s)
+ ost := state.symType(outer)
+ if st != ost {
+ state.ctxt.Errorf(s, "inconsistent types for symbol and its Outer %s (%v != %v)",
+ ldr.SymName(outer), st, ost)
}
}
-
- state.data[symnro] = ro
- state.data[symnrelro] = relro
}
+
+ state.data[sym.SRODATA] = ro
+ state.data[sym.SRODATARELRO] = relro
}
// dodataState holds bits of state information needed by dodata() and the
sect = state.allocateNamedDataSection(segro, ".rodata", sym.ReadOnly, 04)
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.rodata", 0), sect)
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.erodata", 0), sect)
- if !ctxt.UseRelro() {
- ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.types", 0), sect)
- ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.etypes", 0), sect)
- }
for _, symn := range sym.ReadOnly {
symnStartValue := state.datsize
if len(state.data[symn]) != 0 {
xcoffUpdateOuterSize(ctxt, int64(sect.Length), sym.SPCLNTAB)
}
+ /* typelink */
+ sect = state.allocateNamedDataSection(segro, ".typelink", []sym.SymKind{sym.STYPELINK}, 04)
+
+ typelink := ldr.CreateSymForUpdate("runtime.typelink", 0)
+ ldr.SetSymSect(typelink.Sym(), sect)
+ typelink.SetType(sym.SRODATA)
+ state.datsize += typelink.Size()
+ state.checkdatsize(sym.STYPELINK)
+ sect.Length = uint64(state.datsize) - sect.Vaddr
+
/* read-only ELF, Mach-O sections */
state.allocateSingleSymSections(segro, sym.SELFROSECT, sym.SRODATA, 04)
- // There is some data that are conceptually read-only but are written to by
- // relocations. On GNU systems, we can arrange for the dynamic linker to
+ // Read-only data that may require dynamic relocations at run time.
+ //
+ // On GNU systems, we can arrange for the dynamic linker to
// mprotect sections after relocations are applied by giving them write
- // permissions in the object file and calling them ".data.rel.ro.FOO". We
- // divide the .rodata section between actual .rodata and .data.rel.ro.rodata,
- // but for the other sections that this applies to, we just write a read-only
- // .FOO section or a read-write .data.rel.ro.FOO section depending on the
- // situation.
- // TODO(mwhudson): It would make sense to do this more widely, but it makes
- // the system linker segfault on darwin.
- const relroPerm = 06
- const fallbackPerm = 04
- relroSecPerm := fallbackPerm
+ // permissions in the object file and calling them ".data.rel.ro.FOO".
+
+ relroPerm := 04
genrelrosecname := func(suffix string) string {
if suffix == "" {
return ".rodata"
}
return suffix
}
- seg := segro
+ segRelro := segro
if ctxt.UseRelro() {
- segrelro := &Segrelrodata
if ctxt.LinkMode == LinkExternal && !ctxt.IsAIX() && !ctxt.IsDarwin() {
// Using a separate segment with an external
// linker results in some programs moving
// corrupts the moduledata. So we use the
// rodata segment and let the external linker
// sort out a rel.ro segment.
- segrelro = segro
} else {
+ segRelro = &Segrelrodata
// Reset datsize for new segment.
state.datsize = 0
}
+ relroPerm = 06
+
if !ctxt.IsDarwin() { // We don't need the special names on darwin.
genrelrosecname = func(suffix string) string {
return ".data.rel.ro" + suffix
}
}
+ }
- relroReadOnly := []sym.SymKind{}
- for _, symnro := range sym.ReadOnly {
- symn := sym.RelROMap[symnro]
- relroReadOnly = append(relroReadOnly, symn)
+ // checkOuter is a sanity check that for all the symbols of some kind,
+ // which are in a given section, any carrier symbol is also in
+ // that section.
+ checkOuter := func(sect *sym.Section, symn sym.SymKind) {
+ for _, s := range state.data[symn] {
+ outer := ldr.OuterSym(s)
+ if s != 0 && ldr.SymSect(outer) != nil && ldr.SymSect(outer) != sect {
+ ctxt.Errorf(s, "s.Outer (%s) in different section from s, %s != %s", ldr.SymName(outer), ldr.SymSect(outer).Name, sect.Name)
+ }
}
- seg = segrelro
- relroSecPerm = relroPerm
-
- /* data only written by relocations */
- sect = state.allocateNamedDataSection(segrelro, genrelrosecname(""), relroReadOnly, relroSecPerm)
+ }
- ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.types", 0), sect)
- ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.etypes", 0), sect)
+ // createRelroSect will create a section that wil be a relro
+ // section if this link is using relro.
+ createRelroSect := func(name string, symn sym.SymKind) *sym.Section {
+ sect := state.allocateNamedDataSection(segRelro, genrelrosecname(name), []sym.SymKind{symn}, relroPerm)
- for i, symnro := range sym.ReadOnly {
- if i == 0 && symnro == sym.STYPE && ctxt.HeadType != objabi.Haix {
- // Skip forward so that no type
- // reference uses a zero offset.
- // This is unlikely but possible in small
- // programs with no other read-only data.
- state.datsize++
- }
+ if symn == sym.STYPE && ctxt.HeadType != objabi.Haix {
+ // Skip forward so that no type
+ // reference uses a zero offset.
+ // This is unlikely but possible in small
+ // programs with no other read-only data.
+ state.datsize++
+ }
- symn := sym.RelROMap[symnro]
- if symn == sym.Sxxx {
- continue
- }
- symnStartValue := state.datsize
- if len(state.data[symn]) != 0 {
- symnStartValue = aligndatsize(state, symnStartValue, state.data[symn][0])
- }
+ // Align to first symbol.
+ symnStartValue := state.datsize
+ if len(state.data[symn]) > 0 {
+ symnStartValue = aligndatsize(state, state.datsize, state.data[symn][0])
+ }
- for _, s := range state.data[symn] {
- outer := ldr.OuterSym(s)
- if s != 0 && ldr.SymSect(outer) != nil && ldr.SymSect(outer) != sect {
- ctxt.Errorf(s, "s.Outer (%s) in different section from s, %s != %s", ldr.SymName(outer), ldr.SymSect(outer).Name, sect.Name)
- }
- }
- state.assignToSection(sect, symn, sym.SRODATA)
- setCarrierSize(symn, state.datsize-symnStartValue)
- if ctxt.HeadType == objabi.Haix {
- // Read-only symbols might be wrapped inside their outer
- // symbol.
- // XCOFF symbol table needs to know the size of
- // these outer symbols.
- xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
- }
+ checkOuter(sect, symn)
+ state.assignToSection(sect, symn, sym.SRODATA)
+ setCarrierSize(symn, state.datsize-symnStartValue)
+ if ctxt.HeadType == objabi.Haix {
+ // XCOFF symbol table needs to know the size
+ // of outer symbols.
+ xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
}
sect.Length = uint64(state.datsize) - sect.Vaddr
+ return sect
+ }
- state.allocateSingleSymSections(segrelro, sym.SELFRELROSECT, sym.SRODATA, relroSecPerm)
- state.allocateSingleSymSections(segrelro, sym.SMACHORELROSECT, sym.SRODATA, relroSecPerm)
+ if len(state.data[sym.SRODATARELRO]) > 0 {
+ createRelroSect("", sym.SRODATARELRO)
}
- /* typelink */
- sect = state.allocateNamedDataSection(seg, genrelrosecname(".typelink"), []sym.SymKind{sym.STYPELINK}, relroSecPerm)
+ sect = createRelroSect(".go.type", sym.STYPE)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.types", 0), sect)
+ ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.etypes", 0), sect)
- typelink := ldr.CreateSymForUpdate("runtime.typelink", 0)
- ldr.SetSymSect(typelink.Sym(), sect)
- typelink.SetType(sym.SRODATA)
- state.datsize += typelink.Size()
- state.checkdatsize(sym.STYPELINK)
- sect.Length = uint64(state.datsize) - sect.Vaddr
+ sect = createRelroSect(".go.func", sym.SGOFUNC)
+
+ state.allocateSingleSymSections(segRelro, sym.SELFRELROSECT, sym.SRODATA, relroPerm)
+ state.allocateSingleSymSections(segRelro, sym.SMACHORELROSECT, sym.SRODATA, relroPerm)
/* itablink */
- sect = state.allocateNamedDataSection(seg, genrelrosecname(".itablink"), []sym.SymKind{sym.SITABLINK}, relroSecPerm)
+ sect = state.allocateNamedDataSection(segRelro, genrelrosecname(".itablink"), []sym.SymKind{sym.SITABLINK}, relroPerm)
itablink := ldr.CreateSymForUpdate("runtime.itablink", 0)
ldr.SetSymSect(itablink.Sym(), sect)
args: []string{"-ldflags", "-linkmode=internal"},
prog: prog,
mustInternalLink: true,
- wantSecsRO: []string{"__got", "__rodata", "__itablink", "__typelink"},
+ wantSecsRO: []string{"__got", "__rodata", "__itablink"},
},
{
name: "linkmode-external",
args: []string{"-ldflags", "-linkmode=external"},
prog: prog,
mustHaveCGO: true,
- wantSecsRO: []string{"__got", "__rodata", "__itablink", "__typelink"},
+ wantSecsRO: []string{"__got", "__rodata", "__itablink"},
},
{
name: "cgo-linkmode-internal",
prog: progC,
mustHaveCGO: true,
mustInternalLink: true,
- wantSecsRO: []string{"__got", "__rodata", "__itablink", "__typelink"},
+ wantSecsRO: []string{"__got", "__rodata", "__itablink"},
},
{
name: "cgo-linkmode-external",
args: []string{"-ldflags", "-linkmode=external"},
prog: progC,
mustHaveCGO: true,
- wantSecsRO: []string{"__got", "__rodata", "__itablink", "__typelink"},
+ wantSecsRO: []string{"__got", "__rodata", "__itablink"},
},
}
ctxt.xdefine("runtime.egcbss", sym.SRODATA, 0)
// pseudo-symbols to mark locations of type, string, and go string data.
- var symtype, symtyperel loader.Sym
+ var symtype loader.Sym
if !ctxt.DynlinkingGo() {
- if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
- s = ldr.CreateSymForUpdate("type:*", 0)
- s.SetType(sym.STYPE)
- s.SetSize(0)
- s.SetAlign(int32(ctxt.Arch.PtrSize))
- symtype = s.Sym()
-
- s = ldr.CreateSymForUpdate("typerel.*", 0)
- s.SetType(sym.STYPERELRO)
- s.SetSize(0)
- s.SetAlign(int32(ctxt.Arch.PtrSize))
- symtyperel = s.Sym()
- } else {
- s = ldr.CreateSymForUpdate("type:*", 0)
- s.SetType(sym.STYPE)
- s.SetSize(0)
- s.SetAlign(int32(ctxt.Arch.PtrSize))
- symtype = s.Sym()
- symtyperel = s.Sym()
- }
+ s = ldr.CreateSymForUpdate("type:*", 0)
+ s.SetType(sym.STYPE)
+ s.SetSize(0)
+ s.SetAlign(int32(ctxt.Arch.PtrSize))
+ symtype = s.Sym()
setCarrierSym(sym.STYPE, symtype)
- setCarrierSym(sym.STYPERELRO, symtyperel)
}
groupSym := func(name string, t sym.SymKind) loader.Sym {
symgcbits = groupSym("runtime.gcbits.*", sym.SGCBITS)
)
- symgofuncrel := symgofunc
- if ctxt.UseRelro() {
- symgofuncrel = groupSym("go:funcdescrel", sym.SGOFUNCRELRO)
- }
-
// assign specific types so that they sort together.
// within a type they sort by size, so the .* symbols
// just defined above will be first.
case strings.HasSuffix(name, "·f"):
if !ctxt.DynlinkingGo() {
ldr.SetAttrNotInSymbolTable(s, true)
- }
- if ctxt.UseRelro() {
- symGroupType[s] = sym.SGOFUNCRELRO
- if !ctxt.DynlinkingGo() {
- ldr.SetCarrierSym(s, symgofuncrel)
- }
- } else {
- symGroupType[s] = sym.SGOFUNC
ldr.SetCarrierSym(s, symgofunc)
}
+ symGroupType[s] = sym.SGOFUNC
case strings.HasPrefix(name, "type:"):
if !ctxt.DynlinkingGo() {
ldr.SetAttrNotInSymbolTable(s, true)
}
- if ctxt.UseRelro() {
- symGroupType[s] = sym.STYPERELRO
- if symtyperel != 0 {
- ldr.SetCarrierSym(s, symtyperel)
- }
- } else {
- symGroupType[s] = sym.STYPE
- if symtyperel != 0 {
- ldr.SetCarrierSym(s, symtype)
- }
+ symGroupType[s] = sym.STYPE
+ if symtype != 0 {
+ ldr.SetCarrierSym(s, symtype)
}
}
}
switch stype {
default:
Errorf("unknown XCOFF outer symbol for type %s", stype.String())
- case sym.SRODATA, sym.SRODATARELRO, sym.SFUNCTAB, sym.SSTRING:
+ case sym.SRODATA, sym.SFUNCTAB, sym.SSTRING:
// Nothing to do
- case sym.STYPERELRO:
+ case sym.STYPE:
if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
- // runtime.types size must be removed, as it's a real symbol.
- tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
- outerSymSize["typerel.*"] = size - tsize
return
}
- fallthrough
- case sym.STYPE:
if !ctxt.DynlinkingGo() {
// runtime.types size must be removed, as it's a real symbol.
tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
if !ctxt.DynlinkingGo() {
outerSymSize["go:funcdesc"] = size
}
- case sym.SGOFUNCRELRO:
- outerSymSize["go:funcdescrel"] = size
case sym.SGCBITS:
outerSymSize["runtime.gcbits.*"] = size
case sym.SPCLNTAB:
SELFRXSECT // Executable PLT; PPC64 .glink.
SMACHOPLT // Mach-O PLT.
- // Read-only, non-executable, segment.
- STYPE // Type descriptors.
+ // Read-only, non-executable, unrelocated segment.
SSTRING // Used only for XCOFF runtime.rodata symbol?
SGOSTRING // Go string constants.
- SGOFUNC // Function descriptors and funcdata symbols.
SGCBITS // GC bit masks and programs.
SRODATA // General read-only data.
SRODATAFIPSSTART // Start of FIPS read-only data.
SRODATAEND // End of read-only data.
SFUNCTAB // Appears to be unused, except for runtime.etypes.
SPCLNTAB // Pclntab data.
+ STYPELINK // Type links.
SELFROSECT // ELF read-only data: relocs, dynamic linking info.
// Read-only, non-executable, dynamically relocatable segment.
//
- // Types STYPE-SFUNCTAB above are written to the .rodata section by default.
- // When linking a shared object, some conceptually "read only" types need to
- // be written to by relocations and putting them in a section called
- // ".rodata" interacts poorly with the system linkers. The GNU linkers
- // support this situation by arranging for sections of the name
- // ".data.rel.ro.XXX" to be mprotected read only by the dynamic linker after
- // relocations have applied, so when the Go linker is creating a shared
- // object it checks all objects of the above types and bumps any object that
- // has a relocation to it to the corresponding type below, which are then
- // written to sections with appropriate magic names.
- STYPERELRO
- SSTRINGRELRO
- SGOSTRINGRELRO
- SGOFUNCRELRO
- SGCBITSRELRO
+ // This segment holds read-only data that contains pointers to
+ // other parts of the program. When generating a position
+ // independent executable or a shared library, these sections
+ // are "relro", meaning that they start as writable, and are
+ // changed to be read-only after dynamic relocations are applied.
+ //
+ // When no dynamic relocations are required, as when generating
+ // an executable that is not position independent, this is just
+ // part of the normal read-only segment.
SRODATARELRO
- SFUNCTABRELRO
-
+ STYPE
+ SGOFUNC
SELFRELROSECT // ELF-specific read-only relocatable: PLT, etc.
SMACHORELROSECT // Mach-O specific read-only relocatable.
- STYPELINK // Type links.
SITABLINK // Itab links.
// Allocated writable segment.
objabi.SSEHUNWINDINFO: SSEHUNWINDINFO,
}
-// ReadOnly are the symbol kinds that form read-only sections. In some
-// cases, if they will require relocations, they are transformed into
-// rel-ro sections using relROMap.
+// ReadOnly are the symbol kinds that form read-only sections
+// that never require runtime relocations.
var ReadOnly = []SymKind{
- STYPE,
SSTRING,
SGOSTRING,
- SGOFUNC,
SGCBITS,
SRODATA,
SRODATAFIPSSTART,
SFUNCTAB,
}
-// RelROMap describes the transformation of read-only symbols to rel-ro
-// symbols.
-var RelROMap = map[SymKind]SymKind{
- STYPE: STYPERELRO,
- SSTRING: SSTRINGRELRO,
- SGOSTRING: SGOSTRINGRELRO,
- SGOFUNC: SGOFUNCRELRO,
- SGCBITS: SGCBITSRELRO,
- SRODATA: SRODATARELRO,
- SFUNCTAB: SFUNCTABRELRO,
-}
-
// IsText returns true if t is a text type.
func (t SymKind) IsText() bool {
return STEXT <= t && t <= STEXTEND
_ = x[STEXTEND-5]
_ = x[SELFRXSECT-6]
_ = x[SMACHOPLT-7]
- _ = x[STYPE-8]
- _ = x[SSTRING-9]
- _ = x[SGOSTRING-10]
- _ = x[SGOFUNC-11]
- _ = x[SGCBITS-12]
- _ = x[SRODATA-13]
- _ = x[SRODATAFIPSSTART-14]
- _ = x[SRODATAFIPS-15]
- _ = x[SRODATAFIPSEND-16]
- _ = x[SRODATAEND-17]
- _ = x[SFUNCTAB-18]
- _ = x[SPCLNTAB-19]
- _ = x[SELFROSECT-20]
- _ = x[STYPERELRO-21]
- _ = x[SSTRINGRELRO-22]
- _ = x[SGOSTRINGRELRO-23]
- _ = x[SGOFUNCRELRO-24]
- _ = x[SGCBITSRELRO-25]
- _ = x[SRODATARELRO-26]
- _ = x[SFUNCTABRELRO-27]
- _ = x[SELFRELROSECT-28]
- _ = x[SMACHORELROSECT-29]
- _ = x[STYPELINK-30]
- _ = x[SITABLINK-31]
- _ = x[SFirstWritable-32]
- _ = x[SBUILDINFO-33]
- _ = x[SFIPSINFO-34]
- _ = x[SELFSECT-35]
- _ = x[SMACHO-36]
- _ = x[SWINDOWS-37]
- _ = x[SMODULEDATA-38]
- _ = x[SELFGOT-39]
- _ = x[SMACHOGOT-40]
- _ = x[SNOPTRDATA-41]
- _ = x[SNOPTRDATAFIPSSTART-42]
- _ = x[SNOPTRDATAFIPS-43]
- _ = x[SNOPTRDATAFIPSEND-44]
- _ = x[SNOPTRDATAEND-45]
- _ = x[SINITARR-46]
- _ = x[SDATA-47]
- _ = x[SDATAFIPSSTART-48]
- _ = x[SDATAFIPS-49]
- _ = x[SDATAFIPSEND-50]
- _ = x[SDATAEND-51]
- _ = x[SXCOFFTOC-52]
- _ = x[SBSS-53]
- _ = x[SNOPTRBSS-54]
- _ = x[SLIBFUZZER_8BIT_COUNTER-55]
- _ = x[SCOVERAGE_COUNTER-56]
- _ = x[SCOVERAGE_AUXVAR-57]
- _ = x[STLSBSS-58]
- _ = x[SFirstUnallocated-59]
- _ = x[SXREF-60]
- _ = x[SMACHOSYMSTR-61]
- _ = x[SMACHOSYMTAB-62]
- _ = x[SMACHOINDIRECTPLT-63]
- _ = x[SMACHOINDIRECTGOT-64]
- _ = x[SDYNIMPORT-65]
- _ = x[SHOSTOBJ-66]
- _ = x[SUNDEFEXT-67]
- _ = x[SDWARFSECT-68]
- _ = x[SDWARFCUINFO-69]
- _ = x[SDWARFCONST-70]
- _ = x[SDWARFFCN-71]
- _ = x[SDWARFABSFCN-72]
- _ = x[SDWARFTYPE-73]
- _ = x[SDWARFVAR-74]
- _ = x[SDWARFRANGE-75]
- _ = x[SDWARFLOC-76]
- _ = x[SDWARFLINES-77]
- _ = x[SDWARFADDR-78]
- _ = x[SSEHUNWINDINFO-79]
- _ = x[SSEHSECT-80]
+ _ = x[SSTRING-8]
+ _ = x[SGOSTRING-9]
+ _ = x[SGCBITS-10]
+ _ = x[SRODATA-11]
+ _ = x[SRODATAFIPSSTART-12]
+ _ = x[SRODATAFIPS-13]
+ _ = x[SRODATAFIPSEND-14]
+ _ = x[SRODATAEND-15]
+ _ = x[SFUNCTAB-16]
+ _ = x[SPCLNTAB-17]
+ _ = x[STYPELINK-18]
+ _ = x[SELFROSECT-19]
+ _ = x[SRODATARELRO-20]
+ _ = x[STYPE-21]
+ _ = x[SGOFUNC-22]
+ _ = x[SELFRELROSECT-23]
+ _ = x[SMACHORELROSECT-24]
+ _ = x[SITABLINK-25]
+ _ = x[SFirstWritable-26]
+ _ = x[SBUILDINFO-27]
+ _ = x[SFIPSINFO-28]
+ _ = x[SELFSECT-29]
+ _ = x[SMACHO-30]
+ _ = x[SWINDOWS-31]
+ _ = x[SMODULEDATA-32]
+ _ = x[SELFGOT-33]
+ _ = x[SMACHOGOT-34]
+ _ = x[SNOPTRDATA-35]
+ _ = x[SNOPTRDATAFIPSSTART-36]
+ _ = x[SNOPTRDATAFIPS-37]
+ _ = x[SNOPTRDATAFIPSEND-38]
+ _ = x[SNOPTRDATAEND-39]
+ _ = x[SINITARR-40]
+ _ = x[SDATA-41]
+ _ = x[SDATAFIPSSTART-42]
+ _ = x[SDATAFIPS-43]
+ _ = x[SDATAFIPSEND-44]
+ _ = x[SDATAEND-45]
+ _ = x[SXCOFFTOC-46]
+ _ = x[SBSS-47]
+ _ = x[SNOPTRBSS-48]
+ _ = x[SLIBFUZZER_8BIT_COUNTER-49]
+ _ = x[SCOVERAGE_COUNTER-50]
+ _ = x[SCOVERAGE_AUXVAR-51]
+ _ = x[STLSBSS-52]
+ _ = x[SFirstUnallocated-53]
+ _ = x[SXREF-54]
+ _ = x[SMACHOSYMSTR-55]
+ _ = x[SMACHOSYMTAB-56]
+ _ = x[SMACHOINDIRECTPLT-57]
+ _ = x[SMACHOINDIRECTGOT-58]
+ _ = x[SDYNIMPORT-59]
+ _ = x[SHOSTOBJ-60]
+ _ = x[SUNDEFEXT-61]
+ _ = x[SDWARFSECT-62]
+ _ = x[SDWARFCUINFO-63]
+ _ = x[SDWARFCONST-64]
+ _ = x[SDWARFFCN-65]
+ _ = x[SDWARFABSFCN-66]
+ _ = x[SDWARFTYPE-67]
+ _ = x[SDWARFVAR-68]
+ _ = x[SDWARFRANGE-69]
+ _ = x[SDWARFLOC-70]
+ _ = x[SDWARFLINES-71]
+ _ = x[SDWARFADDR-72]
+ _ = x[SSEHUNWINDINFO-73]
+ _ = x[SSEHSECT-74]
}
-const _SymKind_name = "SxxxSTEXTSTEXTFIPSSTARTSTEXTFIPSSTEXTFIPSENDSTEXTENDSELFRXSECTSMACHOPLTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASRODATAFIPSSTARTSRODATAFIPSSRODATAFIPSENDSRODATAENDSFUNCTABSPCLNTABSELFROSECTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSELFRELROSECTSMACHORELROSECTSTYPELINKSITABLINKSFirstWritableSBUILDINFOSFIPSINFOSELFSECTSMACHOSWINDOWSSMODULEDATASELFGOTSMACHOGOTSNOPTRDATASNOPTRDATAFIPSSTARTSNOPTRDATAFIPSSNOPTRDATAFIPSENDSNOPTRDATAENDSINITARRSDATASDATAFIPSSTARTSDATAFIPSSDATAFIPSENDSDATAENDSXCOFFTOCSBSSSNOPTRBSSSLIBFUZZER_8BIT_COUNTERSCOVERAGE_COUNTERSCOVERAGE_AUXVARSTLSBSSSFirstUnallocatedSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSDYNIMPORTSHOSTOBJSUNDEFEXTSDWARFSECTSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSDWARFADDRSSEHUNWINDINFOSSEHSECT"
+const _SymKind_name = "SxxxSTEXTSTEXTFIPSSTARTSTEXTFIPSSTEXTFIPSENDSTEXTENDSELFRXSECTSMACHOPLTSSTRINGSGOSTRINGSGCBITSSRODATASRODATAFIPSSTARTSRODATAFIPSSRODATAFIPSENDSRODATAENDSFUNCTABSPCLNTABSTYPELINKSELFROSECTSRODATARELROSTYPESGOFUNCSELFRELROSECTSMACHORELROSECTSITABLINKSFirstWritableSBUILDINFOSFIPSINFOSELFSECTSMACHOSWINDOWSSMODULEDATASELFGOTSMACHOGOTSNOPTRDATASNOPTRDATAFIPSSTARTSNOPTRDATAFIPSSNOPTRDATAFIPSENDSNOPTRDATAENDSINITARRSDATASDATAFIPSSTARTSDATAFIPSSDATAFIPSENDSDATAENDSXCOFFTOCSBSSSNOPTRBSSSLIBFUZZER_8BIT_COUNTERSCOVERAGE_COUNTERSCOVERAGE_AUXVARSTLSBSSSFirstUnallocatedSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSDYNIMPORTSHOSTOBJSUNDEFEXTSDWARFSECTSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSDWARFADDRSSEHUNWINDINFOSSEHSECT"
-var _SymKind_index = [...]uint16{0, 4, 9, 23, 32, 44, 52, 62, 71, 76, 83, 92, 99, 106, 113, 129, 140, 154, 164, 172, 180, 190, 200, 212, 226, 238, 250, 262, 275, 288, 303, 312, 321, 335, 345, 354, 362, 368, 376, 387, 394, 403, 413, 432, 446, 463, 476, 484, 489, 503, 512, 524, 532, 541, 545, 554, 577, 594, 610, 617, 634, 639, 651, 663, 680, 697, 707, 715, 724, 734, 746, 757, 766, 778, 788, 797, 808, 817, 828, 838, 852, 860}
+var _SymKind_index = [...]uint16{0, 4, 9, 23, 32, 44, 52, 62, 71, 78, 87, 94, 101, 117, 128, 142, 152, 160, 168, 177, 187, 199, 204, 211, 224, 239, 248, 262, 272, 281, 289, 295, 303, 314, 321, 330, 340, 359, 373, 390, 403, 411, 416, 430, 439, 451, 459, 468, 472, 481, 504, 521, 537, 544, 561, 566, 578, 590, 607, 624, 634, 642, 651, 661, 673, 684, 693, 705, 715, 724, 735, 744, 755, 765, 779, 787}
func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) {
ldr.SymSect(ldr.Lookup("runtime.rodata", 0)),
ldr.SymSect(ldr.Lookup("runtime.typelink", 0)),
ldr.SymSect(ldr.Lookup("runtime.itablink", 0)),
+ ldr.SymSect(ldr.Lookup("runtime.types", 0)),
+ ldr.SymSect(ldr.Lookup("go:funcdesc", 0)),
ldr.SymSect(ldr.Lookup("runtime.firstmoduledata", 0)),
ldr.SymSect(ldr.Lookup("runtime.pclntab", 0)),
ldr.SymSect(ldr.Lookup("runtime.noptrdata", 0)),
// so there is nothing to test here.
}
}
+
+const typeSrc = `
+package main
+
+import (
+ "fmt"
+ "unsafe"
+)
+
+type MyInt int
+
+var vals = []any{
+ 0,
+ 0.1,
+ "",
+ MyInt(0),
+ struct{ f int }{0},
+ func() {},
+}
+
+var global int
+
+func main() {
+ fmt.Printf("global %#x\n", &global)
+ for _, v := range vals {
+ // Unsafe assumption: the first word of a value
+ // of type any is the type descriptor.
+ td := *(*uintptr)(unsafe.Pointer(&v))
+ fmt.Printf("%#x\n", td)
+ }
+}
+`
+
+// Test that type data is stored in the types section.
+func TestTypePlacement(t *testing.T) {
+ testenv.MustHaveGoRun(t)
+ t.Parallel()
+
+ tmpdir := t.TempDir()
+ src := filepath.Join(tmpdir, "x.go")
+ if err := os.WriteFile(src, []byte(typeSrc), 0o444); err != nil {
+ t.Fatal(err)
+ }
+
+ exe := filepath.Join(tmpdir, "x.exe")
+ cmd := goCmd(t, "build", "-o", exe, src)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("build failed; %v, output:\n%s", err, out)
+ }
+
+ cmd = testenv.Command(t, exe)
+ var stdout, stderr strings.Builder
+ cmd.Stdout = &stdout
+ cmd.Stderr = &stderr
+ if err := cmd.Run(); err != nil {
+ t.Fatalf("running test program failed: %v, stdout:\n%s\nstderr:\n%s", err, &stdout, &stderr)
+ }
+ stderrString := stderr.String()
+ if stderrString != "" {
+ t.Fatalf("running test program printed to stderr:\n%s", stderrString)
+ }
+
+ t.Logf("\n%s", &stdout)
+
+ var globalExeAddr uint64
+ var addrs []uint64
+ globalNext := false
+ for s := range strings.FieldsSeq(stdout.String()) {
+ if globalNext {
+ v, err := strconv.ParseUint(s, 0, 64)
+ if err != nil {
+ t.Errorf("failed to parse test program output %s: %v", s, err)
+ }
+ globalExeAddr = v
+ globalNext = false
+ } else if s == "global" {
+ globalNext = true
+ } else {
+ addr, err := strconv.ParseUint(s, 0, 64)
+ if err != nil {
+ t.Errorf("failed to parse test program output %q: %v", s, err)
+ }
+ addrs = append(addrs, addr)
+ }
+ }
+
+ ef, _ := elf.Open(exe)
+ mf, _ := macho.Open(exe)
+ pf, _ := pe.Open(exe)
+ xf, _ := xcoff.Open(exe)
+ // TODO: plan9
+ if ef == nil && mf == nil && pf == nil && xf == nil {
+ t.Skip("unrecognized executable file format")
+ }
+
+ const globalName = "main.global"
+ var typeStart, typeEnd uint64
+ var globalObjAddr uint64
+ switch {
+ case ef != nil:
+ defer ef.Close()
+
+ for _, sec := range ef.Sections {
+ if sec.Name == ".go.type" {
+ typeStart = sec.Addr
+ typeEnd = sec.Addr + sec.Size
+ break
+ }
+ }
+
+ syms, err := ef.Symbols()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if typeStart == 0 && typeEnd == 0 {
+ // We can fail to find the section for PIE.
+ // Fall back to symbols.
+ for _, sym := range syms {
+ switch sym.Name {
+ case "runtime.types":
+ typeStart = sym.Value
+ case "runtime.etypes":
+ typeEnd = sym.Value
+ }
+ }
+ }
+
+ for _, sym := range syms {
+ if sym.Name == globalName {
+ globalObjAddr = sym.Value
+ break
+ }
+ }
+
+ case mf != nil:
+ defer mf.Close()
+
+ for _, sec := range mf.Sections {
+ if sec.Name == "__go_type" {
+ typeStart = sec.Addr
+ typeEnd = sec.Addr + sec.Size
+ break
+ }
+ }
+
+ for _, sym := range mf.Symtab.Syms {
+ if sym.Name == globalName {
+ globalObjAddr = sym.Value
+ break
+ }
+ }
+
+ case pf != nil:
+ defer pf.Close()
+
+ var imageBase uint64
+ switch ohdr := pf.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ imageBase = uint64(ohdr.ImageBase)
+ case *pe.OptionalHeader64:
+ imageBase = ohdr.ImageBase
+ }
+
+ var typeSym, eTypeSym *pe.Symbol
+ for _, sym := range pf.Symbols {
+ switch sym.Name {
+ case "runtime.types":
+ typeSym = sym
+ case "runtime.etypes":
+ eTypeSym = sym
+ case globalName:
+ globalSec := pf.Sections[sym.SectionNumber-1]
+ globalObjAddr = imageBase + uint64(globalSec.VirtualAddress+sym.Value)
+ }
+ }
+
+ if typeSym == nil {
+ t.Fatal("could not find symbol runtime.types")
+ }
+ if eTypeSym == nil {
+ t.Fatal("could not find symbol runtime.etypes")
+ }
+ if typeSym.SectionNumber != eTypeSym.SectionNumber {
+ t.Fatalf("runtime.types section %d != runtime.etypes section %d", typeSym.SectionNumber, eTypeSym.SectionNumber)
+ }
+
+ sec := pf.Sections[typeSym.SectionNumber-1]
+
+ typeStart = imageBase + uint64(sec.VirtualAddress+typeSym.Value)
+ typeEnd = imageBase + uint64(sec.VirtualAddress+eTypeSym.Value)
+
+ case xf != nil:
+ defer xf.Close()
+
+ for _, sec := range xf.Sections {
+ if sec.Name == ".go.type" {
+ typeStart = sec.VirtualAddress
+ typeEnd = sec.VirtualAddress + sec.Size
+ break
+ }
+ }
+
+ for _, sym := range xf.Symbols {
+ if sym.Name == globalName {
+ globalObjAddr = sym.Value
+ break
+ }
+ }
+ }
+
+ if typeStart == 0 || typeEnd == 0 {
+ t.Fatalf("failed to find type descriptor addresses; found %#x to %#x", typeStart, typeEnd)
+ }
+ t.Logf("type start: %#x type end: %#x", typeStart, typeEnd)
+
+ offset := globalExeAddr - globalObjAddr
+ t.Logf("execution offset: %#x", offset)
+
+ for _, addr := range addrs {
+ addr -= offset
+ if addr < typeStart || addr >= typeEnd {
+ t.Errorf("type descriptor address %#x out of range: not between %#x and %#x", addr, typeStart, typeEnd)
+ }
+ }
+}