Skip to content

Commit 4b17c81

Browse files
eymayweliveindetail
authored andcommitted
[jitlink/rtdydl][checker] Add TargetFlag dependent disassembler switching support
Some targets such as AArch32 make use of TargetFlags to indicate ISA mode. Depending on the TargetFlag, MCDisassembler and similar target specific objects should be reinitialized with the correct Target Triple. Backends with similar needs can easily extend this implementation for their usecase. The drivers llvm-rtdyld and llvm-jitlink have their SymbolInfo's extended to take TargetFlag into account. RuntimeDyldChecker can now create necessary TargetInfo to reinitialize MCDisassembler and MCInstPrinter. The required triple is obtained from the new getTripleFromTargetFlag function by checking the TargetFlag. In addition, breaking changes for RuntimeDyld COFF Thumb tests are fixed by making the backend emit a TargetFlag. Reviewed By: lhames, sgraenitz Differential Revision: https://reviews.llvm.org/D158280
1 parent b0ea279 commit 4b17c81

File tree

15 files changed

+253
-63
lines changed

15 files changed

+253
-63
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -623,10 +623,8 @@ class Symbol {
623623
this->S = static_cast<uint8_t>(S);
624624
}
625625

626-
/// Check whether the given target flags are set for this Symbol.
627-
bool hasTargetFlags(TargetFlagsType Flags) const {
628-
return static_cast<TargetFlagsType>(TargetFlags) & Flags;
629-
}
626+
/// Get the target flags of this Symbol.
627+
TargetFlagsType getTargetFlags() const { return TargetFlags; }
630628

631629
/// Set the target flags for this Symbol.
632630
void setTargetFlags(TargetFlagsType Flags) {

llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ namespace llvm {
2323
namespace jitlink {
2424
namespace aarch32 {
2525

26+
/// Check whether the given target flags are set for this Symbol.
27+
bool hasTargetFlags(Symbol &Sym, TargetFlagsType Flags);
28+
2629
/// JITLink-internal AArch32 fixup kinds
2730
enum EdgeKind_aarch32 : Edge::Kind {
2831

llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "llvm/ADT/DenseMap.h"
1313
#include "llvm/ExecutionEngine/JITSymbol.h"
1414
#include "llvm/Support/Endian.h"
15+
#include "llvm/TargetParser/SubtargetFeature.h"
16+
#include "llvm/TargetParser/Triple.h"
1517
#include <optional>
1618

1719
#include <cstdint>
@@ -29,6 +31,9 @@ class RuntimeDyld;
2931
class RuntimeDyldCheckerImpl;
3032
class raw_ostream;
3133

34+
/// Holds target-specific properties for a symbol.
35+
using TargetFlagsType = uint8_t;
36+
3237
/// RuntimeDyld invariant checker for verifying that RuntimeDyld has
3338
/// correctly applied relocations.
3439
///
@@ -78,10 +83,11 @@ class RuntimeDyldChecker {
7883
public:
7984
MemoryRegionInfo() = default;
8085

81-
/// Constructor for symbols/sections with content.
82-
MemoryRegionInfo(ArrayRef<char> Content, JITTargetAddress TargetAddress)
86+
/// Constructor for symbols/sections with content and TargetFlag.
87+
MemoryRegionInfo(ArrayRef<char> Content, JITTargetAddress TargetAddress,
88+
TargetFlagsType TargetFlags)
8389
: ContentPtr(Content.data()), Size(Content.size()),
84-
TargetAddress(TargetAddress) {}
90+
TargetAddress(TargetAddress), TargetFlags(TargetFlags) {}
8591

8692
/// Constructor for zero-fill symbols/sections.
8793
MemoryRegionInfo(uint64_t Size, JITTargetAddress TargetAddress)
@@ -127,10 +133,20 @@ class RuntimeDyldChecker {
127133
/// Return the target address for this region.
128134
JITTargetAddress getTargetAddress() const { return TargetAddress; }
129135

136+
/// Get the target flags for this Symbol.
137+
TargetFlagsType getTargetFlags() const { return TargetFlags; }
138+
139+
/// Set the target flags for this Symbol.
140+
void setTargetFlags(TargetFlagsType Flags) {
141+
assert(Flags <= 1 && "Add more bits to store more than one flag");
142+
TargetFlags = Flags;
143+
}
144+
130145
private:
131146
const char *ContentPtr = nullptr;
132147
uint64_t Size = 0;
133148
JITTargetAddress TargetAddress = 0;
149+
TargetFlagsType TargetFlags = 0;
134150
};
135151

136152
using IsSymbolValidFunction = std::function<bool(StringRef Symbol)>;
@@ -148,9 +164,8 @@ class RuntimeDyldChecker {
148164
GetSectionInfoFunction GetSectionInfo,
149165
GetStubInfoFunction GetStubInfo,
150166
GetGOTInfoFunction GetGOTInfo,
151-
support::endianness Endianness,
152-
MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
153-
raw_ostream &ErrStream);
167+
support::endianness Endianness, Triple TT,
168+
SubtargetFeatures TF, raw_ostream &ErrStream);
154169
~RuntimeDyldChecker();
155170

156171
/// Check a single expression against the attached RuntimeDyld

llvm/lib/ExecutionEngine/JITLink/aarch32.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ namespace llvm {
2525
namespace jitlink {
2626
namespace aarch32 {
2727

28+
/// Check whether the given target flags are set for this Symbol.
29+
bool hasTargetFlags(Symbol &Sym, TargetFlagsType Flags) {
30+
return static_cast<TargetFlagsType>(Sym.getTargetFlags()) & Flags;
31+
}
32+
2833
/// Encode 22-bit immediate value for branch instructions without J1J2 range
2934
/// extension (formats B T4, BL T1 and BLX T2).
3035
///
@@ -287,7 +292,7 @@ Error applyFixupData(LinkGraph &G, Block &B, const Edge &E) {
287292
int64_t Addend = E.getAddend();
288293
Symbol &TargetSymbol = E.getTarget();
289294
uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
290-
assert(!TargetSymbol.hasTargetFlags(ThumbSymbol));
295+
assert(!hasTargetFlags(TargetSymbol, ThumbSymbol));
291296

292297
// Regular data relocations have size 4, alignment 1 and write the full 32-bit
293298
// result to the place; no need for overflow checking. There are three
@@ -341,14 +346,14 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
341346
int64_t Addend = E.getAddend();
342347
Symbol &TargetSymbol = E.getTarget();
343348
uint64_t TargetAddress = TargetSymbol.getAddress().getValue();
344-
if (TargetSymbol.hasTargetFlags(ThumbSymbol))
349+
if (hasTargetFlags(TargetSymbol, ThumbSymbol))
345350
TargetAddress |= 0x01;
346351

347352
switch (Kind) {
348353
case Thumb_Jump24: {
349354
if (!checkOpcode<Thumb_Jump24>(R))
350355
return makeUnexpectedOpcodeError(G, R, Kind);
351-
if (!(TargetSymbol.hasTargetFlags(ThumbSymbol)))
356+
if (!hasTargetFlags(TargetSymbol, ThumbSymbol))
352357
return make_error<JITLinkError>("Branch relocation needs interworking "
353358
"stub when bridging to ARM: " +
354359
StringRef(G.getEdgeKindName(Kind)));
@@ -375,7 +380,7 @@ Error applyFixupThumb(LinkGraph &G, Block &B, const Edge &E,
375380

376381
// The call instruction itself is Thumb. The call destination can either be
377382
// Thumb or Arm. We use BL to stay in Thumb and BLX to change to Arm.
378-
bool TargetIsArm = !TargetSymbol.hasTargetFlags(ThumbSymbol);
383+
bool TargetIsArm = !hasTargetFlags(TargetSymbol, ThumbSymbol);
379384
bool InstrIsBlx = (R.Lo & FixupInfo<Thumb_Call>::LoBitNoBlx) == 0;
380385
if (TargetIsArm != InstrIsBlx) {
381386
if (LLVM_LIKELY(TargetIsArm)) {

llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ ExecutorAddr getJITSymbolPtrForSymbol(Symbol &Sym, const Triple &TT) {
4646
case Triple::armeb:
4747
case Triple::thumb:
4848
case Triple::thumbeb:
49-
if (Sym.hasTargetFlags(aarch32::ThumbSymbol)) {
49+
if (hasTargetFlags(Sym, aarch32::ThumbSymbol)) {
5050
// Set LSB to indicate thumb target
5151
assert(Sym.isCallable() && "Only callable symbols can have thumb flag");
5252
assert((Sym.getAddress().getValue() & 0x01) == 0 && "LSB is clear");

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp

Lines changed: 147 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@
1010
#include "RuntimeDyldCheckerImpl.h"
1111
#include "llvm/ADT/STLExtras.h"
1212
#include "llvm/ADT/StringExtras.h"
13+
#include "llvm/MC/MCAsmInfo.h"
1314
#include "llvm/MC/MCContext.h"
1415
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
1516
#include "llvm/MC/MCInst.h"
17+
#include "llvm/MC/MCInstPrinter.h"
18+
#include "llvm/MC/MCInstrInfo.h"
19+
#include "llvm/MC/MCRegisterInfo.h"
20+
#include "llvm/MC/MCSubtargetInfo.h"
21+
#include "llvm/MC/MCTargetOptions.h"
22+
#include "llvm/MC/TargetRegistry.h"
1623
#include "llvm/Support/Endian.h"
1724
#include "llvm/Support/MSVCErrorWorkarounds.h"
1825
#include "llvm/Support/MemoryBuffer.h"
@@ -25,6 +32,19 @@
2532

2633
using namespace llvm;
2734

35+
namespace {
36+
struct TargetInfo {
37+
const Target *TheTarget;
38+
std::unique_ptr<MCSubtargetInfo> STI;
39+
std::unique_ptr<MCRegisterInfo> MRI;
40+
std::unique_ptr<MCAsmInfo> MAI;
41+
std::unique_ptr<MCContext> Ctx;
42+
std::unique_ptr<MCDisassembler> Disassembler;
43+
std::unique_ptr<MCInstrInfo> MII;
44+
std::unique_ptr<MCInstPrinter> InstPrinter;
45+
};
46+
} // anonymous namespace
47+
2848
namespace llvm {
2949

3050
// Helper class that implements the language evaluated by RuntimeDyldChecker.
@@ -276,6 +296,20 @@ class RuntimeDyldCheckerExprEval {
276296
"");
277297

278298
unsigned OpIdx = OpIdxExpr.getValue();
299+
300+
auto printInst = [this](StringRef Symbol, MCInst Inst,
301+
raw_string_ostream &ErrMsgStream) {
302+
auto TI = getTargetInfo(
303+
Checker.getTripleFromTargetFlag(Checker.getTargetFlag(Symbol)));
304+
if (auto E = TI.takeError()) {
305+
errs() << "Error obtaining instruction printer: "
306+
<< toString(std::move(E)) << "\n";
307+
return std::make_pair(EvalResult(ErrMsgStream.str()), "");
308+
}
309+
Inst.dump_pretty(ErrMsgStream, TI->InstPrinter.get());
310+
return std::make_pair(EvalResult(ErrMsgStream.str()), "");
311+
};
312+
279313
if (OpIdx >= Inst.getNumOperands()) {
280314
std::string ErrMsg;
281315
raw_string_ostream ErrMsgStream(ErrMsg);
@@ -284,8 +318,8 @@ class RuntimeDyldCheckerExprEval {
284318
<< "'. Instruction has only "
285319
<< format("%i", Inst.getNumOperands())
286320
<< " operands.\nInstruction is:\n ";
287-
Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter);
288-
return std::make_pair(EvalResult(ErrMsgStream.str()), "");
321+
322+
return printInst(Symbol, Inst, ErrMsgStream);
289323
}
290324

291325
const MCOperand &Op = Inst.getOperand(OpIdx);
@@ -294,9 +328,8 @@ class RuntimeDyldCheckerExprEval {
294328
raw_string_ostream ErrMsgStream(ErrMsg);
295329
ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '"
296330
<< Symbol << "' is not an immediate.\nInstruction is:\n ";
297-
Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter);
298331

299-
return std::make_pair(EvalResult(ErrMsgStream.str()), "");
332+
return printInst(Symbol, Inst, ErrMsgStream);
300333
}
301334

302335
return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
@@ -687,31 +720,101 @@ class RuntimeDyldCheckerExprEval {
687720

688721
bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size,
689722
int64_t Offset) const {
690-
MCDisassembler *Dis = Checker.Disassembler;
723+
auto TI = getTargetInfo(
724+
Checker.getTripleFromTargetFlag(Checker.getTargetFlag(Symbol)));
725+
726+
if (auto E = TI.takeError()) {
727+
errs() << "Error obtaining disassembler: " << toString(std::move(E))
728+
<< "\n";
729+
return false;
730+
}
731+
691732
StringRef SymbolMem = Checker.getSymbolContent(Symbol);
692733
ArrayRef<uint8_t> SymbolBytes(SymbolMem.bytes_begin() + Offset,
693734
SymbolMem.size() - Offset);
694735

695736
MCDisassembler::DecodeStatus S =
696-
Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls());
737+
TI->Disassembler->getInstruction(Inst, Size, SymbolBytes, 0, nulls());
697738

698739
return (S == MCDisassembler::Success);
699740
}
741+
742+
Expected<TargetInfo>
743+
getTargetInfo(const Triple &TT,
744+
const SubtargetFeatures &TF = SubtargetFeatures()) const {
745+
746+
auto TripleName = TT.str();
747+
std::string ErrorStr;
748+
const Target *TheTarget =
749+
TargetRegistry::lookupTarget(TripleName, ErrorStr);
750+
if (!TheTarget)
751+
return make_error<StringError>("Error accessing target '" + TripleName +
752+
"': " + ErrorStr,
753+
inconvertibleErrorCode());
754+
755+
std::unique_ptr<MCSubtargetInfo> STI(
756+
TheTarget->createMCSubtargetInfo(TripleName, "", TF.getString()));
757+
if (!STI)
758+
return make_error<StringError>("Unable to create subtarget for " +
759+
TripleName,
760+
inconvertibleErrorCode());
761+
762+
std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
763+
if (!MRI)
764+
return make_error<StringError>("Unable to create target register info "
765+
"for " +
766+
TripleName,
767+
inconvertibleErrorCode());
768+
769+
MCTargetOptions MCOptions;
770+
std::unique_ptr<MCAsmInfo> MAI(
771+
TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
772+
if (!MAI)
773+
return make_error<StringError>("Unable to create target asm info " +
774+
TripleName,
775+
inconvertibleErrorCode());
776+
777+
auto Ctx = std::make_unique<MCContext>(Triple(TripleName), MAI.get(),
778+
MRI.get(), STI.get());
779+
780+
std::unique_ptr<MCDisassembler> Disassembler(
781+
TheTarget->createMCDisassembler(*STI, *Ctx));
782+
if (!Disassembler)
783+
return make_error<StringError>("Unable to create disassembler for " +
784+
TripleName,
785+
inconvertibleErrorCode());
786+
787+
std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
788+
if (!MII)
789+
return make_error<StringError>("Unable to create instruction info for" +
790+
TripleName,
791+
inconvertibleErrorCode());
792+
793+
std::unique_ptr<MCInstPrinter> InstPrinter(TheTarget->createMCInstPrinter(
794+
Triple(TripleName), 0, *MAI, *MII, *MRI));
795+
if (!InstPrinter)
796+
return make_error<StringError>(
797+
"Unable to create instruction printer for" + TripleName,
798+
inconvertibleErrorCode());
799+
800+
return TargetInfo({TheTarget, std::move(STI), std::move(MRI),
801+
std::move(MAI), std::move(Ctx), std::move(Disassembler),
802+
std::move(MII), std::move(InstPrinter)});
803+
}
700804
};
701805
} // namespace llvm
702806

703807
RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(
704808
IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo,
705809
GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo,
706-
GetGOTInfoFunction GetGOTInfo, support::endianness Endianness,
707-
MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
708-
raw_ostream &ErrStream)
810+
GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, Triple TT,
811+
SubtargetFeatures TF, raw_ostream &ErrStream)
709812
: IsSymbolValid(std::move(IsSymbolValid)),
710813
GetSymbolInfo(std::move(GetSymbolInfo)),
711814
GetSectionInfo(std::move(GetSectionInfo)),
712815
GetStubInfo(std::move(GetStubInfo)), GetGOTInfo(std::move(GetGOTInfo)),
713-
Endianness(Endianness), Disassembler(Disassembler),
714-
InstPrinter(InstPrinter), ErrStream(ErrStream) {}
816+
Endianness(Endianness), TT(std::move(TT)), TF(std::move(TF)),
817+
ErrStream(ErrStream) {}
715818

716819
bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const {
717820
CheckExpr = CheckExpr.trim();
@@ -822,6 +925,36 @@ StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const {
822925
return {SymInfo->getContent().data(), SymInfo->getContent().size()};
823926
}
824927

928+
TargetFlagsType RuntimeDyldCheckerImpl::getTargetFlag(StringRef Symbol) const {
929+
auto SymInfo = GetSymbolInfo(Symbol);
930+
if (!SymInfo) {
931+
logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
932+
return TargetFlagsType{};
933+
}
934+
return SymInfo->getTargetFlags();
935+
}
936+
937+
Triple
938+
RuntimeDyldCheckerImpl::getTripleFromTargetFlag(TargetFlagsType Flag) const {
939+
Triple TheTriple = TT;
940+
941+
switch (TT.getArch()) {
942+
case Triple::ArchType::arm:
943+
if (~Flag & 0x1)
944+
return TT;
945+
TheTriple.setArchName((Twine("thumb") + TT.getArchName().substr(3)).str());
946+
return TheTriple;
947+
case Triple::ArchType::thumb:
948+
if (Flag & 0x1)
949+
return TT;
950+
TheTriple.setArchName((Twine("arm") + TT.getArchName().substr(5)).str());
951+
return TheTriple;
952+
953+
default:
954+
return TT;
955+
}
956+
}
957+
825958
std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
826959
StringRef FileName, StringRef SectionName, bool IsInsideLoad) const {
827960

@@ -884,13 +1017,12 @@ std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(
8841017
RuntimeDyldChecker::RuntimeDyldChecker(
8851018
IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo,
8861019
GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo,
887-
GetGOTInfoFunction GetGOTInfo, support::endianness Endianness,
888-
MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
889-
raw_ostream &ErrStream)
1020+
GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, Triple TT,
1021+
SubtargetFeatures TF, raw_ostream &ErrStream)
8901022
: Impl(::std::make_unique<RuntimeDyldCheckerImpl>(
8911023
std::move(IsSymbolValid), std::move(GetSymbolInfo),
8921024
std::move(GetSectionInfo), std::move(GetStubInfo),
893-
std::move(GetGOTInfo), Endianness, Disassembler, InstPrinter,
1025+
std::move(GetGOTInfo), Endianness, std::move(TT), std::move(TF),
8941026
ErrStream)) {}
8951027

8961028
RuntimeDyldChecker::~RuntimeDyldChecker() = default;

0 commit comments

Comments
 (0)