1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package s390x
32
33 import (
34 "cmd/internal/objabi"
35 "cmd/internal/sys"
36 "cmd/link/internal/ld"
37 "cmd/link/internal/loader"
38 "cmd/link/internal/sym"
39 "debug/elf"
40 "log"
41 )
42
43
44
45
46
47
48
49
50
51
52
53 func gentext(ctxt *ld.Link, ldr *loader.Loader) {
54 initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
55 if initfunc == nil {
56 return
57 }
58
59
60 initfunc.AddUint8(0xc0)
61 initfunc.AddUint8(0x20)
62 initfunc.AddSymRef(ctxt.Arch, ctxt.Moduledata, 6, objabi.R_PCREL, 4)
63 r1 := initfunc.Relocs()
64 ldr.SetRelocVariant(initfunc.Sym(), r1.Count()-1, sym.RV_390_DBL)
65
66
67 initfunc.AddUint8(0xc0)
68 initfunc.AddUint8(0xf4)
69 initfunc.AddSymRef(ctxt.Arch, addmoduledata, 6, objabi.R_CALL, 4)
70 r2 := initfunc.Relocs()
71 ldr.SetRelocVariant(initfunc.Sym(), r2.Count()-1, sym.RV_390_DBL)
72
73
74 initfunc.AddUint32(ctxt.Arch, 0)
75 }
76
77 func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
78 targ := r.Sym()
79 var targType sym.SymKind
80 if targ != 0 {
81 targType = ldr.SymType(targ)
82 }
83
84 switch r.Type() {
85 default:
86 if r.Type() >= objabi.ElfRelocOffset {
87 ldr.Errorf(s, "unexpected relocation type %d", r.Type())
88 return false
89 }
90
91
92 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_12),
93 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT12):
94 ldr.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type()-objabi.ElfRelocOffset)
95 return false
96
97 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_8),
98 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_16),
99 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_32),
100 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_64):
101 if targType == sym.SDYNIMPORT {
102 ldr.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", ldr.SymName(targ))
103 }
104 su := ldr.MakeSymbolUpdater(s)
105 su.SetRelocType(rIdx, objabi.R_ADDR)
106 if target.IsPIE() && target.IsInternal() {
107
108
109
110 break
111 }
112 return true
113
114 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16),
115 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32),
116 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC64):
117 if targType == sym.SDYNIMPORT {
118 ldr.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", ldr.SymName(targ))
119 }
120 if targType == 0 || targType == sym.SXREF {
121 ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
122 }
123 su := ldr.MakeSymbolUpdater(s)
124 su.SetRelocType(rIdx, objabi.R_PCREL)
125 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
126 return true
127
128 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT16),
129 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT32),
130 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT64):
131 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
132 return true
133
134 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT16DBL),
135 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32DBL):
136 su := ldr.MakeSymbolUpdater(s)
137 su.SetRelocType(rIdx, objabi.R_PCREL)
138 ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
139 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
140 if targType == sym.SDYNIMPORT {
141 addpltsym(target, ldr, syms, targ)
142 r.SetSym(syms.PLT)
143 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
144 }
145 return true
146
147 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32),
148 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT64):
149 su := ldr.MakeSymbolUpdater(s)
150 su.SetRelocType(rIdx, objabi.R_PCREL)
151 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
152 if targType == sym.SDYNIMPORT {
153 addpltsym(target, ldr, syms, targ)
154 r.SetSym(syms.PLT)
155 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
156 }
157 return true
158
159 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_COPY):
160 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
161 return false
162
163 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GLOB_DAT):
164 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
165 return false
166
167 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_JMP_SLOT):
168 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
169 return false
170
171 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_RELATIVE):
172 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset)
173 return false
174
175 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTOFF):
176 if targType == sym.SDYNIMPORT {
177 ldr.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", ldr.SymName(targ))
178 }
179 su := ldr.MakeSymbolUpdater(s)
180 su.SetRelocType(rIdx, objabi.R_GOTOFF)
181 return true
182
183 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPC):
184 su := ldr.MakeSymbolUpdater(s)
185 su.SetRelocType(rIdx, objabi.R_PCREL)
186 r.SetSym(syms.GOT)
187 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
188 return true
189
190 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16DBL),
191 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32DBL):
192 su := ldr.MakeSymbolUpdater(s)
193 su.SetRelocType(rIdx, objabi.R_PCREL)
194 ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
195 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
196 if targType == sym.SDYNIMPORT {
197 ldr.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", ldr.SymName(targ))
198 }
199 return true
200
201 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPCDBL):
202 su := ldr.MakeSymbolUpdater(s)
203 su.SetRelocType(rIdx, objabi.R_PCREL)
204 ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
205 r.SetSym(syms.GOT)
206 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz()))
207 return true
208
209 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTENT):
210 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_390_GLOB_DAT))
211 su := ldr.MakeSymbolUpdater(s)
212 su.SetRelocType(rIdx, objabi.R_PCREL)
213 ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL)
214 r.SetSym(syms.GOT)
215 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ))+int64(r.Siz()))
216 return true
217 }
218
219
220 relocs := ldr.Relocs(s)
221 r = relocs.At(rIdx)
222
223 switch r.Type() {
224 case objabi.R_CALL, objabi.R_PCRELDBL:
225 if targType != sym.SDYNIMPORT {
226
227 return true
228 }
229 if target.IsExternal() {
230
231 return true
232 }
233
234 addpltsym(target, ldr, syms, targ)
235 su := ldr.MakeSymbolUpdater(s)
236 su.SetRelocSym(rIdx, syms.PLT)
237 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
238 return true
239
240 case objabi.R_ADDR:
241 if ldr.SymType(s).IsText() && target.IsElf() {
242
243
244
245 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_390_GLOB_DAT))
246 su := ldr.MakeSymbolUpdater(s)
247 su.SetRelocSym(rIdx, syms.GOT)
248 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
249 return true
250 }
251
252
253 if target.IsPIE() && target.IsInternal() {
254
255
256
257
258
259
260
261
262
263 switch ldr.SymName(s) {
264 case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
265 return false
266 }
267 } else {
268
269
270
271
272
273
274 if t := ldr.SymType(s); !t.IsDATA() && !t.IsRODATA() {
275 break
276 }
277 }
278
279 if target.IsElf() {
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297 rela := ldr.MakeSymbolUpdater(syms.Rela)
298 rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
299 if r.Siz() == 8 {
300 rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_390_RELATIVE)))
301 } else {
302 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
303 }
304 rela.AddAddrPlus(target.Arch, targ, r.Add())
305
306
307
308
309 return true
310 }
311 }
312
313
314 return targType != sym.SDYNIMPORT
315 }
316
317 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
318 out.Write64(uint64(sectoff))
319
320 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
321 siz := r.Size
322 switch r.Type {
323 default:
324 return false
325 case objabi.R_TLS_LE:
326 switch siz {
327 default:
328 return false
329 case 4:
330
331 out.Write64(uint64(elf.R_390_TLS_LE32) | uint64(elfsym)<<32)
332 case 8:
333
334 out.Write64(uint64(elf.R_390_TLS_LE64) | uint64(elfsym)<<32)
335 }
336 case objabi.R_TLS_IE:
337 switch siz {
338 default:
339 return false
340 case 4:
341 out.Write64(uint64(elf.R_390_TLS_IEENT) | uint64(elfsym)<<32)
342 }
343 case objabi.R_ADDR, objabi.R_DWARFSECREF:
344 switch siz {
345 default:
346 return false
347 case 4:
348 out.Write64(uint64(elf.R_390_32) | uint64(elfsym)<<32)
349 case 8:
350 out.Write64(uint64(elf.R_390_64) | uint64(elfsym)<<32)
351 }
352 case objabi.R_GOTPCREL:
353 if siz == 4 {
354 out.Write64(uint64(elf.R_390_GOTENT) | uint64(elfsym)<<32)
355 } else {
356 return false
357 }
358 case objabi.R_PCREL, objabi.R_PCRELDBL, objabi.R_CALL:
359 elfrel := elf.R_390_NONE
360 rVariant := ldr.RelocVariant(s, ri)
361 isdbl := rVariant&sym.RV_TYPE_MASK == sym.RV_390_DBL
362
363
364 switch r.Type {
365 case objabi.R_PCRELDBL, objabi.R_CALL:
366 isdbl = true
367 }
368 if ldr.SymType(r.Xsym) == sym.SDYNIMPORT && (ldr.SymElfType(r.Xsym) == elf.STT_FUNC || r.Type == objabi.R_CALL) {
369 if isdbl {
370 switch siz {
371 case 2:
372 elfrel = elf.R_390_PLT16DBL
373 case 4:
374 elfrel = elf.R_390_PLT32DBL
375 }
376 } else {
377 switch siz {
378 case 4:
379 elfrel = elf.R_390_PLT32
380 case 8:
381 elfrel = elf.R_390_PLT64
382 }
383 }
384 } else {
385 if isdbl {
386 switch siz {
387 case 2:
388 elfrel = elf.R_390_PC16DBL
389 case 4:
390 elfrel = elf.R_390_PC32DBL
391 }
392 } else {
393 switch siz {
394 case 2:
395 elfrel = elf.R_390_PC16
396 case 4:
397 elfrel = elf.R_390_PC32
398 case 8:
399 elfrel = elf.R_390_PC64
400 }
401 }
402 }
403 if elfrel == elf.R_390_NONE {
404 return false
405 }
406 out.Write64(uint64(elfrel) | uint64(elfsym)<<32)
407 }
408
409 out.Write64(uint64(r.Xadd))
410 return true
411 }
412
413 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
414 if plt.Size() == 0 {
415
416 plt.AddUint8(0xe3)
417 plt.AddUint8(0x10)
418 plt.AddUint8(0xf0)
419 plt.AddUint8(0x38)
420 plt.AddUint8(0x00)
421 plt.AddUint8(0x24)
422
423 plt.AddUint8(0xc0)
424 plt.AddUint8(0x10)
425 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 6, objabi.R_PCRELDBL, 4)
426
427 plt.AddUint8(0xd2)
428 plt.AddUint8(0x07)
429 plt.AddUint8(0xf0)
430 plt.AddUint8(0x30)
431 plt.AddUint8(0x10)
432 plt.AddUint8(0x08)
433
434 plt.AddUint8(0xe3)
435 plt.AddUint8(0x10)
436 plt.AddUint8(0x10)
437 plt.AddUint8(0x10)
438 plt.AddUint8(0x00)
439 plt.AddUint8(0x04)
440
441 plt.AddUint8(0x07)
442 plt.AddUint8(0xf1)
443
444 plt.AddUint8(0x07)
445 plt.AddUint8(0x00)
446
447 plt.AddUint8(0x07)
448 plt.AddUint8(0x00)
449
450 plt.AddUint8(0x07)
451 plt.AddUint8(0x00)
452
453
454 gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0)
455
456 gotplt.AddUint64(ctxt.Arch, 0)
457 gotplt.AddUint64(ctxt.Arch, 0)
458 }
459 }
460
461 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
462 return false
463 }
464
465 func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (o int64, nExtReloc int, ok bool) {
466 return val, 0, false
467 }
468
469 func archrelocvariant(target *ld.Target, ldr *loader.Loader, r loader.Reloc, rv sym.RelocVariant, s loader.Sym, t int64, p []byte) int64 {
470 switch rv & sym.RV_TYPE_MASK {
471 default:
472 ldr.Errorf(s, "unexpected relocation variant %d", rv)
473 return t
474
475 case sym.RV_NONE:
476 return t
477
478 case sym.RV_390_DBL:
479 if t&1 != 0 {
480 ldr.Errorf(s, "%s+%v is not 2-byte aligned", ldr.SymName(r.Sym()), ldr.SymValue(r.Sym()))
481 }
482 return t >> 1
483 }
484 }
485
486 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
487 if ldr.SymPlt(s) >= 0 {
488 return
489 }
490
491 ld.Adddynsym(ldr, target, syms, s)
492
493 if target.IsElf() {
494 plt := ldr.MakeSymbolUpdater(syms.PLT)
495 gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
496 rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
497 if plt.Size() == 0 {
498 panic("plt is not set up")
499 }
500
501
502 plt.AddUint8(0xc0)
503 plt.AddUint8(0x10)
504 plt.AddPCRelPlus(target.Arch, gotplt.Sym(), gotplt.Size()+6)
505 pltrelocs := plt.Relocs()
506 ldr.SetRelocVariant(plt.Sym(), pltrelocs.Count()-1, sym.RV_390_DBL)
507
508
509 gotplt.AddAddrPlus(target.Arch, plt.Sym(), plt.Size()+8)
510
511 plt.AddUint8(0xe3)
512 plt.AddUint8(0x10)
513 plt.AddUint8(0x10)
514 plt.AddUint8(0x00)
515 plt.AddUint8(0x00)
516 plt.AddUint8(0x04)
517
518 plt.AddUint8(0x07)
519 plt.AddUint8(0xf1)
520
521 plt.AddUint8(0x0d)
522 plt.AddUint8(0x10)
523
524 plt.AddUint8(0xe3)
525 plt.AddUint8(0x10)
526 plt.AddUint8(0x10)
527 plt.AddUint8(0x0c)
528 plt.AddUint8(0x00)
529 plt.AddUint8(0x14)
530
531 plt.AddUint8(0xc0)
532 plt.AddUint8(0xf4)
533
534 plt.AddUint32(target.Arch, uint32(-((plt.Size() - 2) >> 1)))
535
536 plt.AddUint32(target.Arch, uint32(rela.Size()))
537
538
539 rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
540
541 sDynid := ldr.SymDynid(s)
542 rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_390_JMP_SLOT)))
543 rela.AddUint64(target.Arch, 0)
544
545 ldr.SetPlt(s, int32(plt.Size()-32))
546
547 } else {
548 ldr.Errorf(s, "addpltsym: unsupported binary format")
549 }
550 }
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567 func tlsIEtoLE(P []byte, off, size int) {
568
569
570
571
572 if off < 2 {
573 log.Fatalf("R_390_TLS_IEENT relocation at offset %d is too small", off)
574 }
575
576
577
578 if P[off-2] != 0xc0 || P[off-1]&0x0f != 0x00 {
579 log.Fatalf("R_390_TLS_IEENT relocation not preceded by LARL instruction: %02x %02x", P[off-2], P[off-1])
580 }
581
582
583 reg := P[off-1] >> 4
584
585
586
587 P[off-1] = (reg << 4) | 0x01
588
589
590
591
592
593
594 P[off+4] = 0x07
595 P[off+5] = 0x00
596 P[off+6] = 0x07
597 P[off+7] = 0x00
598 P[off+8] = 0x07
599 P[off+9] = 0x00
600 }
601
View as plain text