mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/link,runtime: remove relocations from stkobjs
Use an offset from go.func.* instead. This removes the last relocation from funcdata symbols, which lets us simplify that code. size before after Δ % addr2line 3683218 3680706 -2512 -0.068% api 4951074 4944850 -6224 -0.126% asm 4744258 4757586 +13328 +0.281% buildid 2419986 2418546 -1440 -0.060% cgo 4218306 4197346 -20960 -0.497% compile 22132066 22076882 -55184 -0.249% cover 4432834 4411362 -21472 -0.484% dist 3111202 3091346 -19856 -0.638% doc 3583602 3563234 -20368 -0.568% fix 3023922 3020658 -3264 -0.108% link 6188034 6164642 -23392 -0.378% nm 3665826 3646818 -19008 -0.519% objdump 4015234 4012450 -2784 -0.069% pack 2155010 2153554 -1456 -0.068% pprof 13044178 13011522 -32656 -0.250% test2json 2402146 2383906 -18240 -0.759% trace 9765410 9736514 -28896 -0.296% vet 6681250 6655058 -26192 -0.392% total 104217556 103926980 -290576 -0.279% relocs before after Δ % addr2line 25563 25066 -497 -1.944% api 18409 17176 -1233 -6.698% asm 18903 18271 -632 -3.343% buildid 9513 9233 -280 -2.943% cgo 17103 16222 -881 -5.151% compile 64825 60421 -4404 -6.794% cover 19464 18479 -985 -5.061% dist 10798 10135 -663 -6.140% doc 13503 12735 -768 -5.688% fix 11465 10820 -645 -5.626% link 23214 21849 -1365 -5.880% nm 25480 24987 -493 -1.935% objdump 26610 26057 -553 -2.078% pack 7951 7665 -286 -3.597% pprof 63964 60761 -3203 -5.008% test2json 8735 8389 -346 -3.961% trace 39639 37180 -2459 -6.203% vet 25970 24044 -1926 -7.416% total 431108 409489 -21619 -5.015% Change-Id: I43c26196a008da6d1cb3a782eea2f428778bd569 Reviewed-on: https://go-review.googlesource.com/c/go/+/353138 Trust: Josh Bleecher Snyder <josharian@gmail.com> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
ae83301ab2
commit
3100dc1a7f
8 changed files with 69 additions and 60 deletions
|
|
@ -1443,7 +1443,7 @@ func (lv *liveness) emitStackObjects() *obj.LSym {
|
||||||
}
|
}
|
||||||
off = objw.Uint32(x, off, uint32(sz))
|
off = objw.Uint32(x, off, uint32(sz))
|
||||||
off = objw.Uint32(x, off, uint32(ptrdata))
|
off = objw.Uint32(x, off, uint32(ptrdata))
|
||||||
off = objw.SymPtr(x, off, lsym, 0)
|
off = objw.SymPtrOff(x, off, lsym)
|
||||||
}
|
}
|
||||||
|
|
||||||
if base.Flag.Live != 0 {
|
if base.Flag.Live != 0 {
|
||||||
|
|
|
||||||
|
|
@ -1367,6 +1367,11 @@ func (state *dodataState) makeRelroForSharedLib(target *Link) {
|
||||||
// the relro data.
|
// the relro data.
|
||||||
isRelro = true
|
isRelro = true
|
||||||
}
|
}
|
||||||
|
case sym.SGOFUNC:
|
||||||
|
// 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 isRelro {
|
||||||
state.setSymType(s, symnrelro)
|
state.setSymType(s, symnrelro)
|
||||||
|
|
|
||||||
|
|
@ -711,7 +711,7 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym
|
||||||
ldr := ctxt.loader
|
ldr := ctxt.loader
|
||||||
deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
|
deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
|
||||||
gofunc := ldr.Lookup("go.func.*", 0)
|
gofunc := ldr.Lookup("go.func.*", 0)
|
||||||
gofuncrel := ldr.Lookup("go.funcrel.*", 0)
|
gofuncBase := ldr.SymValue(gofunc)
|
||||||
textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
|
textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
|
||||||
funcdata := []loader.Sym{}
|
funcdata := []loader.Sym{}
|
||||||
var pcsp, pcfile, pcline, pcinline loader.Sym
|
var pcsp, pcfile, pcline, pcinline loader.Sym
|
||||||
|
|
@ -813,24 +813,10 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
outer := ldr.OuterSym(fdsym)
|
if outer := ldr.OuterSym(fdsym); outer != gofunc {
|
||||||
if outer == 0 {
|
panic(fmt.Sprintf("bad carrier sym for symbol %s (funcdata %s#%d), want go.func.* got %s", ldr.SymName(fdsym), ldr.SymName(s), j, ldr.SymName(outer)))
|
||||||
panic(fmt.Sprintf("no carrier sym for symbol %s (funcdata %s#%d)", ldr.SymName(fdsym), ldr.SymName(s), j))
|
|
||||||
}
|
}
|
||||||
rel := uint32(ldr.SymValue(fdsym) - ldr.SymValue(outer))
|
sb.SetUint32(ctxt.Arch, int64(dataoff), uint32(ldr.SymValue(fdsym)-gofuncBase))
|
||||||
// Record gofunc vs gofuncrel in bottom bit. See runtime/symtab.go:funcdata.
|
|
||||||
// TODO: The only symbols that in gofuncrel are .stkobj symbols.
|
|
||||||
// Remove those relocations, and simplify this.
|
|
||||||
rel <<= 1
|
|
||||||
switch outer {
|
|
||||||
case gofunc:
|
|
||||||
case gofuncrel:
|
|
||||||
rel |= 1
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("expected symbol %s (funcdata %s#%d) to be placed in go.func.* or go.funcrel.*, got %s (%d)",
|
|
||||||
ldr.SymName(fdsym), ldr.SymName(s), j, ldr.SymName(outer), outer))
|
|
||||||
}
|
|
||||||
sb.SetUint32(ctxt.Arch, int64(dataoff), rel)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -569,13 +569,8 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
|
||||||
strings.HasSuffix(name, ".args_stackmap"),
|
strings.HasSuffix(name, ".args_stackmap"),
|
||||||
strings.HasSuffix(name, ".stkobj"):
|
strings.HasSuffix(name, ".stkobj"):
|
||||||
ldr.SetAttrNotInSymbolTable(s, true)
|
ldr.SetAttrNotInSymbolTable(s, true)
|
||||||
if ctxt.UseRelro() && strings.HasSuffix(name, ".stkobj") {
|
symGroupType[s] = sym.SGOFUNC
|
||||||
symGroupType[s] = sym.SGOFUNCRELRO
|
ldr.SetCarrierSym(s, symgofunc)
|
||||||
ldr.SetCarrierSym(s, symgofuncrel)
|
|
||||||
} else {
|
|
||||||
symGroupType[s] = sym.SGOFUNC
|
|
||||||
ldr.SetCarrierSym(s, symgofunc)
|
|
||||||
}
|
|
||||||
if ctxt.Debugvlog != 0 {
|
if ctxt.Debugvlog != 0 {
|
||||||
align := ldr.SymAlign(s)
|
align := ldr.SymAlign(s)
|
||||||
liveness += (ldr.SymSize(s) + int64(align) - 1) &^ (int64(align) - 1)
|
liveness += (ldr.SymSize(s) + int64(align) - 1) &^ (int64(align) - 1)
|
||||||
|
|
@ -676,12 +671,8 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
|
||||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcbss", 0))
|
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcbss", 0))
|
||||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.types", 0))
|
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.types", 0))
|
||||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etypes", 0))
|
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etypes", 0))
|
||||||
|
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.rodata", 0))
|
||||||
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("go.func.*", 0))
|
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("go.func.*", 0))
|
||||||
if gofuncrel := ldr.Lookup("go.funcrel.*", 0); gofuncrel != 0 {
|
|
||||||
moduledata.AddAddr(ctxt.Arch, gofuncrel)
|
|
||||||
} else {
|
|
||||||
moduledata.AddUint(ctxt.Arch, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctxt.IsAIX() && ctxt.IsExternal() {
|
if ctxt.IsAIX() && ctxt.IsExternal() {
|
||||||
// Add R_XCOFFREF relocation to prevent ld's garbage collection of
|
// Add R_XCOFFREF relocation to prevent ld's garbage collection of
|
||||||
|
|
|
||||||
|
|
@ -803,7 +803,7 @@ func scanstack(gp *g, gcw *gcWork) {
|
||||||
println()
|
println()
|
||||||
printunlock()
|
printunlock()
|
||||||
}
|
}
|
||||||
gcdata := r.gcdata
|
gcdata := r.gcdata()
|
||||||
var s *mspan
|
var s *mspan
|
||||||
if r.useGCProg() {
|
if r.useGCProg() {
|
||||||
// This path is pretty unlikely, an object large enough
|
// This path is pretty unlikely, an object large enough
|
||||||
|
|
@ -923,7 +923,8 @@ func scanframeworker(frame *stkframe, state *stackScanState, gcw *gcWork) {
|
||||||
// varp is 0 for defers, where there are no locals.
|
// varp is 0 for defers, where there are no locals.
|
||||||
// In that case, there can't be a pointer to its args, either.
|
// In that case, there can't be a pointer to its args, either.
|
||||||
// (And all args would be scanned above anyway.)
|
// (And all args would be scanned above anyway.)
|
||||||
for i, obj := range objs {
|
for i := range objs {
|
||||||
|
obj := &objs[i]
|
||||||
off := obj.off
|
off := obj.off
|
||||||
base := frame.varp // locals base pointer
|
base := frame.varp // locals base pointer
|
||||||
if off >= 0 {
|
if off >= 0 {
|
||||||
|
|
@ -937,7 +938,7 @@ func scanframeworker(frame *stkframe, state *stackScanState, gcw *gcWork) {
|
||||||
if stackTraceDebug {
|
if stackTraceDebug {
|
||||||
println("stkobj at", hex(ptr), "of size", obj.size)
|
println("stkobj at", hex(ptr), "of size", obj.size)
|
||||||
}
|
}
|
||||||
state.addObject(ptr, &objs[i])
|
state.addObject(ptr, obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -687,6 +687,7 @@ func schedinit() {
|
||||||
modulesinit() // provides activeModules
|
modulesinit() // provides activeModules
|
||||||
typelinksinit() // uses maps, activeModules
|
typelinksinit() // uses maps, activeModules
|
||||||
itabsinit() // uses activeModules
|
itabsinit() // uses activeModules
|
||||||
|
stkobjinit() // must run before GC starts
|
||||||
|
|
||||||
sigsave(&_g_.m.sigmask)
|
sigsave(&_g_.m.sigmask)
|
||||||
initSigmask = _g_.m.sigmask
|
initSigmask = _g_.m.sigmask
|
||||||
|
|
|
||||||
|
|
@ -691,7 +691,8 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
|
||||||
// Adjust pointers in all stack objects (whether they are live or not).
|
// Adjust pointers in all stack objects (whether they are live or not).
|
||||||
// See comments in mgcmark.go:scanframeworker.
|
// See comments in mgcmark.go:scanframeworker.
|
||||||
if frame.varp != 0 {
|
if frame.varp != 0 {
|
||||||
for _, obj := range objs {
|
for i := range objs {
|
||||||
|
obj := &objs[i]
|
||||||
off := obj.off
|
off := obj.off
|
||||||
base := frame.varp // locals base pointer
|
base := frame.varp // locals base pointer
|
||||||
if off >= 0 {
|
if off >= 0 {
|
||||||
|
|
@ -705,7 +706,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ptrdata := obj.ptrdata()
|
ptrdata := obj.ptrdata()
|
||||||
gcdata := obj.gcdata
|
gcdata := obj.gcdata()
|
||||||
var s *mspan
|
var s *mspan
|
||||||
if obj.useGCProg() {
|
if obj.useGCProg() {
|
||||||
// See comments in mgcmark.go:scanstack
|
// See comments in mgcmark.go:scanstack
|
||||||
|
|
@ -1321,7 +1322,7 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args
|
||||||
// We don't actually use argmap in this case, but we need to fake the stack object
|
// We don't actually use argmap in this case, but we need to fake the stack object
|
||||||
// record for these frames which contain an internal/abi.RegArgs at a hard-coded offset.
|
// record for these frames which contain an internal/abi.RegArgs at a hard-coded offset.
|
||||||
// This offset matches the assembly code on amd64 and arm64.
|
// This offset matches the assembly code on amd64 and arm64.
|
||||||
objs = methodValueCallFrameObjs
|
objs = methodValueCallFrameObjs[:]
|
||||||
} else {
|
} else {
|
||||||
p := funcdata(f, _FUNCDATA_StackObjects)
|
p := funcdata(f, _FUNCDATA_StackObjects)
|
||||||
if p != nil {
|
if p != nil {
|
||||||
|
|
@ -1340,23 +1341,33 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var methodValueCallFrameObjs [1]stackObjectRecord // initialized in stackobjectinit
|
||||||
abiRegArgsEface interface{} = abi.RegArgs{}
|
|
||||||
abiRegArgsType *_type = efaceOf(&abiRegArgsEface)._type
|
|
||||||
methodValueCallFrameObjs = []stackObjectRecord{
|
|
||||||
{
|
|
||||||
off: -int32(alignUp(abiRegArgsType.size, 8)), // It's always the highest address local.
|
|
||||||
size: int32(abiRegArgsType.size),
|
|
||||||
_ptrdata: int32(abiRegArgsType.ptrdata),
|
|
||||||
gcdata: abiRegArgsType.gcdata,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func stkobjinit() {
|
||||||
|
var abiRegArgsEface interface{} = abi.RegArgs{}
|
||||||
|
abiRegArgsType := efaceOf(&abiRegArgsEface)._type
|
||||||
if abiRegArgsType.kind&kindGCProg != 0 {
|
if abiRegArgsType.kind&kindGCProg != 0 {
|
||||||
throw("abiRegArgsType needs GC Prog, update methodValueCallFrameObjs")
|
throw("abiRegArgsType needs GC Prog, update methodValueCallFrameObjs")
|
||||||
}
|
}
|
||||||
|
// Set methodValueCallFrameObjs[0].gcdataoff so that
|
||||||
|
// stackObjectRecord.gcdata() will work correctly with it.
|
||||||
|
ptr := uintptr(unsafe.Pointer(&methodValueCallFrameObjs[0]))
|
||||||
|
var mod *moduledata
|
||||||
|
for datap := &firstmoduledata; datap != nil; datap = datap.next {
|
||||||
|
if datap.gofunc <= ptr && ptr < datap.end {
|
||||||
|
mod = datap
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mod == nil {
|
||||||
|
throw("methodValueCallFrameObjs is not in a module")
|
||||||
|
}
|
||||||
|
methodValueCallFrameObjs[0] = stackObjectRecord{
|
||||||
|
off: -int32(alignUp(abiRegArgsType.size, 8)), // It's always the highest address local.
|
||||||
|
size: int32(abiRegArgsType.size),
|
||||||
|
_ptrdata: int32(abiRegArgsType.ptrdata),
|
||||||
|
gcdataoff: uint32(uintptr(unsafe.Pointer(abiRegArgsType.gcdata)) - mod.rodata),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A stackObjectRecord is generated by the compiler for each stack object in a stack frame.
|
// A stackObjectRecord is generated by the compiler for each stack object in a stack frame.
|
||||||
|
|
@ -1365,10 +1376,10 @@ type stackObjectRecord struct {
|
||||||
// offset in frame
|
// offset in frame
|
||||||
// if negative, offset from varp
|
// if negative, offset from varp
|
||||||
// if non-negative, offset from argp
|
// if non-negative, offset from argp
|
||||||
off int32
|
off int32
|
||||||
size int32
|
size int32
|
||||||
_ptrdata int32 // ptrdata, or -ptrdata is GC prog is used
|
_ptrdata int32 // ptrdata, or -ptrdata is GC prog is used
|
||||||
gcdata *byte // pointer map or GC prog of the type
|
gcdataoff uint32 // offset to gcdata from moduledata.rodata
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *stackObjectRecord) useGCProg() bool {
|
func (r *stackObjectRecord) useGCProg() bool {
|
||||||
|
|
@ -1383,6 +1394,23 @@ func (r *stackObjectRecord) ptrdata() uintptr {
|
||||||
return uintptr(x)
|
return uintptr(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gcdata returns pointer map or GC prog of the type.
|
||||||
|
func (r *stackObjectRecord) gcdata() *byte {
|
||||||
|
ptr := uintptr(unsafe.Pointer(r))
|
||||||
|
var mod *moduledata
|
||||||
|
for datap := &firstmoduledata; datap != nil; datap = datap.next {
|
||||||
|
if datap.gofunc <= ptr && ptr < datap.end {
|
||||||
|
mod = datap
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If you get a panic here due to a nil mod,
|
||||||
|
// you may have made a copy of a stackObjectRecord.
|
||||||
|
// You must use the original pointer.
|
||||||
|
res := mod.rodata + uintptr(r.gcdataoff)
|
||||||
|
return (*byte)(unsafe.Pointer(res))
|
||||||
|
}
|
||||||
|
|
||||||
// This is exported as ABI0 via linkname so obj can call it.
|
// This is exported as ABI0 via linkname so obj can call it.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
|
|
|
||||||
|
|
@ -427,7 +427,8 @@ type moduledata struct {
|
||||||
noptrbss, enoptrbss uintptr
|
noptrbss, enoptrbss uintptr
|
||||||
end, gcdata, gcbss uintptr
|
end, gcdata, gcbss uintptr
|
||||||
types, etypes uintptr
|
types, etypes uintptr
|
||||||
gofunc, gofuncrel uintptr // go.func.*, go.funcrel.*
|
rodata uintptr
|
||||||
|
gofunc uintptr // go.func.*
|
||||||
|
|
||||||
textsectmap []textsect
|
textsectmap []textsect
|
||||||
typelinks []int32 // offsets from types
|
typelinks []int32 // offsets from types
|
||||||
|
|
@ -1092,11 +1093,7 @@ func funcdata(f funcInfo, i uint8) unsafe.Pointer {
|
||||||
if off == ^uint32(0) {
|
if off == ^uint32(0) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
base := f.datap.gofunc
|
return unsafe.Pointer(f.datap.gofunc + uintptr(off))
|
||||||
if off&1 != 0 {
|
|
||||||
base = f.datap.gofuncrel
|
|
||||||
}
|
|
||||||
return unsafe.Pointer(base + uintptr(off>>1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// step advances to the next pc, value pair in the encoded table.
|
// step advances to the next pc, value pair in the encoded table.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue