diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index a2024bcedec76d..d28af163c7eee0 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -383,12 +383,16 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) { offset := (signext24(r.Add()&0xffffff) + 2) * 4 var tramp loader.Sym for i := 0; ; i++ { - name := ldr.SymName(rs) + fmt.Sprintf("%+d-tramp%d", offset, i) + oName := ldr.SymName(rs) + name := oName + fmt.Sprintf("%+d-tramp%d", offset, i) tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs))) if ldr.SymType(tramp) == sym.SDYNIMPORT { // don't reuse trampoline defined in other module continue } + if oName == "runtime.deferreturn" { + ldr.SetIsDeferReturnTramp(tramp, true) + } if ldr.SymValue(tramp) == 0 { // either the trampoline does not exist -- we need to create one, // or found one the address which is not assigned -- this will be diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 00c29c63e071bd..5cbb7bbaccb44a 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -161,7 +161,7 @@ func (state *pclnState) computeDeferReturn(target *Target, s loader.Sym) uint32 // set the resumption point to PC_B. lastWasmAddr = uint32(r.Add()) } - if r.Type().IsDirectCall() && r.Sym() == state.deferReturnSym { + if r.Type().IsDirectCall() && (r.Sym() == state.deferReturnSym || state.ldr.IsDeferReturnTramp(r.Sym())) { if target.IsWasm() { deferreturn = lastWasmAddr - 1 } else { diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 2627218ced8575..8e6451d270e767 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -236,7 +236,8 @@ type Loader struct { outdata [][]byte // symbol's data in the output buffer extRelocs [][]ExtReloc // symbol's external relocations - itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.* + itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.* + deferReturnTramp map[Sym]bool // whether the symbol is a trampoline of a deferreturn call objByPkg map[string]*oReader // map package path to its Go object reader @@ -362,6 +363,7 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorRepor attrCgoExportDynamic: make(map[Sym]struct{}), attrCgoExportStatic: make(map[Sym]struct{}), itablink: make(map[Sym]struct{}), + deferReturnTramp: make(map[Sym]bool), extStaticSyms: make(map[nameVer]Sym), builtinSyms: make([]Sym, nbuiltin), flags: flags, @@ -1062,6 +1064,16 @@ func (l *Loader) IsItabLink(i Sym) bool { return false } +// Return whether this is a trampoline of a deferreturn call. +func (l *Loader) IsDeferReturnTramp(i Sym) bool { + return l.deferReturnTramp[i] +} + +// Set that i is a trampoline of a deferreturn call. +func (l *Loader) SetIsDeferReturnTramp(i Sym, v bool) { + l.deferReturnTramp[i] = v +} + // growValues grows the slice used to store symbol values. func (l *Loader) growValues(reqLen int) { curLen := len(l.values) diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index bd4827ecb54bf4..fc714c9dd1c882 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -686,16 +686,20 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) { // target is at some offset within the function. Calls to duff+8 and duff+256 must appear as // distinct trampolines. - name := ldr.SymName(rs) + oName := ldr.SymName(rs) + name := oName if r.Add() == 0 { - name = name + fmt.Sprintf("-tramp%d", i) + name += fmt.Sprintf("-tramp%d", i) } else { - name = name + fmt.Sprintf("%+x-tramp%d", r.Add(), i) + name += fmt.Sprintf("%+x-tramp%d", r.Add(), i) } // Look up the trampoline in case it already exists tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs))) + if oName == "runtime.deferreturn" { + ldr.SetIsDeferReturnTramp(tramp, true) + } if ldr.SymValue(tramp) == 0 { break } diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 1c9e1779116a67..5ff9912a11a886 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -629,10 +629,23 @@ func TestFuncAlign(t *testing.T) { } } -const helloSrc = ` +const testTrampSrc = ` package main import "fmt" -func main() { fmt.Println("hello") } +func main() { + fmt.Println("hello") + + defer func(){ + if e := recover(); e == nil { + panic("did not panic") + } + }() + f1() +} + +// Test deferreturn trampolines. See issue #39049. +func f1() { defer f2() } +func f2() { panic("XXX") } ` func TestTrampoline(t *testing.T) { @@ -655,7 +668,7 @@ func TestTrampoline(t *testing.T) { defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "hello.go") - err = ioutil.WriteFile(src, []byte(helloSrc), 0666) + err = ioutil.WriteFile(src, []byte(testTrampSrc), 0666) if err != nil { t.Fatal(err) }