@@ -40,10 +40,11 @@ import (
40
40
"encoding/binary"
41
41
"fmt"
42
42
"log"
43
+ "strconv"
43
44
"strings"
44
45
)
45
46
46
- func genplt (ctxt * ld.Link , ldr * loader.Loader ) {
47
+ func genpltstub (ctxt * ld.Link , ldr * loader.Loader , r loader. Reloc , s loader. Sym ) ( sym loader. Sym , firstUse bool ) {
47
48
// The ppc64 ABI PLT has similar concepts to other
48
49
// architectures, but is laid out quite differently. When we
49
50
// see an R_PPC64_REL24 relocation to a dynamic symbol
@@ -92,53 +93,82 @@ func genplt(ctxt *ld.Link, ldr *loader.Loader) {
92
93
//
93
94
// This assumes "case 1" from the ABI, where the caller needs
94
95
// us to save and restore the TOC pointer.
95
- var stubs []loader.Sym
96
- for _ , s := range ctxt .Textp {
97
- relocs := ldr .Relocs (s )
98
- for i := 0 ; i < relocs .Count (); i ++ {
99
- r := relocs .At (i )
100
- if r .Type () != objabi .ElfRelocOffset + objabi .RelocType (elf .R_PPC64_REL24 ) || ldr .SymType (r .Sym ()) != sym .SDYNIMPORT {
101
- continue
102
- }
103
96
104
- // Reserve PLT entry and generate symbol
105
- // resolver
106
- addpltsym (ctxt , ldr , r .Sym ())
107
-
108
- // Generate call stub. Important to note that we're looking
109
- // up the stub using the same version as the parent symbol (s),
110
- // needed so that symtoc() will select the right .TOC. symbol
111
- // when processing the stub. In older versions of the linker
112
- // this was done by setting stub.Outer to the parent, but
113
- // if the stub has the right version initially this is not needed.
114
- n := fmt .Sprintf ("%s.%s" , ldr .SymName (s ), ldr .SymName (r .Sym ()))
115
- stub := ldr .CreateSymForUpdate (n , ldr .SymVersion (s ))
116
- if stub .Size () == 0 {
117
- stubs = append ( stubs , stub . Sym ())
118
- gencallstub (ctxt , ldr , 1 , stub , r .Sym ())
119
- }
97
+ // Reserve PLT entry and generate symbol
98
+ // resolver
99
+ addpltsym (ctxt , ldr , r .Sym ())
100
+
101
+ // Generate call stub. Important to note that we're looking
102
+ // up the stub using the same version as the parent symbol (s),
103
+ // needed so that symtoc() will select the right .TOC. symbol
104
+ // when processing the stub. In older versions of the linker
105
+ // this was done by setting stub.Outer to the parent, but
106
+ // if the stub has the right version initially this is not needed.
107
+ n := fmt .Sprintf ("%s.%s" , ldr .SymName (s ), ldr .SymName (r .Sym ()))
108
+ stub := ldr .CreateSymForUpdate (n , ldr .SymVersion (s ))
109
+ firstUse = stub .Size () == 0
110
+ if firstUse {
111
+ gencallstub (ctxt , ldr , 1 , stub , r .Sym ())
112
+ }
120
113
121
- // Update the relocation to use the call stub
122
- r .SetSym (stub .Sym ())
114
+ // Update the relocation to use the call stub
115
+ r .SetSym (stub .Sym ())
123
116
124
- // Make the symbol writeable so we can fixup toc.
125
- su := ldr .MakeSymbolUpdater (s )
126
- su .MakeWritable ()
127
- p := su .Data ()
117
+ // Make the symbol writeable so we can fixup toc.
118
+ su := ldr .MakeSymbolUpdater (s )
119
+ su .MakeWritable ()
120
+ p := su .Data ()
128
121
129
- // Check for toc restore slot (a nop), and replace with toc restore.
130
- var nop uint32
131
- if len (p ) >= int (r .Off ()+ 8 ) {
132
- nop = ctxt .Arch .ByteOrder .Uint32 (p [r .Off ()+ 4 :])
133
- }
134
- if nop != 0x60000000 {
135
- ldr .Errorf (s , "Symbol %s is missing toc restoration slot at offset %d" , ldr .SymName (s ), r .Off ()+ 4 )
122
+ // Check for toc restore slot (a nop), and replace with toc restore.
123
+ var nop uint32
124
+ if len (p ) >= int (r .Off ()+ 8 ) {
125
+ nop = ctxt .Arch .ByteOrder .Uint32 (p [r .Off ()+ 4 :])
126
+ }
127
+ if nop != 0x60000000 {
128
+ ldr .Errorf (s , "Symbol %s is missing toc restoration slot at offset %d" , ldr .SymName (s ), r .Off ()+ 4 )
129
+ }
130
+ const o1 = 0xe8410018 // ld r2,24(r1)
131
+ ctxt .Arch .ByteOrder .PutUint32 (p [r .Off ()+ 4 :], o1 )
132
+
133
+ return stub .Sym (), firstUse
134
+ }
135
+
136
+ // Scan relocs and generate PLT stubs and generate/fixup ABI defined functions created by the linker
137
+ func genstubs (ctxt * ld.Link , ldr * loader.Loader ) {
138
+ var stubs []loader.Sym
139
+ var abifuncs []loader.Sym
140
+ for _ , s := range ctxt .Textp {
141
+ relocs := ldr .Relocs (s )
142
+ for i := 0 ; i < relocs .Count (); i ++ {
143
+ if r := relocs .At (i ); r .Type () == objabi .ElfRelocOffset + objabi .RelocType (elf .R_PPC64_REL24 ) {
144
+ switch ldr .SymType (r .Sym ()) {
145
+ case sym .SDYNIMPORT :
146
+ // This call goes throught the PLT, generate and call through a PLT stub.
147
+ if sym , firstUse := genpltstub (ctxt , ldr , r , s ); firstUse {
148
+ stubs = append (stubs , sym )
149
+ }
150
+
151
+ case sym .SXREF :
152
+ // Is this an ELF ABI defined function which is (in practice)
153
+ // generated by the linker to save/restore callee save registers?
154
+ // These are defined similarly for both PPC64 ELF and ELFv2.
155
+ targName := ldr .SymName (r .Sym ())
156
+ if strings .HasPrefix (targName , "_save" ) || strings .HasPrefix (targName , "_rest" ) {
157
+ if sym , firstUse := rewriteABIFuncReloc (ctxt , ldr , targName , r ); firstUse {
158
+ abifuncs = append (abifuncs , sym )
159
+ }
160
+ }
161
+ }
136
162
}
137
- const o1 = 0xe8410018 // ld r2,24(r1)
138
- ctxt .Arch .ByteOrder .PutUint32 (p [r .Off ()+ 4 :], o1 )
139
163
}
140
164
}
141
- // Put call stubs at the beginning (instead of the end).
165
+
166
+ // Append any usage of the go versions of ELF save/restore
167
+ // functions to the end of the callstub list to minimize
168
+ // chances a trampoline might be needed.
169
+ stubs = append (stubs , abifuncs ... )
170
+
171
+ // Put stubs at the beginning (instead of the end).
142
172
// So when resolving the relocations to calls to the stubs,
143
173
// the addresses are known and trampolines can be inserted
144
174
// when necessary.
@@ -202,13 +232,74 @@ func genaddmoduledata(ctxt *ld.Link, ldr *loader.Loader) {
202
232
o (0x4e800020 )
203
233
}
204
234
235
+ // Rewrite ELF (v1 or v2) calls to _savegpr0_n, _savegpr1_n, _savefpr_n, _restfpr_n, _savevr_m, or
236
+ // _restvr_m (14<=n<=31, 20<=m<=31). Redirect them to runtime.elf_restgpr0+(n-14)*4,
237
+ // runtime.elf_restvr+(m-20)*8, and similar.
238
+ //
239
+ // These functions are defined in the ELFv2 ABI (generated when using gcc -Os option) to save and
240
+ // restore callee-saved registers (as defined in the PPC64 ELF ABIs) from registers n or m to 31 of
241
+ // the named type. R12 and R0 are sometimes used in exceptional ways described in the ABI.
242
+ //
243
+ // Final note, this is only needed when linking internally. The external linker will generate these
244
+ // functions if they are used.
245
+ func rewriteABIFuncReloc (ctxt * ld.Link , ldr * loader.Loader , tname string , r loader.Reloc ) (sym loader.Sym , firstUse bool ) {
246
+ s := strings .Split (tname , "_" )
247
+ // A valid call will split like {"", "savegpr0", "20"}
248
+ if len (s ) != 3 {
249
+ return 0 , false // Not an abi func.
250
+ }
251
+ minReg := 14 // _savegpr0_{n}, _savegpr1_{n}, _savefpr_{n}, 14 <= n <= 31
252
+ offMul := 4 // 1 instruction per register op.
253
+ switch s [1 ] {
254
+ case "savegpr0" , "savegpr1" , "savefpr" :
255
+ case "restgpr0" , "restgpr1" , "restfpr" :
256
+ case "savevr" , "restvr" :
257
+ minReg = 20 // _savevr_{n} or _restvr_{n}, 20 <= n <= 31
258
+ offMul = 8 // 2 instructions per register op.
259
+ default :
260
+ return 0 , false // Not an abi func
261
+ }
262
+ n , e := strconv .Atoi (s [2 ])
263
+ if e != nil || n < minReg || n > 31 || r .Add () != 0 {
264
+ return 0 , false // Invalid register number, or non-zero addend. Not an abi func.
265
+ }
266
+
267
+ // tname is a valid relocation to an ABI defined register save/restore function. Re-relocate
268
+ // them to a go version of these functions in runtime/asm_ppc64x.s
269
+ ts := ldr .LookupOrCreateSym ("runtime.elf_" + s [1 ], 0 )
270
+ r .SetSym (ts )
271
+ r .SetAdd (int64 ((n - minReg ) * offMul ))
272
+ firstUse = ! ldr .AttrReachable (ts )
273
+ if firstUse {
274
+ ldr .SetAttrReachable (ts , true )
275
+ // This function only becomes reachable now. It has been dropped from
276
+ // the text section (it was unreachable until now), it needs included.
277
+ //
278
+ // Similarly, TOC regeneration should not happen for these functions,
279
+ // remove it from this save/restore function.
280
+ if ldr .AttrShared (ts ) {
281
+ sb := ldr .MakeSymbolUpdater (ts )
282
+ sb .SetData (sb .Data ()[8 :])
283
+ sb .SetSize (sb .Size () - 8 )
284
+ relocs := sb .Relocs ()
285
+ // Only one PCREL reloc to .TOC. should be present.
286
+ if relocs .Count () != 1 {
287
+ log .Fatalf ("Unexpected number of relocs in %s\n " , ldr .SymName (ts ))
288
+ }
289
+ sb .ResetRelocs ()
290
+
291
+ }
292
+ }
293
+ return ts , firstUse
294
+ }
295
+
205
296
func gentext (ctxt * ld.Link , ldr * loader.Loader ) {
206
297
if ctxt .DynlinkingGo () {
207
298
genaddmoduledata (ctxt , ldr )
208
299
}
209
300
210
301
if ctxt .LinkMode == ld .LinkInternal {
211
- genplt (ctxt , ldr )
302
+ genstubs (ctxt , ldr )
212
303
}
213
304
}
214
305
@@ -863,6 +954,13 @@ func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, ta
863
954
o1 = uint32 (0x3c000000 ) | 12 << 21 // lis r12,targetaddr hi
864
955
o2 = uint32 (0x38000000 ) | 12 << 21 | 12 << 16 // addi r12,r12,targetaddr lo
865
956
957
+ // ELFv2 save/restore functions use R0/R12 in special ways, therefore trampolines
958
+ // as generated here will not always work correctly.
959
+ if strings .HasPrefix (ldr .SymName (target ), "runtime.elf_" ) {
960
+ log .Fatalf ("Internal linker does not support trampolines to ELFv2 ABI" +
961
+ " register save/restore function %s" , ldr .SymName (target ))
962
+ }
963
+
866
964
t := ldr .SymValue (target )
867
965
if t == 0 || r2Valid (ctxt ) || ctxt .IsExternal () {
868
966
// Target address is unknown, generate relocations
0 commit comments