24#define DEBUG_TYPE "jitlink"
57 return SignExtend64<22>(Imm11H << 12 | Imm11L << 1);
71 return HalfWords{S | Imm10, J1 | J2 | Imm11};
85 return SignExtend64<25>(S << 14 | I1 | I2 | Imm10 << 12 | Imm11 << 1);
94 return (
Value >> 2) & 0x00ffffff;
103 return SignExtend64<26>((
Value & 0x00ffffff) << 2);
116 return HalfWords{Imm1 << 10 | Imm4, Imm3 << 12 | Imm8};
129 uint32_t Imm16 = Imm4 << 12 | Imm1 << 11 | Imm3 << 8 | Imm8;
130 assert(Imm16 <= 0xffff &&
"Decoded value out-of-range");
160 return (Imm4 << 16) | Imm12;
171 return (Imm4 << 12) | Imm12;
199struct WritableThumbRelocation {
201 WritableThumbRelocation(
char *FixupPtr)
202 :
Hi{*reinterpret_cast<support::ulittle16_t *>(FixupPtr)},
203 Lo{*reinterpret_cast<support::ulittle16_t *>(FixupPtr + 2)} {}
209struct ThumbRelocation {
211 ThumbRelocation(
const char *FixupPtr)
216 ThumbRelocation(WritableThumbRelocation &Writable)
217 :
Hi{Writable.
Hi},
Lo(Writable.
Lo) {}
223struct WritableArmRelocation {
224 WritableArmRelocation(
char *FixupPtr)
230struct ArmRelocation {
231 ArmRelocation(
const char *FixupPtr)
234 ArmRelocation(WritableArmRelocation &Writable) :
Wd{Writable.
Wd} {}
239Error makeUnexpectedOpcodeError(
const LinkGraph &
G,
const ThumbRelocation &R,
241 return make_error<JITLinkError>(
242 formatv(
"Invalid opcode [ {0:x4}, {1:x4} ] for relocation: {2}",
244 G.getEdgeKindName(Kind)));
247Error makeUnexpectedOpcodeError(
const LinkGraph &
G,
const ArmRelocation &R,
249 return make_error<JITLinkError>(
250 formatv(
"Invalid opcode {0:x8} for relocation: {1}",
251 static_cast<uint32_t>(
R.Wd),
G.getEdgeKindName(Kind)));
254template <EdgeKind_aarch32 K>
constexpr bool isArm() {
257template <EdgeKind_aarch32 K>
constexpr bool isThumb() {
261template <EdgeKind_aarch32 K>
static bool checkOpcodeArm(
uint32_t Wd) {
262 return (
Wd & FixupInfo<K>::OpcodeMask) == FixupInfo<K>::Opcode;
265template <EdgeKind_aarch32 K>
267 return (
Hi & FixupInfo<K>::OpcodeMask.
Hi) == FixupInfo<K>::Opcode.Hi &&
268 (
Lo & FixupInfo<K>::OpcodeMask.Lo) == FixupInfo<K>::Opcode.
Lo;
271class FixupInfoTable {
276 populateEntries<FirstArmRelocation, LastArmRelocation>();
277 populateEntries<FirstThumbRelocation, LastThumbRelocation>();
281 assert(K < Data.size() &&
"Index out of bounds");
282 return Data.at(K).get();
286 template <EdgeKind_aarch32 K, EdgeKind_aarch32 LastK>
void populateEntries() {
287 assert(K < Data.size() &&
"Index out of range");
288 assert(Data.at(K) ==
nullptr &&
"Initialized entries are immutable");
289 Data[
K] = initEntry<K>();
290 if constexpr (
K < LastK) {
292 populateEntries<Next, LastK>();
296 template <EdgeKind_aarch32 K>
297 static std::unique_ptr<FixupInfoBase> initEntry() {
298 auto Entry = std::make_unique<FixupInfo<K>>();
299 static_assert(isArm<K>() != isThumb<K>(),
"Classes are mutually exclusive");
300 if constexpr (isArm<K>())
301 Entry->checkOpcode = checkOpcodeArm<K>;
302 if constexpr (isThumb<K>())
303 Entry->checkOpcode = checkOpcodeThumb<K>;
308 std::array<std::unique_ptr<FixupInfoBase>, Items> Data;
311ManagedStatic<FixupInfoTable> DynFixupInfos;
318 "Edge kind must be Arm relocation");
321 assert(
Info.checkOpcode &&
"Opcode check is mandatory for Arm edges");
322 if (!
Info.checkOpcode(R.Wd))
323 return makeUnexpectedOpcodeError(
G, R, Kind);
331 "Edge kind must be Thumb relocation");
334 assert(
Info.checkOpcode &&
"Opcode check is mandatory for Thumb edges");
335 if (!
Info.checkOpcode(R.Hi, R.Lo))
336 return makeUnexpectedOpcodeError(
G, R, Kind);
342 return DynFixupInfos->getEntry(K);
345template <EdgeKind_aarch32 Kind>
352template <EdgeKind_aarch32 Kind>
358template <EdgeKind_aarch32 Kind>
362 "Value bits exceed bit range of given mask");
363 R.Hi = (R.Hi & ~Mask.Hi) |
Reg.Hi;
364 R.Lo = (R.Lo & ~Mask.Lo) |
Reg.Lo;
367template <EdgeKind_aarch32 Kind>
370 assert((Mask &
Reg) ==
Reg &&
"Value bits exceed bit range of given mask");
371 R.Wd = (R.Wd & ~Mask) |
Reg;
374template <EdgeKind_aarch32 Kind>
377 assert((Mask.Hi & Imm.Hi) == Imm.Hi && (Mask.Lo & Imm.Lo) == Imm.Lo &&
378 "Value bits exceed bit range of given mask");
379 R.Hi = (R.Hi & ~Mask.Hi) | Imm.Hi;
380 R.Lo = (R.Lo & ~Mask.Lo) | Imm.Lo;
383template <EdgeKind_aarch32 Kind>
386 assert((Mask & Imm) == Imm &&
"Value bits exceed bit range of given mask");
387 R.Wd = (R.Wd & ~Mask) | Imm;
393 const char *BlockWorkingMem =
B.getContent().data();
394 const char *FixupPtr = BlockWorkingMem +
Offset;
404 return make_error<JITLinkError>(
405 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
406 " can not read implicit addend for aarch32 edge kind " +
407 G.getEdgeKindName(Kind));
413 ArmRelocation R(
B.getContent().data() +
Offset);
415 return std::move(Err);
427 return make_error<JITLinkError>(
428 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
429 " can not read implicit addend for aarch32 edge kind " +
430 G.getEdgeKindName(Kind));
436 ThumbRelocation R(
B.getContent().data() +
Offset);
438 return std::move(Err);
458 return make_error<JITLinkError>(
459 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
460 " can not read implicit addend for aarch32 edge kind " +
461 G.getEdgeKindName(Kind));
466 using namespace support;
468 char *BlockWorkingMem =
B.getAlreadyMutableContent().data();
469 char *FixupPtr = BlockWorkingMem +
E.getOffset();
472 uint64_t FixupAddress = (
B.getAddress() +
E.getOffset()).getValue();
473 int64_t Addend =
E.getAddend();
474 Symbol &TargetSymbol =
E.getTarget();
481 int64_t
Value = TargetAddress - FixupAddress + Addend;
482 if (!isInt<32>(
Value))
491 int64_t
Value = TargetAddress + Addend;
492 if (!isUInt<32>(
Value))
501 int64_t
Value = TargetAddress - FixupAddress + Addend;
502 if (!isInt<31>(
Value))
516 return make_error<JITLinkError>(
517 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
518 " encountered unfixable aarch32 edge kind " +
519 G.getEdgeKindName(
E.getKind()));
524 WritableArmRelocation R(
B.getAlreadyMutableContent().data() +
E.getOffset());
529 uint64_t FixupAddress = (
B.getAddress() +
E.getOffset()).getValue();
530 int64_t Addend =
E.getAddend();
531 Symbol &TargetSymbol =
E.getTarget();
537 return make_error<JITLinkError>(
"Branch relocation needs interworking "
538 "stub when bridging to Thumb: " +
541 int64_t
Value = TargetAddress - FixupAddress + Addend;
543 if (!isInt<26>(
Value))
552 return make_error<JITLinkError>(
"Relocation expects an unconditional "
553 "BL/BLX branch instruction: " +
556 int64_t
Value = TargetAddress - FixupAddress + Addend;
562 if (TargetIsThumb != InstrIsBlx) {
573 if (!isInt<26>(
Value))
590 return make_error<JITLinkError>(
591 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
592 " encountered unfixable aarch32 edge kind " +
593 G.getEdgeKindName(
E.getKind()));
599 WritableThumbRelocation R(
B.getAlreadyMutableContent().data() +
605 uint64_t FixupAddress = (
B.getAddress() +
E.getOffset()).getValue();
606 int64_t Addend =
E.getAddend();
607 Symbol &TargetSymbol =
E.getTarget();
613 return make_error<JITLinkError>(
"Branch relocation needs interworking "
614 "stub when bridging to ARM: " +
617 int64_t
Value = TargetAddress - FixupAddress + Addend;
619 if (!isInt<25>(
Value))
623 if (!isInt<22>(
Value))
632 int64_t
Value = TargetAddress - FixupAddress + Addend;
638 if (TargetIsArm != InstrIsBlx) {
652 if (!isInt<25>(
Value))
656 if (!isInt<22>(
Value))
663 "Opcode BLX implies H bit is clear (avoid UB in BLX T2)");
678 uint16_t Value = ((TargetAddress + Addend - FixupAddress) & 0xffff);
683 uint16_t Value = (((TargetAddress + Addend - FixupAddress) >> 16) & 0xffff);
689 return make_error<JITLinkError>(
690 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
691 " encountered unfixable aarch32 edge kind " +
692 G.getEdgeKindName(
E.getKind()));
704template <
size_t Size>
707 static_assert(
Size == 4,
"Pointers are 32-bit");
717 constexpr int64_t GOTEntryAddend = 0;
719 return G.addAnonymousSymbol(
B, 0,
B.getSize(),
false,
false);
724 switch (
E.getKind()) {
733 <<
" edge at " <<
B->getFixupAddress(
E) <<
" ("
734 <<
B->getAddress() <<
" + "
735 <<
formatv(
"{0:x}",
E.getOffset()) <<
") into "
736 <<
G.getEdgeKindName(KindToSet) <<
"\n");
737 E.setKind(KindToSet);
745 0x04, 0xf0, 0x1f, 0xe5,
746 0x00, 0x00, 0x00, 0x00,
750 0x00, 0xc0, 0x00, 0xe3,
751 0x00, 0xc0, 0x40, 0xe3,
752 0x1c, 0xff, 0x2f, 0xe1
756 0x40, 0xf2, 0x00, 0x0c,
757 0xc0, 0xf2, 0x00, 0x0c,
762template <
size_t Size>
780 [[maybe_unused]]
const char *StubPtr =
B.getContent().data();
782 assert(checkRegister<Thumb_MovwAbsNC>(StubPtr, Reg12) &&
783 checkRegister<Thumb_MovtAbs>(StubPtr + 4, Reg12) &&
784 "Linker generated stubs may only corrupt register r12 (IP)");
793 [[maybe_unused]]
const char *StubPtr =
B.getContent().data();
795 assert(checkRegister<Arm_MovwAbsNC>(StubPtr, Reg12) &&
796 checkRegister<Arm_MovtAbs>(StubPtr + 4, Reg12) &&
797 "Linker generated stubs may only corrupt register r12 (IP)");
805 if (!
Target.isDefined()) {
806 switch (
E.getKind()) {
820 switch (
E.getKind()) {
822 return TargetIsThumb;
824 return !TargetIsThumb;
840 if (Thumb && !Slot.ThumbEntry) {
842 &
G.addAnonymousSymbol(*Slot.B, ThumbEntrypointOffset, 4,
true,
false);
845 if (!Thumb && !Slot.ArmEntry)
847 &
G.addAnonymousSymbol(*Slot.B, ArmEntrypointOffset, 8,
true,
false);
848 return Thumb ? Slot.ThumbEntry : Slot.ArmEntry;
856 assert(
Target.hasName() &&
"Edge cannot point to anonymous target");
865 << StubsSection->
getName() <<
"\n";
874 Symbol *StubEntrypoint = getOrCreateSlotEntrypoint(
G, *Slot, UseThumb);
877 dbgs() <<
" Using " << (UseThumb ?
"Thumb" :
"Arm") <<
" entrypoint "
878 << *StubEntrypoint <<
" in "
882 E.setTarget(*StubEntrypoint);
893 LLVM_DEBUG(
dbgs() <<
" Preparing " << (MakeThumb ?
"Thumb" :
"Arm")
894 <<
" stub for " <<
G.getEdgeKindName(
E.getKind())
895 <<
" edge at " <<
B->getFixupAddress(
E) <<
" ("
896 <<
B->getAddress() <<
" + "
897 <<
formatv(
"{0:x}",
E.getOffset()) <<
")\n");
900 assert(
Target.hasName() &&
"Edge cannot point to anonymous target");
909 StubSymbol = &
G.addAnonymousSymbol(
B, 0,
B.getSize(),
true,
false);
914 dbgs() <<
" Created " << (MakeThumb ?
"Thumb" :
"Arm") <<
" entry for "
916 << *StubSymbol <<
"\n";
921 "Instruction set states of stub and relocation site should be equal");
923 dbgs() <<
" Using " << (MakeThumb ?
"Thumb" :
"Arm") <<
" entry "
924 << *StubSymbol <<
" in "
928 E.setTarget(*StubSymbol);
933#define KIND_NAME_CASE(K) \
960#define CPUARCH_NAME_CASE(K) \
964 using namespace ARMBuildAttrs;
988#undef CPUARCH_NAME_CASE
static bool isThumb(const MCSubtargetInfo &STI)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Analysis containing CSE Info
#define LLVM_LIKELY(EXPR)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
#define CPUARCH_NAME_CASE(K)
support::ulittle16_t & Lo
support::ulittle32_t & Wd
#define KIND_NAME_CASE(K)
support::ulittle16_t & Hi
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
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.
const char * getName() const
getName - Get the target name.
LLVM Value Representation.
An Addressable with content and edges.
Section & getSection() const
Return the parent section for this block.
Represents fixups and constraints in the LinkGraph.
Represents an object file section.
StringRef getName() const
Returns the name of this section.
TargetFlagsType getTargetFlags() const
Get the target flags of this Symbol.
void setTargetFlags(TargetFlagsType Flags)
Set the target flags for this Symbol.
orc::ExecutorAddr getAddress() const
Returns the address of this symbol.
Block & getBlock()
Return the Block for this Symbol (Symbol must be defined).
Symbol & getEntryForTarget(LinkGraph &G, Symbol &Target)
Return the constructed entry.
bool visitEdge(LinkGraph &G, Block *B, Edge &E)
static StringRef getSectionName()
Symbol & createEntry(LinkGraph &G, Symbol &Target)
static StringRef getSectionName()
Name of the object file section that will contain all our stubs.
bool visitEdge(LinkGraph &G, Block *B, Edge &E)
Implements link-graph traversal via visitExistingEdges()
static StringRef getSectionName()
Name of the object file section that will contain all our stubs.
bool visitEdge(LinkGraph &G, Block *B, Edge &E)
Implements link-graph traversal via visitExistingEdges().
Represents an address in the executor process.
uint64_t getValue() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
EdgeKind_aarch32
JITLink-internal AArch32 fixup kinds.
@ Data_RequestGOTAndTransformToDelta32
Create GOT entry and store offset.
@ Arm_MovtAbs
Write immediate value to the top halfword of the destination register.
@ Data_PRel31
Relative 31-bit value relocation that preserves the most-significant bit.
@ Data_Pointer32
Absolute 32-bit value relocation.
@ FirstThumbRelocation
Relocations of class Thumb16 and Thumb32 (covers Thumb instruction subset)
@ 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_MovtPrel
Write PC-relative immediate value to the top halfword of the destination register.
@ 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.
@ FirstArmRelocation
Relocations of class Arm (covers fixed-width 4-byte instruction subset)
@ 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.
@ Thumb_MovwPrelNC
Write PC-relative immediate value to the lower halfword of the destination register.
static Block & createStubThumbv7(LinkGraph &G, Section &S, Symbol &Target)
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,...
static bool needsStub(const Edge &E)
HalfWords encodeRegMovtT1MovwT3(int64_t Value)
Encode register ID for instruction formats MOVT T1 and MOVW T3.
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.
Expected< int64_t > readAddendData(LinkGraph &G, Block &B, Edge::OffsetT Offset, Edge::Kind Kind)
Helper function to read the initial addend for Data-class relocations.
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.
const uint8_t ArmThumbv5LdrPc[]
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.
static Block & allocStub(LinkGraph &G, Section &S, const uint8_t(&Code)[Size])
Create a new node in the link-graph for the given stub template.
const uint8_t GOTEntryInit[]
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,...
static Error checkOpcode(LinkGraph &G, const ArmRelocation &R, Edge::Kind Kind)
int64_t decodeImmBA1BlA1BlxA2(int64_t Value)
Decode 26-bit immediate value for branch instructions (formats B A1, BL A1 and BLX A2).
Expected< int64_t > readAddendThumb(LinkGraph &G, Block &B, Edge::OffsetT Offset, Edge::Kind Kind, const ArmConfig &ArmCfg)
Helper function to read the initial addend for Thumb-class relocations.
void writeRegister(WritableThumbRelocation &R, HalfWords Reg)
bool checkRegister(const ThumbRelocation &R, HalfWords Reg)
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,...
static Block & allocPointer(LinkGraph &G, Section &S, const uint8_t(&Content)[Size])
Create a new node in the link-graph for the given pointer value.
void writeImmediate(WritableThumbRelocation &R, HalfWords Imm)
static Block & createStubArmv7(LinkGraph &G, Section &S, Symbol &Target)
Expected< int64_t > readAddendArm(LinkGraph &G, Block &B, Edge::OffsetT Offset, Edge::Kind Kind)
Helper function to read the initial addend for Arm-class relocations.
static Block & createStubPrev7(LinkGraph &G, Section &S, Symbol &Target)
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)
void write32le(void *P, uint32_t V)
void write32be(void *P, uint32_t V)
uint32_t read32be(const void *P)
uint32_t read32le(const void *P)
detail::packed_endian_specific_integral< uint16_t, llvm::endianness::little, unaligned > ulittle16_t
detail::packed_endian_specific_integral< uint32_t, llvm::endianness::little, unaligned > ulittle32_t
This is an optimization pass for GlobalISel generic memory operations.
auto formatv(const char *Fmt, Ts &&...Vals) -> formatv_object< decltype(std::make_tuple(support::detail::build_format_adapter(std::forward< Ts >(Vals))...))>
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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.
FixupInfo checks for Arm edge kinds work on 32-bit words.
FixupInfo base class is required for dynamic lookups.
static const FixupInfoBase * getDynFixupInfo(Edge::Kind K)
FixupInfo check for Thumb32 edge kinds work on a pair of 16-bit halfwords.
Collection of named constants per fixup kind.
Immutable pair of halfwords, Hi and Lo, with overflow check.