aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2026-03-06 15:44:41 -0800
committerGopher Robot <gobot@golang.org>2026-03-07 06:09:36 -0800
commit383000da24e9b32dbe3cae4c48cbb233d7c62253 (patch)
tree730a9c9b264260ed6efe2c0aecf35d0d2519b116 /src/cmd/internal
parentb9545da71c2f5e93355d82a1f9b5ead02f2bc617 (diff)
downloadgo-383000da24e9b32dbe3cae4c48cbb233d7c62253.tar.xz
cmd/internal/obj: fix indirect tail call code
The assembler isn't handling this correctly for most architectures. Of course, the two I tried first, arm64 and amd64, worked, so I assumed other archs could handle it also. Apparently not. Should fix dashboard failures introduced by CL 751465. Change-Id: I9fc4f123d11acf3d10cc9806abfb93ec077509a7 Reviewed-on: https://go-review.googlesource.com/c/go/+/752560 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Keith Randall <khr@google.com> Auto-Submit: Keith Randall <khr@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Diffstat (limited to 'src/cmd/internal')
-rw-r--r--src/cmd/internal/obj/arm/obj5.go26
-rw-r--r--src/cmd/internal/obj/loong64/obj.go12
-rw-r--r--src/cmd/internal/obj/mips/obj0.go12
-rw-r--r--src/cmd/internal/obj/ppc64/obj9.go24
-rw-r--r--src/cmd/internal/obj/riscv/obj.go7
-rw-r--r--src/cmd/internal/obj/s390x/objz.go11
6 files changed, 67 insertions, 25 deletions
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 79f08a41ea..62870731b5 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -352,16 +352,25 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case obj.ARET:
nocache(p)
+
+ retSym, retReg := p.To.Sym, p.To.Reg
+ if retReg == obj.REG_NONE {
+ retReg = REGLINK
+ }
+ p.To.Sym = nil
+ p.To.Name = obj.NAME_NONE
+ p.To.Reg = obj.REG_NONE
+
if cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
p.As = AB
p.From = obj.Addr{}
- if p.To.Sym != nil { // retjmp
+ if retSym != nil { // retjmp
p.To.Type = obj.TYPE_BRANCH
} else {
p.To.Type = obj.TYPE_MEM
p.To.Offset = 0
- p.To.Reg = REGLINK
+ p.To.Reg = retReg
}
break
@@ -380,14 +389,17 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// this ARET, they come from a branch
// with the same stackframe, so no spadj.
- if p.To.Sym != nil { // retjmp
+ if retSym != nil || retReg != REGLINK { // retjmp
p.To.Reg = REGLINK
q2 = obj.Appendp(p, newprog)
q2.As = AB
- q2.To.Type = obj.TYPE_BRANCH
- q2.To.Sym = p.To.Sym
- p.To.Sym = nil
- p.To.Name = obj.NAME_NONE
+ if retSym != nil {
+ q2.To.Type = obj.TYPE_BRANCH
+ q2.To.Sym = retSym
+ } else {
+ q2.To.Type = obj.TYPE_MEM
+ q2.To.Reg = retReg
+ }
p = q2
}
diff --git a/src/cmd/internal/obj/loong64/obj.go b/src/cmd/internal/obj/loong64/obj.go
index 51a28d130c..fcf10d2307 100644
--- a/src/cmd/internal/obj/loong64/obj.go
+++ b/src/cmd/internal/obj/loong64/obj.go
@@ -359,9 +359,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
break
}
- retSym := p.To.Sym
+ retSym, retReg := p.To.Sym, p.To.Reg
+ if retReg == obj.REG_NONE {
+ retReg = REGLINK
+ }
p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
p.To.Sym = nil
+ p.To.Reg = obj.REG_NONE
if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
@@ -373,7 +377,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Sym = retSym
} else {
p.To.Type = obj.TYPE_MEM
- p.To.Reg = REGLINK
+ p.To.Reg = retReg
p.To.Offset = 0
}
p.Mark |= BRANCH
@@ -397,7 +401,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
} else {
q.To.Type = obj.TYPE_MEM
q.To.Offset = 0
- q.To.Reg = REGLINK
+ q.To.Reg = retReg
}
q.Mark |= BRANCH
q.Spadj = +autosize
@@ -438,7 +442,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
} else {
q1.To.Type = obj.TYPE_MEM
q1.To.Offset = 0
- q1.To.Reg = REGLINK
+ q1.To.Reg = retReg
}
q1.Mark |= BRANCH
q1.Spadj = +autosize
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
index bbed88e9d6..4ade03a778 100644
--- a/src/cmd/internal/obj/mips/obj0.go
+++ b/src/cmd/internal/obj/mips/obj0.go
@@ -364,9 +364,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
break
}
- retSym := p.To.Sym
+ retSym, retReg := p.To.Sym, p.To.Reg
+ if retReg == obj.REG_NONE {
+ retReg = REGLINK
+ }
p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
p.To.Sym = nil
+ p.To.Reg = obj.REG_NONE
if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
@@ -378,7 +382,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Sym = retSym
} else {
p.To.Type = obj.TYPE_MEM
- p.To.Reg = REGLINK
+ p.To.Reg = retReg
p.To.Offset = 0
}
p.Mark |= BRANCH
@@ -401,7 +405,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.To.Sym = retSym
} else {
q.To.Type = obj.TYPE_MEM
- q.To.Reg = REGLINK
+ q.To.Reg = retReg
q.To.Offset = 0
}
q.Mark |= BRANCH
@@ -443,7 +447,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
} else {
q1.To.Type = obj.TYPE_MEM
q1.To.Offset = 0
- q1.To.Reg = REGLINK
+ q1.To.Reg = retReg
}
q1.Mark |= BRANCH
q1.Spadj = +autosize
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index bae2965639..323420fefa 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -965,7 +965,23 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
break
}
- retTarget := p.To.Sym
+ retTarget, retReg := p.To.Sym, p.To.Reg
+ if retReg == obj.REG_NONE {
+ retReg = REG_LR
+ } else {
+ // Move target address into REG_CTR.
+ // (Indirect branches can only go to REG_LR or REG_CTR.)
+ x := newprog()
+ *x = *p
+ p.As = AMOVD
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = retReg
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = REG_CTR
+ retReg = REG_CTR
+ p.Link = x
+ p = x
+ }
if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
@@ -973,7 +989,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From = obj.Addr{}
if retTarget == nil {
p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_LR
+ p.To.Reg = retReg
} else {
p.To.Type = obj.TYPE_BRANCH
p.To.Sym = retTarget
@@ -994,7 +1010,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Pos = p.Pos
if retTarget == nil {
q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_LR
+ q.To.Reg = retReg
} else {
q.To.Type = obj.TYPE_BRANCH
q.To.Sym = retTarget
@@ -1063,7 +1079,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.Pos = p.Pos
if retTarget == nil {
q1.To.Type = obj.TYPE_REG
- q1.To.Reg = REG_LR
+ q1.To.Reg = retReg
} else {
q1.To.Type = obj.TYPE_BRANCH
q1.To.Sym = retTarget
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 24e0a454cd..e9005fe0db 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -596,7 +596,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case obj.ARET:
// Replace RET with epilogue.
- retJMP := p.To.Sym
+ retJMP, retReg := p.To.Sym, p.To.Reg
+ if retReg == obj.REG_NONE {
+ retReg = REG_LR
+ }
if stacksize != 0 {
// Restore LR.
@@ -621,7 +624,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.As = AJALR
p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
p.Reg = obj.REG_NONE
- p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
+ p.To = obj.Addr{Type: obj.TYPE_REG, Reg: retReg}
}
// "Add back" the stack removed in the previous instruction.
diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go
index 4bfc1f7b2c..d877589573 100644
--- a/src/cmd/internal/obj/s390x/objz.go
+++ b/src/cmd/internal/obj/s390x/objz.go
@@ -385,7 +385,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
case obj.ARET:
- retTarget := p.To.Sym
+ retTarget, retReg := p.To.Sym, p.To.Reg
+ if retReg == obj.REG_NONE {
+ retReg = REG_LR
+ }
if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
@@ -393,7 +396,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From = obj.Addr{}
if retTarget == nil {
p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_LR
+ p.To.Reg = retReg
} else {
p.To.Type = obj.TYPE_BRANCH
p.To.Sym = retTarget
@@ -414,7 +417,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.From = obj.Addr{}
if retTarget == nil {
q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_LR
+ q.To.Reg = retReg
} else {
q.To.Type = obj.TYPE_BRANCH
q.To.Sym = retTarget
@@ -450,7 +453,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.From = obj.Addr{}
if retTarget == nil {
q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_LR
+ q.To.Reg = retReg
} else {
q.To.Type = obj.TYPE_BRANCH
q.To.Sym = retTarget