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 amd64
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 func gentext(ctxt *ld.Link, ldr *loader.Loader) {
44 initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
45 if initfunc == nil {
46 return
47 }
48
49 o := func(op ...uint8) {
50 for _, op1 := range op {
51 initfunc.AddUint8(op1)
52 }
53 }
54
55
56
57
58 o(0x48, 0x8d, 0x3d)
59 initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 0)
60
61
62 o(0xe8)
63 initfunc.AddSymRef(ctxt.Arch, addmoduledata, 0, objabi.R_CALL, 4)
64
65 o(0xc3)
66 }
67
68 func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
69 targ := r.Sym()
70 var targType sym.SymKind
71 if targ != 0 {
72 targType = ldr.SymType(targ)
73 }
74
75 switch rt := r.Type(); rt {
76 default:
77 if rt >= objabi.ElfRelocOffset {
78 ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
79 return false
80 }
81
82
83 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
84 if targType == sym.SDYNIMPORT {
85 ldr.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", ldr.SymName(targ))
86 }
87 if targType == 0 || targType == sym.SXREF {
88 ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
89 }
90 su := ldr.MakeSymbolUpdater(s)
91 su.SetRelocType(rIdx, objabi.R_PCREL)
92 su.SetRelocAdd(rIdx, r.Add()+4)
93 return true
94
95 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
96 if targType == sym.SDYNIMPORT {
97 ldr.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", ldr.SymName(targ))
98 }
99 if targType == 0 || targType == sym.SXREF {
100 ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
101 }
102 su := ldr.MakeSymbolUpdater(s)
103 su.SetRelocType(rIdx, objabi.R_PCREL)
104 su.SetRelocAdd(rIdx, r.Add()+8)
105 return true
106
107 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
108 su := ldr.MakeSymbolUpdater(s)
109 su.SetRelocType(rIdx, objabi.R_PCREL)
110 su.SetRelocAdd(rIdx, r.Add()+4)
111 if targType == sym.SDYNIMPORT {
112 addpltsym(target, ldr, syms, targ)
113 su.SetRelocSym(rIdx, syms.PLT)
114 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
115 }
116
117 return true
118
119 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL),
120 objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX),
121 objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX):
122 su := ldr.MakeSymbolUpdater(s)
123 if targType != sym.SDYNIMPORT {
124
125 sData := ldr.Data(s)
126 if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
127 su.MakeWritable()
128
129 writeableData := su.Data()
130 writeableData[r.Off()-2] = 0x8d
131 su.SetRelocType(rIdx, objabi.R_PCREL)
132 su.SetRelocAdd(rIdx, r.Add()+4)
133 return true
134 }
135 }
136
137
138
139 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_X86_64_GLOB_DAT))
140
141 su.SetRelocType(rIdx, objabi.R_PCREL)
142 su.SetRelocSym(rIdx, syms.GOT)
143 su.SetRelocAdd(rIdx, r.Add()+4+int64(ldr.SymGot(targ)))
144 return true
145
146 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
147 if targType == sym.SDYNIMPORT {
148 ldr.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", ldr.SymName(targ))
149 }
150 su := ldr.MakeSymbolUpdater(s)
151 su.SetRelocType(rIdx, objabi.R_ADDR)
152 if target.IsPIE() && target.IsInternal() {
153
154
155
156 break
157 }
158 return true
159
160
161 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
162 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
163 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
164 su := ldr.MakeSymbolUpdater(s)
165 su.SetRelocType(rIdx, objabi.R_ADDR)
166
167 if targType == sym.SDYNIMPORT {
168 ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
169 }
170 if target.IsPIE() && target.IsInternal() {
171
172
173
174 if rt == objabi.MachoRelocOffset+ld.MACHO_X86_64_RELOC_UNSIGNED*2 {
175 break
176 } else {
177
178
179 ldr.Errorf(s, "unsupported relocation for PIE: %v", rt)
180 }
181 }
182 return true
183
184 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SUBTRACTOR*2 + 0:
185
186
187
188
189
190
191
192
193
194
195
196
197
198 su := ldr.MakeSymbolUpdater(s)
199 outer, off := ld.FoldSubSymbolOffset(ldr, targ)
200 if outer != s {
201 ldr.Errorf(s, "unsupported X86_64_RELOC_SUBTRACTOR reloc: target %s, outer %s",
202 ldr.SymName(targ), ldr.SymName(outer))
203 break
204 }
205 relocs := su.Relocs()
206 if rIdx+1 >= relocs.Count() || relocs.At(rIdx+1).Type() != objabi.MachoRelocOffset+ld.MACHO_X86_64_RELOC_UNSIGNED*2+0 || relocs.At(rIdx+1).Off() != r.Off() {
207 ldr.Errorf(s, "unexpected X86_64_RELOC_SUBTRACTOR reloc, must be followed by X86_64_RELOC_UNSIGNED at the same offset: %d %v %d", rIdx, relocs.At(rIdx+1).Type(), relocs.At(rIdx+1).Off())
208 }
209
210 su.SetRelocType(rIdx+1, objabi.R_PCREL)
211 su.SetRelocAdd(rIdx+1, r.Add()+int64(r.Off())-off)
212
213 su.SetRelocSiz(rIdx, 0)
214 return true
215
216 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
217 if targType == sym.SDYNIMPORT {
218 addpltsym(target, ldr, syms, targ)
219 su := ldr.MakeSymbolUpdater(s)
220 su.SetRelocSym(rIdx, syms.PLT)
221 su.SetRelocType(rIdx, objabi.R_PCREL)
222 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
223 return true
224 }
225 fallthrough
226
227 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
228 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
229 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
230 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
231 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
232 su := ldr.MakeSymbolUpdater(s)
233 su.SetRelocType(rIdx, objabi.R_PCREL)
234
235 if targType == sym.SDYNIMPORT {
236 ldr.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", ldr.SymName(targ))
237 }
238 return true
239
240 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
241 if targType != sym.SDYNIMPORT {
242
243
244 sdata := ldr.Data(s)
245 if r.Off() < 2 || sdata[r.Off()-2] != 0x8b {
246 ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
247 return false
248 }
249
250 su := ldr.MakeSymbolUpdater(s)
251 su.MakeWritable()
252 sdata = su.Data()
253 sdata[r.Off()-2] = 0x8d
254 su.SetRelocType(rIdx, objabi.R_PCREL)
255 return true
256 }
257 fallthrough
258
259 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
260 if targType != sym.SDYNIMPORT {
261 ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
262 }
263 ld.AddGotSym(target, ldr, syms, targ, 0)
264 su := ldr.MakeSymbolUpdater(s)
265 su.SetRelocType(rIdx, objabi.R_PCREL)
266 su.SetRelocSym(rIdx, syms.GOT)
267 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
268 return true
269 }
270
271
272 relocs := ldr.Relocs(s)
273 r = relocs.At(rIdx)
274
275 switch r.Type() {
276 case objabi.R_CALL:
277 if targType != sym.SDYNIMPORT {
278
279 return true
280 }
281 if target.IsExternal() {
282
283 return true
284 }
285
286
287 addpltsym(target, ldr, syms, targ)
288 su := ldr.MakeSymbolUpdater(s)
289 su.SetRelocSym(rIdx, syms.PLT)
290 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
291 return true
292
293 case objabi.R_PCREL:
294 if targType == sym.SDYNIMPORT && ldr.SymType(s).IsText() && target.IsDarwin() {
295
296
297 if r.Add() != 0 {
298 ldr.Errorf(s, "unexpected nonzero addend for dynamic symbol %s", ldr.SymName(targ))
299 return false
300 }
301 su := ldr.MakeSymbolUpdater(s)
302 if r.Off() >= 2 && su.Data()[r.Off()-2] == 0x8d {
303 su.MakeWritable()
304 su.Data()[r.Off()-2] = 0x8b
305 if target.IsInternal() {
306 ld.AddGotSym(target, ldr, syms, targ, 0)
307 su.SetRelocSym(rIdx, syms.GOT)
308 su.SetRelocAdd(rIdx, int64(ldr.SymGot(targ)))
309 } else {
310 su.SetRelocType(rIdx, objabi.R_GOTPCREL)
311 }
312 return true
313 }
314 ldr.Errorf(s, "unexpected R_PCREL reloc for dynamic symbol %s: not preceded by LEAQ instruction", ldr.SymName(targ))
315 }
316
317 case objabi.R_ADDR:
318 if ldr.SymType(s).IsText() && target.IsElf() {
319 su := ldr.MakeSymbolUpdater(s)
320 if target.IsSolaris() {
321 addpltsym(target, ldr, syms, targ)
322 su.SetRelocSym(rIdx, syms.PLT)
323 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
324 return true
325 }
326
327
328
329 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_X86_64_GLOB_DAT))
330
331 su.SetRelocSym(rIdx, syms.GOT)
332 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
333 return true
334 }
335
336
337 if target.IsPIE() && target.IsInternal() {
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 switch ldr.SymName(s) {
370 case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
371 return false
372 }
373 } else {
374
375
376
377
378
379
380 if t := ldr.SymType(s); !t.IsDATA() && !t.IsRODATA() {
381 break
382 }
383 }
384
385 if target.IsElf() {
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403 rela := ldr.MakeSymbolUpdater(syms.Rela)
404 rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
405 if r.Siz() == 8 {
406 rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
407 } else {
408 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
409 }
410 rela.AddAddrPlus(target.Arch, targ, int64(r.Add()))
411
412
413
414
415 return true
416 }
417
418 if target.IsDarwin() {
419
420
421
422 ld.MachoAddRebase(s, int64(r.Off()))
423
424
425
426
427 return true
428 }
429 case objabi.R_GOTPCREL:
430 if target.IsExternal() {
431
432 return true
433 }
434
435
436 }
437
438 return false
439 }
440
441 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
442 out.Write64(uint64(sectoff))
443
444 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
445 siz := r.Size
446 switch r.Type {
447 default:
448 return false
449 case objabi.R_ADDR, objabi.R_DWARFSECREF:
450 if siz == 4 {
451 out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32)
452 } else if siz == 8 {
453 out.Write64(uint64(elf.R_X86_64_64) | uint64(elfsym)<<32)
454 } else {
455 return false
456 }
457 case objabi.R_TLS_LE:
458 if siz == 4 {
459 out.Write64(uint64(elf.R_X86_64_TPOFF32) | uint64(elfsym)<<32)
460 } else {
461 return false
462 }
463 case objabi.R_TLS_IE:
464 if siz == 4 {
465 out.Write64(uint64(elf.R_X86_64_GOTTPOFF) | uint64(elfsym)<<32)
466 } else {
467 return false
468 }
469 case objabi.R_CALL:
470 if siz == 4 {
471 if ldr.SymType(r.Xsym) == sym.SDYNIMPORT {
472 out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
473 } else {
474 out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
475 }
476 } else {
477 return false
478 }
479 case objabi.R_PCREL:
480 if siz == 4 {
481 if ldr.SymType(r.Xsym) == sym.SDYNIMPORT && ldr.SymElfType(r.Xsym) == elf.STT_FUNC {
482 out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
483 } else {
484 out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
485 }
486 } else {
487 return false
488 }
489 case objabi.R_GOTPCREL:
490 if siz == 4 {
491 out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
492 } else {
493 return false
494 }
495 }
496
497 out.Write64(uint64(r.Xadd))
498 return true
499 }
500
501 func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
502 var v uint32
503
504 rs := r.Xsym
505 rt := r.Type
506
507 if !ldr.SymType(s).IsDWARF() {
508 if ldr.SymDynid(rs) < 0 {
509 ldr.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
510 return false
511 }
512
513 v = uint32(ldr.SymDynid(rs))
514 v |= 1 << 27
515 } else {
516 v = uint32(ldr.SymSect(rs).Extnum)
517 if v == 0 {
518 ldr.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymSect(rs).Name, ldr.SymType(rs), ldr.SymType(rs))
519 return false
520 }
521 }
522
523 switch rt {
524 default:
525 return false
526
527 case objabi.R_ADDR:
528 v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
529
530 case objabi.R_CALL:
531 v |= 1 << 24
532 v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
533
534
535 case objabi.R_PCREL:
536 v |= 1 << 24
537 v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
538 case objabi.R_GOTPCREL:
539 v |= 1 << 24
540 v |= ld.MACHO_X86_64_RELOC_GOT_LOAD << 28
541 }
542
543 switch r.Size {
544 default:
545 return false
546
547 case 1:
548 v |= 0 << 25
549
550 case 2:
551 v |= 1 << 25
552
553 case 4:
554 v |= 2 << 25
555
556 case 8:
557 v |= 3 << 25
558 }
559
560 out.Write32(uint32(sectoff))
561 out.Write32(v)
562 return true
563 }
564
565 func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
566 var v uint32
567
568 rs := r.Xsym
569 rt := r.Type
570
571 if ldr.SymDynid(rs) < 0 {
572 ldr.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
573 return false
574 }
575
576 out.Write32(uint32(sectoff))
577 out.Write32(uint32(ldr.SymDynid(rs)))
578
579 switch rt {
580 default:
581 return false
582
583 case objabi.R_DWARFSECREF:
584 v = ld.IMAGE_REL_AMD64_SECREL
585
586 case objabi.R_ADDR:
587 if r.Size == 8 {
588 v = ld.IMAGE_REL_AMD64_ADDR64
589 } else {
590 v = ld.IMAGE_REL_AMD64_ADDR32
591 }
592
593 case objabi.R_PEIMAGEOFF:
594 v = ld.IMAGE_REL_AMD64_ADDR32NB
595
596 case objabi.R_CALL,
597 objabi.R_PCREL:
598 v = ld.IMAGE_REL_AMD64_REL32
599 }
600
601 out.Write16(uint16(v))
602
603 return true
604 }
605
606 func archreloc(*ld.Target, *loader.Loader, *ld.ArchSyms, loader.Reloc, loader.Sym, int64) (int64, int, bool) {
607 return -1, 0, false
608 }
609
610 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
611 log.Fatalf("unexpected relocation variant")
612 return -1
613 }
614
615 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
616 if plt.Size() == 0 {
617
618 plt.AddUint8(0xff)
619
620 plt.AddUint8(0x35)
621 plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 8)
622
623
624 plt.AddUint8(0xff)
625
626 plt.AddUint8(0x25)
627 plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 16)
628
629
630 plt.AddUint32(ctxt.Arch, 0x00401f0f)
631
632
633 got.AddAddrPlus(ctxt.Arch, dynamic, 0)
634
635 got.AddUint64(ctxt.Arch, 0)
636 got.AddUint64(ctxt.Arch, 0)
637 }
638 }
639
640 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
641 if ldr.SymPlt(s) >= 0 {
642 return
643 }
644
645 ld.Adddynsym(ldr, target, syms, s)
646
647 if target.IsElf() {
648 plt := ldr.MakeSymbolUpdater(syms.PLT)
649 got := ldr.MakeSymbolUpdater(syms.GOTPLT)
650 rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
651 if plt.Size() == 0 {
652 panic("plt is not set up")
653 }
654
655
656 plt.AddUint8(0xff)
657
658 plt.AddUint8(0x25)
659 plt.AddPCRelPlus(target.Arch, got.Sym(), got.Size())
660
661
662 got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
663
664
665 plt.AddUint8(0x68)
666
667 plt.AddUint32(target.Arch, uint32((got.Size()-24-8)/8))
668
669
670 plt.AddUint8(0xe9)
671
672 plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
673
674
675 rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
676
677 sDynid := ldr.SymDynid(s)
678 rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
679 rela.AddUint64(target.Arch, 0)
680
681 ldr.SetPlt(s, int32(plt.Size()-16))
682 } else if target.IsDarwin() {
683 ld.AddGotSym(target, ldr, syms, s, 0)
684
685 sDynid := ldr.SymDynid(s)
686 lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
687 lep.AddUint32(target.Arch, uint32(sDynid))
688
689 plt := ldr.MakeSymbolUpdater(syms.PLT)
690 ldr.SetPlt(s, int32(plt.Size()))
691
692
693 plt.AddUint8(0xff)
694 plt.AddUint8(0x25)
695 plt.AddPCRelPlus(target.Arch, syms.GOT, int64(ldr.SymGot(s)))
696 } else {
697 ldr.Errorf(s, "addpltsym: unsupported binary format")
698 }
699 }
700
701 func tlsIEtoLE(P []byte, off, size int) {
702
703
704
705
706
707
708
709 if off < 3 {
710 log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction")
711 }
712 op := P[off-3 : off]
713 reg := op[2] >> 3
714
715 if op[1] == 0x8b || reg == 4 {
716
717 if op[0] == 0x4c {
718 op[0] = 0x49
719 } else if size == 4 && op[0] == 0x44 {
720 op[0] = 0x41
721 }
722 if op[1] == 0x8b {
723 op[1] = 0xc7
724 } else {
725 op[1] = 0x81
726 }
727 op[2] = 0xc0 | reg
728 } else {
729
730
731
732
733 log.Fatalf("expected TLS IE op to be MOVQ, got %v", op)
734 }
735 }
736
View as plain text