Skip to content

Commit 1ed636d

Browse files
committed
cmd/link/internal/ppc64: fix trampoline reuse distance calculation
If a compatible trampoline has been inserted by a previously laid function in the same section, and is known to be sufficiently close, it can be reused. When testing if the trampoline can be reused, the addend of the direct call should be ignored. It is already encoded in the trampoline. If the addend is non-zero, and the target sufficiently far away, and just beyond direct call reach, this may cause the trampoline to be incorrectly reused. This was observed on go1.17.13 and openshift-installer commit f3c53b382 building in release mode with the following error: github.com/aliyun/alibaba-cloud-sdk-go/services/cms.(*Client).DescribeMonitoringAgentAccessKeyWithChan.func1: direct call too far: runtime.duffzero+1f0-tramp0-1 -2000078 Fixes #56775 Change-Id: I54af957302506d4e3cd5d3121542c83fe980e912 Reviewed-on: https://go-review.googlesource.com/c/go/+/451415 Reviewed-by: Cherry Mui <[email protected]> Run-TryBot: Paul Murphy <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Lynn Boger <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent 349d398 commit 1ed636d

File tree

2 files changed

+103
-2
lines changed

2 files changed

+103
-2
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Verify PPC64 does not reuse a trampoline which is too far away.
2+
# This tests an edge case where the direct call relocation addend should
3+
# be ignored when computing the distance from the direct call to the
4+
# already placed trampoline
5+
[short] skip
6+
[!GOARCH:ppc64] [!GOARCH:ppc64le] skip
7+
[GOOS:aix] skip
8+
9+
# Note, this program does not run. Presumably, 'DWORD $0' is simpler to
10+
# assembly 2^26 or so times.
11+
#
12+
# We build something which should be laid out as such:
13+
#
14+
# bar.Bar
15+
# main.Func1
16+
# bar.Bar+400-tramp0
17+
# main.BigAsm
18+
# main.Func2
19+
# bar.Bar+400-tramp1
20+
#
21+
# bar.Bar needs to be placed far enough away to generate relocations
22+
# from main package calls. and main.Func1 and main.Func2 are placed
23+
# a bit more than the direct call limit apart, but not more than 0x400
24+
# bytes beyond it (to verify the reloc calc).
25+
26+
go build
27+
28+
-- go.mod --
29+
30+
module foo
31+
32+
go 1.19
33+
34+
-- main.go --
35+
36+
package main
37+
38+
import "foo/bar"
39+
40+
func Func1()
41+
42+
func main() {
43+
Func1()
44+
bar.Bar2()
45+
}
46+
47+
-- foo.s --
48+
49+
TEXT main·Func1(SB),0,$0-0
50+
CALL bar·Bar+0x400(SB)
51+
CALL main·BigAsm(SB)
52+
// A trampoline will be placed here to bar.Bar
53+
54+
// This creates a gap sufficiently large to prevent trampoline reuse
55+
#define NOP64 DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0;
56+
#define NOP256 NOP64 NOP64 NOP64 NOP64
57+
#define NOP2S10 NOP256 NOP256 NOP256 NOP256
58+
#define NOP2S12 NOP2S10 NOP2S10 NOP2S10 NOP2S10
59+
#define NOP2S14 NOP2S12 NOP2S12 NOP2S12 NOP2S12
60+
#define NOP2S16 NOP2S14 NOP2S14 NOP2S14 NOP2S14
61+
#define NOP2S18 NOP2S16 NOP2S16 NOP2S16 NOP2S16
62+
#define NOP2S20 NOP2S18 NOP2S18 NOP2S18 NOP2S18
63+
#define NOP2S22 NOP2S20 NOP2S20 NOP2S20 NOP2S20
64+
#define NOP2S24 NOP2S22 NOP2S22 NOP2S22 NOP2S22
65+
#define BIGNOP NOP2S24 NOP2S24
66+
TEXT main·BigAsm(SB),0,$0-0
67+
// Fill to the direct call limit so Func2 must generate a new trampoline.
68+
// As the implicit trampoline above is just barely unreachable.
69+
BIGNOP
70+
MOVD $main·Func2(SB), R3
71+
72+
TEXT main·Func2(SB),0,$0-0
73+
CALL bar·Bar+0x400(SB)
74+
// Another trampoline should be placed here.
75+
76+
-- bar/bar.s --
77+
78+
#define NOP64 DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0;
79+
#define NOP256 NOP64 NOP64 NOP64 NOP64
80+
#define NOP2S10 NOP256 NOP256 NOP256 NOP256
81+
#define NOP2S12 NOP2S10 NOP2S10 NOP2S10 NOP2S10
82+
#define NOP2S14 NOP2S12 NOP2S12 NOP2S12 NOP2S12
83+
#define NOP2S16 NOP2S14 NOP2S14 NOP2S14 NOP2S14
84+
#define NOP2S18 NOP2S16 NOP2S16 NOP2S16 NOP2S16
85+
#define NOP2S20 NOP2S18 NOP2S18 NOP2S18 NOP2S18
86+
#define NOP2S22 NOP2S20 NOP2S20 NOP2S20 NOP2S20
87+
#define NOP2S24 NOP2S22 NOP2S22 NOP2S22 NOP2S22
88+
#define BIGNOP NOP2S24 NOP2S24 NOP2S10
89+
// A very big not very interesting function.
90+
TEXT bar·Bar(SB),0,$0-0
91+
BIGNOP
92+
93+
-- bar/bar.go --
94+
95+
package bar
96+
97+
func Bar()
98+
99+
func Bar2() {
100+
}

src/cmd/link/internal/ppc64/asm.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -994,8 +994,9 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
994994
if ldr.SymValue(tramp) == 0 {
995995
break
996996
}
997-
998-
t = ldr.SymValue(tramp) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
997+
// Note, the trampoline is always called directly. The addend of the original relocation is accounted for in the
998+
// trampoline itself.
999+
t = ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
9991000

10001001
// With internal linking, the trampoline can be used if it is not too far.
10011002
// With external linking, the trampoline must be in this section for it to be reused.

0 commit comments

Comments
 (0)