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 }
402
403 return false
404 }
405
406 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
407 out.Write64(uint64(sectoff))
408
409 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
410 siz := r.Size
411 switch r.Type {
412 default:
413 return false
414 case objabi.R_ADDR, objabi.R_DWARFSECREF:
415 if siz == 4 {
416 out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32)
417 } else if siz == 8 {
418 out.Write64(uint64(elf.R_X86_64_64) | uint64(elfsym)<<32)
419 } else {
420 return false
421 }
422 case objabi.R_TLS_LE:
423 if siz == 4 {
424 out.Write64(uint64(elf.R_X86_64_TPOFF32) | uint64(elfsym)<<32)
425 } else {
426 return false
427 }
428 case objabi.R_TLS_IE:
429 if siz == 4 {
430 out.Write64(uint64(elf.R_X86_64_GOTTPOFF) | uint64(elfsym)<<32)
431 } else {
432 return false
433 }
434 case objabi.R_CALL:
435 if siz == 4 {
436 if ldr.SymType(r.Xsym) == sym.SDYNIMPORT {
437 out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
438 } else {
439 out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
440 }
441 } else {
442 return false
443 }
444 case objabi.R_PCREL:
445 if siz == 4 {
446 if ldr.SymType(r.Xsym) == sym.SDYNIMPORT && ldr.SymElfType(r.Xsym) == elf.STT_FUNC {
447 out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
448 } else {
449 out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
450 }
451 } else {
452 return false
453 }
454 case objabi.R_GOTPCREL:
455 if siz == 4 {
456 out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
457 } else {
458 return false
459 }
460 }
461
462 out.Write64(uint64(r.Xadd))
463 return true
464 }
465
466 func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
467 var v uint32
468
469 rs := r.Xsym
470 rt := r.Type
471
472 if !ldr.SymType(s).IsDWARF() {
473 if ldr.SymDynid(rs) < 0 {
474 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))
475 return false
476 }
477
478 v = uint32(ldr.SymDynid(rs))
479 v |= 1 << 27
480 } else {
481 v = uint32(ldr.SymSect(rs).Extnum)
482 if v == 0 {
483 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))
484 return false
485 }
486 }
487
488 switch rt {
489 default:
490 return false
491
492 case objabi.R_ADDR:
493 v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
494
495 case objabi.R_CALL:
496 v |= 1 << 24
497 v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
498
499
500 case objabi.R_PCREL:
501 v |= 1 << 24
502 v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
503 case objabi.R_GOTPCREL:
504 v |= 1 << 24
505 v |= ld.MACHO_X86_64_RELOC_GOT_LOAD << 28
506 }
507
508 switch r.Size {
509 default:
510 return false
511
512 case 1:
513 v |= 0 << 25
514
515 case 2:
516 v |= 1 << 25
517
518 case 4:
519 v |= 2 << 25
520
521 case 8:
522 v |= 3 << 25
523 }
524
525 out.Write32(uint32(sectoff))
526 out.Write32(v)
527 return true
528 }
529
530 func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
531 var v uint32
532
533 rs := r.Xsym
534 rt := r.Type
535
536 if ldr.SymDynid(rs) < 0 {
537 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))
538 return false
539 }
540
541 out.Write32(uint32(sectoff))
542 out.Write32(uint32(ldr.SymDynid(rs)))
543
544 switch rt {
545 default:
546 return false
547
548 case objabi.R_DWARFSECREF:
549 v = ld.IMAGE_REL_AMD64_SECREL
550
551 case objabi.R_ADDR:
552 if r.Size == 8 {
553 v = ld.IMAGE_REL_AMD64_ADDR64
554 } else {
555 v = ld.IMAGE_REL_AMD64_ADDR32
556 }
557
558 case objabi.R_PEIMAGEOFF:
559 v = ld.IMAGE_REL_AMD64_ADDR32NB
560
561 case objabi.R_CALL,
562 objabi.R_PCREL:
563 v = ld.IMAGE_REL_AMD64_REL32
564 }
565
566 out.Write16(uint16(v))
567
568 return true
569 }
570
571 func archreloc(*ld.Target, *loader.Loader, *ld.ArchSyms, loader.Reloc, loader.Sym, int64) (int64, int, bool) {
572 return -1, 0, false
573 }
574
575 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
576 log.Fatalf("unexpected relocation variant")
577 return -1
578 }
579
580 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
581 if plt.Size() == 0 {
582
583 plt.AddUint8(0xff)
584
585 plt.AddUint8(0x35)
586 plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 8)
587
588
589 plt.AddUint8(0xff)
590
591 plt.AddUint8(0x25)
592 plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 16)
593
594
595 plt.AddUint32(ctxt.Arch, 0x00401f0f)
596
597
598 got.AddAddrPlus(ctxt.Arch, dynamic, 0)
599
600 got.AddUint64(ctxt.Arch, 0)
601 got.AddUint64(ctxt.Arch, 0)
602 }
603 }
604
605 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
606 if ldr.SymPlt(s) >= 0 {
607 return
608 }
609
610 ld.Adddynsym(ldr, target, syms, s)
611
612 if target.IsElf() {
613 plt := ldr.MakeSymbolUpdater(syms.PLT)
614 got := ldr.MakeSymbolUpdater(syms.GOTPLT)
615 rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
616 if plt.Size() == 0 {
617 panic("plt is not set up")
618 }
619
620
621 plt.AddUint8(0xff)
622
623 plt.AddUint8(0x25)
624 plt.AddPCRelPlus(target.Arch, got.Sym(), got.Size())
625
626
627 got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
628
629
630 plt.AddUint8(0x68)
631
632 plt.AddUint32(target.Arch, uint32((got.Size()-24-8)/8))
633
634
635 plt.AddUint8(0xe9)
636
637 plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
638
639
640 rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
641
642 sDynid := ldr.SymDynid(s)
643 rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
644 rela.AddUint64(target.Arch, 0)
645
646 ldr.SetPlt(s, int32(plt.Size()-16))
647 } else if target.IsDarwin() {
648 ld.AddGotSym(target, ldr, syms, s, 0)
649
650 sDynid := ldr.SymDynid(s)
651 lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
652 lep.AddUint32(target.Arch, uint32(sDynid))
653
654 plt := ldr.MakeSymbolUpdater(syms.PLT)
655 ldr.SetPlt(s, int32(plt.Size()))
656
657
658 plt.AddUint8(0xff)
659 plt.AddUint8(0x25)
660 plt.AddPCRelPlus(target.Arch, syms.GOT, int64(ldr.SymGot(s)))
661 } else {
662 ldr.Errorf(s, "addpltsym: unsupported binary format")
663 }
664 }
665
666 func tlsIEtoLE(P []byte, off, size int) {
667
668
669
670
671
672
673
674 if off < 3 {
675 log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction")
676 }
677 op := P[off-3 : off]
678 reg := op[2] >> 3
679
680 if op[1] == 0x8b || reg == 4 {
681
682 if op[0] == 0x4c {
683 op[0] = 0x49
684 } else if size == 4 && op[0] == 0x44 {
685 op[0] = 0x41
686 }
687 if op[1] == 0x8b {
688 op[1] = 0xc7
689 } else {
690 op[1] = 0x81
691 }
692 op[2] = 0xc0 | reg
693 } else {
694
695
696
697
698 log.Fatalf("expected TLS IE op to be MOVQ, got %v", op)
699 }
700 }
701
View as plain text