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 if ldr.SymSect(s) == nil {
1285 log.Fatalf("gensymlate: symbol %s has no section (type=%v)", ldr.SymName(s), ldr.SymType(s))
1286 }
1287 v := ldr.SymValue(s)
1288 for off := limit; off < sz; off += limit {
1289 p := ldr.LookupOrCreateSym(offsetLabelName(ldr, s, off), ldr.SymVersion(s))
1290 ldr.SetAttrReachable(p, true)
1291 ldr.SetSymValue(p, v+off)
1292 ldr.SetSymSect(p, ldr.SymSect(s))
1293 if ctxt.IsDarwin() {
1294 ld.AddMachoSym(ldr, p)
1295 } else if ctxt.IsWindows() {
1296 ld.AddPELabelSym(ldr, p)
1297 } else {
1298 panic("missing case in gensymlate")
1299 }
1300
1301 }
1302 }
1303
1304
1305 if s := ldr.Lookup("runtime.duffcopy", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
1306 addLabelSyms(s, 8, 8*64)
1307 }
1308 if s := ldr.Lookup("runtime.duffzero", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
1309 addLabelSyms(s, 4, 4*64)
1310 }
1311
1312 if ctxt.IsDarwin() {
1313 big := false
1314 for _, seg := range ld.Segments {
1315 if seg.Length >= machoRelocLimit {
1316 big = true
1317 break
1318 }
1319 }
1320 if !big {
1321 return
1322 }
1323 }
1324
1325 for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ {
1326 if !ldr.AttrReachable(s) {
1327 continue
1328 }
1329 t := ldr.SymType(s)
1330 if t.IsText() {
1331
1332
1333 continue
1334 }
1335 if t >= sym.SDWARFSECT {
1336 continue
1337 }
1338 if ldr.AttrSpecial(s) || !ldr.TopLevelSym(s) {
1339
1340 continue
1341 }
1342 sz := ldr.SymSize(s)
1343 if sz <= limit {
1344 continue
1345 }
1346 addLabelSyms(s, limit, sz)
1347 }
1348
1349
1350 for _, ss := range ld.CarrierSymByType {
1351 if ss.Sym != 0 && ss.Size > limit {
1352 addLabelSyms(ss.Sym, limit, ss.Size)
1353 }
1354 }
1355 }
1356
1357
1358
1359
1360 func offsetLabelName(ldr *loader.Loader, s loader.Sym, off int64) string {
1361 if off>>20<<20 == off {
1362 return fmt.Sprintf("%s+%dMB", ldr.SymExtname(s), off>>20)
1363 }
1364 return fmt.Sprintf("%s+%d", ldr.SymExtname(s), off)
1365 }
1366
1367
1368 func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
1369 relocs := ldr.Relocs(s)
1370 r := relocs.At(ri)
1371 const pcrel = 1
1372 switch r.Type() {
1373 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
1374 objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26),
1375 objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_BRANCH26*2 + pcrel:
1376
1377
1378 fallthrough
1379 case objabi.R_CALLARM64:
1380 var t int64
1381
1382
1383
1384 if ldr.SymValue(rs) != 0 {
1385 t = ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
1386 }
1387 if t >= 1<<27 || t < -1<<27 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && (ldr.SymPkg(s) == "" || ldr.SymPkg(s) != ldr.SymPkg(rs))) {
1388
1389
1390
1391 var tramp loader.Sym
1392 for i := 0; ; i++ {
1393 oName := ldr.SymName(rs)
1394 name := oName + fmt.Sprintf("%+x-tramp%d", r.Add(), i)
1395 tramp = ldr.LookupOrCreateSym(name, ldr.SymVersion(rs))
1396 ldr.SetAttrReachable(tramp, true)
1397 if ldr.SymType(tramp) == sym.SDYNIMPORT {
1398
1399 continue
1400 }
1401 if oName == "runtime.deferreturn" {
1402 ldr.SetIsDeferReturnTramp(tramp, true)
1403 }
1404 if ldr.SymValue(tramp) == 0 {
1405
1406
1407
1408 break
1409 }
1410
1411 t = ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
1412 if t >= -1<<27 && t < 1<<27 {
1413
1414
1415 break
1416 }
1417 }
1418 if ldr.SymType(tramp) == 0 {
1419
1420 trampb := ldr.MakeSymbolUpdater(tramp)
1421 ctxt.AddTramp(trampb, ldr.SymType(s))
1422 if ldr.SymType(rs) == sym.SDYNIMPORT {
1423 if r.Add() != 0 {
1424 ctxt.Errorf(s, "nonzero addend for DYNIMPORT call: %v+%d", ldr.SymName(rs), r.Add())
1425 }
1426 gentrampgot(ctxt, ldr, trampb, rs)
1427 } else {
1428 gentramp(ctxt, ldr, trampb, rs, r.Add())
1429 }
1430 }
1431
1432 sb := ldr.MakeSymbolUpdater(s)
1433 relocs := sb.Relocs()
1434 r := relocs.At(ri)
1435 r.SetSym(tramp)
1436 r.SetAdd(0)
1437 }
1438 default:
1439 ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
1440 }
1441 }
1442
1443
1444 func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
1445 tramp.SetSize(12)
1446 P := make([]byte, tramp.Size())
1447 o1 := uint32(0x90000010)
1448 o2 := uint32(0x91000210)
1449 o3 := uint32(0xd61f0200)
1450 ctxt.Arch.ByteOrder.PutUint32(P, o1)
1451 ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
1452 ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
1453 tramp.SetData(P)
1454
1455 r, _ := tramp.AddRel(objabi.R_ADDRARM64)
1456 r.SetSiz(8)
1457 r.SetSym(target)
1458 r.SetAdd(offset)
1459 }
1460
1461
1462 func gentrampgot(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym) {
1463 tramp.SetSize(12)
1464 P := make([]byte, tramp.Size())
1465 o1 := uint32(0x90000010)
1466 o2 := uint32(0xf9400210)
1467 o3 := uint32(0xd61f0200)
1468 ctxt.Arch.ByteOrder.PutUint32(P, o1)
1469 ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
1470 ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
1471 tramp.SetData(P)
1472
1473 r, _ := tramp.AddRel(objabi.R_ARM64_GOTPCREL)
1474 r.SetSiz(8)
1475 r.SetSym(target)
1476 }
1477
View as plain text