diff options
| author | Josh Bleecher Snyder <josharian@gmail.com> | 2021-09-24 10:57:37 -0700 |
|---|---|---|
| committer | Josh Bleecher Snyder <josharian@gmail.com> | 2021-10-05 23:25:06 +0000 |
| commit | e31c9ab557e9f5ee20a61914f1a2bf94191997dc (patch) | |
| tree | a1e031064b7a58ad8954e5b21be208971d04db33 /src/runtime | |
| parent | 96fface83ad69b6d6ad8059d61d232737572e85d (diff) | |
| download | go-e31c9ab557e9f5ee20a61914f1a2bf94191997dc.tar.xz | |
cmd/link,runtime: remove functab relocations
Use an offset from runtime.text instead.
This removes the last relocation from functab generation,
which lets us simplify that code.
size before after Δ %
addr2line 3680818 3652498 -28320 -0.769%
api 4944850 4892418 -52432 -1.060%
asm 4757586 4711266 -46320 -0.974%
buildid 2418546 2392578 -25968 -1.074%
cgo 4197346 4164818 -32528 -0.775%
compile 22076882 21875890 -200992 -0.910%
cover 4411362 4358418 -52944 -1.200%
dist 3091346 3062738 -28608 -0.925%
doc 3563234 3532610 -30624 -0.859%
fix 3020658 2991666 -28992 -0.960%
link 6164642 6110834 -53808 -0.873%
nm 3646818 3618482 -28336 -0.777%
objdump 4012594 3983042 -29552 -0.736%
pack 2153554 2128338 -25216 -1.171%
pprof 13011666 12870114 -141552 -1.088%
test2json 2383906 2357554 -26352 -1.105%
trace 9736514 9631186 -105328 -1.082%
vet 6655058 6580370 -74688 -1.122%
total 103927380 102914820 -1012560 -0.974%
relocs before after Δ %
addr2line 25069 22709 -2360 -9.414%
api 17176 13321 -3855 -22.444%
asm 18271 15630 -2641 -14.455%
buildid 9233 7352 -1881 -20.373%
cgo 16222 13044 -3178 -19.591%
compile 60421 46299 -14122 -23.373%
cover 18479 14526 -3953 -21.392%
dist 10135 7733 -2402 -23.700%
doc 12735 9940 -2795 -21.947%
fix 10820 8341 -2479 -22.911%
link 21849 17785 -4064 -18.600%
nm 24988 22642 -2346 -9.389%
objdump 26060 23462 -2598 -9.969%
pack 7665 5936 -1729 -22.557%
pprof 60764 50998 -9766 -16.072%
test2json 8389 6431 -1958 -23.340%
trace 37180 29382 -7798 -20.974%
vet 24044 19055 -4989 -20.749%
total 409499 334585 -74914 -18.294%
Caching the field size in debug/gosym.funcTab
avoids a 20% PCToLine performance regression.
name old time/op new time/op delta
115/LineToPC-8 56.4µs ± 3% 57.3µs ± 2% +1.66% (p=0.006 n=15+13)
115/PCToLine-8 188ns ± 2% 190ns ± 3% +1.46% (p=0.030 n=15+15)
Change-Id: I2816a1b28e62b01852e3b306f08546f1e56cd5ac
Reviewed-on: https://go-review.googlesource.com/c/go/+/352191
Trust: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/plugin.go | 2 | ||||
| -rw-r--r-- | src/runtime/symtab.go | 34 |
2 files changed, 21 insertions, 15 deletions
diff --git a/src/runtime/plugin.go b/src/runtime/plugin.go index 500663bfe2..ab3d802389 100644 --- a/src/runtime/plugin.go +++ b/src/runtime/plugin.go @@ -96,7 +96,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}, errstr s func pluginftabverify(md *moduledata) { badtable := false for i := 0; i < len(md.ftab); i++ { - entry := md.ftab[i].entry + entry := md.textAddr(uintptr(md.ftab[i].entryoff)) if md.minpc <= entry && entry <= md.maxpc { continue } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index f423957f88..647300b0c4 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -553,8 +553,8 @@ func modulesinit() { } type functab struct { - entry uintptr - funcoff uintptr + entryoff uint32 // relative to runtime.text + funcoff uint32 } // Mapping information for secondary text sections @@ -604,16 +604,16 @@ func moduledataverify1(datap *moduledata) { nftab := len(datap.ftab) - 1 for i := 0; i < nftab; i++ { // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function. - if datap.ftab[i].entry > datap.ftab[i+1].entry { + if datap.ftab[i].entryoff > datap.ftab[i+1].entryoff { f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap} f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap} f2name := "end" if i+1 < nftab { f2name = funcname(f2) } - println("function symbol table not sorted by PC:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name, ", plugin:", datap.pluginpath) + println("function symbol table not sorted by PC offset:", hex(datap.ftab[i].entryoff), funcname(f1), ">", hex(datap.ftab[i+1].entryoff), f2name, ", plugin:", datap.pluginpath) for j := 0; j <= i; j++ { - println("\t", hex(datap.ftab[j].entry), funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap})) + println("\t", hex(datap.ftab[j].entryoff), funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap})) } if GOOS == "aix" && isarchive { println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive") @@ -622,8 +622,12 @@ func moduledataverify1(datap *moduledata) { } } - if datap.minpc != datap.ftab[0].entry || - datap.maxpc != datap.ftab[nftab].entry { + min := datap.textAddr(uintptr(datap.ftab[0].entryoff)) + // The max PC is outside of the text section. + // Subtract 1 to get a PC inside the text section, look it up, then add 1 back in. + max := datap.textAddr(uintptr(datap.ftab[nftab].entryoff-1)) + 1 + if datap.minpc != min || datap.maxpc != max { + println("minpc=", hex(datap.minpc), "min=", hex(min), "maxpc=", hex(datap.maxpc), "max=", hex(max)) throw("minpc or maxpc invalid") } @@ -649,6 +653,9 @@ func moduledataverify1(datap *moduledata) { // Each function's offset is compared against the section vaddrs and sizes to determine the containing section. // Then the section relative offset is added to the section's // relocated baseaddr to compute the function addess. +// +// It is nosplit because it is part of the findfunc implementation. +//go:nosplit func (md *moduledata) textAddr(off uintptr) uintptr { var res uintptr if len(md.textsectmap) > 1 { @@ -808,24 +815,23 @@ func findfunc(pc uintptr) funcInfo { if idx >= uint32(len(datap.ftab)) { idx = uint32(len(datap.ftab) - 1) } - if pc < datap.ftab[idx].entry { + if pc < datap.textAddr(uintptr(datap.ftab[idx].entryoff)) { // With multiple text sections, the idx might reference a function address that - // is higher than the pc being searched, so search backward until the matching address is found. - - for datap.ftab[idx].entry > pc && idx > 0 { + // is higher than the pcOff being searched, so search backward until the matching address is found. + for datap.textAddr(uintptr(datap.ftab[idx].entryoff)) > pc && idx > 0 { idx-- } if idx == 0 { throw("findfunc: bad findfunctab entry idx") } } else { - // linear search to find func with pc >= entry. - for datap.ftab[idx+1].entry <= pc { + // linear search to find func with pcOff >= entry. + for datap.textAddr(uintptr(datap.ftab[idx+1].entryoff)) <= pc { idx++ } } funcoff := datap.ftab[idx].funcoff - if funcoff == ^uintptr(0) { + if funcoff == ^uint32(0) { // With multiple text sections, there may be functions inserted by the external // linker that are not known by Go. This means there may be holes in the PC // range covered by the func table. The invalid funcoff value indicates a hole. |
