return
}
+ // Set up the function's LSym early to avoid data races with the assemblers.
+ // Do this before walk, as walk needs the LSym to set attributes/relocations
+ // (e.g. in markTypeUsedInInterface).
+ fn.Func.initLSym(true)
+
walk(fn)
if nerrors != 0 {
return
return
}
- // Set up the function's LSym early to avoid data races with the assemblers.
- fn.Func.initLSym(true)
-
// Make sure type syms are declared for all types that might
// be types of stack objects. We need to do this here
// because symbols must be allocated before the parallel
return Isconst(val, CTNIL)
}
- markTypeUsedInInterface(val.Type)
+ markTypeUsedInInterface(val.Type, l.Sym.Linksym())
var itab *Node
if l.Type.IsEmptyInterface() {
fromType := n.Left.Type
toType := n.Type
- if !fromType.IsInterface() {
- markTypeUsedInInterface(fromType)
+ if !fromType.IsInterface() && !Curfn.Func.Nname.isBlank() { // skip unnamed functions (func _())
+ markTypeUsedInInterface(fromType, Curfn.Func.lsym)
}
// typeword generates the type word of the interface value.
// markTypeUsedInInterface marks that type t is converted to an interface.
// This information is used in the linker in dead method elimination.
-func markTypeUsedInInterface(t *types.Type) {
- typenamesym(t).Linksym().Set(obj.AttrUsedInIface, true)
+func markTypeUsedInInterface(t *types.Type, from *obj.LSym) {
+ tsym := typenamesym(t).Linksym()
+ // Emit a marker relocation. The linker will know the type is converted
+ // to an interface if "from" is reachable.
+ r := obj.Addrel(from)
+ r.Sym = tsym
+ r.Type = objabi.R_USEIFACE
}
// rtconvfn returns the parameter and result types that will be used by a
// Also need to check for reflect package itself (see Issue #38515).
if s := res0.Type.Sym; s != nil && s.Name == "Method" && isReflectPkg(s.Pkg) {
Curfn.Func.SetReflectMethod(true)
+ // The LSym is initialized at this point. We need to set the attribute on the LSym.
+ Curfn.Func.lsym.Set(obj.AttrReflectMethod, true)
}
}
buffer := make([]byte, 0)
changed := true
loop := 0
+ nrelocs0 := len(c.cursym.R)
for changed {
if loop > 100 {
c.ctxt.Diag("stuck in spanz loop")
}
changed = false
buffer = buffer[:0]
- c.cursym.R = make([]obj.Reloc, 0)
+ for i := range c.cursym.R[nrelocs0:] {
+ c.cursym.R[nrelocs0+i] = obj.Reloc{}
+ }
+ c.cursym.R = c.cursym.R[:nrelocs0] // preserve marker relocations generated by the compiler
for p := c.cursym.Func.Text; p != nil; p = p.Link {
pc := int64(len(buffer))
if pc != p.Pc {
panic("bad name for Call")
}
r := obj.Addrel(s)
+ r.Siz = 1 // actually variable sized
r.Off = int32(w.Len())
r.Type = objabi.R_CALL
if p.Mark&WasmImport != 0 {
case AI32Const, AI64Const:
if p.From.Name == obj.NAME_EXTERN {
r := obj.Addrel(s)
+ r.Siz = 1 // actually variable sized
r.Off = int32(w.Len())
r.Type = objabi.R_ADDR
r.Sym = p.From.Sym
var c int32
errors := ctxt.Errors
var nops []nopPad // Padding for a particular assembly (reuse slice storage if multiple assemblies)
+ nrelocs0 := len(s.R)
for {
// This loop continues while there are reasons to re-assemble
// whole block, like the presence of long forward jumps.
reAssemble := false
- for i := range s.R {
- s.R[i] = obj.Reloc{}
+ for i := range s.R[nrelocs0:] {
+ s.R[nrelocs0+i] = obj.Reloc{}
}
- s.R = s.R[:0]
+ s.R = s.R[:nrelocs0] // preserve marker relocations generated by the compiler
s.P = s.P[:0]
c = 0
var pPrev *obj.Prog
// should be linked into the final binary, even if there are no other
// direct references. (This is used for types reachable by reflection.)
R_USETYPE
+ // R_USEIFACE marks a type is converted to an interface in the function this
+ // relocation is applied to. The target is a type descriptor.
+ // This is a marker relocation (0-sized), for the linker's reachabililty
+ // analysis.
+ R_USEIFACE
// R_METHODOFF resolves to a 32-bit offset from the beginning of the section
// holding the data being relocated to the referenced symbol.
// It is a variant of R_ADDROFF used when linking from the uncommonType of a
import "strconv"
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[R_ADDR-1]
+ _ = x[R_ADDRPOWER-2]
+ _ = x[R_ADDRARM64-3]
+ _ = x[R_ADDRMIPS-4]
+ _ = x[R_ADDROFF-5]
+ _ = x[R_WEAKADDROFF-6]
+ _ = x[R_SIZE-7]
+ _ = x[R_CALL-8]
+ _ = x[R_CALLARM-9]
+ _ = x[R_CALLARM64-10]
+ _ = x[R_CALLIND-11]
+ _ = x[R_CALLPOWER-12]
+ _ = x[R_CALLMIPS-13]
+ _ = x[R_CALLRISCV-14]
+ _ = x[R_CONST-15]
+ _ = x[R_PCREL-16]
+ _ = x[R_TLS_LE-17]
+ _ = x[R_TLS_IE-18]
+ _ = x[R_GOTOFF-19]
+ _ = x[R_PLT0-20]
+ _ = x[R_PLT1-21]
+ _ = x[R_PLT2-22]
+ _ = x[R_USEFIELD-23]
+ _ = x[R_USETYPE-24]
+ _ = x[R_USEIFACE-25]
+ _ = x[R_METHODOFF-26]
+ _ = x[R_POWER_TOC-27]
+ _ = x[R_GOTPCREL-28]
+ _ = x[R_JMPMIPS-29]
+ _ = x[R_DWARFSECREF-30]
+ _ = x[R_DWARFFILEREF-31]
+ _ = x[R_ARM64_TLS_LE-32]
+ _ = x[R_ARM64_TLS_IE-33]
+ _ = x[R_ARM64_GOTPCREL-34]
+ _ = x[R_ARM64_GOT-35]
+ _ = x[R_ARM64_PCREL-36]
+ _ = x[R_ARM64_LDST8-37]
+ _ = x[R_ARM64_LDST32-38]
+ _ = x[R_ARM64_LDST64-39]
+ _ = x[R_ARM64_LDST128-40]
+ _ = x[R_POWER_TLS_LE-41]
+ _ = x[R_POWER_TLS_IE-42]
+ _ = x[R_POWER_TLS-43]
+ _ = x[R_ADDRPOWER_DS-44]
+ _ = x[R_ADDRPOWER_GOT-45]
+ _ = x[R_ADDRPOWER_PCREL-46]
+ _ = x[R_ADDRPOWER_TOCREL-47]
+ _ = x[R_ADDRPOWER_TOCREL_DS-48]
+ _ = x[R_RISCV_PCREL_ITYPE-49]
+ _ = x[R_RISCV_PCREL_STYPE-50]
+ _ = x[R_PCRELDBL-51]
+ _ = x[R_ADDRMIPSU-52]
+ _ = x[R_ADDRMIPSTLS-53]
+ _ = x[R_ADDRCUOFF-54]
+ _ = x[R_WASMIMPORT-55]
+ _ = x[R_XCOFFREF-56]
+}
+
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 219, 230, 240, 249, 262, 276, 290, 304, 320, 331, 344, 357, 371, 385, 400, 414, 428, 439, 453, 468, 485, 503, 524, 543, 562, 572, 583, 596, 607, 619, 629}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 229, 240, 250, 259, 272, 286, 300, 314, 330, 341, 354, 367, 381, 395, 410, 424, 438, 449, 463, 478, 495, 513, 534, 553, 572, 582, 593, 606, 617, 629, 639}
func (i RelocType) String() string {
i -= 1
relocs := ctxt.loader.Relocs(s)
for ri := 0; ri < relocs.Count(); ri++ {
r := relocs.At(ri)
+ if r.IsMarker() {
+ continue // skip marker relocations
+ }
targ := r.Sym()
if targ == 0 {
continue
relocs := ldr.Relocs(s)
for ri := 0; ri < relocs.Count(); ri++ {
r := relocs.At(ri)
+ if r.IsMarker() {
+ continue // skip marker relocations
+ }
if ctxt.BuildMode == BuildModePIE && ctxt.LinkMode == LinkInternal {
// It's expected that some relocations will be done
// later by relocsym (R_TLS_LE, R_ADDROFF), so
// do nothing for now as we still load all type symbols.
continue
}
+ if t == objabi.R_USEIFACE {
+ // R_USEIFACE is a marker relocation that tells the linker the type is
+ // converted to an interface, i.e. should have UsedInIface set. See the
+ // comment below for why we need to unset the Reachable bit and re-mark it.
+ rs := r.Sym()
+ if !d.ldr.AttrUsedInIface(rs) {
+ d.ldr.SetAttrUsedInIface(rs, true)
+ if d.ldr.AttrReachable(rs) {
+ d.ldr.SetAttrReachable(rs, false)
+ d.mark(rs, symIdx)
+ }
+ }
+ continue
+ }
rs := r.Sym()
if isgotype && usedInIface && d.ldr.IsGoType(rs) && !d.ldr.AttrUsedInIface(rs) {
// If a type is converted to an interface, it is possible to obtain an
var e interface{}
func main() {
- p = new(T) // used T, but never converted to interface
+ p = new(T) // used T, but never converted to interface in any reachable code
e.(I).M() // used I and I.M
}
+
+func Unused() { // convert T to interface, but this function is not reachable
+ var i I = T(0)
+ i.M()
+}
+
+var Unused2 interface{} = T(1) // convert T to interface, in an unreachable global initializer
func (rel Reloc) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) + rel.typ }
func (rel Reloc) Sym() Sym { return rel.l.resolve(rel.r, rel.Reloc.Sym()) }
func (rel Reloc) SetSym(s Sym) { rel.Reloc.SetSym(goobj.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) }
+func (rel Reloc) IsMarker() bool { return rel.Siz() == 0 }
func (rel Reloc) SetType(t objabi.RelocType) {
if t != objabi.RelocType(uint8(t)) {
off := int32(0)
for ri := 0; ri < relocs.Count(); ri++ {
r := relocs.At(ri)
+ if r.Siz() == 0 {
+ continue // skip marker relocations
+ }
wfn.Write(P[off:r.Off()])
off = r.Off()
rs := ldr.ResolveABIAlias(r.Sym())