1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package riscv64
6
7import (
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// fakeLabelName matches the RISCV_FAKE_LABEL_NAME from binutils.
21const fakeLabelName = ".L0 "
22
23func gentext(ctxt *ld.Link, ldr *loader.Loader) {}
24
25func findHI20Reloc(ldr *loader.Loader, s loader.Sym, val int64) *loader.Reloc {
26	outer := ldr.OuterSym(s)
27	if outer == 0 {
28		return nil
29	}
30	relocs := ldr.Relocs(outer)
31	start := sort.Search(relocs.Count(), func(i int) bool { return ldr.SymValue(outer)+int64(relocs.At(i).Off()) >= val })
32	for idx := start; idx < relocs.Count(); idx++ {
33		r := relocs.At(idx)
34		if ldr.SymValue(outer)+int64(r.Off()) != val {
35			break
36		}
37		if r.Type() == objabi.R_RISCV_GOT_HI20 || r.Type() == objabi.R_RISCV_PCREL_HI20 {
38			return &r
39		}
40	}
41	return nil
42}
43
44func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
45	targ := r.Sym()
46
47	var targType sym.SymKind
48	if targ != 0 {
49		targType = ldr.SymType(targ)
50	}
51
52	switch r.Type() {
53	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_CALL),
54		objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_CALL_PLT):
55
56		if targType == sym.SDYNIMPORT {
57			addpltsym(target, ldr, syms, targ)
58			su := ldr.MakeSymbolUpdater(s)
59			su.SetRelocSym(rIdx, syms.PLT)
60			su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
61		}
62		if targType == 0 || targType == sym.SXREF {
63			ldr.Errorf(s, "unknown symbol %s in RISCV call", ldr.SymName(targ))
64		}
65		su := ldr.MakeSymbolUpdater(s)
66		su.SetRelocType(rIdx, objabi.R_RISCV_CALL)
67		return true
68
69	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_GOT_HI20):
70		if targType != sym.SDYNIMPORT {
71			// TODO(jsing): Could convert to non-GOT reference.
72		}
73
74		ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_RISCV_64))
75		su := ldr.MakeSymbolUpdater(s)
76		su.SetRelocType(rIdx, objabi.R_RISCV_GOT_HI20)
77		su.SetRelocSym(rIdx, syms.GOT)
78		su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
79		return true
80
81	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_HI20):
82		su := ldr.MakeSymbolUpdater(s)
83		su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_HI20)
84		return true
85
86	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_LO12_I):
87		if r.Add() != 0 {
88			ldr.Errorf(s, "R_RISCV_PCREL_LO12_I with non-zero addend")
89		}
90		su := ldr.MakeSymbolUpdater(s)
91		su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_I)
92		return true
93
94	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_LO12_S):
95		if r.Add() != 0 {
96			ldr.Errorf(s, "R_RISCV_PCREL_LO12_S with non-zero addend")
97		}
98		su := ldr.MakeSymbolUpdater(s)
99		su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_S)
100		return true
101
102	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_BRANCH):
103		su := ldr.MakeSymbolUpdater(s)
104		su.SetRelocType(rIdx, objabi.R_RISCV_RVC_BRANCH)
105		return true
106
107	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_JUMP):
108		su := ldr.MakeSymbolUpdater(s)
109		su.SetRelocType(rIdx, objabi.R_RISCV_RVC_JUMP)
110		return true
111
112	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_BRANCH):
113		su := ldr.MakeSymbolUpdater(s)
114		su.SetRelocType(rIdx, objabi.R_RISCV_BRANCH)
115		return true
116
117	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RELAX):
118		// Ignore relaxations, at least for now.
119		return true
120
121	default:
122		if r.Type() >= objabi.ElfRelocOffset {
123			ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
124			return false
125		}
126	}
127
128	// Reread the reloc to incorporate any changes in type above.
129	relocs := ldr.Relocs(s)
130	r = relocs.At(rIdx)
131
132	switch r.Type() {
133	case objabi.R_RISCV_CALL:
134		if targType != sym.SDYNIMPORT {
135			// nothing to do, the relocation will be laid out in reloc
136			return true
137		}
138		if target.IsExternal() {
139			// External linker will do this relocation.
140			return true
141		}
142		// Internal linking.
143		if r.Add() != 0 {
144			ldr.Errorf(s, "PLT reference with non-zero addend (%v)", r.Add())
145		}
146		// Build a PLT entry and change the relocation target to that entry.
147		addpltsym(target, ldr, syms, targ)
148		su := ldr.MakeSymbolUpdater(s)
149		su.SetRelocSym(rIdx, syms.PLT)
150		su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
151
152		return true
153	}
154
155	return false
156}
157
158func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) {
159	if ctxt.LinkMode != ld.LinkExternal {
160		return
161	}
162
163	// Generate a local text symbol for each relocation target, as the
164	// R_RISCV_PCREL_LO12_* relocations generated by elfreloc1 need it.
165	if ctxt.Textp == nil {
166		log.Fatal("genSymsLate called before Textp has been assigned")
167	}
168	var hi20Syms []loader.Sym
169	for _, s := range ctxt.Textp {
170		relocs := ldr.Relocs(s)
171		for ri := 0; ri < relocs.Count(); ri++ {
172			r := relocs.At(ri)
173			if r.Type() != objabi.R_RISCV_CALL && r.Type() != objabi.R_RISCV_PCREL_ITYPE &&
174				r.Type() != objabi.R_RISCV_PCREL_STYPE && r.Type() != objabi.R_RISCV_TLS_IE {
175				continue
176			}
177			if r.Off() == 0 && ldr.SymType(s) == sym.STEXT {
178				// Use the symbol for the function instead of creating
179				// an overlapping symbol.
180				continue
181			}
182
183			// TODO(jsing): Consider generating ELF symbols without needing
184			// loader symbols, in order to reduce memory consumption. This
185			// would require changes to genelfsym so that it called
186			// putelfsym and putelfsyment as appropriate.
187			sb := ldr.MakeSymbolBuilder(fakeLabelName)
188			sb.SetType(sym.STEXT)
189			sb.SetValue(ldr.SymValue(s) + int64(r.Off()))
190			sb.SetLocal(true)
191			sb.SetReachable(true)
192			sb.SetVisibilityHidden(true)
193			sb.SetSect(ldr.SymSect(s))
194			if outer := ldr.OuterSym(s); outer != 0 {
195				ldr.AddInteriorSym(outer, sb.Sym())
196			}
197			hi20Syms = append(hi20Syms, sb.Sym())
198		}
199	}
200	ctxt.Textp = append(ctxt.Textp, hi20Syms...)
201	ldr.SortSyms(ctxt.Textp)
202}
203
204func findHI20Symbol(ctxt *ld.Link, ldr *loader.Loader, val int64) loader.Sym {
205	idx := sort.Search(len(ctxt.Textp), func(i int) bool { return ldr.SymValue(ctxt.Textp[i]) >= val })
206	if idx >= len(ctxt.Textp) {
207		return 0
208	}
209	if s := ctxt.Textp[idx]; ldr.SymValue(s) == val && ldr.SymType(s) == sym.STEXT {
210		return s
211	}
212	return 0
213}
214
215func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
216	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
217	switch r.Type {
218	case objabi.R_ADDR, objabi.R_DWARFSECREF:
219		out.Write64(uint64(sectoff))
220		switch r.Size {
221		case 4:
222			out.Write64(uint64(elf.R_RISCV_32) | uint64(elfsym)<<32)
223		case 8:
224			out.Write64(uint64(elf.R_RISCV_64) | uint64(elfsym)<<32)
225		default:
226			ld.Errorf(nil, "unknown size %d for %v relocation", r.Size, r.Type)
227			return false
228		}
229		out.Write64(uint64(r.Xadd))
230
231	case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
232		out.Write64(uint64(sectoff))
233		out.Write64(uint64(elf.R_RISCV_JAL) | uint64(elfsym)<<32)
234		out.Write64(uint64(r.Xadd))
235
236	case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE:
237		// Find the text symbol for the AUIPC instruction targeted
238		// by this relocation.
239		relocs := ldr.Relocs(s)
240		offset := int64(relocs.At(ri).Off())
241		hi20Sym := findHI20Symbol(ctxt, ldr, ldr.SymValue(s)+offset)
242		if hi20Sym == 0 {
243			ld.Errorf(nil, "failed to find text symbol for HI20 relocation at %d (%x)", sectoff, ldr.SymValue(s)+offset)
244			return false
245		}
246		hi20ElfSym := ld.ElfSymForReloc(ctxt, hi20Sym)
247
248		// Emit two relocations - a R_RISCV_PCREL_HI20 relocation and a
249		// corresponding R_RISCV_PCREL_LO12_I or R_RISCV_PCREL_LO12_S relocation.
250		// Note that the LO12 relocation must point to a target that has a valid
251		// HI20 PC-relative relocation text symbol, which in turn points to the
252		// given symbol. For further details see section 8.4.9 of the RISC-V ABIs
253		// Specification:
254		//
255		//  https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
256		//
257		var hiRel, loRel elf.R_RISCV
258		switch r.Type {
259		case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE:
260			hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_I
261		case objabi.R_RISCV_PCREL_STYPE:
262			hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_S
263		case objabi.R_RISCV_TLS_IE:
264			hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_I
265		}
266		out.Write64(uint64(sectoff))
267		out.Write64(uint64(hiRel) | uint64(elfsym)<<32)
268		out.Write64(uint64(r.Xadd))
269		out.Write64(uint64(sectoff + 4))
270		out.Write64(uint64(loRel) | uint64(hi20ElfSym)<<32)
271		out.Write64(uint64(0))
272
273	case objabi.R_RISCV_TLS_LE:
274		out.Write64(uint64(sectoff))
275		out.Write64(uint64(elf.R_RISCV_TPREL_HI20) | uint64(elfsym)<<32)
276		out.Write64(uint64(r.Xadd))
277		out.Write64(uint64(sectoff + 4))
278		out.Write64(uint64(elf.R_RISCV_TPREL_LO12_I) | uint64(elfsym)<<32)
279		out.Write64(uint64(r.Xadd))
280
281	default:
282		return false
283	}
284
285	return true
286}
287
288func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
289	if plt.Size() != 0 {
290		return
291	}
292	if gotplt.Size() != 0 {
293		ctxt.Errorf(gotplt.Sym(), "got.plt is not empty")
294	}
295
296	// See section 8.4.6 of the RISC-V ABIs Specification:
297	//
298	//  https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
299	//
300	// 1:   auipc  t2, %pcrel_hi(.got.plt)
301	//      sub    t1, t1, t3               # shifted .got.plt offset + hdr size + 12
302	//      l[w|d] t3, %pcrel_lo(1b)(t2)    # _dl_runtime_resolve
303	//      addi   t1, t1, -(hdr size + 12) # shifted .got.plt offset
304	//      addi   t0, t2, %pcrel_lo(1b)    # &.got.plt
305	//      srli   t1, t1, log2(16/PTRSIZE) # .got.plt offset
306	//      l[w|d] t0, PTRSIZE(t0)          # link map
307	//      jr     t3
308
309	plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_RISCV_PCREL_HI20, 4)
310	plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x00000397) // auipc   t2,0x0
311
312	sb := ldr.MakeSymbolBuilder(fakeLabelName)
313	sb.SetType(sym.STEXT)
314	sb.SetValue(ldr.SymValue(plt.Sym()) + plt.Size() - 4)
315	sb.SetLocal(true)
316	sb.SetReachable(true)
317	sb.SetVisibilityHidden(true)
318	plt.AddInteriorSym(sb.Sym())
319
320	plt.AddUint32(ctxt.Arch, 0x41c30333) // sub     t1,t1,t3
321
322	plt.AddSymRef(ctxt.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
323	plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x0003be03) // ld      t3,0(t2)
324
325	plt.AddUint32(ctxt.Arch, 0xfd430313) // addi    t1,t1,-44
326
327	plt.AddSymRef(ctxt.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
328	plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x00038293) // addi    t0,t2,0
329
330	plt.AddUint32(ctxt.Arch, 0x00135313) // srli    t1,t1,0x1
331	plt.AddUint32(ctxt.Arch, 0x0082b283) // ld      t0,8(t0)
332	plt.AddUint32(ctxt.Arch, 0x00008e02) // jr      t3
333
334	gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0) // got.plt[0] = _dl_runtime_resolve
335	gotplt.AddUint64(ctxt.Arch, 0)            // got.plt[1] = link map
336}
337
338func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
339	if ldr.SymPlt(s) >= 0 {
340		return
341	}
342
343	ld.Adddynsym(ldr, target, syms, s)
344
345	plt := ldr.MakeSymbolUpdater(syms.PLT)
346	gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
347	rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
348	if plt.Size() == 0 {
349		panic("plt is not set up")
350	}
351
352	// See section 8.4.6 of the RISC-V ABIs Specification:
353	//
354	//  https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
355	//
356	// 1:  auipc   t3, %pcrel_hi([email protected])
357	//     l[w|d]  t3, %pcrel_lo(1b)(t3)
358	//     jalr    t1, t3
359	//     nop
360
361	plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_RISCV_PCREL_HI20, 4)
362	plt.SetUint32(target.Arch, plt.Size()-4, 0x00000e17) // auipc   t3,0x0
363
364	sb := ldr.MakeSymbolBuilder(fakeLabelName)
365	sb.SetType(sym.STEXT)
366	sb.SetValue(ldr.SymValue(plt.Sym()) + plt.Size() - 4)
367	sb.SetLocal(true)
368	sb.SetReachable(true)
369	sb.SetVisibilityHidden(true)
370	plt.AddInteriorSym(sb.Sym())
371
372	plt.AddSymRef(target.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
373	plt.SetUint32(target.Arch, plt.Size()-4, 0x000e3e03) // ld      t3,0(t3)
374	plt.AddUint32(target.Arch, 0x000e0367)               // jalr    t1,t3
375	plt.AddUint32(target.Arch, 0x00000001)               // nop
376
377	ldr.SetPlt(s, int32(plt.Size()-16))
378
379	// add to got.plt: pointer to plt[0]
380	gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
381
382	// rela
383	rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
384	sDynid := ldr.SymDynid(s)
385
386	rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_RISCV_JUMP_SLOT)))
387	rela.AddUint64(target.Arch, 0)
388}
389
390func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
391	log.Fatalf("machoreloc1 not implemented")
392	return false
393}
394
395func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (o int64, nExtReloc int, ok bool) {
396	rs := r.Sym()
397	pc := ldr.SymValue(s) + int64(r.Off())
398
399	// If the call points to a trampoline, see if we can reach the symbol
400	// directly. This situation can occur when the relocation symbol is
401	// not assigned an address until after the trampolines are generated.
402	if r.Type() == objabi.R_RISCV_JAL_TRAMP {
403		relocs := ldr.Relocs(rs)
404		if relocs.Count() != 1 {
405			ldr.Errorf(s, "trampoline %v has %d relocations", ldr.SymName(rs), relocs.Count())
406		}
407		tr := relocs.At(0)
408		if tr.Type() != objabi.R_RISCV_CALL {
409			ldr.Errorf(s, "trampoline %v has unexpected relocation %v", ldr.SymName(rs), tr.Type())
410		}
411		trs := tr.Sym()
412		if ldr.SymValue(trs) != 0 && ldr.SymType(trs) != sym.SDYNIMPORT && ldr.SymType(trs) != sym.SUNDEFEXT {
413			trsOff := ldr.SymValue(trs) + tr.Add() - pc
414			if trsOff >= -(1<<20) && trsOff < (1<<20) {
415				r.SetType(objabi.R_RISCV_JAL)
416				r.SetSym(trs)
417				r.SetAdd(tr.Add())
418				rs = trs
419			}
420		}
421
422	}
423
424	if target.IsExternal() {
425		switch r.Type() {
426		case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
427			return val, 1, true
428
429		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:
430			return val, 2, true
431		}
432
433		return val, 0, false
434	}
435
436	off := ldr.SymValue(rs) + r.Add() - pc
437
438	switch r.Type() {
439	case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
440		// Generate instruction immediates.
441		imm, err := riscv.EncodeJImmediate(off)
442		if err != nil {
443			ldr.Errorf(s, "cannot encode J-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
444		}
445		immMask := int64(riscv.JTypeImmMask)
446
447		val = (val &^ immMask) | int64(imm)
448
449		return val, 0, true
450
451	case objabi.R_RISCV_TLS_IE:
452		log.Fatalf("cannot handle R_RISCV_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
453		return val, 0, false
454
455	case objabi.R_RISCV_TLS_LE:
456		// Generate LUI and ADDIW instruction immediates.
457		off := r.Add()
458
459		low, high, err := riscv.Split32BitImmediate(off)
460		if err != nil {
461			ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
462		}
463
464		luiImm, err := riscv.EncodeUImmediate(high)
465		if err != nil {
466			ldr.Errorf(s, "cannot encode R_RISCV_TLS_LE LUI relocation offset for %s: %v", ldr.SymName(rs), err)
467		}
468
469		addiwImm, err := riscv.EncodeIImmediate(low)
470		if err != nil {
471			ldr.Errorf(s, "cannot encode R_RISCV_TLS_LE I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
472		}
473
474		lui := int64(uint32(val))
475		addiw := int64(uint32(val >> 32))
476
477		lui = (lui &^ riscv.UTypeImmMask) | int64(uint32(luiImm))
478		addiw = (addiw &^ riscv.ITypeImmMask) | int64(uint32(addiwImm))
479
480		return addiw<<32 | lui, 0, true
481
482	case objabi.R_RISCV_BRANCH:
483		pc := ldr.SymValue(s) + int64(r.Off())
484		off := ldr.SymValue(rs) + r.Add() - pc
485
486		imm, err := riscv.EncodeBImmediate(off)
487		if err != nil {
488			ldr.Errorf(s, "cannot encode B-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
489		}
490		ins := (int64(uint32(val)) &^ riscv.BTypeImmMask) | int64(uint32(imm))
491
492		return ins, 0, true
493
494	case objabi.R_RISCV_RVC_BRANCH, objabi.R_RISCV_RVC_JUMP:
495		pc := ldr.SymValue(s) + int64(r.Off())
496		off := ldr.SymValue(rs) + r.Add() - pc
497
498		var err error
499		var imm, immMask int64
500		switch r.Type() {
501		case objabi.R_RISCV_RVC_BRANCH:
502			immMask = riscv.CBTypeImmMask
503			imm, err = riscv.EncodeCBImmediate(off)
504			if err != nil {
505				ldr.Errorf(s, "cannot encode CB-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
506			}
507		case objabi.R_RISCV_RVC_JUMP:
508			immMask = riscv.CJTypeImmMask
509			imm, err = riscv.EncodeCJImmediate(off)
510			if err != nil {
511				ldr.Errorf(s, "cannot encode CJ-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
512			}
513		default:
514			panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
515		}
516
517		ins := (int64(uint16(val)) &^ immMask) | int64(uint16(imm))
518
519		return ins, 0, true
520
521	case objabi.R_RISCV_GOT_HI20, objabi.R_RISCV_PCREL_HI20:
522		pc := ldr.SymValue(s) + int64(r.Off())
523		off := ldr.SymValue(rs) + r.Add() - pc
524
525		// Generate AUIPC immediates.
526		_, high, err := riscv.Split32BitImmediate(off)
527		if err != nil {
528			ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
529		}
530
531		auipcImm, err := riscv.EncodeUImmediate(high)
532		if err != nil {
533			ldr.Errorf(s, "cannot encode R_RISCV_PCREL_ AUIPC relocation offset for %s: %v", ldr.SymName(rs), err)
534		}
535
536		auipc := int64(uint32(val))
537		auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm))
538
539		return auipc, 0, true
540
541	case objabi.R_RISCV_PCREL_LO12_I, objabi.R_RISCV_PCREL_LO12_S:
542		hi20Reloc := findHI20Reloc(ldr, rs, ldr.SymValue(rs))
543		if hi20Reloc == nil {
544			ldr.Errorf(s, "missing HI20 relocation for LO12 relocation with %s (%d)", ldr.SymName(rs), rs)
545		}
546
547		pc := ldr.SymValue(s) + int64(hi20Reloc.Off())
548		off := ldr.SymValue(hi20Reloc.Sym()) + hi20Reloc.Add() - pc
549
550		low, _, err := riscv.Split32BitImmediate(off)
551		if err != nil {
552			ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
553		}
554
555		var imm, immMask int64
556		switch r.Type() {
557		case objabi.R_RISCV_PCREL_LO12_I:
558			immMask = riscv.ITypeImmMask
559			imm, err = riscv.EncodeIImmediate(low)
560			if err != nil {
561				ldr.Errorf(s, "cannot encode objabi.R_RISCV_PCREL_LO12_I I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
562			}
563		case objabi.R_RISCV_PCREL_LO12_S:
564			immMask = riscv.STypeImmMask
565			imm, err = riscv.EncodeSImmediate(low)
566			if err != nil {
567				ldr.Errorf(s, "cannot encode R_RISCV_PCREL_LO12_S S-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
568			}
569		default:
570			panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
571		}
572
573		ins := int64(uint32(val))
574		ins = (ins &^ immMask) | int64(uint32(imm))
575		return ins, 0, true
576
577	case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE:
578		// Generate AUIPC and second instruction immediates.
579		low, high, err := riscv.Split32BitImmediate(off)
580		if err != nil {
581			ldr.Errorf(s, "pc-relative 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 AUIPC relocation offset for %s: %v", ldr.SymName(rs), err)
587		}
588
589		var secondImm, secondImmMask int64
590		switch r.Type() {
591		case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE:
592			secondImmMask = riscv.ITypeImmMask
593			secondImm, err = riscv.EncodeIImmediate(low)
594			if err != nil {
595				ldr.Errorf(s, "cannot encode I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
596			}
597		case objabi.R_RISCV_PCREL_STYPE:
598			secondImmMask = riscv.STypeImmMask
599			secondImm, err = riscv.EncodeSImmediate(low)
600			if err != nil {
601				ldr.Errorf(s, "cannot encode S-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
602			}
603		default:
604			panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
605		}
606
607		auipc := int64(uint32(val))
608		second := int64(uint32(val >> 32))
609
610		auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm))
611		second = (second &^ secondImmMask) | int64(uint32(secondImm))
612
613		return second<<32 | auipc, 0, true
614	}
615
616	return val, 0, false
617}
618
619func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
620	log.Fatalf("archrelocvariant")
621	return -1
622}
623
624func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
625	switch r.Type() {
626	case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
627		return ld.ExtrelocSimple(ldr, r), true
628
629	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:
630		return ld.ExtrelocViaOuterSym(ldr, r, s), true
631	}
632	return loader.ExtReloc{}, false
633}
634
635func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
636	relocs := ldr.Relocs(s)
637	r := relocs.At(ri)
638
639	switch r.Type() {
640	case objabi.R_RISCV_JAL:
641		pc := ldr.SymValue(s) + int64(r.Off())
642		off := ldr.SymValue(rs) + r.Add() - pc
643
644		// Relocation symbol has an address and is directly reachable,
645		// therefore there is no need for a trampoline.
646		if ldr.SymValue(rs) != 0 && off >= -(1<<20) && off < (1<<20) && (*ld.FlagDebugTramp <= 1 || ldr.SymPkg(s) == ldr.SymPkg(rs)) {
647			break
648		}
649
650		// Relocation symbol is too far for a direct call or has not
651		// yet been given an address. See if an existing trampoline is
652		// reachable and if so, reuse it. Otherwise we need to create
653		// a new trampoline.
654		var tramp loader.Sym
655		for i := 0; ; i++ {
656			oName := ldr.SymName(rs)
657			name := fmt.Sprintf("%s-tramp%d", oName, i)
658			if r.Add() != 0 {
659				name = fmt.Sprintf("%s%+x-tramp%d", oName, r.Add(), i)
660			}
661			tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
662			ldr.SetAttrReachable(tramp, true)
663			if ldr.SymType(tramp) == sym.SDYNIMPORT {
664				// Do not reuse trampoline defined in other module.
665				continue
666			}
667			if oName == "runtime.deferreturn" {
668				ldr.SetIsDeferReturnTramp(tramp, true)
669			}
670			if ldr.SymValue(tramp) == 0 {
671				// Either trampoline does not exist or we found one
672				// that does not have an address assigned and will be
673				// laid down immediately after the current function.
674				break
675			}
676
677			trampOff := ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
678			if trampOff >= -(1<<20) && trampOff < (1<<20) {
679				// An existing trampoline that is reachable.
680				break
681			}
682		}
683		if ldr.SymType(tramp) == 0 {
684			trampb := ldr.MakeSymbolUpdater(tramp)
685			ctxt.AddTramp(trampb)
686			genCallTramp(ctxt.Arch, ctxt.LinkMode, ldr, trampb, rs, int64(r.Add()))
687		}
688		sb := ldr.MakeSymbolUpdater(s)
689		if ldr.SymValue(rs) == 0 {
690			// In this case the target symbol has not yet been assigned an
691			// address, so we have to assume a trampoline is required. Mark
692			// this as a call via a trampoline so that we can potentially
693			// switch to a direct call during relocation.
694			sb.SetRelocType(ri, objabi.R_RISCV_JAL_TRAMP)
695		}
696		relocs := sb.Relocs()
697		r := relocs.At(ri)
698		r.SetSym(tramp)
699		r.SetAdd(0)
700
701	case objabi.R_RISCV_CALL:
702		// Nothing to do, already using AUIPC+JALR.
703
704	default:
705		ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
706	}
707}
708
709func genCallTramp(arch *sys.Arch, linkmode ld.LinkMode, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
710	tramp.AddUint32(arch, 0x00000f97) // AUIPC	$0, X31
711	tramp.AddUint32(arch, 0x000f8067) // JALR	X0, (X31)
712
713	r, _ := tramp.AddRel(objabi.R_RISCV_CALL)
714	r.SetSiz(8)
715	r.SetSym(target)
716	r.SetAdd(offset)
717}
718