LLVM: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
25
26using namespace llvm;
27
30
31
32
35 cl::desc("Emit R_RISCV_SET_ULEB128/E_RISCV_SUB_ULEB128 if appropriate"));
36
39 unsigned Type;
41#define ELF_RELOC(NAME, ID) .Case(#NAME, ID)
42#include "llvm/BinaryFormat/ELFRelocs/RISCV.def"
43#undef ELF_RELOC
44#define ELF_RISCV_NONSTANDARD_RELOC(_VENDOR, NAME, ID) .Case(#NAME, ID)
45#include "llvm/BinaryFormat/ELFRelocs/RISCV_nonstandard.def"
46#undef ELF_RISCV_NONSTANDARD_RELOC
47 .Case("BFD_RELOC_NONE", ELF::R_RISCV_NONE)
48 .Case("BFD_RELOC_32", ELF::R_RISCV_32)
49 .Case("BFD_RELOC_64", ELF::R_RISCV_64)
51 if (Type != -1u)
53 }
54 return std::nullopt;
55}
56
60
61
62
63
64 {"fixup_riscv_hi20", 12, 20, 0},
65 {"fixup_riscv_lo12_i", 20, 12, 0},
66 {"fixup_riscv_12_i", 20, 12, 0},
67 {"fixup_riscv_lo12_s", 0, 32, 0},
68 {"fixup_riscv_pcrel_hi20", 12, 20,
70 {"fixup_riscv_pcrel_lo12_i", 20, 12,
72 {"fixup_riscv_pcrel_lo12_s", 0, 32,
75 {"fixup_riscv_tprel_hi20", 12, 20, 0},
76 {"fixup_riscv_tprel_lo12_i", 20, 12, 0},
77 {"fixup_riscv_tprel_lo12_s", 0, 32, 0},
78 {"fixup_riscv_tprel_add", 0, 0, 0},
87 {"fixup_riscv_relax", 0, 0, 0},
88 {"fixup_riscv_align", 0, 0, 0},
89
90 {"fixup_riscv_tlsdesc_hi20", 12, 20,
92 {"fixup_riscv_tlsdesc_load_lo12", 20, 12, 0},
93 {"fixup_riscv_tlsdesc_add_lo12", 20, 12, 0},
94 {"fixup_riscv_tlsdesc_call", 0, 0, 0},
95 };
97 "Not all fixup kinds added to Infos array");
98
99
100
103
106
108 "Invalid kind!");
110}
111
112
113
114
121 return true;
122 switch (Fixup.getTargetKind()) {
123 default:
124 break;
130 if (Target.isAbsolute())
131 return false;
132 break;
137 return true;
138 }
139
140 return STI->hasFeature(RISCV::FeatureRelax) || ForceRelocs;
141}
142
147 return false;
148
150 unsigned Kind = Fixup.getTargetKind();
151
152
153
154
155
156 if (!Resolved && !WasForced)
157 return true;
158
159 switch (Kind) {
160 default:
161 return false;
163
164
167
168
171
172
173 return !isInt<13>(Offset);
174 }
175}
176
181 default:
183 case RISCV::C_BEQZ:
184 case RISCV::C_BNEZ:
185 case RISCV::C_J:
186 case RISCV::C_JAL: {
188 assert(Success && "Can't uncompress instruction");
189 break;
190 }
191 case RISCV::BEQ:
192 case RISCV::BNE:
193 case RISCV::BLT:
194 case RISCV::BGE:
195 case RISCV::BLTU:
196 case RISCV::BGEU:
201 break;
202 }
203 Inst = std::move(Res);
204}
205
208 bool &WasRelaxed) const {
210
211 int64_t LineDelta = DF.getLineDelta();
212 const MCExpr &AddrDelta = DF.getAddrDelta();
215 size_t OldSize = Data.size();
216
218 [[maybe_unused]] bool IsAbsolute =
220 assert(IsAbsolute && "CFA with invalid expression");
221
222 Data.clear();
223 Fixups.clear();
225
226
228 OS << uint8_t(dwarf::DW_LNS_advance_line);
230 }
231
233 std::pair<MCFixupKind, MCFixupKind> Fixup;
234
235
236
237
238 if (Value > 60000) {
239 unsigned PtrSize = C.getAsmInfo()->getCodePointerSize();
240
241 OS << uint8_t(dwarf::DW_LNS_extended_op);
243
244 OS << uint8_t(dwarf::DW_LNE_set_address);
246 assert((PtrSize == 4 || PtrSize == 8) && "Unexpected pointer size");
249 } else {
250 OS << uint8_t(dwarf::DW_LNS_fixed_advance_pc);
254 }
255
256 const MCBinaryExpr &MBE = cast(AddrDelta);
259
261 OS << uint8_t(dwarf::DW_LNS_extended_op);
263 OS << uint8_t(dwarf::DW_LNE_end_sequence);
264 } else {
265 OS << uint8_t(dwarf::DW_LNS_copy);
266 }
267
268 WasRelaxed = OldSize != Data.size();
269 return true;
270}
271
274 bool &WasRelaxed) const {
275 const MCExpr &AddrDelta = DF.getAddrDelta();
278 size_t OldSize = Data.size();
279
281 if (AddrDelta.evaluateAsAbsolute(Value, Asm))
282 return false;
283 [[maybe_unused]] bool IsAbsolute =
285 assert(IsAbsolute && "CFA with invalid expression");
286
287 Data.clear();
288 Fixups.clear();
290
291 assert(Asm.getContext().getAsmInfo()->getMinInstAlignment() == 1 &&
292 "expected 1-byte alignment");
293 if (Value == 0) {
294 WasRelaxed = OldSize != Data.size();
295 return true;
296 }
297
298 auto AddFixups = [&Fixups, &AddrDelta](unsigned Offset,
299 std::pair<unsigned, unsigned> Fixup) {
300 const MCBinaryExpr &MBE = cast(AddrDelta);
301 Fixups.push_back(
304 std::get<0>(Fixup))));
305 Fixups.push_back(
308 std::get<1>(Fixup))));
309 };
310
312 OS << uint8_t(dwarf::DW_CFA_advance_loc);
313 AddFixups(0, {ELF::R_RISCV_SET6, ELF::R_RISCV_SUB6});
314 } else if (isUInt<8>(Value)) {
315 OS << uint8_t(dwarf::DW_CFA_advance_loc1);
317 AddFixups(1, {ELF::R_RISCV_SET8, ELF::R_RISCV_SUB8});
318 } else if (isUInt<16>(Value)) {
319 OS << uint8_t(dwarf::DW_CFA_advance_loc2);
321 AddFixups(1, {ELF::R_RISCV_SET16, ELF::R_RISCV_SUB16});
322 } else if (isUInt<32>(Value)) {
323 OS << uint8_t(dwarf::DW_CFA_advance_loc4);
325 AddFixups(1, {ELF::R_RISCV_SET32, ELF::R_RISCV_SUB32});
326 } else {
328 }
329
330 WasRelaxed = OldSize != Data.size();
331 return true;
332}
333
336 int64_t &Value) const {
338 return std::make_pair(false, false);
343 }
345}
346
347
348
350 switch (Op) {
351 default:
352 return Op;
353 case RISCV::C_BEQZ:
354 return RISCV::BEQ;
355 case RISCV::C_BNEZ:
356 return RISCV::BNE;
357 case RISCV::C_J:
358 case RISCV::C_JAL:
359 return RISCV::JAL;
360 case RISCV::BEQ:
361 return RISCV::PseudoLongBEQ;
362 case RISCV::BNE:
363 return RISCV::PseudoLongBNE;
364 case RISCV::BLT:
365 return RISCV::PseudoLongBLT;
366 case RISCV::BGE:
367 return RISCV::PseudoLongBGE;
368 case RISCV::BLTU:
369 return RISCV::PseudoLongBLTU;
370 case RISCV::BGEU:
371 return RISCV::PseudoLongBGEU;
372 }
373}
374
378}
379
382
383
384
385
386
387
388 if (Count % 2) {
390 Count -= 1;
391 }
392
393 bool UseCompressedNop = STI->hasFeature(RISCV::FeatureStdExtC) ||
394 STI->hasFeature(RISCV::FeatureStdExtZca);
395
396 if (Count % 4 == 2) {
397 OS.write(UseCompressedNop ? "\x01\0" : "\0\0", 2);
398 Count -= 2;
399 }
400
401
402 for (; Count >= 4; Count -= 4)
403 OS.write("\x13\0\0\0", 4);
404
405 return true;
406}
407
410 switch (Fixup.getTargetKind()) {
411 default:
417 llvm_unreachable("Relocation should be unconditionally forced\n");
428 return Value & 0xfff;
430 if (!isInt<12>(Value)) {
432 "operand must be a constant 12-bit integer");
433 }
434 return Value & 0xfff;
438 return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7);
442
443 return ((Value + 0x800) >> 12) & 0xfffff;
445 if (!isInt<21>(Value))
448 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned");
449
450 unsigned Sbit = (Value >> 20) & 0x1;
451 unsigned Hi8 = (Value >> 12) & 0xff;
452 unsigned Mid1 = (Value >> 11) & 0x1;
453 unsigned Lo10 = (Value >> 1) & 0x3ff;
454
455
456
457
458 Value = (Sbit << 19) | (Lo10 << 9) | (Mid1 << 8) | Hi8;
460 }
462 if (!isInt<13>(Value))
465 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned");
466
467
468 unsigned Sbit = (Value >> 12) & 0x1;
469 unsigned Hi1 = (Value >> 11) & 0x1;
470 unsigned Mid6 = (Value >> 5) & 0x3f;
471 unsigned Lo4 = (Value >> 1) & 0xf;
472
473
474
475
476 Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7);
478 }
481
482
483
484 uint64_t UpperImm = (Value + 0x800ULL) & 0xfffff000ULL;
486 return UpperImm | ((LowerImm << 20) << 32);
487 }
489 if (!isInt<12>(Value))
491
492 unsigned Bit11 = (Value >> 11) & 0x1;
493 unsigned Bit4 = (Value >> 4) & 0x1;
494 unsigned Bit9_8 = (Value >> 8) & 0x3;
495 unsigned Bit10 = (Value >> 10) & 0x1;
496 unsigned Bit6 = (Value >> 6) & 0x1;
497 unsigned Bit7 = (Value >> 7) & 0x1;
498 unsigned Bit3_1 = (Value >> 1) & 0x7;
499 unsigned Bit5 = (Value >> 5) & 0x1;
500 Value = (Bit11 << 10) | (Bit4 << 9) | (Bit9_8 << 7) | (Bit10 << 6) |
501 (Bit6 << 5) | (Bit7 << 4) | (Bit3_1 << 1) | Bit5;
503 }
505 if (!isInt<9>(Value))
507
508 unsigned Bit8 = (Value >> 8) & 0x1;
509 unsigned Bit7_6 = (Value >> 6) & 0x3;
510 unsigned Bit5 = (Value >> 5) & 0x1;
511 unsigned Bit4_3 = (Value >> 3) & 0x3;
512 unsigned Bit2_1 = (Value >> 1) & 0x3;
513 Value = (Bit8 << 12) | (Bit4_3 << 10) | (Bit7_6 << 5) | (Bit2_1 << 3) |
514 (Bit5 << 2);
516 }
517
518 }
519}
520
527 const MCFixup *AUIPCFixup;
530 switch (Fixup.getTargetKind()) {
531 default:
535 AUIPCFixup = &Fixup;
536 AUIPCDF = DF;
537 AUIPCTarget = Target;
538 break;
541 AUIPCFixup = cast(Fixup.getValue())->getPCRelHiFixup(&AUIPCDF);
542 if (!AUIPCFixup) {
543 Asm.getContext().reportError(Fixup.getLoc(),
544 "could not find corresponding %pcrel_hi");
545 return true;
546 }
547
548
549
552 return true;
553 break;
554 }
555 }
556
558 return false;
559
561 const MCSymbolELF &SA = cast(A->getSymbol());
563 return false;
564
568 if (!IsResolved)
569 return false;
570
572 Value -= Asm.getFragmentOffset(*AUIPCDF) + AUIPCFixup->getOffset();
573
575 WasForced = true;
576 return false;
577 }
578
579 return true;
580}
581
586 uint64_t &FixedValue) const {
587 uint64_t FixedValueA, FixedValueB;
588 unsigned TA = 0, TB = 0;
589 switch (Fixup.getKind()) {
591 TA = ELF::R_RISCV_ADD8;
592 TB = ELF::R_RISCV_SUB8;
593 break;
595 TA = ELF::R_RISCV_ADD16;
596 TB = ELF::R_RISCV_SUB16;
597 break;
599 TA = ELF::R_RISCV_ADD32;
600 TB = ELF::R_RISCV_SUB32;
601 break;
603 TA = ELF::R_RISCV_ADD64;
604 TB = ELF::R_RISCV_SUB64;
605 break;
607 TA = ELF::R_RISCV_SET_ULEB128;
608 TB = ELF::R_RISCV_SUB_ULEB128;
609 break;
610 default:
612 }
616 Fixup.getOffset(), nullptr,
619 Fixup.getOffset(), nullptr,
621 auto &Assembler = const_cast<MCAssembler &>(Asm);
622 Asm.getWriter().recordRelocation(Assembler, &F, FA, A, FixedValueA);
623 Asm.getWriter().recordRelocation(Assembler, &F, FB, B, FixedValueB);
624 FixedValue = FixedValueA - FixedValueB;
625 return true;
626}
627
631 bool IsResolved,
635 return;
636 MCContext &Ctx = Asm.getContext();
639 return;
640
642
643
645
647 unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8;
648
649 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
650
651
652
653 for (unsigned i = 0; i != NumBytes; ++i) {
655 }
656}
657
658
659
660
661
664
666 if (!STI->hasFeature(RISCV::FeatureRelax))
667 return false;
668
669 bool UseCompressedNop = STI->hasFeature(RISCV::FeatureStdExtC) ||
670 STI->hasFeature(RISCV::FeatureStdExtZca);
671 unsigned MinNopLen = UseCompressedNop ? 2 : 4;
672
674 return false;
675 } else {
677 return true;
678 }
679}
680
681
682
683
684
685
688
690 if (!STI->hasFeature(RISCV::FeatureRelax))
691 return false;
692
693
694
695 unsigned Count;
697 return false;
698
699 MCContext &Ctx = Asm.getContext();
701
704
707
708 Asm.getWriter().recordRelocation(Asm, &AF, Fixup, NopBytes, FixedValue);
709
710 return true;
711}
712
713std::unique_ptr
716}
717
725}
unsigned const MachineRegisterInfo * MRI
static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target, uint64_t Value, MCContext &Ctx, const Triple &TheTriple, bool IsResolved)
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Analysis containing CSE Info
static RegisterPass< DebugifyFunctionPass > DF("debugify-function", "Attach debug info to a function")
PowerPC TLS Dynamic Call Fixup
static cl::opt< bool > RelaxBranches("riscv-asm-relax-branches", cl::init(true), cl::Hidden)
static cl::opt< bool > ULEB128Reloc("riscv-uleb128-reloc", cl::init(true), cl::Hidden, cl::desc("Emit R_RISCV_SET_ULEB128/E_RISCV_SUB_ULEB128 if appropriate"))
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This class represents an Operation in the Expression.
Align getAlignment() const
const MCSubtargetInfo * getSubtargetInfo() const
Generic interface to target specific assembler backends.
virtual const MCFixupKindInfo & getFixupKindInfo(MCFixupKind Kind) const
Get information on a fixup kind.
Binary assembler expressions.
const MCExpr * getLHS() const
Get the left-hand side expression of the binary operator.
const MCExpr * getRHS() const
Get the right-hand side expression of the binary operator.
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Context object for machine code objects.
void reportError(SMLoc L, const Twine &Msg)
SmallVectorImpl< MCFixup > & getFixups()
Base class for the full range of assembler expressions which are needed for parsing.
bool evaluateKnownAbsolute(int64_t &Res, const MCAssembler &Asm) const
Aggressive variant of evaluateAsRelocatable when relocations are unavailable (e.g.
bool evaluateAsRelocatable(MCValue &Res, const MCAssembler *Asm, const MCFixup *Fixup) const
Try to evaluate the expression to a relocatable value, i.e.
Encode information on a single operation to perform on a byte sequence (e.g., an encoded instruction)...
const MCExpr * getValue() const
uint32_t getOffset() const
static MCFixup create(uint32_t Offset, const MCExpr *Value, MCFixupKind Kind, SMLoc Loc=SMLoc())
MCSection * getParent() const
Instances of this class represent a single low-level machine instruction.
unsigned getOpcode() const
void addOperand(const MCOperand Op)
void setOpcode(unsigned Op)
const MCOperand & getOperand(unsigned i) const
const MCExpr & getValue() const
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
A relaxable fragment holds on to its MCInst, since it may need to be relaxed during the assembler lay...
Generic base class for all target subtargets.
bool hasFeature(unsigned Feature) const
const Triple & getTargetTriple() const
unsigned getBinding() const
Represent a reference to a symbol from inside an expression.
bool isUndefined(bool SetUsed=true) const
isUndefined - Check if this symbol undefined (i.e., implicitly defined).
MCSection & getSection() const
Get the section associated with a defined, non-absolute symbol.
This represents an "assembler immediate".
int64_t getConstant() const
static MCValue get(const MCSymbolRefExpr *SymA, const MCSymbolRefExpr *SymB=nullptr, int64_t Val=0, uint32_t RefKind=0)
const MCSymbolRefExpr * getSymB() const
const MCSymbolRefExpr * getSymA() const
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
bool relaxDwarfLineAddr(const MCAssembler &Asm, MCDwarfLineAddrFragment &DF, bool &WasRelaxed) const override
std::pair< bool, bool > relaxLEB128(const MCAssembler &Asm, MCLEBFragment &LF, int64_t &Value) const override
std::unique_ptr< MCObjectTargetWriter > createObjectTargetWriter() const override
bool relaxDwarfCFA(const MCAssembler &Asm, MCDwarfCallFrameFragment &DF, bool &WasRelaxed) const override
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef< char > Data, uint64_t Value, bool IsResolved, const MCSubtargetInfo *STI) const override
Apply the Value for given Fixup into the provided data fragment, at the offset specified by the fixup...
void relaxInstruction(MCInst &Inst, const MCSubtargetInfo &STI) const override
Relax the instruction in the given fragment to the next wider instruction.
bool evaluateTargetFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCFragment *DF, const MCValue &Target, const MCSubtargetInfo *STI, uint64_t &Value, bool &WasForced) override
const MCFixupKindInfo & getFixupKindInfo(MCFixupKind Kind) const override
Get information on a fixup kind.
bool fixupNeedsRelaxationAdvanced(const MCAssembler &Asm, const MCFixup &Fixup, bool Resolved, uint64_t Value, const MCRelaxableFragment *DF, const bool WasForced) const override
Target specific predicate for whether a given fixup requires the associated instruction to be relaxed...
bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, const uint64_t Value, const MCSubtargetInfo *STI) override
Hook to check if a relocation is needed for some target specific reason.
bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF, unsigned &Size) override
Hook to check if extra nop bytes must be inserted for alignment directive.
bool mayNeedRelaxation(const MCInst &Inst, const MCSubtargetInfo &STI) const override
Check whether the given instruction may need relaxation.
bool writeNopData(raw_ostream &OS, uint64_t Count, const MCSubtargetInfo *STI) const override
Write an (optimal) nop sequence of Count bytes to the given output.
unsigned getRelaxedOpcode(unsigned Op) const
bool handleAddSubRelocations(const MCAssembler &Asm, const MCFragment &F, const MCFixup &Fixup, const MCValue &Target, uint64_t &FixedValue) const override
bool shouldInsertFixupForCodeAlign(MCAssembler &Asm, MCAlignFragment &AF) override
Hook which indicates if the target requires a fixup to be generated when handling an align directive ...
unsigned getNumFixupKinds() const override
Get the number of target specific fixup kinds.
std::optional< MCFixupKind > getFixupKind(StringRef Name) const override
Map a relocation name used in .reloc to a fixup kind.
Represents a location in source code.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
StringRef - Represent a constant reference to a string, i.e.
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
bool isOSBinFormatELF() const
Tests whether the OS uses the ELF binary format.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & write_zeros(unsigned NumZeros)
write_zeros - Insert 'NumZeros' nulls.
uint64_t tell() const
tell - Return the current offset with the file.
raw_ostream & write(unsigned char C)
A raw_ostream that writes to an SmallVector or SmallString.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
bool uncompress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI)
static std::pair< MCFixupKind, MCFixupKind > getRelocPairForSize(unsigned Size)
@ fixup_riscv_tprel_lo12_s
@ fixup_riscv_tls_got_hi20
@ fixup_riscv_tls_gd_hi20
@ fixup_riscv_pcrel_lo12_i
@ fixup_riscv_pcrel_lo12_s
@ fixup_riscv_tprel_lo12_i
@ fixup_riscv_tlsdesc_load_lo12
@ fixup_riscv_tlsdesc_hi20
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
std::unique_ptr< MCObjectTargetWriter > createRISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit)
bool isUIntN(unsigned N, uint64_t x)
Checks if an unsigned integer fits into the given (dynamic) bit width.
MCFixupKind
Extensible enumeration to represent the type of a fixup.
@ FirstLiteralRelocationKind
The range [FirstLiteralRelocationKind, MaxTargetFixupKind) is used for relocations coming from ....
@ FK_Data_8
A eight-byte fixup.
@ FK_Data_1
A one-byte fixup.
@ FK_Data_4
A four-byte fixup.
@ FK_Data_leb128
A leb128 fixup.
@ FK_Data_2
A two-byte fixup.
MCAsmBackend * createRISCVAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, const MCTargetOptions &Options)
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
DWARFExpression::Operation Op
unsigned encodeSLEB128(int64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a SLEB128 value to an output stream.
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
uint64_t value() const
This is a hole in the type system and should not be abused.
Target independent information on a fixup kind.
@ FKF_IsTarget
Should this fixup be evaluated in a target dependent manner?
@ FKF_IsPCRel
Is this fixup kind PCrelative? This is used by the assembler backend to evaluate fixup values in a ta...