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
// 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 {
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
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,
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)
// 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
}
}
}
-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) {
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)
}