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