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