github.com/bir3/gocompiler@v0.3.205/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 26 func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) { 27 if ctxt.LinkMode != ld.LinkExternal { 28 return 29 } 30 31 // Generate a local text symbol for each relocation target, as the 32 // R_RISCV_PCREL_LO12_* relocations generated by elfreloc1 need it. 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 // Use the symbol for the function instead of creating 47 // an overlapping symbol. 48 continue 49 } 50 51 // TODO(jsing): Consider generating ELF symbols without needing 52 // loader symbols, in order to reduce memory consumption. This 53 // would require changes to genelfsym so that it called 54 // putelfsym and putelfsyment as appropriate. 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 // Find the text symbol for the AUIPC instruction targeted 106 // by this relocation. 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 // Emit two relocations - a R_RISCV_PCREL_HI20 relocation and a 117 // corresponding R_RISCV_PCREL_LO12_I or R_RISCV_PCREL_LO12_S relocation. 118 // Note that the LO12 relocation must point to a target that has a valid 119 // HI20 PC-relative relocation text symbol, which in turn points to the 120 // given symbol. For further details see the ELF specification for RISC-V: 121 // 122 // https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#pc-relative-symbol-addresses 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 // If the call points to a trampoline, see if we can reach the symbol 163 // directly. This situation can occur when the relocation symbol is 164 // not assigned an address until after the trampolines are generated. 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 // Generate instruction immediates. 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 // TLS relocations are not currently handled for internal linking. 216 // For now, TLS is only used when cgo is in use and cgo currently 217 // requires external linking. However, we need to accept these 218 // relocations so that code containing TLS variables will link, 219 // even when they're not being used. For now, replace these 220 // instructions with EBREAK to detect accidental use. 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 // Generate AUIPC and second instruction immediates. 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 // Relocation symbol has an address and is directly reachable, 292 // therefore there is no need for a trampoline. 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 // Relocation symbol is too far for a direct call or has not 298 // yet been given an address. See if an existing trampoline is 299 // reachable and if so, reuse it. Otherwise we need to create 300 // a new trampoline. 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 // Do not reuse trampoline defined in other module. 312 continue 313 } 314 if oName == "runtime.deferreturn" { 315 ldr.SetIsDeferReturnTramp(tramp, true) 316 } 317 if ldr.SymValue(tramp) == 0 { 318 // Either trampoline does not exist or we found one 319 // that does not have an address assigned and will be 320 // laid down immediately after the current function. 321 break 322 } 323 324 trampOff := ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off())) 325 if trampOff >= -(1<<20) && trampOff < (1<<20) { 326 // An existing trampoline that is reachable. 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 // In this case the target symbol has not yet been assigned an 338 // address, so we have to assume a trampoline is required. Mark 339 // this as a call via a trampoline so that we can potentially 340 // switch to a direct call during relocation. 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) // AUIPC $0, X31 355 tramp.AddUint32(arch, 0x000f8067) // JALR X0, (X31) 356 357 r, _ := tramp.AddRel(objabi.R_RISCV_PCREL_ITYPE) 358 r.SetSiz(8) 359 r.SetSym(target) 360 r.SetAdd(offset) 361 }