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 arm64
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 "fmt"
41 "log"
42 )
43
44 func gentext(ctxt *ld.Link, ldr *loader.Loader) {
45 initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
46 if initfunc == nil {
47 return
48 }
49
50 o := func(op uint32) {
51 initfunc.AddUint32(ctxt.Arch, op)
52 }
53
54
55
56
57
58 o(0x90000000)
59 o(0x91000000)
60 rel, _ := initfunc.AddRel(objabi.R_ADDRARM64)
61 rel.SetOff(0)
62 rel.SetSiz(8)
63 rel.SetSym(ctxt.Moduledata)
64
65
66
67 o(0x14000000)
68 rel2, _ := initfunc.AddRel(objabi.R_CALLARM64)
69 rel2.SetOff(8)
70 rel2.SetSiz(4)
71 rel2.SetSym(addmoduledata)
72 }
73
74 func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
75 targ := r.Sym()
76 var targType sym.SymKind
77 if targ != 0 {
78 targType = ldr.SymType(targ)
79 }
80
81 const pcrel = 1
82 switch r.Type() {
83 default:
84 if r.Type() >= objabi.ElfRelocOffset {
85 ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
86 return false
87 }
88
89
90 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL32):
91 if targType == sym.SDYNIMPORT {
92 ldr.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", ldr.SymName(targ))
93 }
94 if targType == 0 || targType == sym.SXREF {
95 ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
96 }
97 su := ldr.MakeSymbolUpdater(s)
98 su.SetRelocType(rIdx, objabi.R_PCREL)
99 su.SetRelocAdd(rIdx, r.Add()+4)
100 return true
101
102 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL64):
103 if targType == sym.SDYNIMPORT {
104 ldr.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", ldr.SymName(targ))
105 }
106 if targType == 0 || targType == sym.SXREF {
107 ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
108 }
109 su := ldr.MakeSymbolUpdater(s)
110 su.SetRelocType(rIdx, objabi.R_PCREL)
111 su.SetRelocAdd(rIdx, r.Add()+8)
112 return true
113
114 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
115 objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26):
116 if targType == sym.SDYNIMPORT {
117 addpltsym(target, ldr, syms, targ)
118 su := ldr.MakeSymbolUpdater(s)
119 su.SetRelocSym(rIdx, syms.PLT)
120 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
121 }
122 if targType == 0 || targType == sym.SXREF {
123 ldr.Errorf(s, "unknown symbol %s in callarm64", ldr.SymName(targ))
124 }
125 su := ldr.MakeSymbolUpdater(s)
126 su.SetRelocType(rIdx, objabi.R_CALLARM64)
127 return true
128
129 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE),
130 objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC):
131 if targType != sym.SDYNIMPORT {
132
133
134 }
135
136
137
138 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_AARCH64_GLOB_DAT))
139 su := ldr.MakeSymbolUpdater(s)
140 su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
141 su.SetRelocSym(rIdx, syms.GOT)
142 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
143 return true
144
145 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21),
146 objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC):
147 if targType == sym.SDYNIMPORT {
148 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
149 }
150 if targType == 0 || targType == sym.SXREF {
151 ldr.Errorf(s, "unknown symbol %s", ldr.SymName(targ))
152 }
153 su := ldr.MakeSymbolUpdater(s)
154 su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
155 return true
156
157 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64):
158 if targType == sym.SDYNIMPORT {
159 ldr.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", ldr.SymName(targ))
160 }
161 su := ldr.MakeSymbolUpdater(s)
162 su.SetRelocType(rIdx, objabi.R_ADDR)
163 if target.IsPIE() && target.IsInternal() {
164
165
166
167 break
168 }
169 return true
170
171 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC):
172 if targType == sym.SDYNIMPORT {
173 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
174 }
175 su := ldr.MakeSymbolUpdater(s)
176 su.SetRelocType(rIdx, objabi.R_ARM64_LDST8)
177 return true
178
179 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST16_ABS_LO12_NC):
180 if targType == sym.SDYNIMPORT {
181 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
182 }
183 su := ldr.MakeSymbolUpdater(s)
184 su.SetRelocType(rIdx, objabi.R_ARM64_LDST16)
185 return true
186
187 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC):
188 if targType == sym.SDYNIMPORT {
189 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
190 }
191 su := ldr.MakeSymbolUpdater(s)
192 su.SetRelocType(rIdx, objabi.R_ARM64_LDST32)
193 return true
194
195 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC):
196 if targType == sym.SDYNIMPORT {
197 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
198 }
199 su := ldr.MakeSymbolUpdater(s)
200 su.SetRelocType(rIdx, objabi.R_ARM64_LDST64)
201
202 return true
203
204 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC):
205 if targType == sym.SDYNIMPORT {
206 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
207 }
208 su := ldr.MakeSymbolUpdater(s)
209 su.SetRelocType(rIdx, objabi.R_ARM64_LDST128)
210 return true
211
212
213 case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_UNSIGNED*2:
214 if targType == sym.SDYNIMPORT {
215 ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
216 }
217 su := ldr.MakeSymbolUpdater(s)
218 su.SetRelocType(rIdx, objabi.R_ADDR)
219 if target.IsPIE() && target.IsInternal() {
220
221
222
223 break
224 }
225 return true
226
227 case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_SUBTRACTOR*2:
228
229
230
231 outer, off := ld.FoldSubSymbolOffset(ldr, targ)
232 if outer != s {
233
234 ldr.Errorf(s, "unsupported ARM64_RELOC_SUBTRACTOR reloc: target %s, outer %s", ldr.SymName(targ), ldr.SymName(outer))
235 break
236 }
237 su := ldr.MakeSymbolUpdater(s)
238 relocs := su.Relocs()
239 if rIdx+1 >= relocs.Count() || relocs.At(rIdx+1).Type() != objabi.MachoRelocOffset+ld.MACHO_ARM64_RELOC_UNSIGNED*2 || relocs.At(rIdx+1).Off() != r.Off() {
240 ldr.Errorf(s, "unexpected ARM64_RELOC_SUBTRACTOR reloc, must be followed by ARM64_RELOC_UNSIGNED at same offset")
241 break
242 }
243 su.SetRelocType(rIdx+1, objabi.R_PCREL)
244 su.SetRelocAdd(rIdx+1, r.Add()+int64(r.Off())+int64(r.Siz())-off)
245
246 su.SetRelocSiz(rIdx, 0)
247 return true
248
249 case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_BRANCH26*2 + pcrel:
250 su := ldr.MakeSymbolUpdater(s)
251 su.SetRelocType(rIdx, objabi.R_CALLARM64)
252 if targType == sym.SDYNIMPORT {
253 addpltsym(target, ldr, syms, targ)
254 su.SetRelocSym(rIdx, syms.PLT)
255 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
256 }
257 return true
258
259 case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGE21*2 + pcrel,
260 objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGEOFF12*2:
261 if targType == sym.SDYNIMPORT {
262 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
263 }
264 su := ldr.MakeSymbolUpdater(s)
265 su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
266 return true
267
268 case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21*2 + pcrel,
269 objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12*2:
270 if targType != sym.SDYNIMPORT {
271
272
273 data := ldr.Data(s)
274 off := r.Off()
275 if int(off+3) >= len(data) {
276 ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
277 return false
278 }
279 o := target.Arch.ByteOrder.Uint32(data[off:])
280 su := ldr.MakeSymbolUpdater(s)
281 switch {
282 case (o>>24)&0x9f == 0x90:
283
284 case o>>24 == 0xf9:
285
286 o = (0x91 << 24) | (o & (1<<22 - 1))
287 su.MakeWritable()
288 su.SetUint32(target.Arch, int64(off), o)
289 default:
290 ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
291 return false
292 }
293 su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
294 return true
295 }
296 ld.AddGotSym(target, ldr, syms, targ, 0)
297 su := ldr.MakeSymbolUpdater(s)
298 su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
299 su.SetRelocSym(rIdx, syms.GOT)
300 su.SetRelocAdd(rIdx, int64(ldr.SymGot(targ)))
301 return true
302
303 case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_POINTER_TO_GOT*2 + pcrel:
304 if targType != sym.SDYNIMPORT {
305 ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
306 }
307 ld.AddGotSym(target, ldr, syms, targ, 0)
308 su := ldr.MakeSymbolUpdater(s)
309 su.SetRelocType(rIdx, objabi.R_PCREL)
310 su.SetRelocSym(rIdx, syms.GOT)
311 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz())+int64(ldr.SymGot(targ)))
312 return true
313 }
314
315
316 relocs := ldr.Relocs(s)
317 r = relocs.At(rIdx)
318
319 switch r.Type() {
320 case objabi.R_CALLARM64:
321 if targType != sym.SDYNIMPORT {
322
323 return true
324 }
325 if target.IsExternal() {
326
327 return true
328 }
329
330 if r.Add() != 0 {
331 ldr.Errorf(s, "PLT call with non-zero addend (%v)", r.Add())
332 }
333
334 addpltsym(target, ldr, syms, targ)
335 su := ldr.MakeSymbolUpdater(s)
336 su.SetRelocSym(rIdx, syms.PLT)
337 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
338 return true
339
340 case objabi.R_ADDRARM64:
341 if targType == sym.SDYNIMPORT && ldr.SymType(s).IsText() && target.IsDarwin() {
342
343
344 if r.Add() != 0 {
345 ldr.Errorf(s, "unexpected nonzero addend for dynamic symbol %s", ldr.SymName(targ))
346 return false
347 }
348 su := ldr.MakeSymbolUpdater(s)
349 data := ldr.Data(s)
350 off := r.Off()
351 if int(off+8) > len(data) {
352 ldr.Errorf(s, "unexpected R_ADDRARM64 reloc for dynamic symbol %s", ldr.SymName(targ))
353 return false
354 }
355 o := target.Arch.ByteOrder.Uint32(data[off+4:])
356 if o>>24 == 0x91 {
357
358 o = (0xf9 << 24) | 1<<22 | (o & (1<<22 - 1))
359 su.MakeWritable()
360 su.SetUint32(target.Arch, int64(off+4), o)
361 if target.IsInternal() {
362 ld.AddGotSym(target, ldr, syms, targ, 0)
363 su.SetRelocSym(rIdx, syms.GOT)
364 su.SetRelocAdd(rIdx, int64(ldr.SymGot(targ)))
365 su.SetRelocType(rIdx, objabi.R_ARM64_PCREL_LDST64)
366 } else {
367 su.SetRelocType(rIdx, objabi.R_ARM64_GOTPCREL)
368 }
369 return true
370 }
371 ldr.Errorf(s, "unexpected R_ADDRARM64 reloc for dynamic symbol %s", ldr.SymName(targ))
372 }
373
374 case objabi.R_ADDR:
375 if ldr.SymType(s).IsText() && target.IsElf() {
376
377
378
379 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_AARCH64_GLOB_DAT))
380 su := ldr.MakeSymbolUpdater(s)
381 su.SetRelocSym(rIdx, syms.GOT)
382 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
383 return true
384 }
385
386
387 if target.IsPIE() && target.IsInternal() {
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419 switch ldr.SymName(s) {
420 case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
421 return false
422 }
423 } else {
424
425
426
427
428
429
430 if t := ldr.SymType(s); !t.IsDATA() && !t.IsRODATA() {
431 break
432 }
433 }
434
435 if target.IsElf() {
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453 rela := ldr.MakeSymbolUpdater(syms.Rela)
454 rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
455 if r.Siz() == 8 {
456 rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
457 } else {
458 ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
459 }
460 rela.AddAddrPlus(target.Arch, targ, r.Add())
461
462
463
464
465 return true
466 }
467
468 if target.IsDarwin() {
469
470
471
472 ld.MachoAddRebase(s, int64(r.Off()))
473
474
475
476
477 return true
478 }
479
480 case objabi.R_ARM64_GOTPCREL:
481 if target.IsExternal() {
482
483 return true
484 }
485 if targType != sym.SDYNIMPORT {
486 ldr.Errorf(s, "R_ARM64_GOTPCREL target is not SDYNIMPORT symbol: %v", ldr.SymName(targ))
487 }
488 if r.Add() != 0 {
489 ldr.Errorf(s, "R_ARM64_GOTPCREL with non-zero addend (%v)", r.Add())
490 }
491 if target.IsElf() {
492 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_AARCH64_GLOB_DAT))
493 } else {
494 ld.AddGotSym(target, ldr, syms, targ, 0)
495 }
496
497 su := ldr.MakeSymbolUpdater(s)
498 r.SetType(objabi.R_ARM64_GOT)
499 r.SetSiz(4)
500 r.SetSym(syms.GOT)
501 r.SetAdd(int64(ldr.SymGot(targ)))
502 r2, _ := su.AddRel(objabi.R_ARM64_GOT)
503 r2.SetSiz(4)
504 r2.SetOff(r.Off() + 4)
505 r2.SetSym(syms.GOT)
506 r2.SetAdd(int64(ldr.SymGot(targ)))
507 return true
508 }
509 return false
510 }
511
512 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
513 out.Write64(uint64(sectoff))
514
515 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
516 siz := r.Size
517 switch r.Type {
518 default:
519 return false
520 case objabi.R_ADDR, objabi.R_DWARFSECREF:
521 switch siz {
522 case 4:
523 out.Write64(uint64(elf.R_AARCH64_ABS32) | uint64(elfsym)<<32)
524 case 8:
525 out.Write64(uint64(elf.R_AARCH64_ABS64) | uint64(elfsym)<<32)
526 default:
527 return false
528 }
529 case objabi.R_ADDRARM64:
530
531 out.Write64(uint64(elf.R_AARCH64_ADR_PREL_PG_HI21) | uint64(elfsym)<<32)
532 out.Write64(uint64(r.Xadd))
533 out.Write64(uint64(sectoff + 4))
534 out.Write64(uint64(elf.R_AARCH64_ADD_ABS_LO12_NC) | uint64(elfsym)<<32)
535
536 case objabi.R_ARM64_PCREL_LDST8,
537 objabi.R_ARM64_PCREL_LDST16,
538 objabi.R_ARM64_PCREL_LDST32,
539 objabi.R_ARM64_PCREL_LDST64:
540
541 out.Write64(uint64(elf.R_AARCH64_ADR_PREL_PG_HI21) | uint64(elfsym)<<32)
542 out.Write64(uint64(r.Xadd))
543 out.Write64(uint64(sectoff + 4))
544 var ldstType elf.R_AARCH64
545 switch r.Type {
546 case objabi.R_ARM64_PCREL_LDST8:
547 ldstType = elf.R_AARCH64_LDST8_ABS_LO12_NC
548 case objabi.R_ARM64_PCREL_LDST16:
549 ldstType = elf.R_AARCH64_LDST16_ABS_LO12_NC
550 case objabi.R_ARM64_PCREL_LDST32:
551 ldstType = elf.R_AARCH64_LDST32_ABS_LO12_NC
552 case objabi.R_ARM64_PCREL_LDST64:
553 ldstType = elf.R_AARCH64_LDST64_ABS_LO12_NC
554 }
555 out.Write64(uint64(ldstType) | uint64(elfsym)<<32)
556
557 case objabi.R_ARM64_TLS_LE:
558 out.Write64(uint64(elf.R_AARCH64_TLSLE_MOVW_TPREL_G0) | uint64(elfsym)<<32)
559 case objabi.R_ARM64_TLS_IE:
560 out.Write64(uint64(elf.R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) | uint64(elfsym)<<32)
561 out.Write64(uint64(r.Xadd))
562 out.Write64(uint64(sectoff + 4))
563 out.Write64(uint64(elf.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) | uint64(elfsym)<<32)
564 case objabi.R_ARM64_GOTPCREL:
565 out.Write64(uint64(elf.R_AARCH64_ADR_GOT_PAGE) | uint64(elfsym)<<32)
566 out.Write64(uint64(r.Xadd))
567 out.Write64(uint64(sectoff + 4))
568 out.Write64(uint64(elf.R_AARCH64_LD64_GOT_LO12_NC) | uint64(elfsym)<<32)
569 case objabi.R_CALLARM64:
570 if siz != 4 {
571 return false
572 }
573 out.Write64(uint64(elf.R_AARCH64_CALL26) | uint64(elfsym)<<32)
574
575 }
576 out.Write64(uint64(r.Xadd))
577
578 return true
579 }
580
581
582 func signext21(x int64) int64 { return x << (64 - 21) >> (64 - 21) }
583 func signext24(x int64) int64 { return x << (64 - 24) >> (64 - 24) }
584
585 func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
586 var v uint32
587
588 rs := r.Xsym
589 rt := r.Type
590 siz := r.Size
591 xadd := r.Xadd
592
593 if xadd != signext24(xadd) && rt != objabi.R_ADDR {
594
595
596
597
598 label := ldr.Lookup(offsetLabelName(ldr, rs, xadd/machoRelocLimit*machoRelocLimit), ldr.SymVersion(rs))
599 if label != 0 {
600 xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label)
601 rs = label
602 }
603 if xadd != signext24(xadd) {
604 ldr.Errorf(s, "internal error: relocation addend overflow: %s+0x%x", ldr.SymName(rs), xadd)
605 }
606 }
607 if rt == objabi.R_CALLARM64 && xadd != 0 {
608 label := ldr.Lookup(offsetLabelName(ldr, rs, xadd), ldr.SymVersion(rs))
609 if label != 0 {
610 xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label)
611 rs = label
612 }
613 }
614
615 if !ldr.SymType(s).IsDWARF() {
616 if ldr.SymDynid(rs) < 0 {
617 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))
618 return false
619 }
620
621 v = uint32(ldr.SymDynid(rs))
622 v |= 1 << 27
623 } else {
624 v = uint32(ldr.SymSect(rs).Extnum)
625 if v == 0 {
626 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))
627 return false
628 }
629 }
630
631 switch rt {
632 default:
633 return false
634 case objabi.R_ADDR:
635 v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
636 case objabi.R_CALLARM64:
637 if xadd != 0 {
638
639 ldr.Errorf(s, "unexpected non-zero addend: %s+%d", ldr.SymName(rs), xadd)
640 }
641 v |= 1 << 24
642 v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
643 case objabi.R_ADDRARM64,
644 objabi.R_ARM64_PCREL_LDST8,
645 objabi.R_ARM64_PCREL_LDST16,
646 objabi.R_ARM64_PCREL_LDST32,
647 objabi.R_ARM64_PCREL_LDST64:
648 siz = 4
649
650
651 if r.Xadd != 0 {
652 out.Write32(uint32(sectoff + 4))
653 out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
654 }
655 out.Write32(uint32(sectoff + 4))
656 out.Write32(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
657 if r.Xadd != 0 {
658 out.Write32(uint32(sectoff))
659 out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
660 }
661 v |= 1 << 24
662 v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
663 case objabi.R_ARM64_GOTPCREL:
664 siz = 4
665
666
667 if r.Xadd != 0 {
668 out.Write32(uint32(sectoff + 4))
669 out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
670 }
671 out.Write32(uint32(sectoff + 4))
672 out.Write32(v | (ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 << 28) | (2 << 25))
673 if r.Xadd != 0 {
674 out.Write32(uint32(sectoff))
675 out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
676 }
677 v |= 1 << 24
678 v |= ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 << 28
679 }
680
681 switch siz {
682 default:
683 return false
684 case 1:
685 v |= 0 << 25
686 case 2:
687 v |= 1 << 25
688 case 4:
689 v |= 2 << 25
690 case 8:
691 v |= 3 << 25
692 }
693
694 out.Write32(uint32(sectoff))
695 out.Write32(v)
696 return true
697 }
698
699 func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
700 rs := r.Xsym
701 rt := r.Type
702
703 if (rt == objabi.R_ADDRARM64 || rt == objabi.R_ARM64_PCREL_LDST8 || rt == objabi.R_ARM64_PCREL_LDST16 ||
704 rt == objabi.R_ARM64_PCREL_LDST32 || rt == objabi.R_ARM64_PCREL_LDST64) && r.Xadd != signext21(r.Xadd) {
705
706
707 label := ldr.Lookup(offsetLabelName(ldr, rs, r.Xadd/peRelocLimit*peRelocLimit), ldr.SymVersion(rs))
708 if label == 0 {
709 ldr.Errorf(s, "invalid relocation: %v %s+0x%x", rt, ldr.SymName(rs), r.Xadd)
710 return false
711 }
712 rs = label
713 }
714 if rt == objabi.R_CALLARM64 && r.Xadd != 0 {
715 label := ldr.Lookup(offsetLabelName(ldr, rs, r.Xadd), ldr.SymVersion(rs))
716 if label == 0 {
717 ldr.Errorf(s, "invalid relocation: %v %s+0x%x", rt, ldr.SymName(rs), r.Xadd)
718 return false
719 }
720 rs = label
721 }
722 symdynid := ldr.SymDynid(rs)
723 if symdynid < 0 {
724 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))
725 return false
726 }
727
728 switch rt {
729 default:
730 return false
731
732 case objabi.R_DWARFSECREF:
733 out.Write32(uint32(sectoff))
734 out.Write32(uint32(symdynid))
735 out.Write16(ld.IMAGE_REL_ARM64_SECREL)
736
737 case objabi.R_ADDR:
738 out.Write32(uint32(sectoff))
739 out.Write32(uint32(symdynid))
740 if r.Size == 8 {
741 out.Write16(ld.IMAGE_REL_ARM64_ADDR64)
742 } else {
743 out.Write16(ld.IMAGE_REL_ARM64_ADDR32)
744 }
745
746 case objabi.R_PEIMAGEOFF:
747 out.Write16(ld.IMAGE_REL_ARM64_ADDR32NB)
748
749 case objabi.R_ADDRARM64:
750
751 out.Write32(uint32(sectoff))
752 out.Write32(uint32(symdynid))
753 out.Write16(ld.IMAGE_REL_ARM64_PAGEBASE_REL21)
754
755 out.Write32(uint32(sectoff + 4))
756 out.Write32(uint32(symdynid))
757 out.Write16(ld.IMAGE_REL_ARM64_PAGEOFFSET_12A)
758
759 case objabi.R_ARM64_PCREL_LDST8,
760 objabi.R_ARM64_PCREL_LDST16,
761 objabi.R_ARM64_PCREL_LDST32,
762 objabi.R_ARM64_PCREL_LDST64:
763
764 out.Write32(uint32(sectoff))
765 out.Write32(uint32(symdynid))
766 out.Write16(ld.IMAGE_REL_ARM64_PAGEBASE_REL21)
767
768 out.Write32(uint32(sectoff + 4))
769 out.Write32(uint32(symdynid))
770 out.Write16(ld.IMAGE_REL_ARM64_PAGEOFFSET_12L)
771
772 case objabi.R_CALLARM64:
773
774 out.Write32(uint32(sectoff))
775 out.Write32(uint32(symdynid))
776 out.Write16(ld.IMAGE_REL_ARM64_BRANCH26)
777 }
778
779 return true
780 }
781
782 func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (int64, int, bool) {
783 const noExtReloc = 0
784 const isOk = true
785
786 rs := r.Sym()
787
788 if target.IsExternal() {
789 nExtReloc := 0
790 switch rt := r.Type(); rt {
791 default:
792 case objabi.R_ARM64_GOTPCREL,
793 objabi.R_ARM64_PCREL_LDST8,
794 objabi.R_ARM64_PCREL_LDST16,
795 objabi.R_ARM64_PCREL_LDST32,
796 objabi.R_ARM64_PCREL_LDST64,
797 objabi.R_ADDRARM64:
798
799
800 rs, off := ld.FoldSubSymbolOffset(ldr, rs)
801 xadd := r.Add() + off
802 rst := ldr.SymType(rs)
803 if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
804 ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
805 }
806
807 nExtReloc = 2
808 if target.IsDarwin() && xadd != 0 {
809 nExtReloc = 4
810 }
811
812 if target.IsWindows() {
813 var o0, o1 uint32
814 if target.IsBigEndian() {
815 o0 = uint32(val >> 32)
816 o1 = uint32(val)
817 } else {
818 o0 = uint32(val)
819 o1 = uint32(val >> 32)
820 }
821
822
823
824
825
826
827
828
829
830
831 xadd := uint32(xadd)
832 o0 |= (xadd&3)<<29 | (xadd&0xffffc)<<3
833 switch rt {
834 case objabi.R_ARM64_PCREL_LDST8, objabi.R_ADDRARM64:
835 o1 |= (xadd & 0xfff) << 10
836 case objabi.R_ARM64_PCREL_LDST16:
837 if xadd&0x1 != 0 {
838 ldr.Errorf(s, "offset for 16-bit load/store has unaligned value %d", xadd&0xfff)
839 }
840 o1 |= ((xadd & 0xfff) >> 1) << 10
841 case objabi.R_ARM64_PCREL_LDST32:
842 if xadd&0x3 != 0 {
843 ldr.Errorf(s, "offset for 32-bit load/store has unaligned value %d", xadd&0xfff)
844 }
845 o1 |= ((xadd & 0xfff) >> 2) << 10
846 case objabi.R_ARM64_PCREL_LDST64:
847 if xadd&0x7 != 0 {
848 ldr.Errorf(s, "offset for 64-bit load/store has unaligned value %d", xadd&0xfff)
849 }
850 o1 |= ((xadd & 0xfff) >> 3) << 10
851 }
852
853 if target.IsBigEndian() {
854 val = int64(o0)<<32 | int64(o1)
855 } else {
856 val = int64(o1)<<32 | int64(o0)
857 }
858 }
859
860 return val, nExtReloc, isOk
861
862 case objabi.R_CALLARM64:
863 nExtReloc = 1
864 return val, nExtReloc, isOk
865
866 case objabi.R_ARM64_TLS_LE:
867 nExtReloc = 1
868 return val, nExtReloc, isOk
869
870 case objabi.R_ARM64_TLS_IE:
871 nExtReloc = 2
872 return val, nExtReloc, isOk
873
874 case objabi.R_ADDR:
875 if target.IsWindows() && r.Add() != 0 {
876 if r.Siz() == 8 {
877 val = r.Add()
878 } else if target.IsBigEndian() {
879 val = int64(uint32(val)) | r.Add()<<32
880 } else {
881 val = val>>32<<32 | int64(uint32(r.Add()))
882 }
883 return val, 1, true
884 }
885 }
886 }
887
888 switch rt := r.Type(); rt {
889 case objabi.R_ADDRARM64,
890 objabi.R_ARM64_PCREL_LDST8,
891 objabi.R_ARM64_PCREL_LDST16,
892 objabi.R_ARM64_PCREL_LDST32,
893 objabi.R_ARM64_PCREL_LDST64:
894 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
895 if t >= 1<<32 || t < -1<<32 {
896 ldr.Errorf(s, "program too large, address relocation distance = %d", t)
897 }
898
899 var o0, o1 uint32
900
901 if target.IsBigEndian() {
902 o0 = uint32(val >> 32)
903 o1 = uint32(val)
904 } else {
905 o0 = uint32(val)
906 o1 = uint32(val >> 32)
907 }
908
909 o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
910 switch rt {
911 case objabi.R_ARM64_PCREL_LDST8, objabi.R_ADDRARM64:
912 o1 |= uint32(t&0xfff) << 10
913 case objabi.R_ARM64_PCREL_LDST16:
914 if t&0x1 != 0 {
915 ldr.Errorf(s, "offset for 16-bit load/store has unaligned value %d", t&0xfff)
916 }
917 o1 |= (uint32(t&0xfff) >> 1) << 10
918 case objabi.R_ARM64_PCREL_LDST32:
919 if t&0x3 != 0 {
920 ldr.Errorf(s, "offset for 32-bit load/store has unaligned value %d", t&0xfff)
921 }
922 o1 |= (uint32(t&0xfff) >> 2) << 10
923 case objabi.R_ARM64_PCREL_LDST64:
924 if t&0x7 != 0 {
925 ldr.Errorf(s, "offset for 64-bit load/store has unaligned value %d", t&0xfff)
926 }
927 o1 |= (uint32(t&0xfff) >> 3) << 10
928 }
929
930
931 if target.IsBigEndian() {
932 return int64(o0)<<32 | int64(o1), noExtReloc, true
933 }
934 return int64(o1)<<32 | int64(o0), noExtReloc, true
935
936 case objabi.R_ARM64_TLS_LE:
937 if target.IsDarwin() {
938 ldr.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
939 }
940
941
942 v := ldr.SymValue(rs) + int64(2*target.Arch.PtrSize)
943 if v < 0 || v >= 32678 {
944 ldr.Errorf(s, "TLS offset out of range %d", v)
945 }
946 return val | (v << 5), noExtReloc, true
947
948 case objabi.R_ARM64_TLS_IE:
949 if target.IsPIE() && target.IsElf() {
950
951
952
953 if !target.IsLinux() {
954 ldr.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
955 }
956
957
958
959 v := ldr.SymAddr(rs) + int64(2*target.Arch.PtrSize) + r.Add()
960 if v < 0 || v >= 32678 {
961 ldr.Errorf(s, "TLS offset out of range %d", v)
962 }
963
964 var o0, o1 uint32
965 if target.IsBigEndian() {
966 o0 = uint32(val >> 32)
967 o1 = uint32(val)
968 } else {
969 o0 = uint32(val)
970 o1 = uint32(val >> 32)
971 }
972
973
974
975 o0 = 0xd2a00000 | o0&0x1f | (uint32((v>>16)&0xffff) << 5)
976
977
978 if v&3 != 0 {
979 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", v)
980 }
981 o1 = 0xf2800000 | o1&0x1f | (uint32(v&0xffff) << 5)
982
983
984 if target.IsBigEndian() {
985 return int64(o0)<<32 | int64(o1), noExtReloc, isOk
986 }
987 return int64(o1)<<32 | int64(o0), noExtReloc, isOk
988 } else {
989 log.Fatalf("cannot handle R_ARM64_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
990 }
991
992 case objabi.R_CALLARM64:
993 var t int64
994 if ldr.SymType(rs) == sym.SDYNIMPORT {
995 t = (ldr.SymAddr(syms.PLT) + r.Add()) - (ldr.SymValue(s) + int64(r.Off()))
996 } else {
997 t = (ldr.SymAddr(rs) + r.Add()) - (ldr.SymValue(s) + int64(r.Off()))
998 }
999 if t >= 1<<27 || t < -1<<27 {
1000 ldr.Errorf(s, "program too large, call relocation distance = %d", t)
1001 }
1002 return val | ((t >> 2) & 0x03ffffff), noExtReloc, true
1003
1004 case objabi.R_ARM64_GOT:
1005 if (val>>24)&0x9f == 0x90 {
1006
1007
1008 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1009 if t >= 1<<32 || t < -1<<32 {
1010 ldr.Errorf(s, "program too large, address relocation distance = %d", t)
1011 }
1012 var o0 uint32
1013 o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
1014 return val | int64(o0), noExtReloc, isOk
1015 } else if val>>24 == 0xf9 {
1016
1017
1018 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1019 if t&7 != 0 {
1020 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LD64_GOT_LO12_NC", t)
1021 }
1022 var o1 uint32
1023 o1 |= uint32(t&0xfff) << (10 - 3)
1024 return val | int64(uint64(o1)), noExtReloc, isOk
1025 } else {
1026 ldr.Errorf(s, "unsupported instruction for %x R_GOTARM64", val)
1027 }
1028
1029 case objabi.R_ARM64_PCREL:
1030
1031
1032
1033
1034 if (val>>24)&0x9f == 0x90 {
1035
1036
1037 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1038 if t >= 1<<32 || t < -1<<32 {
1039 ldr.Errorf(s, "program too large, address relocation distance = %d", t)
1040 }
1041 o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
1042 if target.IsWindows() {
1043 val &^= 3<<29 | 0x7ffff<<5
1044 }
1045 return val | int64(o0), noExtReloc, isOk
1046 } else if (val>>24)&0x9f == 0x91 {
1047
1048
1049 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1050 o1 := uint32(t&0xfff) << 10
1051 if target.IsWindows() {
1052 val &^= 0xfff << 10
1053 }
1054 return val | int64(o1), noExtReloc, isOk
1055 } else if (val>>24)&0x3b == 0x39 {
1056
1057
1058
1059 shift := uint32(val) >> 30
1060 if shift == 0 && (val>>20)&0x048 == 0x048 {
1061 shift = 4
1062 }
1063 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1064 if t&(1<<shift-1) != 0 {
1065 ldr.Errorf(s, "invalid address: %x for relocation type: ARM64_RELOC_PAGEOFF12", t)
1066 }
1067 o1 := (uint32(t&0xfff) >> shift) << 10
1068 if target.IsWindows() {
1069 val &^= 0xfff << 10
1070 }
1071 return val | int64(o1), noExtReloc, isOk
1072 } else {
1073 ldr.Errorf(s, "unsupported instruction for %x R_ARM64_PCREL", val)
1074 }
1075
1076 case objabi.R_ARM64_LDST8:
1077 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1078 o0 := uint32(t&0xfff) << 10
1079 return val | int64(o0), noExtReloc, true
1080
1081 case objabi.R_ARM64_LDST16:
1082 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1083 if t&1 != 0 {
1084 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST16_ABS_LO12_NC", t)
1085 }
1086 o0 := (uint32(t&0xfff) >> 1) << 10
1087 return val | int64(o0), noExtReloc, true
1088
1089 case objabi.R_ARM64_LDST32:
1090 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1091 if t&3 != 0 {
1092 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST32_ABS_LO12_NC", t)
1093 }
1094 o0 := (uint32(t&0xfff) >> 2) << 10
1095 return val | int64(o0), noExtReloc, true
1096
1097 case objabi.R_ARM64_LDST64:
1098 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1099 if t&7 != 0 {
1100 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST64_ABS_LO12_NC", t)
1101 }
1102 o0 := (uint32(t&0xfff) >> 3) << 10
1103 return val | int64(o0), noExtReloc, true
1104
1105 case objabi.R_ARM64_LDST128:
1106 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1107 if t&15 != 0 {
1108 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST128_ABS_LO12_NC", t)
1109 }
1110 o0 := (uint32(t&0xfff) >> 4) << 10
1111 return val | int64(o0), noExtReloc, true
1112 }
1113
1114 return val, 0, false
1115 }
1116
1117 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
1118 log.Fatalf("unexpected relocation variant")
1119 return -1
1120 }
1121
1122 func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
1123 switch rt := r.Type(); rt {
1124 case objabi.R_ARM64_GOTPCREL,
1125 objabi.R_ARM64_PCREL_LDST8,
1126 objabi.R_ARM64_PCREL_LDST16,
1127 objabi.R_ARM64_PCREL_LDST32,
1128 objabi.R_ARM64_PCREL_LDST64,
1129 objabi.R_ADDRARM64:
1130 rr := ld.ExtrelocViaOuterSym(ldr, r, s)
1131 return rr, true
1132 case objabi.R_CALLARM64,
1133 objabi.R_ARM64_TLS_LE,
1134 objabi.R_ARM64_TLS_IE:
1135 return ld.ExtrelocSimple(ldr, r), true
1136 }
1137 return loader.ExtReloc{}, false
1138 }
1139
1140 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
1141 if plt.Size() == 0 {
1142
1143
1144 plt.AddUint32(ctxt.Arch, 0xa9bf7bf0)
1145
1146
1147
1148 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
1149 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x90000010)
1150
1151
1152
1153 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
1154 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0xf9400211)
1155
1156
1157 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_PCREL, 4)
1158 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x91000210)
1159
1160
1161 plt.AddUint32(ctxt.Arch, 0xd61f0220)
1162
1163
1164 plt.AddUint32(ctxt.Arch, 0xd503201f)
1165 plt.AddUint32(ctxt.Arch, 0xd503201f)
1166 plt.AddUint32(ctxt.Arch, 0xd503201f)
1167
1168
1169 if gotplt.Size() != 0 {
1170 ctxt.Errorf(gotplt.Sym(), "got.plt is not empty at the very beginning")
1171 }
1172 gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0)
1173
1174 gotplt.AddUint64(ctxt.Arch, 0)
1175 gotplt.AddUint64(ctxt.Arch, 0)
1176 }
1177 }
1178
1179 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
1180 if ldr.SymPlt(s) >= 0 {
1181 return
1182 }
1183
1184 ld.Adddynsym(ldr, target, syms, s)
1185
1186 if target.IsElf() {
1187 plt := ldr.MakeSymbolUpdater(syms.PLT)
1188 gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
1189 rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
1190 if plt.Size() == 0 {
1191 panic("plt is not set up")
1192 }
1193
1194
1195 plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
1196 plt.SetUint32(target.Arch, plt.Size()-4, 0x90000010)
1197 relocs := plt.Relocs()
1198 plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
1199
1200
1201
1202 plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
1203 plt.SetUint32(target.Arch, plt.Size()-4, 0xf9400211)
1204 relocs = plt.Relocs()
1205 plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
1206
1207
1208 plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
1209 plt.SetUint32(target.Arch, plt.Size()-4, 0x91000210)
1210 relocs = plt.Relocs()
1211 plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_PCREL)
1212
1213
1214 plt.AddUint32(target.Arch, 0xd61f0220)
1215
1216
1217 gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
1218
1219
1220 rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
1221 sDynid := ldr.SymDynid(s)
1222
1223 rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
1224 rela.AddUint64(target.Arch, 0)
1225
1226 ldr.SetPlt(s, int32(plt.Size()-16))
1227 } else if target.IsDarwin() {
1228 ld.AddGotSym(target, ldr, syms, s, 0)
1229
1230 sDynid := ldr.SymDynid(s)
1231 lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
1232 lep.AddUint32(target.Arch, uint32(sDynid))
1233
1234 plt := ldr.MakeSymbolUpdater(syms.PLT)
1235 ldr.SetPlt(s, int32(plt.Size()))
1236
1237
1238 plt.AddUint32(target.Arch, 0x90000010)
1239 r, _ := plt.AddRel(objabi.R_ARM64_GOT)
1240 r.SetOff(int32(plt.Size() - 4))
1241 r.SetSiz(4)
1242 r.SetSym(syms.GOT)
1243 r.SetAdd(int64(ldr.SymGot(s)))
1244
1245
1246 plt.AddUint32(target.Arch, 0xf9400211)
1247 r, _ = plt.AddRel(objabi.R_ARM64_GOT)
1248 r.SetOff(int32(plt.Size() - 4))
1249 r.SetSiz(4)
1250 r.SetSym(syms.GOT)
1251 r.SetAdd(int64(ldr.SymGot(s)))
1252
1253
1254 plt.AddUint32(target.Arch, 0xd61f0220)
1255 } else {
1256 ldr.Errorf(s, "addpltsym: unsupported binary format")
1257 }
1258 }
1259
1260 const (
1261 machoRelocLimit = 1 << 23
1262 peRelocLimit = 1 << 20
1263 )
1264
1265 func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
1266
1267
1268
1269
1270
1271
1272
1273 if !ctxt.IsDarwin() && !ctxt.IsWindows() || !ctxt.IsExternal() {
1274 return
1275 }
1276
1277 limit := int64(machoRelocLimit)
1278 if ctxt.IsWindows() {
1279 limit = peRelocLimit
1280 }
1281
1282
1283 addLabelSyms := func(s loader.Sym, limit, sz int64) {
1284 v := ldr.SymValue(s)
1285 for off := limit; off < sz; off += limit {
1286 p := ldr.LookupOrCreateSym(offsetLabelName(ldr, s, off), ldr.SymVersion(s))
1287 ldr.SetAttrReachable(p, true)
1288 ldr.SetSymValue(p, v+off)
1289 ldr.SetSymSect(p, ldr.SymSect(s))
1290 if ctxt.IsDarwin() {
1291 ld.AddMachoSym(ldr, p)
1292 } else if ctxt.IsWindows() {
1293 ld.AddPELabelSym(ldr, p)
1294 } else {
1295 panic("missing case in gensymlate")
1296 }
1297
1298 }
1299 }
1300
1301
1302 if s := ldr.Lookup("runtime.duffcopy", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
1303 addLabelSyms(s, 8, 8*64)
1304 }
1305 if s := ldr.Lookup("runtime.duffzero", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
1306 addLabelSyms(s, 4, 4*64)
1307 }
1308
1309 if ctxt.IsDarwin() {
1310 big := false
1311 for _, seg := range ld.Segments {
1312 if seg.Length >= machoRelocLimit {
1313 big = true
1314 break
1315 }
1316 }
1317 if !big {
1318 return
1319 }
1320 }
1321
1322 for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ {
1323 if !ldr.AttrReachable(s) {
1324 continue
1325 }
1326 t := ldr.SymType(s)
1327 if t.IsText() {
1328
1329
1330 continue
1331 }
1332 if t >= sym.SDWARFSECT {
1333 continue
1334 }
1335 sz := ldr.SymSize(s)
1336 if sz <= limit {
1337 continue
1338 }
1339 addLabelSyms(s, limit, sz)
1340 }
1341
1342
1343 for _, ss := range ld.CarrierSymByType {
1344 if ss.Sym != 0 && ss.Size > limit {
1345 addLabelSyms(ss.Sym, limit, ss.Size)
1346 }
1347 }
1348 }
1349
1350
1351
1352
1353 func offsetLabelName(ldr *loader.Loader, s loader.Sym, off int64) string {
1354 if off>>20<<20 == off {
1355 return fmt.Sprintf("%s+%dMB", ldr.SymExtname(s), off>>20)
1356 }
1357 return fmt.Sprintf("%s+%d", ldr.SymExtname(s), off)
1358 }
1359
1360
1361 func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
1362 relocs := ldr.Relocs(s)
1363 r := relocs.At(ri)
1364 const pcrel = 1
1365 switch r.Type() {
1366 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
1367 objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26),
1368 objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_BRANCH26*2 + pcrel:
1369
1370
1371 fallthrough
1372 case objabi.R_CALLARM64:
1373 var t int64
1374
1375
1376
1377 if ldr.SymValue(rs) != 0 {
1378 t = ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
1379 }
1380 if t >= 1<<27 || t < -1<<27 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && (ldr.SymPkg(s) == "" || ldr.SymPkg(s) != ldr.SymPkg(rs))) {
1381
1382
1383
1384 var tramp loader.Sym
1385 for i := 0; ; i++ {
1386 oName := ldr.SymName(rs)
1387 name := oName + fmt.Sprintf("%+x-tramp%d", r.Add(), i)
1388 tramp = ldr.LookupOrCreateSym(name, ldr.SymVersion(rs))
1389 ldr.SetAttrReachable(tramp, true)
1390 if ldr.SymType(tramp) == sym.SDYNIMPORT {
1391
1392 continue
1393 }
1394 if oName == "runtime.deferreturn" {
1395 ldr.SetIsDeferReturnTramp(tramp, true)
1396 }
1397 if ldr.SymValue(tramp) == 0 {
1398
1399
1400
1401 break
1402 }
1403
1404 t = ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
1405 if t >= -1<<27 && t < 1<<27 {
1406
1407
1408 break
1409 }
1410 }
1411 if ldr.SymType(tramp) == 0 {
1412
1413 trampb := ldr.MakeSymbolUpdater(tramp)
1414 ctxt.AddTramp(trampb, ldr.SymType(s))
1415 if ldr.SymType(rs) == sym.SDYNIMPORT {
1416 if r.Add() != 0 {
1417 ctxt.Errorf(s, "nonzero addend for DYNIMPORT call: %v+%d", ldr.SymName(rs), r.Add())
1418 }
1419 gentrampgot(ctxt, ldr, trampb, rs)
1420 } else {
1421 gentramp(ctxt, ldr, trampb, rs, r.Add())
1422 }
1423 }
1424
1425 sb := ldr.MakeSymbolUpdater(s)
1426 relocs := sb.Relocs()
1427 r := relocs.At(ri)
1428 r.SetSym(tramp)
1429 r.SetAdd(0)
1430 }
1431 default:
1432 ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
1433 }
1434 }
1435
1436
1437 func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
1438 tramp.SetSize(12)
1439 P := make([]byte, tramp.Size())
1440 o1 := uint32(0x90000010)
1441 o2 := uint32(0x91000210)
1442 o3 := uint32(0xd61f0200)
1443 ctxt.Arch.ByteOrder.PutUint32(P, o1)
1444 ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
1445 ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
1446 tramp.SetData(P)
1447
1448 r, _ := tramp.AddRel(objabi.R_ADDRARM64)
1449 r.SetSiz(8)
1450 r.SetSym(target)
1451 r.SetAdd(offset)
1452 }
1453
1454
1455 func gentrampgot(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym) {
1456 tramp.SetSize(12)
1457 P := make([]byte, tramp.Size())
1458 o1 := uint32(0x90000010)
1459 o2 := uint32(0xf9400210)
1460 o3 := uint32(0xd61f0200)
1461 ctxt.Arch.ByteOrder.PutUint32(P, o1)
1462 ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
1463 ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
1464 tramp.SetData(P)
1465
1466 r, _ := tramp.AddRel(objabi.R_ARM64_GOTPCREL)
1467 r.SetSiz(8)
1468 r.SetSym(target)
1469 }
1470
View as plain text