22#define DEBUG_TYPE "jitlink"
55 return SignExtend64<22>(Imm11H << 12 | Imm11L << 1);
69 return HalfWords{S | Imm10, J1 | J2 | Imm11};
83 return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1);
92 return (
Value >> 2) & 0x00ffffff;
101 return SignExtend64<26>((
Value & 0x00ffffff) << 2);
114 return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8};
127 uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8;
128 assert(Imm16 <= 0xffff &&
"Decoded value out-of-range");
158 return (Imm4 << 16) | Imm12;
169 return (Imm4 << 12) | Imm12;
198 :
Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)},
199 Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {}
208 :
Hi{*reinterpret_cast<
const support::ulittle16_t *>(FixupPtr)},
209 Lo{*reinterpret_cast<
const support::ulittle16_t *>(FixupPtr + 2)} {}
213 :
Hi{Writable.
Hi},
Lo(Writable.
Lo) {}
221 :
Wd{*reinterpret_cast<support::ulittle32_t *>(FixupPtr)} {}
229 :
Wd{*reinterpret_cast<
const support::ulittle32_t *>(FixupPtr)} {}
238 return make_error<JITLinkError>(
239 formatv(
"Invalid opcode [ {0:x4}, {1:x4} ] for relocation: {2}",
241 G.getEdgeKindName(Kind)));
246 return make_error<JITLinkError>(
247 formatv(
"Invalid opcode {0:x8} for relocation: {1}",
248 static_cast<uint32_t>(R.Wd),
G.getEdgeKindName(Kind)));
262template <EdgeKind_aarch32 Kind>
269template <EdgeKind_aarch32 Kind>
275template <EdgeKind_aarch32 Kind>
279 "Value bits exceed bit range of given mask");
280 R.Hi = (R.Hi & ~Mask.Hi) |
Reg.Hi;
281 R.Lo = (R.Lo & ~Mask.Lo) |
Reg.Lo;
284template <EdgeKind_aarch32 Kind>
287 assert((Mask &
Reg) ==
Reg &&
"Value bits exceed bit range of given mask");
288 R.Wd = (R.Wd & ~Mask) |
Reg;
291template <EdgeKind_aarch32 Kind>
294 assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Lo & Imm.Lo) == Imm.Lo &&
295 "Value bits exceed bit range of given mask");
296 R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi;
297 R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo;
300template <EdgeKind_aarch32 Kind>
303 assert((Mask & Imm) == Imm &&
"Value bits exceed bit range of given mask");
304 R.Wd = (R.Wd & ~Mask) | Imm;
312 const char *BlockWorkingMem =
B.getContent().data();
313 const char *FixupPtr = BlockWorkingMem +
E.getOffset();
320 return make_error<JITLinkError>(
321 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
322 " can not read implicit addend for aarch32 edge kind " +
323 G.getEdgeKindName(
E.getKind()));
333 if (!checkOpcode<Arm_Call>(R))
338 if (!checkOpcode<Arm_Jump24>(R))
343 if (!checkOpcode<Arm_MovwAbsNC>(R))
348 if (!checkOpcode<Arm_MovtAbs>(R))
353 return make_error<JITLinkError>(
354 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
355 " can not read implicit addend for aarch32 edge kind " +
356 G.getEdgeKindName(
E.getKind()));
367 if (!checkOpcode<Thumb_Call>(R))
374 if (!checkOpcode<Thumb_Jump24>(R))
381 if (!checkOpcode<Thumb_MovwAbsNC>(R))
387 if (!checkOpcode<Thumb_MovtAbs>(R))
393 return make_error<JITLinkError>(
394 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
395 " can not read implicit addend for aarch32 edge kind " +
396 G.getEdgeKindName(
E.getKind()));
401 using namespace support;
403 char *BlockWorkingMem =
B.getAlreadyMutableContent().data();
404 char *FixupPtr = BlockWorkingMem +
E.getOffset();
406 auto Write32 = [FixupPtr,
Endian =
G.getEndianness()](int64_t
Value) {
407 assert(
Endian != native &&
"Must be explicit: little or big");
408 assert(isInt<32>(
Value) &&
"Must be in signed 32-bit range");
411 endian::write32<little>(FixupPtr, Imm);
413 endian::write32<big>(FixupPtr, Imm);
417 uint64_t FixupAddress = (
B.getAddress() +
E.getOffset()).getValue();
418 int64_t Addend =
E.getAddend();
419 Symbol &TargetSymbol =
E.getTarget();
427 int64_t
Value = TargetAddress - FixupAddress + Addend;
428 if (!isInt<32>(
Value))
434 int64_t
Value = TargetAddress + Addend;
435 if (!isInt<32>(
Value))
441 return make_error<JITLinkError>(
442 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
443 " encountered unfixable aarch32 edge kind " +
444 G.getEdgeKindName(
E.getKind()));
451 uint64_t FixupAddress = (
B.getAddress() +
E.getOffset()).getValue();
452 int64_t Addend =
E.getAddend();
453 Symbol &TargetSymbol =
E.getTarget();
458 if (!checkOpcode<Arm_Jump24>(R))
461 return make_error<JITLinkError>(
"Branch relocation needs interworking "
462 "stub when bridging to Thumb: " +
465 int64_t
Value = TargetAddress - FixupAddress + Addend;
467 if (!isInt<26>(
Value))
474 if (!checkOpcode<Arm_Call>(R))
478 return make_error<JITLinkError>(
"Relocation expects an unconditional "
479 "BL/BLX branch instruction: " +
482 int64_t
Value = TargetAddress - FixupAddress + Addend;
488 if (TargetIsThumb != InstrIsBlx) {
499 if (!isInt<26>(
Value))
506 if (!checkOpcode<Arm_MovwAbsNC>(R))
513 if (!checkOpcode<Arm_MovtAbs>(R))
520 return make_error<JITLinkError>(
521 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
522 " encountered unfixable aarch32 edge kind " +
523 G.getEdgeKindName(
E.getKind()));
533 uint64_t FixupAddress = (
B.getAddress() +
E.getOffset()).getValue();
534 int64_t Addend =
E.getAddend();
535 Symbol &TargetSymbol =
E.getTarget();
540 if (!checkOpcode<Thumb_Jump24>(R))
543 return make_error<JITLinkError>(
"Branch relocation needs interworking "
544 "stub when bridging to ARM: " +
547 int64_t
Value = TargetAddress - FixupAddress + Addend;
549 if (!isInt<25>(
Value))
553 if (!isInt<22>(
Value))
562 if (!checkOpcode<Thumb_Call>(R))
565 int64_t
Value = TargetAddress - FixupAddress + Addend;
571 if (TargetIsArm != InstrIsBlx) {
585 if (!isInt<25>(
Value))
589 if (!isInt<22>(
Value))
596 "Opcode BLX implies H bit is clear (avoid UB in BLX T2)");
601 if (!checkOpcode<Thumb_MovwAbsNC>(R))
609 if (!checkOpcode<Thumb_MovtAbs>(R))
617 return make_error<JITLinkError>(
618 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
619 " encountered unfixable aarch32 edge kind " +
620 G.getEdgeKindName(
E.getKind()));
625 0x40, 0xf2, 0x00, 0x0c,
626 0xc0, 0xf2, 0x00, 0x0c,
635 const char *StubPtr =
B.getContent().data();
637 assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) &&
638 checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) &&
639 "Linker generated stubs may only corrupt register r12 (IP)");
643 Symbol &Stub =
G.addAnonymousSymbol(
B, 0,
B.getSize(),
true,
false);
649#define KIND_NAME_CASE(K) \
671#define CPUARCH_NAME_CASE(K) \
675 using namespace ARMBuildAttrs;
699#undef CPUARCH_NAME_CASE
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_LIKELY(EXPR)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
#define CPUARCH_NAME_CASE(K)
#define KIND_NAME_CASE(K)
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
StringRef - Represent a constant reference to a string, i.e.
Target - Wrapper for Target specific information.
LLVM Value Representation.
An Addressable with content and edges.
Represents fixups and constraints in the LinkGraph.
void setTargetFlags(TargetFlagsType Flags)
Set the target flags for this Symbol.
orc::ExecutorAddr getAddress() const
Returns the address of this symbol.
Symbol & createEntry(LinkGraph &G, Symbol &Target)
Create a branch range extension stub for the class's flavor.
uint64_t getValue() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Expected< int64_t > readAddendThumb(LinkGraph &G, Block &B, const Edge &E, const ArmConfig &ArmCfg)
Helper function to read the initial addend for Thumb-class relocations.
@ Arm_MovtAbs
Write immediate value to the top halfword of the destination register.
@ Data_Pointer32
Absolute 32-bit value relocation.
@ Arm_MovwAbsNC
Write immediate value to the lower halfword of the destination register.
@ Arm_Call
Write immediate value for unconditional PC-relative branch with link.
@ Thumb_Jump24
Write immediate value for PC-relative branch without link.
@ Arm_Jump24
Write immediate value for conditional PC-relative branch without link.
@ Thumb_MovwAbsNC
Write immediate value to the lower halfword of the destination register.
@ Data_Delta32
Relative 32-bit value relocation.
@ Thumb_Call
Write immediate value for unconditional PC-relative branch with link.
@ Thumb_MovtAbs
Write immediate value to the top halfword of the destination register.
Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E, const ArmConfig &ArmCfg)
Helper function to apply the fixup for Thumb-class relocations.
int64_t decodeImmBT4BlT1BlxT2(uint32_t Hi, uint32_t Lo)
Decode 22-bit immediate value for branch instructions without J1J2 range extension (formats B T4,...
HalfWords encodeRegMovtT1MovwT3(int64_t Value)
Encode register ID for instruction formats MOVT T1 and MOVW T3.
bool checkOpcode(const ThumbRelocation &R)
Error applyFixupData(LinkGraph &G, Block &B, const Edge &E)
Helper function to apply the fixup for Data-class relocations.
uint32_t encodeRegMovtA1MovwA2(int64_t Value)
Encode register ID for instruction formats MOVT A1 and MOVW A2.
HalfWords encodeImmBT4BlT1BlxT2(int64_t Value)
Encode 22-bit immediate value for branch instructions without J1J2 range extension (formats B T4,...
int64_t decodeRegMovtT1MovwT3(uint32_t Hi, uint32_t Lo)
Decode register ID from instruction formats MOVT T1 and MOVW T3.
const char * getCPUArchName(ARMBuildAttrs::CPUArch K)
Human-readable name for a given CPU architecture kind.
uint16_t decodeImmMovtT1MovwT3(uint32_t Hi, uint32_t Lo)
Decode 16-bit immediate value from move instruction formats MOVT T1 and MOVW T3.
uint32_t encodeImmBA1BlA1BlxA2(int64_t Value)
Encode 26-bit immediate value for branch instructions (formats B A1, BL A1 and BLX A2).
uint32_t encodeImmMovtA1MovwA2(uint16_t Value)
Encode 16-bit immediate value for move instruction formats MOVT A1 and MOVW A2.
Error applyFixupArm(LinkGraph &G, Block &B, const Edge &E)
Helper function to apply the fixup for Arm-class relocations.
HalfWords encodeImmMovtT1MovwT3(uint16_t Value)
Encode 16-bit immediate value for move instruction formats MOVT T1 and MOVW T3.
const char * getEdgeKindName(Edge::Kind K)
Get a human-readable name for the given AArch32 edge kind.
int64_t decodeRegMovtA1MovwA2(uint64_t Value)
Decode register ID for instruction formats MOVT A1 and MOVW A2.
bool hasTargetFlags(Symbol &Sym, TargetFlagsType Flags)
Check whether the given target flags are set for this Symbol.
Error makeUnexpectedOpcodeError(const LinkGraph &G, const ThumbRelocation &R, Edge::Kind Kind)
uint16_t decodeImmMovtA1MovwA2(uint64_t Value)
Decode 16-bit immediate value for move instruction formats MOVT A1 and MOVW A2.
const uint8_t Thumbv7ABS[]
HalfWords encodeImmBT4BlT1BlxT2_J1J2(int64_t Value)
Encode 25-bit immediate value for branch instructions with J1J2 range extension (formats B T4,...
int64_t decodeImmBA1BlA1BlxA2(int64_t Value)
Decode 26-bit immediate value for branch instructions (formats B A1, BL A1 and BLX A2).
void writeRegister(WritableThumbRelocation &R, HalfWords Reg)
Expected< int64_t > readAddendArm(LinkGraph &G, Block &B, const Edge &E)
Helper function to read the initial addend for Arm-class relocations.
bool checkRegister(const ThumbRelocation &R, HalfWords Reg)
Expected< int64_t > readAddendData(LinkGraph &G, Block &B, const Edge &E)
Helper function to read the initial addend for Data-class relocations.
int64_t decodeImmBT4BlT1BlxT2_J1J2(uint32_t Hi, uint32_t Lo)
Decode 25-bit immediate value for branch instructions with J1J2 range extension (formats B T4,...
void writeImmediate(WritableThumbRelocation &R, HalfWords Imm)
Error makeTargetOutOfRangeError(const LinkGraph &G, const Block &B, const Edge &E)
Create an out of range error for the given edge in the given block.
const char * getGenericEdgeKindName(Edge::Kind K)
Returns the string name of the given generic edge kind, or "unknown" otherwise.
uint8_t TargetFlagsType
Holds target-specific properties for a symbol.
uint32_t read32(const void *P, endianness E)
This is an optimization pass for GlobalISel generic memory operations.
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
JITLink sub-arch configuration for Arm CPU models.
ArmRelocation(const char *FixupPtr)
const support::ulittle32_t & Wd
ArmRelocation(WritableArmRelocation &Writable)
Collection of named constants per fixup kind.
Immutable pair of halfwords, Hi and Lo, with overflow check.
ThumbRelocation(WritableThumbRelocation &Writable)
Create a read-only Thumb32 fixup from a writeable one.
ThumbRelocation(const char *FixupPtr)
Create a read-only reference to a Thumb32 fixup.
const support::ulittle16_t & Lo
const support::ulittle16_t & Hi
support::ulittle32_t & Wd
WritableArmRelocation(char *FixupPtr)
32-bit Thumb instructions are stored as two little-endian halfwords.
WritableThumbRelocation(char *FixupPtr)
Create a writable reference to a Thumb32 fixup.
support::ulittle16_t & Hi
support::ulittle16_t & Lo