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 }
25
26 func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) {
27 if ctxt.LinkMode != ld.LinkExternal {
28 return
29 }
30
31
32
33 if ctxt.Textp == nil {
34 log.Fatal("genSymsLate called before Textp has been assigned")
35 }
36 var hi20Syms []loader.Sym
37 for _, s := range ctxt.Textp {
38 relocs := ldr.Relocs(s)
39 for ri := 0; ri < relocs.Count(); ri++ {
40 r := relocs.At(ri)
41 if r.Type() != objabi.R_RISCV_PCREL_ITYPE && r.Type() != objabi.R_RISCV_PCREL_STYPE &&
42 r.Type() != objabi.R_RISCV_TLS_IE_ITYPE && r.Type() != objabi.R_RISCV_TLS_IE_STYPE {
43 continue
44 }
45 if r.Off() == 0 && ldr.SymType(s) == sym.STEXT {
46
47
48 continue
49 }
50
51
52
53
54
55 sb := ldr.MakeSymbolBuilder(fakeLabelName)
56 sb.SetType(sym.STEXT)
57 sb.SetValue(ldr.SymValue(s) + int64(r.Off()))
58 sb.SetLocal(true)
59 sb.SetReachable(true)
60 sb.SetVisibilityHidden(true)
61 sb.SetSect(ldr.SymSect(s))
62 if outer := ldr.OuterSym(s); outer != 0 {
63 ldr.AddInteriorSym(outer, sb.Sym())
64 }
65 hi20Syms = append(hi20Syms, sb.Sym())
66 }
67 }
68 ctxt.Textp = append(ctxt.Textp, hi20Syms...)
69 ldr.SortSyms(ctxt.Textp)
70 }
71
72 func findHI20Symbol(ctxt *ld.Link, ldr *loader.Loader, val int64) loader.Sym {
73 idx := sort.Search(len(ctxt.Textp), func(i int) bool { return ldr.SymValue(ctxt.Textp[i]) >= val })
74 if idx >= len(ctxt.Textp) {
75 return 0
76 }
77 if s := ctxt.Textp[idx]; ldr.SymValue(s) == val && ldr.SymType(s) == sym.STEXT {
78 return s
79 }
80 return 0
81 }
82
83 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
84 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
85 switch r.Type {
86 case objabi.R_ADDR, objabi.R_DWARFSECREF:
87 out.Write64(uint64(sectoff))
88 switch r.Size {
89 case 4:
90 out.Write64(uint64(elf.R_RISCV_32) | uint64(elfsym)<<32)
91 case 8:
92 out.Write64(uint64(elf.R_RISCV_64) | uint64(elfsym)<<32)
93 default:
94 ld.Errorf(nil, "unknown size %d for %v relocation", r.Size, r.Type)
95 return false
96 }
97 out.Write64(uint64(r.Xadd))
98
99 case objabi.R_RISCV_CALL, objabi.R_RISCV_CALL_TRAMP:
100 out.Write64(uint64(sectoff))
101 out.Write64(uint64(elf.R_RISCV_JAL) | uint64(elfsym)<<32)
102 out.Write64(uint64(r.Xadd))
103
104 case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
105
106
107 relocs := ldr.Relocs(s)
108 offset := int64(relocs.At(ri).Off())
109 hi20Sym := findHI20Symbol(ctxt, ldr, ldr.SymValue(s)+offset)
110 if hi20Sym == 0 {
111 ld.Errorf(nil, "failed to find text symbol for HI20 relocation at %d (%x)", sectoff, ldr.SymValue(s)+offset)
112 return false
113 }
114 hi20ElfSym := ld.ElfSymForReloc(ctxt, hi20Sym)
115
116
117
118
119
120
121
122
123
124 var hiRel, loRel elf.R_RISCV
125 switch r.Type {
126 case objabi.R_RISCV_PCREL_ITYPE:
127 hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_I
128 case objabi.R_RISCV_PCREL_STYPE:
129 hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_S
130 case objabi.R_RISCV_TLS_IE_ITYPE:
131 hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_I
132 case objabi.R_RISCV_TLS_IE_STYPE:
133 hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_S
134 }
135 out.Write64(uint64(sectoff))
136 out.Write64(uint64(hiRel) | uint64(elfsym)<<32)
137 out.Write64(uint64(r.Xadd))
138 out.Write64(uint64(sectoff + 4))
139 out.Write64(uint64(loRel) | uint64(hi20ElfSym)<<32)
140 out.Write64(uint64(0))
141
142 default:
143 return false
144 }
145
146 return true
147 }
148
149 func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
150 log.Fatalf("elfsetupplt")
151 }
152
153 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
154 log.Fatalf("machoreloc1 not implemented")
155 return false
156 }
157
158 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) {
159 rs := r.Sym()
160 pc := ldr.SymValue(s) + int64(r.Off())
161
162
163
164
165 if r.Type() == objabi.R_RISCV_CALL_TRAMP {
166 relocs := ldr.Relocs(rs)
167 if relocs.Count() != 1 {
168 ldr.Errorf(s, "trampoline %v has %d relocations", ldr.SymName(rs), relocs.Count())
169 }
170 tr := relocs.At(0)
171 if tr.Type() != objabi.R_RISCV_PCREL_ITYPE {
172 ldr.Errorf(s, "trampoline %v has unexpected relocation %v", ldr.SymName(rs), tr.Type())
173 }
174 trs := tr.Sym()
175 if ldr.SymValue(trs) != 0 && ldr.SymType(trs) != sym.SDYNIMPORT && ldr.SymType(trs) != sym.SUNDEFEXT {
176 trsOff := ldr.SymValue(trs) + tr.Add() - pc
177 if trsOff >= -(1<<20) && trsOff < (1<<20) {
178 r.SetType(objabi.R_RISCV_CALL)
179 r.SetSym(trs)
180 r.SetAdd(tr.Add())
181 rs = trs
182 }
183 }
184
185 }
186
187 if target.IsExternal() {
188 switch r.Type() {
189 case objabi.R_RISCV_CALL, objabi.R_RISCV_CALL_TRAMP:
190 return val, 1, true
191
192 case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
193 return val, 2, true
194 }
195
196 return val, 0, false
197 }
198
199 off := ldr.SymValue(rs) + r.Add() - pc
200
201 switch r.Type() {
202 case objabi.R_RISCV_CALL, objabi.R_RISCV_CALL_TRAMP:
203
204 imm, err := riscv.EncodeJImmediate(off)
205 if err != nil {
206 ldr.Errorf(s, "cannot encode R_RISCV_CALL relocation offset for %s: %v", ldr.SymName(rs), err)
207 }
208 immMask := int64(riscv.JTypeImmMask)
209
210 val = (val &^ immMask) | int64(imm)
211
212 return val, 0, true
213
214 case objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
215
216
217
218
219
220
221 const ebreakIns = 0x00100073
222 return ebreakIns<<32 | ebreakIns, 0, true
223
224 case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE:
225
226 low, high, err := riscv.Split32BitImmediate(off)
227 if err != nil {
228 ldr.Errorf(s, "R_RISCV_PCREL_ relocation does not fit in 32 bits: %d", off)
229 }
230
231 auipcImm, err := riscv.EncodeUImmediate(high)
232 if err != nil {
233 ldr.Errorf(s, "cannot encode R_RISCV_PCREL_ AUIPC relocation offset for %s: %v", ldr.SymName(rs), err)
234 }
235
236 var secondImm, secondImmMask int64
237 switch r.Type() {
238 case objabi.R_RISCV_PCREL_ITYPE:
239 secondImmMask = riscv.ITypeImmMask
240 secondImm, err = riscv.EncodeIImmediate(low)
241 if err != nil {
242 ldr.Errorf(s, "cannot encode R_RISCV_PCREL_ITYPE I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
243 }
244 case objabi.R_RISCV_PCREL_STYPE:
245 secondImmMask = riscv.STypeImmMask
246 secondImm, err = riscv.EncodeSImmediate(low)
247 if err != nil {
248 ldr.Errorf(s, "cannot encode R_RISCV_PCREL_STYPE S-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
249 }
250 default:
251 panic(fmt.Sprintf("Unknown relocation type: %v", r.Type()))
252 }
253
254 auipc := int64(uint32(val))
255 second := int64(uint32(val >> 32))
256
257 auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm))
258 second = (second &^ secondImmMask) | int64(uint32(secondImm))
259
260 return second<<32 | auipc, 0, true
261 }
262
263 return val, 0, false
264 }
265
266 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
267 log.Fatalf("archrelocvariant")
268 return -1
269 }
270
271 func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
272 switch r.Type() {
273 case objabi.R_RISCV_CALL, objabi.R_RISCV_CALL_TRAMP:
274 return ld.ExtrelocSimple(ldr, r), true
275
276 case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
277 return ld.ExtrelocViaOuterSym(ldr, r, s), true
278 }
279 return loader.ExtReloc{}, false
280 }
281
282 func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
283 relocs := ldr.Relocs(s)
284 r := relocs.At(ri)
285
286 switch r.Type() {
287 case objabi.R_RISCV_CALL:
288 pc := ldr.SymValue(s) + int64(r.Off())
289 off := ldr.SymValue(rs) + r.Add() - pc
290
291
292
293 if ldr.SymValue(rs) != 0 && off >= -(1<<20) && off < (1<<20) && (*ld.FlagDebugTramp <= 1 || ldr.SymPkg(s) == ldr.SymPkg(rs)) {
294 break
295 }
296
297
298
299
300
301 var tramp loader.Sym
302 for i := 0; ; i++ {
303 oName := ldr.SymName(rs)
304 name := fmt.Sprintf("%s-tramp%d", oName, i)
305 if r.Add() != 0 {
306 name = fmt.Sprintf("%s%+x-tramp%d", oName, r.Add(), i)
307 }
308 tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
309 ldr.SetAttrReachable(tramp, true)
310 if ldr.SymType(tramp) == sym.SDYNIMPORT {
311
312 continue
313 }
314 if oName == "runtime.deferreturn" {
315 ldr.SetIsDeferReturnTramp(tramp, true)
316 }
317 if ldr.SymValue(tramp) == 0 {
318
319
320
321 break
322 }
323
324 trampOff := ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
325 if trampOff >= -(1<<20) && trampOff < (1<<20) {
326
327 break
328 }
329 }
330 if ldr.SymType(tramp) == 0 {
331 trampb := ldr.MakeSymbolUpdater(tramp)
332 ctxt.AddTramp(trampb)
333 genCallTramp(ctxt.Arch, ctxt.LinkMode, ldr, trampb, rs, int64(r.Add()))
334 }
335 sb := ldr.MakeSymbolUpdater(s)
336 if ldr.SymValue(rs) == 0 {
337
338
339
340
341 sb.SetRelocType(ri, objabi.R_RISCV_CALL_TRAMP)
342 }
343 relocs := sb.Relocs()
344 r := relocs.At(ri)
345 r.SetSym(tramp)
346 r.SetAdd(0)
347
348 default:
349 ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
350 }
351 }
352
353 func genCallTramp(arch *sys.Arch, linkmode ld.LinkMode, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
354 tramp.AddUint32(arch, 0x00000f97)
355 tramp.AddUint32(arch, 0x000f8067)
356
357 r, _ := tramp.AddRel(objabi.R_RISCV_PCREL_ITYPE)
358 r.SetSiz(8)
359 r.SetSym(target)
360 r.SetAdd(offset)
361 }
362
View as plain text