aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/cgo/gcc.go17
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM64.rules4
-rw-r--r--src/cmd/compile/internal/ssa/gen/MIPS64.rules3
-rw-r--r--src/cmd/compile/internal/ssa/gen/PPC64.rules4
-rw-r--r--src/cmd/compile/internal/ssa/gen/PPC64Ops.go4
-rw-r--r--src/cmd/compile/internal/ssa/gen/RISCV64.rules2
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM64.go6
-rw-r--r--src/cmd/compile/internal/ssa/rewriteMIPS64.go24
-rw-r--r--src/cmd/compile/internal/ssa/rewritePPC64.go25
-rw-r--r--src/cmd/compile/internal/ssa/rewriteRISCV64.go24
-rw-r--r--src/cmd/go/testdata/script/mod_replace_gopkgin.txt3
-rw-r--r--src/cmd/go/testdata/script/trampoline_reuse_test.txt100
-rw-r--r--src/cmd/go/testdata/script/version_buildvcs_git_gpg.txt105
-rw-r--r--src/cmd/link/internal/ppc64/asm.go5
14 files changed, 194 insertions, 132 deletions
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index dc5639812a..79d27c3e37 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -577,8 +577,23 @@ func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) {
switch e.Tag {
case dwarf.TagVariable:
name, _ := e.Val(dwarf.AttrName).(string)
+ // As of https://reviews.llvm.org/D123534, clang
+ // now emits DW_TAG_variable DIEs that have
+ // no name (so as to be able to describe the
+ // type and source locations of constant strings
+ // like the second arg in the call below:
+ //
+ // myfunction(42, "foo")
+ //
+ // If a var has no name we won't see attempts to
+ // refer to it via "C.<name>", so skip these vars
+ //
+ // See issue 53000 for more context.
+ if name == "" {
+ break
+ }
typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
- if name == "" || typOff == 0 {
+ if typOff == 0 {
if e.Val(dwarf.AttrSpecification) != nil {
// Since we are reading all the DWARF,
// assume we will see the variable elsewhere.
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index 09e70ad13b..ad99960078 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -316,9 +316,9 @@
(FCMPD x (FMOVDconst [0])) => (FCMPD0 x)
(FCMPD (FMOVDconst [0]) x) => (InvertFlags (FCMPD0 x))
-// CSEL needs a flag-generating argument. Synthesize a CMPW if necessary.
+// CSEL needs a flag-generating argument. Synthesize a TSTW if necessary.
(CondSelect x y boolval) && flagArg(boolval) != nil => (CSEL [boolval.Op] x y flagArg(boolval))
-(CondSelect x y boolval) && flagArg(boolval) == nil => (CSEL [OpARM64NotEqual] x y (CMPWconst [0] boolval))
+(CondSelect x y boolval) && flagArg(boolval) == nil => (CSEL [OpARM64NotEqual] x y (TSTWconst [1] boolval))
(OffPtr [off] ptr:(SP)) && is32Bit(off) => (MOVDaddr [int32(off)] ptr)
(OffPtr [off] ptr) => (ADDconst [off] ptr)
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
index 292ff2fc79..0d6d30fa4c 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPS64.rules
+++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
@@ -392,7 +392,8 @@
(AtomicAdd(32|64) ...) => (LoweredAtomicAdd(32|64) ...)
-(AtomicCompareAndSwap(32|64) ...) => (LoweredAtomicCas(32|64) ...)
+(AtomicCompareAndSwap32 ptr old new mem) => (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
+(AtomicCompareAndSwap64 ...) => (LoweredAtomicCas64 ...)
// checks
(NilCheck ...) => (LoweredNilCheck ...)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
index a90a3d0937..f83ed78bab 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -562,9 +562,9 @@
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(XOR x y)) yes no) && z.Uses == 1 => ((EQ|NE|LT|LE|GT|GE) (XORCC x y) yes no)
// Only lower after bool is lowered. It should always lower. This helps ensure the folding below happens reliably.
-(CondSelect x y bool) && flagArg(bool) == nil => (ISEL [6] x y (CMPWconst [0] bool))
+(CondSelect x y bool) && flagArg(bool) == nil => (ISEL [6] x y (Select1 <types.TypeFlags> (ANDCCconst [1] bool)))
// Fold any CR -> GPR -> CR transfers when applying the above rule.
-(ISEL [6] x y (CMPWconst [0] (ISELB [c] one cmp))) => (ISEL [c] x y cmp)
+(ISEL [6] x y (Select1 (ANDCCconst [1] (ISELB [c] one cmp)))) => (ISEL [c] x y cmp)
// Lowering loads
(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) => (MOVDload ptr mem)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
index 59d8af1a9d..d18cbcc787 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
@@ -11,8 +11,8 @@ import "strings"
// Notes:
// - Less-than-64-bit integer types live in the low portion of registers.
-// For now, the upper portion is junk; sign/zero-extension might be optimized in the future, but not yet.
-// - Boolean types are zero or 1; stored in a byte, but loaded with AMOVBZ so the upper bytes of a register are zero.
+// The upper portion is junk.
+// - Boolean types are zero or 1; stored in a byte, with upper bytes of the register containing junk.
// - *const instructions may use a constant larger than the instruction can encode.
// In this case the assembler expands to multiple instructions and uses tmp
// register (R31).
diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64.rules b/src/cmd/compile/internal/ssa/gen/RISCV64.rules
index 7aea622c5e..acef3df389 100644
--- a/src/cmd/compile/internal/ssa/gen/RISCV64.rules
+++ b/src/cmd/compile/internal/ssa/gen/RISCV64.rules
@@ -568,7 +568,7 @@
(AtomicAnd32 ...) => (LoweredAtomicAnd32 ...)
-(AtomicCompareAndSwap32 ...) => (LoweredAtomicCas32 ...)
+(AtomicCompareAndSwap32 ptr old new mem) => (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
(AtomicCompareAndSwap64 ...) => (LoweredAtomicCas64 ...)
(AtomicExchange32 ...) => (LoweredAtomicExchange32 ...)
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index 1ee25c2eee..ad1052f88d 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -23409,7 +23409,7 @@ func rewriteValueARM64_OpCondSelect(v *Value) bool {
}
// match: (CondSelect x y boolval)
// cond: flagArg(boolval) == nil
- // result: (CSEL [OpARM64NotEqual] x y (CMPWconst [0] boolval))
+ // result: (CSEL [OpARM64NotEqual] x y (TSTWconst [1] boolval))
for {
x := v_0
y := v_1
@@ -23419,8 +23419,8 @@ func rewriteValueARM64_OpCondSelect(v *Value) bool {
}
v.reset(OpARM64CSEL)
v.AuxInt = opToAuxInt(OpARM64NotEqual)
- v0 := b.NewValue0(v.Pos, OpARM64CMPWconst, types.TypeFlags)
- v0.AuxInt = int32ToAuxInt(0)
+ v0 := b.NewValue0(v.Pos, OpARM64TSTWconst, types.TypeFlags)
+ v0.AuxInt = int32ToAuxInt(1)
v0.AddArg(boolval)
v.AddArg3(x, y, v0)
return true
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
index 1fbd556b5c..6a0fd3ad6e 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
@@ -52,8 +52,7 @@ func rewriteValueMIPS64(v *Value) bool {
v.Op = OpMIPS64LoweredAtomicAdd64
return true
case OpAtomicCompareAndSwap32:
- v.Op = OpMIPS64LoweredAtomicCas32
- return true
+ return rewriteValueMIPS64_OpAtomicCompareAndSwap32(v)
case OpAtomicCompareAndSwap64:
v.Op = OpMIPS64LoweredAtomicCas64
return true
@@ -697,6 +696,27 @@ func rewriteValueMIPS64_OpAddr(v *Value) bool {
return true
}
}
+func rewriteValueMIPS64_OpAtomicCompareAndSwap32(v *Value) bool {
+ v_3 := v.Args[3]
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
+ // match: (AtomicCompareAndSwap32 ptr old new mem)
+ // result: (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
+ for {
+ ptr := v_0
+ old := v_1
+ new := v_2
+ mem := v_3
+ v.reset(OpMIPS64LoweredAtomicCas32)
+ v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
+ v0.AddArg(old)
+ v.AddArg4(ptr, v0, new, mem)
+ return true
+ }
+}
func rewriteValueMIPS64_OpAvg64u(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index 5a28b9d4f7..c7bcc248fc 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -1167,9 +1167,10 @@ func rewriteValuePPC64_OpCondSelect(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
+ typ := &b.Func.Config.Types
// match: (CondSelect x y bool)
// cond: flagArg(bool) == nil
- // result: (ISEL [6] x y (CMPWconst [0] bool))
+ // result: (ISEL [6] x y (Select1 <types.TypeFlags> (ANDCCconst [1] bool)))
for {
x := v_0
y := v_1
@@ -1179,9 +1180,11 @@ func rewriteValuePPC64_OpCondSelect(v *Value) bool {
}
v.reset(OpPPC64ISEL)
v.AuxInt = int32ToAuxInt(6)
- v0 := b.NewValue0(v.Pos, OpPPC64CMPWconst, types.TypeFlags)
- v0.AuxInt = int32ToAuxInt(0)
- v0.AddArg(bool)
+ v0 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+ v1 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.NewTuple(typ.Int, types.TypeFlags))
+ v1.AuxInt = int64ToAuxInt(1)
+ v1.AddArg(bool)
+ v0.AddArg(v1)
v.AddArg3(x, y, v0)
return true
}
@@ -5895,7 +5898,7 @@ func rewriteValuePPC64_OpPPC64ISEL(v *Value) bool {
v.AddArg(y)
return true
}
- // match: (ISEL [6] x y (CMPWconst [0] (ISELB [c] one cmp)))
+ // match: (ISEL [6] x y (Select1 (ANDCCconst [1] (ISELB [c] one cmp))))
// result: (ISEL [c] x y cmp)
for {
if auxIntToInt32(v.AuxInt) != 6 {
@@ -5903,15 +5906,19 @@ func rewriteValuePPC64_OpPPC64ISEL(v *Value) bool {
}
x := v_0
y := v_1
- if v_2.Op != OpPPC64CMPWconst || auxIntToInt32(v_2.AuxInt) != 0 {
+ if v_2.Op != OpSelect1 {
break
}
v_2_0 := v_2.Args[0]
- if v_2_0.Op != OpPPC64ISELB {
+ if v_2_0.Op != OpPPC64ANDCCconst || auxIntToInt64(v_2_0.AuxInt) != 1 {
+ break
+ }
+ v_2_0_0 := v_2_0.Args[0]
+ if v_2_0_0.Op != OpPPC64ISELB {
break
}
- c := auxIntToInt32(v_2_0.AuxInt)
- cmp := v_2_0.Args[1]
+ c := auxIntToInt32(v_2_0_0.AuxInt)
+ cmp := v_2_0_0.Args[1]
v.reset(OpPPC64ISEL)
v.AuxInt = int32ToAuxInt(c)
v.AddArg3(x, y, cmp)
diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
index 6828d97ff8..b277979061 100644
--- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go
+++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
@@ -61,8 +61,7 @@ func rewriteValueRISCV64(v *Value) bool {
case OpAtomicAnd8:
return rewriteValueRISCV64_OpAtomicAnd8(v)
case OpAtomicCompareAndSwap32:
- v.Op = OpRISCV64LoweredAtomicCas32
- return true
+ return rewriteValueRISCV64_OpAtomicCompareAndSwap32(v)
case OpAtomicCompareAndSwap64:
v.Op = OpRISCV64LoweredAtomicCas64
return true
@@ -765,6 +764,27 @@ func rewriteValueRISCV64_OpAtomicAnd8(v *Value) bool {
return true
}
}
+func rewriteValueRISCV64_OpAtomicCompareAndSwap32(v *Value) bool {
+ v_3 := v.Args[3]
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
+ // match: (AtomicCompareAndSwap32 ptr old new mem)
+ // result: (LoweredAtomicCas32 ptr (SignExt32to64 old) new mem)
+ for {
+ ptr := v_0
+ old := v_1
+ new := v_2
+ mem := v_3
+ v.reset(OpRISCV64LoweredAtomicCas32)
+ v0 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
+ v0.AddArg(old)
+ v.AddArg4(ptr, v0, new, mem)
+ return true
+ }
+}
func rewriteValueRISCV64_OpAtomicOr8(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
diff --git a/src/cmd/go/testdata/script/mod_replace_gopkgin.txt b/src/cmd/go/testdata/script/mod_replace_gopkgin.txt
index df752d9716..8cb034c36c 100644
--- a/src/cmd/go/testdata/script/mod_replace_gopkgin.txt
+++ b/src/cmd/go/testdata/script/mod_replace_gopkgin.txt
@@ -4,6 +4,9 @@
# even if there is an explicit go.mod file containing the
# gopkg.in path.
+skip 'skipping test that depends on an unreliable third-party server; see https://go.dev/issue/54503'
+ # TODO(#54043): Make this test hermetic and re-enable it.
+
[short] skip
[!net] skip
[!exec:git] skip
diff --git a/src/cmd/go/testdata/script/trampoline_reuse_test.txt b/src/cmd/go/testdata/script/trampoline_reuse_test.txt
new file mode 100644
index 0000000000..bca897c16d
--- /dev/null
+++ b/src/cmd/go/testdata/script/trampoline_reuse_test.txt
@@ -0,0 +1,100 @@
+# Verify PPC64 does not reuse a trampoline which is too far away.
+# This tests an edge case where the direct call relocation addend should
+# be ignored when computing the distance from the direct call to the
+# already placed trampoline
+[short] skip
+[!ppc64] [!ppc64le] skip
+[aix] skip
+
+# Note, this program does not run. Presumably, 'DWORD $0' is simpler to
+# assembly 2^26 or so times.
+#
+# We build something which should be laid out as such:
+#
+# bar.Bar
+# main.Func1
+# bar.Bar+400-tramp0
+# main.BigAsm
+# main.Func2
+# bar.Bar+400-tramp1
+#
+# bar.Bar needs to be placed far enough away to generate relocations
+# from main package calls. and main.Func1 and main.Func2 are placed
+# a bit more than the direct call limit apart, but not more than 0x400
+# bytes beyond it (to verify the reloc calc).
+
+go build
+
+-- go.mod --
+
+module foo
+
+go 1.19
+
+-- main.go --
+
+package main
+
+import "foo/bar"
+
+func Func1()
+
+func main() {
+ Func1()
+ bar.Bar2()
+}
+
+-- foo.s --
+
+TEXT main·Func1(SB),0,$0-0
+ CALL bar·Bar+0x400(SB)
+ CALL main·BigAsm(SB)
+// A trampoline will be placed here to bar.Bar
+
+// This creates a gap sufficiently large to prevent trampoline reuse
+#define NOP64 DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0;
+#define NOP256 NOP64 NOP64 NOP64 NOP64
+#define NOP2S10 NOP256 NOP256 NOP256 NOP256
+#define NOP2S12 NOP2S10 NOP2S10 NOP2S10 NOP2S10
+#define NOP2S14 NOP2S12 NOP2S12 NOP2S12 NOP2S12
+#define NOP2S16 NOP2S14 NOP2S14 NOP2S14 NOP2S14
+#define NOP2S18 NOP2S16 NOP2S16 NOP2S16 NOP2S16
+#define NOP2S20 NOP2S18 NOP2S18 NOP2S18 NOP2S18
+#define NOP2S22 NOP2S20 NOP2S20 NOP2S20 NOP2S20
+#define NOP2S24 NOP2S22 NOP2S22 NOP2S22 NOP2S22
+#define BIGNOP NOP2S24 NOP2S24
+TEXT main·BigAsm(SB),0,$0-0
+ // Fill to the direct call limit so Func2 must generate a new trampoline.
+ // As the implicit trampoline above is just barely unreachable.
+ BIGNOP
+ MOVD $main·Func2(SB), R3
+
+TEXT main·Func2(SB),0,$0-0
+ CALL bar·Bar+0x400(SB)
+// Another trampoline should be placed here.
+
+-- bar/bar.s --
+
+#define NOP64 DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0;
+#define NOP256 NOP64 NOP64 NOP64 NOP64
+#define NOP2S10 NOP256 NOP256 NOP256 NOP256
+#define NOP2S12 NOP2S10 NOP2S10 NOP2S10 NOP2S10
+#define NOP2S14 NOP2S12 NOP2S12 NOP2S12 NOP2S12
+#define NOP2S16 NOP2S14 NOP2S14 NOP2S14 NOP2S14
+#define NOP2S18 NOP2S16 NOP2S16 NOP2S16 NOP2S16
+#define NOP2S20 NOP2S18 NOP2S18 NOP2S18 NOP2S18
+#define NOP2S22 NOP2S20 NOP2S20 NOP2S20 NOP2S20
+#define NOP2S24 NOP2S22 NOP2S22 NOP2S22 NOP2S22
+#define BIGNOP NOP2S24 NOP2S24 NOP2S10
+// A very big not very interesting function.
+TEXT bar·Bar(SB),0,$0-0
+ BIGNOP
+
+-- bar/bar.go --
+
+package bar
+
+func Bar()
+
+func Bar2() {
+}
diff --git a/src/cmd/go/testdata/script/version_buildvcs_git_gpg.txt b/src/cmd/go/testdata/script/version_buildvcs_git_gpg.txt
deleted file mode 100644
index dcf97d7c44..0000000000
--- a/src/cmd/go/testdata/script/version_buildvcs_git_gpg.txt
+++ /dev/null
@@ -1,105 +0,0 @@
-# This test checks that VCS information is stamped into Go binaries even when
-# the current commit is signed and the use has configured git to display commit
-# signatures.
-
-[!exec:git] skip
-[!exec:gpg] skip
-[short] skip
-env GOBIN=$GOPATH/bin
-env GNUPGHOME=$WORK/.gpupg
-mkdir $GNUPGHOME
-chmod 0700 $GNUPGHOME
-
-# Create GPG key
-exec gpg --batch --passphrase '' --quick-generate-key gopher@golang.org
-exec gpg --list-secret-keys --with-colons gopher@golang.org
-cp stdout keyinfo.txt
-go run extract_key_id.go keyinfo.txt
-cp stdout keyid.txt
-
-# Initialize repo
-cd repo/
-exec git init
-exec git config user.email gopher@golang.org
-exec git config user.name 'J.R. Gopher'
-exec git config --add log.showSignature true
-go run ../configure_signing_key.go ../keyid.txt
-
-# Create signed commit
-cd a
-exec git add -A
-exec git commit -m 'initial commit' --gpg-sign
-exec git log
-
-# Verify commit signature does not interfere with versioning
-go install
-go version -m $GOBIN/a
-stdout '^\tbuild\tvcs\.revision='
-stdout '^\tbuild\tvcs\.time='
-stdout '^\tbuild\tvcs\.modified=false$'
-
--- repo/README --
-Far out in the uncharted backwaters of the unfashionable end of the western
-spiral arm of the Galaxy lies a small, unregarded yellow sun.
--- repo/a/go.mod --
-module example.com/a
-
-go 1.18
--- repo/a/a.go --
-package main
-
-func main() {}
-
--- extract_key_id.go --
-package main
-
-import "fmt"
-import "io/ioutil"
-import "os"
-import "strings"
-
-func main() {
- err := run(os.Args[1])
- if err != nil {
- panic(err)
- }
-}
-
-func run(keyInfoFilePath string) error {
- contents, err := ioutil.ReadFile(keyInfoFilePath)
- if err != nil {
- return err
- }
- lines := strings.Split(string(contents), "\n")
- for _, line := range lines {
- fields := strings.Split(line, ":")
- if fields[0] == "sec" {
- fmt.Print(fields[4])
- return nil
- }
- }
- return fmt.Errorf("key ID not found in: %s", keyInfoFilePath)
-}
-
--- configure_signing_key.go --
-package main
-
-import "io/ioutil"
-import "os"
-import "os/exec"
-
-func main() {
- err := run(os.Args[1])
- if err != nil {
- panic(err)
- }
-}
-
-func run(keyIdFilePath string) error {
- keyId, err := ioutil.ReadFile(keyIdFilePath)
- if err != nil {
- return err
- }
- gitCmd := exec.Command("git", "config", "user.signingKey", string(keyId))
- return gitCmd.Run()
-}
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index 73c2718a33..879adaa965 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -809,8 +809,9 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
if ldr.SymValue(tramp) == 0 {
break
}
-
- t = ldr.SymValue(tramp) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
+ // Note, the trampoline is always called directly. The addend of the original relocation is accounted for in the
+ // trampoline itself.
+ t = ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
// With internal linking, the trampoline can be used if it is not too far.
// With external linking, the trampoline must be in this section for it to be reused.