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 su := ldr.MakeSymbolUpdater(s)
215 su.SetRelocType(rIdx, objabi.R_ADDR)
216 if target.IsPIE() && target.IsInternal() {
217
218
219
220 break
221 }
222 if targType == sym.SDYNIMPORT {
223 ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
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 if targType == sym.SDYNIMPORT {
473
474
475 ld.MachoAddBind(s, int64(r.Off()), targ)
476 } else {
477 ld.MachoAddRebase(s, int64(r.Off()))
478 }
479
480
481
482
483 return true
484 }
485
486 case objabi.R_ARM64_GOTPCREL:
487 if target.IsExternal() {
488
489 return true
490 }
491 if targType != sym.SDYNIMPORT {
492 ldr.Errorf(s, "R_ARM64_GOTPCREL target is not SDYNIMPORT symbol: %v", ldr.SymName(targ))
493 }
494 if r.Add() != 0 {
495 ldr.Errorf(s, "R_ARM64_GOTPCREL with non-zero addend (%v)", r.Add())
496 }
497 if target.IsElf() {
498 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_AARCH64_GLOB_DAT))
499 } else {
500 ld.AddGotSym(target, ldr, syms, targ, 0)
501 }
502
503 su := ldr.MakeSymbolUpdater(s)
504 r.SetType(objabi.R_ARM64_GOT)
505 r.SetSiz(4)
506 r.SetSym(syms.GOT)
507 r.SetAdd(int64(ldr.SymGot(targ)))
508 r2, _ := su.AddRel(objabi.R_ARM64_GOT)
509 r2.SetSiz(4)
510 r2.SetOff(r.Off() + 4)
511 r2.SetSym(syms.GOT)
512 r2.SetAdd(int64(ldr.SymGot(targ)))
513 return true
514 }
515 return false
516 }
517
518 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
519 out.Write64(uint64(sectoff))
520
521 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
522 siz := r.Size
523 switch r.Type {
524 default:
525 return false
526 case objabi.R_ADDR, objabi.R_DWARFSECREF:
527 switch siz {
528 case 4:
529 out.Write64(uint64(elf.R_AARCH64_ABS32) | uint64(elfsym)<<32)
530 case 8:
531 out.Write64(uint64(elf.R_AARCH64_ABS64) | uint64(elfsym)<<32)
532 default:
533 return false
534 }
535 case objabi.R_ADDRARM64:
536
537 out.Write64(uint64(elf.R_AARCH64_ADR_PREL_PG_HI21) | uint64(elfsym)<<32)
538 out.Write64(uint64(r.Xadd))
539 out.Write64(uint64(sectoff + 4))
540 out.Write64(uint64(elf.R_AARCH64_ADD_ABS_LO12_NC) | uint64(elfsym)<<32)
541
542 case objabi.R_ARM64_PCREL_LDST8,
543 objabi.R_ARM64_PCREL_LDST16,
544 objabi.R_ARM64_PCREL_LDST32,
545 objabi.R_ARM64_PCREL_LDST64:
546
547 out.Write64(uint64(elf.R_AARCH64_ADR_PREL_PG_HI21) | uint64(elfsym)<<32)
548 out.Write64(uint64(r.Xadd))
549 out.Write64(uint64(sectoff + 4))
550 var ldstType elf.R_AARCH64
551 switch r.Type {
552 case objabi.R_ARM64_PCREL_LDST8:
553 ldstType = elf.R_AARCH64_LDST8_ABS_LO12_NC
554 case objabi.R_ARM64_PCREL_LDST16:
555 ldstType = elf.R_AARCH64_LDST16_ABS_LO12_NC
556 case objabi.R_ARM64_PCREL_LDST32:
557 ldstType = elf.R_AARCH64_LDST32_ABS_LO12_NC
558 case objabi.R_ARM64_PCREL_LDST64:
559 ldstType = elf.R_AARCH64_LDST64_ABS_LO12_NC
560 }
561 out.Write64(uint64(ldstType) | uint64(elfsym)<<32)
562
563 case objabi.R_ARM64_TLS_LE:
564 out.Write64(uint64(elf.R_AARCH64_TLSLE_MOVW_TPREL_G0) | uint64(elfsym)<<32)
565 case objabi.R_ARM64_TLS_IE:
566 out.Write64(uint64(elf.R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) | uint64(elfsym)<<32)
567 out.Write64(uint64(r.Xadd))
568 out.Write64(uint64(sectoff + 4))
569 out.Write64(uint64(elf.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) | uint64(elfsym)<<32)
570 case objabi.R_ARM64_GOTPCREL:
571 out.Write64(uint64(elf.R_AARCH64_ADR_GOT_PAGE) | uint64(elfsym)<<32)
572 out.Write64(uint64(r.Xadd))
573 out.Write64(uint64(sectoff + 4))
574 out.Write64(uint64(elf.R_AARCH64_LD64_GOT_LO12_NC) | uint64(elfsym)<<32)
575 case objabi.R_CALLARM64:
576 if siz != 4 {
577 return false
578 }
579 out.Write64(uint64(elf.R_AARCH64_CALL26) | uint64(elfsym)<<32)
580
581 }
582 out.Write64(uint64(r.Xadd))
583
584 return true
585 }
586
587
588 func signext21(x int64) int64 { return x << (64 - 21) >> (64 - 21) }
589 func signext24(x int64) int64 { return x << (64 - 24) >> (64 - 24) }
590
591 func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
592 var v uint32
593
594 rs := r.Xsym
595 rt := r.Type
596 siz := r.Size
597 xadd := r.Xadd
598
599 if xadd != signext24(xadd) && rt != objabi.R_ADDR {
600
601
602
603
604 label := ldr.Lookup(offsetLabelName(ldr, rs, xadd/machoRelocLimit*machoRelocLimit), ldr.SymVersion(rs))
605 if label != 0 {
606 xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label)
607 rs = label
608 }
609 if xadd != signext24(xadd) {
610 ldr.Errorf(s, "internal error: relocation addend overflow: %s+0x%x", ldr.SymName(rs), xadd)
611 }
612 }
613 if rt == objabi.R_CALLARM64 && xadd != 0 {
614 label := ldr.Lookup(offsetLabelName(ldr, rs, xadd), ldr.SymVersion(rs))
615 if label != 0 {
616 xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label)
617 rs = label
618 }
619 }
620
621 if !ldr.SymType(s).IsDWARF() {
622 if ldr.SymDynid(rs) < 0 {
623 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))
624 return false
625 }
626
627 v = uint32(ldr.SymDynid(rs))
628 v |= 1 << 27
629 } else {
630 v = uint32(ldr.SymSect(rs).Extnum)
631 if v == 0 {
632 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))
633 return false
634 }
635 }
636
637 switch rt {
638 default:
639 return false
640 case objabi.R_ADDR:
641 v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
642 case objabi.R_CALLARM64:
643 if xadd != 0 {
644
645 ldr.Errorf(s, "unexpected non-zero addend: %s+%d", ldr.SymName(rs), xadd)
646 }
647 v |= 1 << 24
648 v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
649 case objabi.R_ADDRARM64,
650 objabi.R_ARM64_PCREL_LDST8,
651 objabi.R_ARM64_PCREL_LDST16,
652 objabi.R_ARM64_PCREL_LDST32,
653 objabi.R_ARM64_PCREL_LDST64:
654 siz = 4
655
656
657 if r.Xadd != 0 {
658 out.Write32(uint32(sectoff + 4))
659 out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
660 }
661 out.Write32(uint32(sectoff + 4))
662 out.Write32(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
663 if r.Xadd != 0 {
664 out.Write32(uint32(sectoff))
665 out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
666 }
667 v |= 1 << 24
668 v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
669 case objabi.R_ARM64_GOTPCREL:
670 siz = 4
671
672
673 if r.Xadd != 0 {
674 out.Write32(uint32(sectoff + 4))
675 out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
676 }
677 out.Write32(uint32(sectoff + 4))
678 out.Write32(v | (ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 << 28) | (2 << 25))
679 if r.Xadd != 0 {
680 out.Write32(uint32(sectoff))
681 out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
682 }
683 v |= 1 << 24
684 v |= ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 << 28
685 }
686
687 switch siz {
688 default:
689 return false
690 case 1:
691 v |= 0 << 25
692 case 2:
693 v |= 1 << 25
694 case 4:
695 v |= 2 << 25
696 case 8:
697 v |= 3 << 25
698 }
699
700 out.Write32(uint32(sectoff))
701 out.Write32(v)
702 return true
703 }
704
705 func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
706 rs := r.Xsym
707 rt := r.Type
708
709 if (rt == objabi.R_ADDRARM64 || rt == objabi.R_ARM64_PCREL_LDST8 || rt == objabi.R_ARM64_PCREL_LDST16 ||
710 rt == objabi.R_ARM64_PCREL_LDST32 || rt == objabi.R_ARM64_PCREL_LDST64) && r.Xadd != signext21(r.Xadd) {
711
712
713 label := ldr.Lookup(offsetLabelName(ldr, rs, r.Xadd/peRelocLimit*peRelocLimit), ldr.SymVersion(rs))
714 if label == 0 {
715 ldr.Errorf(s, "invalid relocation: %v %s+0x%x", rt, ldr.SymName(rs), r.Xadd)
716 return false
717 }
718 rs = label
719 }
720 if rt == objabi.R_CALLARM64 && r.Xadd != 0 {
721 label := ldr.Lookup(offsetLabelName(ldr, rs, r.Xadd), ldr.SymVersion(rs))
722 if label == 0 {
723 ldr.Errorf(s, "invalid relocation: %v %s+0x%x", rt, ldr.SymName(rs), r.Xadd)
724 return false
725 }
726 rs = label
727 }
728 symdynid := ldr.SymDynid(rs)
729 if symdynid < 0 {
730 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))
731 return false
732 }
733
734 switch rt {
735 default:
736 return false
737
738 case objabi.R_DWARFSECREF:
739 out.Write32(uint32(sectoff))
740 out.Write32(uint32(symdynid))
741 out.Write16(ld.IMAGE_REL_ARM64_SECREL)
742
743 case objabi.R_ADDR:
744 out.Write32(uint32(sectoff))
745 out.Write32(uint32(symdynid))
746 if r.Size == 8 {
747 out.Write16(ld.IMAGE_REL_ARM64_ADDR64)
748 } else {
749 out.Write16(ld.IMAGE_REL_ARM64_ADDR32)
750 }
751
752 case objabi.R_PEIMAGEOFF:
753 out.Write16(ld.IMAGE_REL_ARM64_ADDR32NB)
754
755 case objabi.R_ADDRARM64:
756
757 out.Write32(uint32(sectoff))
758 out.Write32(uint32(symdynid))
759 out.Write16(ld.IMAGE_REL_ARM64_PAGEBASE_REL21)
760
761 out.Write32(uint32(sectoff + 4))
762 out.Write32(uint32(symdynid))
763 out.Write16(ld.IMAGE_REL_ARM64_PAGEOFFSET_12A)
764
765 case objabi.R_ARM64_PCREL_LDST8,
766 objabi.R_ARM64_PCREL_LDST16,
767 objabi.R_ARM64_PCREL_LDST32,
768 objabi.R_ARM64_PCREL_LDST64:
769
770 out.Write32(uint32(sectoff))
771 out.Write32(uint32(symdynid))
772 out.Write16(ld.IMAGE_REL_ARM64_PAGEBASE_REL21)
773
774 out.Write32(uint32(sectoff + 4))
775 out.Write32(uint32(symdynid))
776 out.Write16(ld.IMAGE_REL_ARM64_PAGEOFFSET_12L)
777
778 case objabi.R_CALLARM64:
779
780 out.Write32(uint32(sectoff))
781 out.Write32(uint32(symdynid))
782 out.Write16(ld.IMAGE_REL_ARM64_BRANCH26)
783 }
784
785 return true
786 }
787
788 func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (int64, int, bool) {
789 const noExtReloc = 0
790 const isOk = true
791
792 rs := r.Sym()
793
794 if target.IsExternal() {
795 nExtReloc := 0
796 switch rt := r.Type(); rt {
797 default:
798 case objabi.R_ARM64_GOTPCREL,
799 objabi.R_ARM64_PCREL_LDST8,
800 objabi.R_ARM64_PCREL_LDST16,
801 objabi.R_ARM64_PCREL_LDST32,
802 objabi.R_ARM64_PCREL_LDST64,
803 objabi.R_ADDRARM64:
804
805
806 rs, off := ld.FoldSubSymbolOffset(ldr, rs)
807 xadd := r.Add() + off
808 rst := ldr.SymType(rs)
809 if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
810 ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
811 }
812
813 nExtReloc = 2
814 if target.IsDarwin() && xadd != 0 {
815 nExtReloc = 4
816 }
817
818 if target.IsWindows() {
819 var o0, o1 uint32
820 if target.IsBigEndian() {
821 o0 = uint32(val >> 32)
822 o1 = uint32(val)
823 } else {
824 o0 = uint32(val)
825 o1 = uint32(val >> 32)
826 }
827
828
829
830
831
832
833
834
835
836
837 xadd := uint32(xadd)
838 o0 |= (xadd&3)<<29 | (xadd&0xffffc)<<3
839 switch rt {
840 case objabi.R_ARM64_PCREL_LDST8, objabi.R_ADDRARM64:
841 o1 |= (xadd & 0xfff) << 10
842 case objabi.R_ARM64_PCREL_LDST16:
843 if xadd&0x1 != 0 {
844 ldr.Errorf(s, "offset for 16-bit load/store has unaligned value %d", xadd&0xfff)
845 }
846 o1 |= ((xadd & 0xfff) >> 1) << 10
847 case objabi.R_ARM64_PCREL_LDST32:
848 if xadd&0x3 != 0 {
849 ldr.Errorf(s, "offset for 32-bit load/store has unaligned value %d", xadd&0xfff)
850 }
851 o1 |= ((xadd & 0xfff) >> 2) << 10
852 case objabi.R_ARM64_PCREL_LDST64:
853 if xadd&0x7 != 0 {
854 ldr.Errorf(s, "offset for 64-bit load/store has unaligned value %d", xadd&0xfff)
855 }
856 o1 |= ((xadd & 0xfff) >> 3) << 10
857 }
858
859 if target.IsBigEndian() {
860 val = int64(o0)<<32 | int64(o1)
861 } else {
862 val = int64(o1)<<32 | int64(o0)
863 }
864 }
865
866 return val, nExtReloc, isOk
867
868 case objabi.R_CALLARM64:
869 nExtReloc = 1
870 return val, nExtReloc, isOk
871
872 case objabi.R_ARM64_TLS_LE:
873 nExtReloc = 1
874 return val, nExtReloc, isOk
875
876 case objabi.R_ARM64_TLS_IE:
877 nExtReloc = 2
878 return val, nExtReloc, isOk
879
880 case objabi.R_ADDR:
881 if target.IsWindows() && r.Add() != 0 {
882 if r.Siz() == 8 {
883 val = r.Add()
884 } else if target.IsBigEndian() {
885 val = int64(uint32(val)) | r.Add()<<32
886 } else {
887 val = val>>32<<32 | int64(uint32(r.Add()))
888 }
889 return val, 1, true
890 }
891 }
892 }
893
894 switch rt := r.Type(); rt {
895 case objabi.R_ADDRARM64,
896 objabi.R_ARM64_PCREL_LDST8,
897 objabi.R_ARM64_PCREL_LDST16,
898 objabi.R_ARM64_PCREL_LDST32,
899 objabi.R_ARM64_PCREL_LDST64:
900 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
901 if t >= 1<<32 || t < -1<<32 {
902 ldr.Errorf(s, "program too large, address relocation distance = %d", t)
903 }
904
905 var o0, o1 uint32
906
907 if target.IsBigEndian() {
908 o0 = uint32(val >> 32)
909 o1 = uint32(val)
910 } else {
911 o0 = uint32(val)
912 o1 = uint32(val >> 32)
913 }
914
915 o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
916 switch rt {
917 case objabi.R_ARM64_PCREL_LDST8, objabi.R_ADDRARM64:
918 o1 |= uint32(t&0xfff) << 10
919 case objabi.R_ARM64_PCREL_LDST16:
920 if t&0x1 != 0 {
921 ldr.Errorf(s, "offset for 16-bit load/store has unaligned value %d", t&0xfff)
922 }
923 o1 |= (uint32(t&0xfff) >> 1) << 10
924 case objabi.R_ARM64_PCREL_LDST32:
925 if t&0x3 != 0 {
926 ldr.Errorf(s, "offset for 32-bit load/store has unaligned value %d", t&0xfff)
927 }
928 o1 |= (uint32(t&0xfff) >> 2) << 10
929 case objabi.R_ARM64_PCREL_LDST64:
930 if t&0x7 != 0 {
931 ldr.Errorf(s, "offset for 64-bit load/store has unaligned value %d", t&0xfff)
932 }
933 o1 |= (uint32(t&0xfff) >> 3) << 10
934 }
935
936
937 if target.IsBigEndian() {
938 return int64(o0)<<32 | int64(o1), noExtReloc, true
939 }
940 return int64(o1)<<32 | int64(o0), noExtReloc, true
941
942 case objabi.R_ARM64_TLS_LE:
943 if target.IsDarwin() {
944 ldr.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
945 }
946
947
948 v := ldr.SymValue(rs) + int64(2*target.Arch.PtrSize)
949 if v < 0 || v >= 32678 {
950 ldr.Errorf(s, "TLS offset out of range %d", v)
951 }
952 return val | (v << 5), noExtReloc, true
953
954 case objabi.R_ARM64_TLS_IE:
955 if target.IsPIE() && target.IsElf() {
956
957
958
959 if !target.IsLinux() {
960 ldr.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
961 }
962
963
964
965 v := ldr.SymAddr(rs) + int64(2*target.Arch.PtrSize) + r.Add()
966 if v < 0 || v >= 32678 {
967 ldr.Errorf(s, "TLS offset out of range %d", v)
968 }
969
970 var o0, o1 uint32
971 if target.IsBigEndian() {
972 o0 = uint32(val >> 32)
973 o1 = uint32(val)
974 } else {
975 o0 = uint32(val)
976 o1 = uint32(val >> 32)
977 }
978
979
980
981 o0 = 0xd2a00000 | o0&0x1f | (uint32((v>>16)&0xffff) << 5)
982
983
984 if v&3 != 0 {
985 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", v)
986 }
987 o1 = 0xf2800000 | o1&0x1f | (uint32(v&0xffff) << 5)
988
989
990 if target.IsBigEndian() {
991 return int64(o0)<<32 | int64(o1), noExtReloc, isOk
992 }
993 return int64(o1)<<32 | int64(o0), noExtReloc, isOk
994 } else {
995 log.Fatalf("cannot handle R_ARM64_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
996 }
997
998 case objabi.R_CALLARM64:
999 var t int64
1000 if ldr.SymType(rs) == sym.SDYNIMPORT {
1001 t = (ldr.SymAddr(syms.PLT) + r.Add()) - (ldr.SymValue(s) + int64(r.Off()))
1002 } else {
1003 t = (ldr.SymAddr(rs) + r.Add()) - (ldr.SymValue(s) + int64(r.Off()))
1004 }
1005 if t >= 1<<27 || t < -1<<27 {
1006 ldr.Errorf(s, "program too large, call relocation distance = %d", t)
1007 }
1008 return val | ((t >> 2) & 0x03ffffff), noExtReloc, true
1009
1010 case objabi.R_ARM64_GOT:
1011 if (val>>24)&0x9f == 0x90 {
1012
1013
1014 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1015 if t >= 1<<32 || t < -1<<32 {
1016 ldr.Errorf(s, "program too large, address relocation distance = %d", t)
1017 }
1018 var o0 uint32
1019 o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
1020 return val | int64(o0), noExtReloc, isOk
1021 } else if val>>24 == 0xf9 {
1022
1023
1024 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1025 if t&7 != 0 {
1026 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LD64_GOT_LO12_NC", t)
1027 }
1028 var o1 uint32
1029 o1 |= uint32(t&0xfff) << (10 - 3)
1030 return val | int64(uint64(o1)), noExtReloc, isOk
1031 } else {
1032 ldr.Errorf(s, "unsupported instruction for %x R_GOTARM64", val)
1033 }
1034
1035 case objabi.R_ARM64_PCREL:
1036
1037
1038
1039
1040 if (val>>24)&0x9f == 0x90 {
1041
1042
1043 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1044 if t >= 1<<32 || t < -1<<32 {
1045 ldr.Errorf(s, "program too large, address relocation distance = %d", t)
1046 }
1047 o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
1048 if target.IsWindows() {
1049 val &^= 3<<29 | 0x7ffff<<5
1050 }
1051 return val | int64(o0), noExtReloc, isOk
1052 } else if (val>>24)&0x9f == 0x91 {
1053
1054
1055 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1056 o1 := uint32(t&0xfff) << 10
1057 if target.IsWindows() {
1058 val &^= 0xfff << 10
1059 }
1060 return val | int64(o1), noExtReloc, isOk
1061 } else if (val>>24)&0x3b == 0x39 {
1062
1063
1064
1065 shift := uint32(val) >> 30
1066 if shift == 0 && (val>>20)&0x048 == 0x048 {
1067 shift = 4
1068 }
1069 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1070 if t&(1<<shift-1) != 0 {
1071 ldr.Errorf(s, "invalid address: %x for relocation type: ARM64_RELOC_PAGEOFF12", t)
1072 }
1073 o1 := (uint32(t&0xfff) >> shift) << 10
1074 if target.IsWindows() {
1075 val &^= 0xfff << 10
1076 }
1077 return val | int64(o1), noExtReloc, isOk
1078 } else {
1079 ldr.Errorf(s, "unsupported instruction for %x R_ARM64_PCREL", val)
1080 }
1081
1082 case objabi.R_ARM64_LDST8:
1083 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1084 o0 := uint32(t&0xfff) << 10
1085 return val | int64(o0), noExtReloc, true
1086
1087 case objabi.R_ARM64_LDST16:
1088 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1089 if t&1 != 0 {
1090 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST16_ABS_LO12_NC", t)
1091 }
1092 o0 := (uint32(t&0xfff) >> 1) << 10
1093 return val | int64(o0), noExtReloc, true
1094
1095 case objabi.R_ARM64_LDST32:
1096 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1097 if t&3 != 0 {
1098 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST32_ABS_LO12_NC", t)
1099 }
1100 o0 := (uint32(t&0xfff) >> 2) << 10
1101 return val | int64(o0), noExtReloc, true
1102
1103 case objabi.R_ARM64_LDST64:
1104 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1105 if t&7 != 0 {
1106 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST64_ABS_LO12_NC", t)
1107 }
1108 o0 := (uint32(t&0xfff) >> 3) << 10
1109 return val | int64(o0), noExtReloc, true
1110
1111 case objabi.R_ARM64_LDST128:
1112 t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
1113 if t&15 != 0 {
1114 ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST128_ABS_LO12_NC", t)
1115 }
1116 o0 := (uint32(t&0xfff) >> 4) << 10
1117 return val | int64(o0), noExtReloc, true
1118 }
1119
1120 return val, 0, false
1121 }
1122
1123 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
1124 log.Fatalf("unexpected relocation variant")
1125 return -1
1126 }
1127
1128 func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
1129 switch rt := r.Type(); rt {
1130 case objabi.R_ARM64_GOTPCREL,
1131 objabi.R_ARM64_PCREL_LDST8,
1132 objabi.R_ARM64_PCREL_LDST16,
1133 objabi.R_ARM64_PCREL_LDST32,
1134 objabi.R_ARM64_PCREL_LDST64,
1135 objabi.R_ADDRARM64:
1136 rr := ld.ExtrelocViaOuterSym(ldr, r, s)
1137 return rr, true
1138 case objabi.R_CALLARM64,
1139 objabi.R_ARM64_TLS_LE,
1140 objabi.R_ARM64_TLS_IE:
1141 return ld.ExtrelocSimple(ldr, r), true
1142 }
1143 return loader.ExtReloc{}, false
1144 }
1145
1146 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
1147 if plt.Size() == 0 {
1148
1149
1150 plt.AddUint32(ctxt.Arch, 0xa9bf7bf0)
1151
1152
1153
1154 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
1155 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x90000010)
1156
1157
1158
1159 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
1160 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0xf9400211)
1161
1162
1163 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_PCREL, 4)
1164 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x91000210)
1165
1166
1167 plt.AddUint32(ctxt.Arch, 0xd61f0220)
1168
1169
1170 plt.AddUint32(ctxt.Arch, 0xd503201f)
1171 plt.AddUint32(ctxt.Arch, 0xd503201f)
1172 plt.AddUint32(ctxt.Arch, 0xd503201f)
1173
1174
1175 if gotplt.Size() != 0 {
1176 ctxt.Errorf(gotplt.Sym(), "got.plt is not empty at the very beginning")
1177 }
1178 gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0)
1179
1180 gotplt.AddUint64(ctxt.Arch, 0)
1181 gotplt.AddUint64(ctxt.Arch, 0)
1182 }
1183 }
1184
1185 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
1186 if ldr.SymPlt(s) >= 0 {
1187 return
1188 }
1189
1190 ld.Adddynsym(ldr, target, syms, s)
1191
1192 if target.IsElf() {
1193 plt := ldr.MakeSymbolUpdater(syms.PLT)
1194 gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
1195 rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
1196 if plt.Size() == 0 {
1197 panic("plt is not set up")
1198 }
1199
1200
1201 plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
1202 plt.SetUint32(target.Arch, plt.Size()-4, 0x90000010)
1203 relocs := plt.Relocs()
1204 plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
1205
1206
1207
1208 plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
1209 plt.SetUint32(target.Arch, plt.Size()-4, 0xf9400211)
1210 relocs = plt.Relocs()
1211 plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
1212
1213
1214 plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
1215 plt.SetUint32(target.Arch, plt.Size()-4, 0x91000210)
1216 relocs = plt.Relocs()
1217 plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_PCREL)
1218
1219
1220 plt.AddUint32(target.Arch, 0xd61f0220)
1221
1222
1223 gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
1224
1225
1226 rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
1227 sDynid := ldr.SymDynid(s)
1228
1229 rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
1230 rela.AddUint64(target.Arch, 0)
1231
1232 ldr.SetPlt(s, int32(plt.Size()-16))
1233 } else if target.IsDarwin() {
1234 ld.AddGotSym(target, ldr, syms, s, 0)
1235
1236 sDynid := ldr.SymDynid(s)
1237 lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
1238 lep.AddUint32(target.Arch, uint32(sDynid))
1239
1240 plt := ldr.MakeSymbolUpdater(syms.PLT)
1241 ldr.SetPlt(s, int32(plt.Size()))
1242
1243
1244 plt.AddUint32(target.Arch, 0x90000010)
1245 r, _ := plt.AddRel(objabi.R_ARM64_GOT)
1246 r.SetOff(int32(plt.Size() - 4))
1247 r.SetSiz(4)
1248 r.SetSym(syms.GOT)
1249 r.SetAdd(int64(ldr.SymGot(s)))
1250
1251
1252 plt.AddUint32(target.Arch, 0xf9400211)
1253 r, _ = plt.AddRel(objabi.R_ARM64_GOT)
1254 r.SetOff(int32(plt.Size() - 4))
1255 r.SetSiz(4)
1256 r.SetSym(syms.GOT)
1257 r.SetAdd(int64(ldr.SymGot(s)))
1258
1259
1260 plt.AddUint32(target.Arch, 0xd61f0220)
1261 } else {
1262 ldr.Errorf(s, "addpltsym: unsupported binary format")
1263 }
1264 }
1265
1266 const (
1267 machoRelocLimit = 1 << 23
1268 peRelocLimit = 1 << 20
1269 )
1270
1271 func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
1272
1273
1274
1275
1276 if !ctxt.IsDarwin() && !ctxt.IsWindows() || !ctxt.IsExternal() {
1277 return
1278 }
1279
1280 limit := int64(machoRelocLimit)
1281 if ctxt.IsWindows() {
1282 limit = peRelocLimit
1283 }
1284
1285
1286 addLabelSyms := func(s loader.Sym, limit, sz int64) {
1287 if ldr.SymSect(s) == nil {
1288 log.Fatalf("gensymlate: symbol %s has no section (type=%v)", ldr.SymName(s), ldr.SymType(s))
1289 }
1290 v := ldr.SymValue(s)
1291 for off := limit; off < sz; off += limit {
1292 p := ldr.LookupOrCreateSym(offsetLabelName(ldr, s, off), ldr.SymVersion(s))
1293 ldr.SetAttrReachable(p, true)
1294 ldr.SetSymValue(p, v+off)
1295 ldr.SetSymSect(p, ldr.SymSect(s))
1296 if ctxt.IsDarwin() {
1297 ld.AddMachoSym(ldr, p)
1298 } else if ctxt.IsWindows() {
1299 ld.AddPELabelSym(ldr, p)
1300 } else {
1301 panic("missing case in gensymlate")
1302 }
1303
1304 }
1305 }
1306
1307 if ctxt.IsDarwin() {
1308 big := false
1309 for _, seg := range ld.Segments {
1310 if seg.Length >= machoRelocLimit {
1311 big = true
1312 break
1313 }
1314 }
1315 if !big {
1316 return
1317 }
1318 }
1319
1320 for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ {
1321 if !ldr.AttrReachable(s) {
1322 continue
1323 }
1324 t := ldr.SymType(s)
1325 if t.IsText() {
1326
1327 continue
1328 }
1329 if t >= sym.SDWARFSECT {
1330 continue
1331 }
1332 if ldr.AttrSpecial(s) || !ldr.TopLevelSym(s) {
1333
1334 continue
1335 }
1336 sz := ldr.SymSize(s)
1337 if sz <= limit {
1338 continue
1339 }
1340 addLabelSyms(s, limit, sz)
1341 }
1342
1343
1344 for _, ss := range ld.CarrierSymByType {
1345 if ss.Sym != 0 && ss.Size > limit {
1346 addLabelSyms(ss.Sym, limit, ss.Size)
1347 }
1348 }
1349 }
1350
1351
1352
1353
1354 func offsetLabelName(ldr *loader.Loader, s loader.Sym, off int64) string {
1355 if off>>20<<20 == off {
1356 return fmt.Sprintf("%s+%dMB", ldr.SymExtname(s), off>>20)
1357 }
1358 return fmt.Sprintf("%s+%d", ldr.SymExtname(s), off)
1359 }
1360
1361
1362 func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
1363 relocs := ldr.Relocs(s)
1364 r := relocs.At(ri)
1365 const pcrel = 1
1366 switch r.Type() {
1367 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
1368 objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26),
1369 objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_BRANCH26*2 + pcrel:
1370
1371
1372 fallthrough
1373 case objabi.R_CALLARM64:
1374 var t int64
1375
1376
1377
1378 if ldr.SymValue(rs) != 0 {
1379 t = ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
1380 }
1381 if t >= 1<<27 || t < -1<<27 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && (ldr.SymPkg(s) == "" || ldr.SymPkg(s) != ldr.SymPkg(rs))) {
1382
1383
1384
1385 var tramp loader.Sym
1386 for i := 0; ; i++ {
1387 oName := ldr.SymName(rs)
1388 name := oName + fmt.Sprintf("%+x-tramp%d", r.Add(), i)
1389 tramp = ldr.LookupOrCreateSym(name, ldr.SymVersion(rs))
1390 ldr.SetAttrReachable(tramp, true)
1391 if ldr.SymType(tramp) == sym.SDYNIMPORT {
1392
1393 continue
1394 }
1395 if oName == "runtime.deferreturn" {
1396 ldr.SetIsDeferReturnTramp(tramp, true)
1397 }
1398 if ldr.SymValue(tramp) == 0 {
1399
1400
1401
1402 break
1403 }
1404
1405 t = ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
1406 if t >= -1<<27 && t < 1<<27 {
1407
1408
1409 break
1410 }
1411 }
1412 if ldr.SymType(tramp) == 0 {
1413
1414 trampb := ldr.MakeSymbolUpdater(tramp)
1415 ctxt.AddTramp(trampb, ldr.SymType(s))
1416 if ldr.SymType(rs) == sym.SDYNIMPORT {
1417 if r.Add() != 0 {
1418 ctxt.Errorf(s, "nonzero addend for DYNIMPORT call: %v+%d", ldr.SymName(rs), r.Add())
1419 }
1420 gentrampgot(ctxt, ldr, trampb, rs)
1421 } else {
1422 gentramp(ctxt, ldr, trampb, rs, r.Add())
1423 }
1424 }
1425
1426 sb := ldr.MakeSymbolUpdater(s)
1427 relocs := sb.Relocs()
1428 r := relocs.At(ri)
1429 r.SetSym(tramp)
1430 r.SetAdd(0)
1431 }
1432 default:
1433 ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
1434 }
1435 }
1436
1437
1438 func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
1439 tramp.SetSize(12)
1440 P := make([]byte, tramp.Size())
1441 o1 := uint32(0x90000010)
1442 o2 := uint32(0x91000210)
1443 o3 := uint32(0xd61f0200)
1444 ctxt.Arch.ByteOrder.PutUint32(P, o1)
1445 ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
1446 ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
1447 tramp.SetData(P)
1448
1449 r, _ := tramp.AddRel(objabi.R_ADDRARM64)
1450 r.SetSiz(8)
1451 r.SetSym(target)
1452 r.SetAdd(offset)
1453 }
1454
1455
1456 func gentrampgot(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym) {
1457 tramp.SetSize(12)
1458 P := make([]byte, tramp.Size())
1459 o1 := uint32(0x90000010)
1460 o2 := uint32(0xf9400210)
1461 o3 := uint32(0xd61f0200)
1462 ctxt.Arch.ByteOrder.PutUint32(P, o1)
1463 ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
1464 ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
1465 tramp.SetData(P)
1466
1467 r, _ := tramp.AddRel(objabi.R_ARM64_GOTPCREL)
1468 r.SetSiz(8)
1469 r.SetSym(target)
1470 }
1471
View as plain text