github.com/bir3/gocompiler@v0.9.2202/src/cmd/link/internal/riscv64/asm.go (about) 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 5 package riscv64 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/internal/obj/riscv" 9 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 10 "github.com/bir3/gocompiler/src/cmd/internal/sys" 11 "github.com/bir3/gocompiler/src/cmd/link/internal/ld" 12 "github.com/bir3/gocompiler/src/cmd/link/internal/loader" 13 "github.com/bir3/gocompiler/src/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. 21 const fakeLabelName = ".L0 " 22 23 func gentext(ctxt *ld.Link, ldr *loader.Loader) {} 24 25 func 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 44 func 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 158 func 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_PCREL_ITYPE && r.Type() != objabi.R_RISCV_PCREL_STYPE && 174 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 204 func 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 215 func 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 288 func 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 338 func 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(function@.got.plt) 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 390 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool { 391 log.Fatalf("machoreloc1 not implemented") 392 return false 393 } 394 395 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) { 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 619 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 { 620 log.Fatalf("archrelocvariant") 621 return -1 622 } 623 624 func 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 635 func 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 709 func 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 }