1 // Copyright 2023 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // When linking C ELFv2 objects, the Go linker may need to insert calling stubs.
6 // A call stub is usually needed when the ELFv2 st_other attribute is different
7 // between caller and callee.
8 //
9 // The type of call stub inserted will vary depending on GOPPC64 and the
10 // buildmode (e.g pie builds shared code, default builds fixed-position code).
11 // CI is set up to run for P8 and P10 machines, and this test is run in both
12 // pie and default modes.
13 //
14 // Several functions are written with interesting st_other attributes, and
15 // call each other to test various calling combinations which require stubs.
16 //
17 // The call tree is as follows, starting from TestPPC64Stubs (A C function):
18 // TestPPC64Stubs (compiled PIC by default by Go)
19 // notoc_func [called TOC -> NOTOC (but R2 is preserved)]
20 // toc_func [called NOTOC -> TOC]
21 // notoc_nor2_func [called TOC -> NOTOC]
22 // random [dynamic TOC call]
23 // random [dynamic NOTOC call]
24 //
25 // Depending on the GOPPC64/buildmode used, and type of call, one of 7 stubs may need inserted:
26 //
27 // TOC -> NOTOC: Save R2, call global entry. (valid for any GOPPC64)
28 // TOC save slot is rewrittent to restore TOC.
29 // NOTOC -> TOC [P10]: A PIC call stub using P10 instructions to call the global entry
30 // NOTOC -> TOC [P8]: A PIC call stub using P8 instructions to call the global entry
31 //
32 // TOC -> dynamic: A PLT call stub is generated which saves R2.
33 // TOC save slot is rewritten to restore TOC.
34 // NOTOC -> dynamic [P10]: A stub using pcrel instructions is generated.
35 // NOTOC -> dynamic [P8/default]: A P8 compatible, non-PIC stub is generated
36 // NOTOC -> dynamic [P8/pie]: A P8 compatible, PIC stub is generated
37 //
38 //
39 // Some notes about other cases:
40 // TOC -> TOC, NOTOC -> NOTOC, NOTOC -> TOC local calls do not require require call stubs.
41 // TOC -> NOTOC (R2 is preserved, st_other==0): A special case where a call stub is not needed.
42
43 // This test requires a binutils with power10 and ELFv2 1.5 support. This is earliest verified version.
44 .if .gasversion. >= 23500
45
46 // A function which does not guarantee R2 is preserved.
47 // R2 is clobbered here to ensure the stubs preserve it.
48 .globl notoc_nor2_func
49 .type notoc_nor2_func, @function
50 notoc_nor2_func:
51 .localentry notoc_nor2_func,1
52 li 2,0
53 blr
54
55 // A function which expects R2 to hold TOC, and has a distinct local entry.
56 .globl toc_func
57 .type toc_func, @function
58 toc_func:
59 addis 2,12,.TOC.-toc_func@ha
60 addi 2,2,.TOC.-toc_func@l
61 .localentry toc_func, .-toc_func
62 mflr 0
63 std 0,16(1)
64 stdu 1,-32(1)
65
66 // Call a NOTOC function which clobbers R2.
67 bl notoc_nor2_func
68 nop
69
70 // Call libc random. This should generate a TOC relative plt stub.
71 bl random
72 nop
73
74 addi 1,1,32
75 ld 0,16(1)
76 mtlr 0
77 blr
78
79 // An ELFv2 st_other==0 function. It preserves R2 (TOC), but does not use it.
80 .globl notoc_func
81 .type notoc_func, @function
82 notoc_func:
83 // Save R2 and LR and stack a frame.
84 mflr 0
85 std 0,16(1)
86 stdu 1,-32(1)
87
88 // Save R2 in TOC save slot.
89 std 2,24(1)
90
91 // clobber R2
92 li 2,0
93
94 // Call type2_func. A call stub from notoc to toc should be inserted.
95 bl toc_func@notoc
96
97 // Call libc random. A notoc plt stub should be inserted.
98 bl random@notoc
99
100 // Return 0 to indicate the test ran.
101 li 3,0
102
103 // Restore R2
104 ld 2,24(1)
105
106 // Restore LR and pop stack
107 addi 1,1,32
108 ld 0,16(1)
109 mtlr 0
110 blr
111
112 .else
113
114 // A stub for older binutils
115 .globl notoc_func
116 .type notoc_func, @function
117 notoc_func:
118 // Return 1 to indicate the test was skipped.
119 li 3,1
120 blr
121
122 .endif
123
View as plain text