1
2
3
4
5 package riscv64
6
7 import (
8 "cmd/internal/obj/riscv"
9 "cmd/internal/objabi"
10 "cmd/internal/sys"
11 "cmd/link/internal/ld"
12 "cmd/link/internal/loader"
13 "cmd/link/internal/sym"
14 "debug/elf"
15 "fmt"
16 "log"
17 "sort"
18 )
19
20
21 const fakeLabelName = ".L0 "
22
23 func gentext(ctxt *ld.Link, ldr *loader.Loader) {
24 initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
25 if initfunc == nil {
26 return
27 }
28
29
30
31
32
33
34
35
36 sz := initfunc.AddSymRef(ctxt.Arch, ctxt.Moduledata, 0, objabi.R_RISCV_PCREL_ITYPE, 8)
37 initfunc.SetUint32(ctxt.Arch, sz-8, 0x00000517)
38 initfunc.SetUint32(ctxt.Arch, sz-4, 0x00050513)
39
40 sz = initfunc.AddSymRef(ctxt.Arch, addmoduledata, 0, objabi.R_RISCV_JAL, 4)
41 initfunc.SetUint32(ctxt.Arch, sz-4, 0x0000006f)
42 }
43
44 func findHI20Reloc(ldr *loader.Loader, s loader.Sym, val int64) *loader.Reloc {
45 outer := ldr.OuterSym(s)
46 if outer == 0 {
47 return nil
48 }
49 relocs := ldr.Relocs(outer)
50 start := sort.Search(relocs.Count(), func(i int) bool { return ldr.SymValue(outer)+int64(relocs.At(i).Off()) >= val })
51 for idx := start; idx < relocs.Count(); idx++ {
52 r := relocs.At(idx)
53 if ldr.SymValue(outer)+int64(r.Off()) != val {
54 break
55 }
56 if r.Type() == objabi.R_RISCV_GOT_HI20 || r.Type() == objabi.R_RISCV_PCREL_HI20 {
57 return &r
58 }
59 }
60 return nil
61 }
62
63 func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
64 targ := r.Sym()
65
66 var targType sym.SymKind
67 if targ != 0 {
68 targType = ldr.SymType(targ)
69 }
70
71 switch r.Type() {
72 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_CALL),
73 objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_CALL_PLT):
74
75 if targType == sym.SDYNIMPORT {
76 addpltsym(target, ldr, syms, targ)
77 su := ldr.MakeSymbolUpdater(s)
78 su.SetRelocSym(rIdx, syms.PLT)
79 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
80 }
81 if targType == 0 || targType == sym.SXREF {
82 ldr.Errorf(s, "unknown symbol %s in RISCV call", ldr.SymName(targ))
83 }
84 su := ldr.MakeSymbolUpdater(s)
85 su.SetRelocType(rIdx, objabi.R_RISCV_CALL)
86 return true
87
88 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_GOT_HI20):
89 if targType != sym.SDYNIMPORT {
90
91 }
92
93 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_RISCV_64))
94 su := ldr.MakeSymbolUpdater(s)
95 su.SetRelocType(rIdx, objabi.R_RISCV_GOT_HI20)
96 su.SetRelocSym(rIdx, syms.GOT)
97 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
98 return true
99
100 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_HI20):
101 su := ldr.MakeSymbolUpdater(s)
102 su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_HI20)
103 return true
104
105 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_LO12_I):
106 if r.Add() != 0 {
107 ldr.Errorf(s, "R_RISCV_PCREL_LO12_I with non-zero addend")
108 }
109 su := ldr.MakeSymbolUpdater(s)
110 su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_I)
111 return true
112
113 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_LO12_S):
114 if r.Add() != 0 {
115 ldr.Errorf(s, "R_RISCV_PCREL_LO12_S with non-zero addend")
116 }
117 su := ldr.MakeSymbolUpdater(s)
118 su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_S)
119 return true
120
121 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_32_PCREL):
122 su := ldr.MakeSymbolUpdater(s)
123 su.SetRelocType(rIdx, objabi.R_PCREL)
124 return true
125
126 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_64):
127 su := ldr.MakeSymbolUpdater(s)
128 su.SetRelocType(rIdx, objabi.R_ADDR)
129 return true
130
131 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_ADD32):
132 su := ldr.MakeSymbolUpdater(s)
133 su.SetRelocType(rIdx, objabi.R_RISCV_ADD32)
134 return true
135
136 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_SUB32):
137 su := ldr.MakeSymbolUpdater(s)
138 su.SetRelocType(rIdx, objabi.R_RISCV_SUB32)
139 return true
140
141 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_BRANCH):
142 su := ldr.MakeSymbolUpdater(s)
143 su.SetRelocType(rIdx, objabi.R_RISCV_RVC_BRANCH)
144 return true
145
146 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_JUMP):
147 su := ldr.MakeSymbolUpdater(s)
148 su.SetRelocType(rIdx, objabi.R_RISCV_RVC_JUMP)
149 return true
150
151 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_BRANCH):
152 su := ldr.MakeSymbolUpdater(s)
153 su.SetRelocType(rIdx, objabi.R_RISCV_BRANCH)
154 return true
155
156 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RELAX):
157
158 return true
159
160 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_JAL):
161 su := ldr.MakeSymbolUpdater(s)
162 su.SetRelocType(rIdx, objabi.R_RISCV_JAL)
163 return true
164
165 default:
166 if r.Type() >= objabi.ElfRelocOffset {
167 ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
168 return false
169 }
170 }
171
172
173 relocs := ldr.Relocs(s)
174 r = relocs.At(rIdx)
175
176 switch r.Type() {
177 case objabi.R_RISCV_CALL:
178 if targType != sym.SDYNIMPORT {
179
180 return true
181 }
182 if target.IsExternal() {
183
184 return true
185 }
186
187 if r.Add() != 0 {
188 ldr.Errorf(s, "PLT reference with non-zero addend (%v)", r.Add())
189 }
190
191 addpltsym(target, ldr, syms, targ)
192 su := ldr.MakeSymbolUpdater(s)
193 su.SetRelocSym(rIdx, syms.PLT)
194 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
195
196 return true
197 }
198
199 return false
200 }
201
202 func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) {
203 if ctxt.LinkMode != ld.LinkExternal {
204 return
205 }
206
207
208
209 if ctxt.Textp == nil {
210 log.Fatal("genSymsLate called before Textp has been assigned")
211 }
212 var hi20Syms []loader.Sym
213 for _, s := range ctxt.Textp {
214 relocs := ldr.Relocs(s)
215 for ri := 0; ri < relocs.Count(); ri++ {
216 r := relocs.At(ri)
217 if r.Type() != objabi.R_RISCV_CALL &&
218 r.Type() != objabi.R_RISCV_PCREL_ITYPE &&
219 r.Type() != objabi.R_RISCV_PCREL_STYPE &&
220 r.Type() != objabi.R_RISCV_TLS_IE &&
221 r.Type() != objabi.R_RISCV_GOT_PCREL_ITYPE {
222 continue
223 }
224 if r.Off() == 0 && ldr.SymType(s).IsText() {
225
226
227 continue
228 }
229
230
231
232
233
234 sb := ldr.MakeSymbolBuilder(fakeLabelName)
235 sb.SetType(sym.STEXT)
236 sb.SetValue(ldr.SymValue(s) + int64(r.Off()))
237 sb.SetLocal(true)
238 sb.SetReachable(true)
239 sb.SetVisibilityHidden(true)
240 sb.SetSect(ldr.SymSect(s))
241 if outer := ldr.OuterSym(s); outer != 0 {
242 ldr.AddInteriorSym(outer, sb.Sym())
243 }
244 hi20Syms = append(hi20Syms, sb.Sym())
245 }
246 }
247 ctxt.Textp = append(ctxt.Textp, hi20Syms...)
248 ldr.SortSyms(ctxt.Textp)
249 }
250
251 func findHI20Symbol(ctxt *ld.Link, ldr *loader.Loader, val int64) loader.Sym {
252 idx := sort.Search(len(ctxt.Textp), func(i int) bool { return ldr.SymValue(ctxt.Textp[i]) >= val })
253 if idx >= len(ctxt.Textp) {
254 return 0
255 }
256 if s := ctxt.Textp[idx]; ldr.SymValue(s) == val && ldr.SymType(s).IsText() {
257 return s
258 }
259 return 0
260 }
261
262 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
263 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
264 switch r.Type {
265 case objabi.R_ADDR, objabi.R_DWARFSECREF:
266 out.Write64(uint64(sectoff))
267 switch r.Size {
268 case 4:
269 out.Write64(uint64(elf.R_RISCV_32) | uint64(elfsym)<<32)
270 case 8:
271 out.Write64(uint64(elf.R_RISCV_64) | uint64(elfsym)<<32)
272 default:
273 ld.Errorf("unknown size %d for %v relocation", r.Size, r.Type)
274 return false
275 }
276 out.Write64(uint64(r.Xadd))
277
278 case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
279 out.Write64(uint64(sectoff))
280 out.Write64(uint64(elf.R_RISCV_JAL) | uint64(elfsym)<<32)
281 out.Write64(uint64(r.Xadd))
282
283 case objabi.R_RISCV_CALL,
284 objabi.R_RISCV_PCREL_ITYPE,
285 objabi.R_RISCV_PCREL_STYPE,
286 objabi.R_RISCV_TLS_IE,
287 objabi.R_RISCV_GOT_PCREL_ITYPE:
288
289
290 relocs := ldr.Relocs(s)
291 offset := int64(relocs.At(ri).Off())
292 hi20Sym := findHI20Symbol(ctxt, ldr, ldr.SymValue(s)+offset)
293 if hi20Sym == 0 {
294 ld.Errorf("failed to find text symbol for HI20 relocation at %d (%x)", sectoff, ldr.SymValue(s)+offset)
295 return false
296 }
297 hi20ElfSym := ld.ElfSymForReloc(ctxt, hi20Sym)
298
299
300
301
302
303
304
305
306
307
308 var hiRel, loRel elf.R_RISCV
309 switch r.Type {
310 case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE:
311 hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_I
312 case objabi.R_RISCV_PCREL_STYPE:
313 hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_S
314 case objabi.R_RISCV_TLS_IE:
315 hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_I
316 case objabi.R_RISCV_GOT_PCREL_ITYPE:
317 hiRel, loRel = elf.R_RISCV_GOT_HI20, elf.R_RISCV_PCREL_LO12_I
318 }
319 out.Write64(uint64(sectoff))
320 out.Write64(uint64(hiRel) | uint64(elfsym)<<32)
321 out.Write64(uint64(r.Xadd))
322 out.Write64(uint64(sectoff + 4))
323 out.Write64(uint64(loRel) | uint64(hi20ElfSym)<<32)
324 out.Write64(uint64(0))
325
326 case objabi.R_RISCV_TLS_LE:
327 out.Write64(uint64(sectoff))
328 out.Write64(uint64(elf.R_RISCV_TPREL_HI20) | uint64(elfsym)<<32)
329 out.Write64(uint64(r.Xadd))
330 out.Write64(uint64(sectoff + 4))
331 out.Write64(uint64(elf.R_RISCV_TPREL_LO12_I) | uint64(elfsym)<<32)
332 out.Write64(uint64(r.Xadd))
333
334 default:
335 return false
336 }
337
338 return true
339 }
340
341 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
342 if plt.Size() != 0 {
343 return
344 }
345 if gotplt.Size() != 0 {
346 ctxt.Errorf(gotplt.Sym(), "got.plt is not empty")
347 }
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_RISCV_PCREL_HI20, 4)
363 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x00000397)
364
365 sb := ldr.MakeSymbolBuilder(fakeLabelName)
366 sb.SetType(sym.STEXT)
367 sb.SetValue(ldr.SymValue(plt.Sym()) + plt.Size() - 4)
368 sb.SetLocal(true)
369 sb.SetReachable(true)
370 sb.SetVisibilityHidden(true)
371 plt.AddInteriorSym(sb.Sym())
372
373 plt.AddUint32(ctxt.Arch, 0x41c30333)
374
375 plt.AddSymRef(ctxt.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
376 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x0003be03)
377
378 plt.AddUint32(ctxt.Arch, 0xfd430313)
379
380 plt.AddSymRef(ctxt.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
381 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x00038293)
382
383 plt.AddUint32(ctxt.Arch, 0x00135313)
384 plt.AddUint32(ctxt.Arch, 0x0082b283)
385 plt.AddUint32(ctxt.Arch, 0x00008e02)
386
387 gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0)
388 gotplt.AddUint64(ctxt.Arch, 0)
389 }
390
391 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
392 if ldr.SymPlt(s) >= 0 {
393 return
394 }
395
396 ld.Adddynsym(ldr, target, syms, s)
397
398 plt := ldr.MakeSymbolUpdater(syms.PLT)
399 gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
400 rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
401 if plt.Size() == 0 {
402 panic("plt is not set up")
403 }
404
405
406
407
408
409
410
411
412
413
414 plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_RISCV_PCREL_HI20, 4)
415 plt.SetUint32(target.Arch, plt.Size()-4, 0x00000e17)
416
417 sb := ldr.MakeSymbolBuilder(fakeLabelName)
418 sb.SetType(sym.STEXT)
419 sb.SetValue(ldr.SymValue(plt.Sym()) + plt.Size() - 4)
420 sb.SetLocal(true)
421 sb.SetReachable(true)
422 sb.SetVisibilityHidden(true)
423 plt.AddInteriorSym(sb.Sym())
424
425 plt.AddSymRef(target.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
426 plt.SetUint32(target.Arch, plt.Size()-4, 0x000e3e03)
427 plt.AddUint32(target.Arch, 0x000e0367)
428 plt.AddUint32(target.Arch, 0x00000001)
429
430 ldr.SetPlt(s, int32(plt.Size()-16))
431
432
433 gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
434
435
436 rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
437 sDynid := ldr.SymDynid(s)
438
439 rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_RISCV_JUMP_SLOT)))
440 rela.AddUint64(target.Arch, 0)
441 }
442
443 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
444 log.Fatalf("machoreloc1 not implemented")
445 return false
446 }
447
448 func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (o int64, nExtReloc int, ok bool) {
449 rs := r.Sym()
450 pc := ldr.SymValue(s) + int64(r.Off())
451
452
453
454
455 if r.Type() == objabi.R_RISCV_JAL_TRAMP {
456 relocs := ldr.Relocs(rs)
457 if relocs.Count() != 1 {
458 ldr.Errorf(s, "trampoline %v has %d relocations", ldr.SymName(rs), relocs.Count())
459 }
460 tr := relocs.At(0)
461 if tr.Type() != objabi.R_RISCV_CALL {
462 ldr.Errorf(s, "trampoline %v has unexpected relocation %v", ldr.SymName(rs), tr.Type())
463 }
464 trs := tr.Sym()
465 if ldr.SymValue(trs) != 0 && ldr.SymType(trs) != sym.SDYNIMPORT && ldr.SymType(trs) != sym.SUNDEFEXT {
466 trsOff := ldr.SymValue(trs) + tr.Add() - pc
467 if trsOff >= -(1<<20) && trsOff < (1<<20) {
468 r.SetType(objabi.R_RISCV_JAL)
469 r.SetSym(trs)
470 r.SetAdd(tr.Add())
471 rs = trs
472 }
473 }
474
475 }
476
477 if target.IsExternal() {
478 switch r.Type() {
479 case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
480 return val, 1, true
481
482 case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE, objabi.R_RISCV_TLS_LE, objabi.R_RISCV_GOT_PCREL_ITYPE:
483 return val, 2, true
484 }
485
486 return val, 0, false
487 }
488
489 off := ldr.SymValue(rs) + r.Add() - pc
490
491 switch r.Type() {
492 case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
493
494 imm, err := riscv.EncodeJImmediate(off)
495 if err != nil {
496 ldr.Errorf(s, "cannot encode J-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
497 }
498 immMask := int64(riscv.JTypeImmMask)
499
500 val = (val &^ immMask) | imm
501
502 return val, 0, true
503
504 case objabi.R_RISCV_TLS_IE:
505 log.Fatalf("cannot handle R_RISCV_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
506 return val, 0, false
507
508 case objabi.R_RISCV_TLS_LE:
509
510 off := r.Add()
511
512 low, high, err := riscv.Split32BitImmediate(off)
513 if err != nil {
514 ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
515 }
516
517 luiImm, err := riscv.EncodeUImmediate(high)
518 if err != nil {
519 ldr.Errorf(s, "cannot encode R_RISCV_TLS_LE LUI relocation offset for %s: %v", ldr.SymName(rs), err)
520 }
521
522 addiwImm, err := riscv.EncodeIImmediate(low)
523 if err != nil {
524 ldr.Errorf(s, "cannot encode R_RISCV_TLS_LE I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
525 }
526
527 lui := int64(uint32(val))
528 addiw := int64(uint32(val >> 32))
529
530 lui = (lui &^ riscv.UTypeImmMask) | int64(uint32(luiImm))
531 addiw = (addiw &^ riscv.ITypeImmMask) | int64(uint32(addiwImm))
532
533 return addiw<<32 | lui, 0, true
534
535 case objabi.R_RISCV_BRANCH:
536 pc := ldr.SymValue(s) + int64(r.Off())
537 off := ldr.SymValue(rs) + r.Add() - pc
538
539 imm, err := riscv.EncodeBImmediate(off)
540 if err != nil {
541 ldr.Errorf(s, "cannot encode B-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
542 }
543 ins := (int64(uint32(val)) &^ riscv.BTypeImmMask) | int64(uint32(imm))
544
545 return ins, 0, true
546
547 case objabi.R_RISCV_RVC_BRANCH, objabi.R_RISCV_RVC_JUMP:
548 pc := ldr.SymValue(s) + int64(r.Off())
549 off := ldr.SymValue(rs) + r.Add() - pc
550
551 var err error
552 var imm, immMask int64
553 switch r.Type() {
554 case objabi.R_RISCV_RVC_BRANCH:
555 immMask = riscv.CBTypeImmMask
556 imm, err = riscv.EncodeCBImmediate(off)
557 if err != nil {
558 ldr.Errorf(s, "cannot encode CB-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
559 }
560 case objabi.R_RISCV_RVC_JUMP:
561 immMask = riscv.CJTypeImmMask
562 imm, err = riscv.EncodeCJImmediate(off)
563 if err != nil {
564 ldr.Errorf(s, "cannot encode CJ-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
565 }
566 default:
567 panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
568 }
569
570 ins := (int64(uint16(val)) &^ immMask) | int64(uint16(imm))
571
572 return ins, 0, true
573
574 case objabi.R_RISCV_GOT_HI20, objabi.R_RISCV_PCREL_HI20:
575 pc := ldr.SymValue(s) + int64(r.Off())
576 off := ldr.SymValue(rs) + r.Add() - pc
577
578
579 _, high, err := riscv.Split32BitImmediate(off)
580 if err != nil {
581 ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
582 }
583
584 auipcImm, err := riscv.EncodeUImmediate(high)
585 if err != nil {
586 ldr.Errorf(s, "cannot encode R_RISCV_PCREL_ AUIPC relocation offset for %s: %v", ldr.SymName(rs), err)
587 }
588
589 auipc := int64(uint32(val))
590 auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm))
591
592 return auipc, 0, true
593
594 case objabi.R_RISCV_PCREL_LO12_I, objabi.R_RISCV_PCREL_LO12_S:
595 hi20Reloc := findHI20Reloc(ldr, rs, ldr.SymValue(rs))
596 if hi20Reloc == nil {
597 ldr.Errorf(s, "missing HI20 relocation for LO12 relocation with %s (%d)", ldr.SymName(rs), rs)
598 }
599
600 pc := ldr.SymValue(s) + int64(hi20Reloc.Off())
601 off := ldr.SymValue(hi20Reloc.Sym()) + hi20Reloc.Add() - pc
602
603 low, _, err := riscv.Split32BitImmediate(off)
604 if err != nil {
605 ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
606 }
607
608 var imm, immMask int64
609 switch r.Type() {
610 case objabi.R_RISCV_PCREL_LO12_I:
611 immMask = riscv.ITypeImmMask
612 imm, err = riscv.EncodeIImmediate(low)
613 if err != nil {
614 ldr.Errorf(s, "cannot encode objabi.R_RISCV_PCREL_LO12_I I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
615 }
616 case objabi.R_RISCV_PCREL_LO12_S:
617 immMask = riscv.STypeImmMask
618 imm, err = riscv.EncodeSImmediate(low)
619 if err != nil {
620 ldr.Errorf(s, "cannot encode R_RISCV_PCREL_LO12_S S-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
621 }
622 default:
623 panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
624 }
625
626 ins := int64(uint32(val))
627 ins = (ins &^ immMask) | int64(uint32(imm))
628 return ins, 0, true
629
630 case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE:
631
632 low, high, err := riscv.Split32BitImmediate(off)
633 if err != nil {
634 ldr.Errorf(s, "pc-relative relocation does not fit in 32 bits: %d", off)
635 }
636
637 auipcImm, err := riscv.EncodeUImmediate(high)
638 if err != nil {
639 ldr.Errorf(s, "cannot encode AUIPC relocation offset for %s: %v", ldr.SymName(rs), err)
640 }
641
642 var secondImm, secondImmMask int64
643 switch r.Type() {
644 case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE:
645 secondImmMask = riscv.ITypeImmMask
646 secondImm, err = riscv.EncodeIImmediate(low)
647 if err != nil {
648 ldr.Errorf(s, "cannot encode I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
649 }
650 case objabi.R_RISCV_PCREL_STYPE:
651 secondImmMask = riscv.STypeImmMask
652 secondImm, err = riscv.EncodeSImmediate(low)
653 if err != nil {
654 ldr.Errorf(s, "cannot encode S-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
655 }
656 default:
657 panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
658 }
659
660 auipc := int64(uint32(val))
661 second := int64(uint32(val >> 32))
662
663 auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm))
664 second = (second &^ secondImmMask) | int64(uint32(secondImm))
665
666 return second<<32 | auipc, 0, true
667
668 case objabi.R_RISCV_ADD32:
669 addr := val + ldr.SymValue(rs) + r.Add()
670 return int64(uint32(addr)), 0, true
671
672 case objabi.R_RISCV_SUB32:
673 addr := val - ldr.SymValue(rs) - r.Add()
674 return int64(uint32(addr)), 0, true
675 }
676
677 return val, 0, false
678 }
679
680 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
681 log.Fatalf("archrelocvariant")
682 return -1
683 }
684
685 func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
686 switch r.Type() {
687 case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
688 return ld.ExtrelocSimple(ldr, r), true
689
690 case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE, objabi.R_RISCV_TLS_LE, objabi.R_RISCV_GOT_PCREL_ITYPE:
691 return ld.ExtrelocViaOuterSym(ldr, r, s), true
692 }
693 return loader.ExtReloc{}, false
694 }
695
696 func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
697 relocs := ldr.Relocs(s)
698 r := relocs.At(ri)
699
700 switch r.Type() {
701 case objabi.R_RISCV_JAL:
702 pc := ldr.SymValue(s) + int64(r.Off())
703 off := ldr.SymValue(rs) + r.Add() - pc
704
705
706
707 if ldr.SymValue(rs) != 0 && off >= -(1<<20) && off < (1<<20) && (*ld.FlagDebugTramp <= 1 || ldr.SymPkg(s) == ldr.SymPkg(rs)) {
708 break
709 }
710
711
712
713
714
715 var tramp loader.Sym
716 for i := 0; ; i++ {
717 oName := ldr.SymName(rs)
718 name := fmt.Sprintf("%s-tramp%d", oName, i)
719 if r.Add() != 0 {
720 name = fmt.Sprintf("%s%+x-tramp%d", oName, r.Add(), i)
721 }
722 tramp = ldr.LookupOrCreateSym(name, ldr.SymVersion(rs))
723 ldr.SetAttrReachable(tramp, true)
724 if ldr.SymType(tramp) == sym.SDYNIMPORT {
725
726 continue
727 }
728 if oName == "runtime.deferreturn" {
729 ldr.SetIsDeferReturnTramp(tramp, true)
730 }
731 if ldr.SymValue(tramp) == 0 {
732
733
734
735 break
736 }
737
738 trampOff := ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
739 if trampOff >= -(1<<20) && trampOff < (1<<20) {
740
741 break
742 }
743 }
744 if ldr.SymType(tramp) == 0 {
745 trampb := ldr.MakeSymbolUpdater(tramp)
746 ctxt.AddTramp(trampb, ldr.SymType(s))
747 genCallTramp(ctxt.Arch, ctxt.LinkMode, ldr, trampb, rs, r.Add())
748 }
749 sb := ldr.MakeSymbolUpdater(s)
750 if ldr.SymValue(rs) == 0 {
751
752
753
754
755 sb.SetRelocType(ri, objabi.R_RISCV_JAL_TRAMP)
756 }
757 relocs := sb.Relocs()
758 r := relocs.At(ri)
759 r.SetSym(tramp)
760 r.SetAdd(0)
761
762 case objabi.R_RISCV_CALL:
763
764
765 default:
766 ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
767 }
768 }
769
770 func genCallTramp(arch *sys.Arch, linkmode ld.LinkMode, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
771 tramp.AddUint32(arch, 0x00000f97)
772 tramp.AddUint32(arch, 0x000f8067)
773
774 r, _ := tramp.AddRel(objabi.R_RISCV_CALL)
775 r.SetSiz(8)
776 r.SetSym(target)
777 r.SetAdd(offset)
778 }
779
View as plain text