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