Skip to content

Commit 76aee8a

Browse files
committed
[JITLink] Refactor EH-frame handling to support eh-frames with existing relocs.
Some targets (E.g. MachO/arm64) use relocations to fix some CFI record fields in the eh-frame section. When relocations are used the initial (pre-relocation) content of the eh-frame section can no longer be interpreted by following the eh-frame specification. This causes errors in the existing eh-frame parser. This patch moves eh-frame handling into two LinkGraph passes that are run after relocations have been parsed (but before they are applied). The first] pass breaks up blocks in the eh-frame section into per-CFI-record blocks, and the second parses blocks of (potentially multiple) CFI records and adds the appropriate edges to any CFI fields that do not have existing relocations. These passes can be run independently of one another. By handling eh-frame splitting/fixing with LinkGraph passes we can both re-use existing relocations for CFI record fields and avoid applying eh-frame fixups before parsing the section (which would complicate the linker and require extra temporary allocations of working memory).
1 parent 8243918 commit 76aee8a

File tree

9 files changed

+704
-348
lines changed

9 files changed

+704
-348
lines changed

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

Lines changed: 163 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ class Addressable {
131131
uint64_t IsAbsolute : 1;
132132
};
133133

134-
using BlockOrdinal = unsigned;
135134
using SectionOrdinal = unsigned;
136135

137136
/// An Addressable with content and edges.
@@ -140,10 +139,9 @@ class Block : public Addressable {
140139

141140
private:
142141
/// Create a zero-fill defined addressable.
143-
Block(Section &Parent, BlockOrdinal Ordinal, JITTargetAddress Size,
144-
JITTargetAddress Address, uint64_t Alignment, uint64_t AlignmentOffset)
145-
: Addressable(Address, true), Parent(Parent), Size(Size),
146-
Ordinal(Ordinal) {
142+
Block(Section &Parent, JITTargetAddress Size, JITTargetAddress Address,
143+
uint64_t Alignment, uint64_t AlignmentOffset)
144+
: Addressable(Address, true), Parent(Parent), Size(Size) {
147145
assert(isPowerOf2_64(Alignment) && "Alignment must be power of 2");
148146
assert(AlignmentOffset < Alignment &&
149147
"Alignment offset cannot exceed alignment");
@@ -154,10 +152,10 @@ class Block : public Addressable {
154152
}
155153

156154
/// Create a defined addressable for the given content.
157-
Block(Section &Parent, BlockOrdinal Ordinal, StringRef Content,
158-
JITTargetAddress Address, uint64_t Alignment, uint64_t AlignmentOffset)
155+
Block(Section &Parent, StringRef Content, JITTargetAddress Address,
156+
uint64_t Alignment, uint64_t AlignmentOffset)
159157
: Addressable(Address, true), Parent(Parent), Data(Content.data()),
160-
Size(Content.size()), Ordinal(Ordinal) {
158+
Size(Content.size()) {
161159
assert(isPowerOf2_64(Alignment) && "Alignment must be power of 2");
162160
assert(AlignmentOffset < Alignment &&
163161
"Alignment offset cannot exceed alignment");
@@ -180,9 +178,6 @@ class Block : public Addressable {
180178
/// Return the parent section for this block.
181179
Section &getSection() const { return Parent; }
182180

183-
/// Return the ordinal for this block.
184-
BlockOrdinal getOrdinal() const { return Ordinal; }
185-
186181
/// Returns true if this is a zero-fill block.
187182
///
188183
/// If true, getSize is callable but getContent is not (the content is
@@ -263,7 +258,6 @@ class Block : public Addressable {
263258
Section &Parent;
264259
const char *Data = nullptr;
265260
size_t Size = 0;
266-
BlockOrdinal Ordinal = 0;
267261
std::vector<Edge> Edges;
268262
};
269263

@@ -357,6 +351,7 @@ class Symbol {
357351
JITTargetAddress Size, bool IsCallable,
358352
bool IsLive) {
359353
assert(SymStorage && "Storage cannot be null");
354+
assert(Offset < Base.getSize() && "Symbol offset is outside block");
360355
auto *Sym = reinterpret_cast<Symbol *>(SymStorage);
361356
new (Sym) Symbol(Base, Offset, StringRef(), Size, Linkage::Strong,
362357
Scope::Local, IsLive, IsCallable);
@@ -368,6 +363,7 @@ class Symbol {
368363
JITTargetAddress Size, Linkage L, Scope S,
369364
bool IsLive, bool IsCallable) {
370365
assert(SymStorage && "Storage cannot be null");
366+
assert(Offset < Base.getSize() && "Symbol offset is outside block");
371367
assert(!Name.empty() && "Name cannot be empty");
372368
auto *Sym = reinterpret_cast<Symbol *>(SymStorage);
373369
new (Sym) Symbol(Base, Offset, Name, Size, L, S, IsLive, IsCallable);
@@ -588,9 +584,6 @@ class Section {
588584
/// Return true if this section contains no symbols.
589585
bool symbols_empty() const { return Symbols.empty(); }
590586

591-
/// Returns the ordinal for the next block.
592-
BlockOrdinal getNextBlockOrdinal() { return NextBlockOrdinal++; }
593-
594587
private:
595588
void addSymbol(Symbol &Sym) {
596589
assert(!Symbols.count(&Sym) && "Symbol is already in this section");
@@ -615,7 +608,6 @@ class Section {
615608
StringRef Name;
616609
sys::Memory::ProtectionFlags Prot;
617610
SectionOrdinal SecOrdinal = 0;
618-
BlockOrdinal NextBlockOrdinal = 0;
619611
BlockSet Blocks;
620612
SymbolSet Symbols;
621613
};
@@ -815,15 +807,13 @@ class LinkGraph {
815807
Block &createContentBlock(Section &Parent, StringRef Content,
816808
uint64_t Address, uint64_t Alignment,
817809
uint64_t AlignmentOffset) {
818-
return createBlock(Parent, Parent.getNextBlockOrdinal(), Content, Address,
819-
Alignment, AlignmentOffset);
810+
return createBlock(Parent, Content, Address, Alignment, AlignmentOffset);
820811
}
821812

822813
/// Create a zero-fill block.
823814
Block &createZeroFillBlock(Section &Parent, uint64_t Size, uint64_t Address,
824815
uint64_t Alignment, uint64_t AlignmentOffset) {
825-
return createBlock(Parent, Parent.getNextBlockOrdinal(), Size, Address,
826-
Alignment, AlignmentOffset);
816+
return createBlock(Parent, Size, Address, Alignment, AlignmentOffset);
827817
}
828818

829819
/// Cache type for the splitBlock function.
@@ -841,11 +831,18 @@ class LinkGraph {
841831
/// is assumed to contain the list of Symbols pointing at B, sorted in
842832
/// descending order of offset.
843833
///
844-
/// Note: The cache is not automatically updated if new symbols are introduced
845-
/// between calls to splitBlock. Any newly introduced symbols may be
846-
/// added to the cache manually (descending offset order must be
847-
/// preserved), or the cache can be set to None and rebuilt by
848-
/// splitBlock on the next call.
834+
/// Notes:
835+
///
836+
/// 1. The newly introduced block will have a new ordinal which will be
837+
/// higher than any other ordinals in the section. Clients are responsible
838+
/// for re-assigning block ordinals to restore a compatible order if
839+
/// needed.
840+
///
841+
/// 2. The cache is not automatically updated if new symbols are introduced
842+
/// between calls to splitBlock. Any newly introduced symbols may be
843+
/// added to the cache manually (descending offset order must be
844+
/// preserved), or the cache can be set to None and rebuilt by
845+
/// splitBlock on the next call.
849846
Block &splitBlock(Block &B, size_t SplitIndex,
850847
SplitBlockCache *Cache = nullptr);
851848

@@ -875,9 +872,8 @@ class LinkGraph {
875872
uint64_t Alignment, bool IsLive) {
876873
auto &Sym = Symbol::constructCommon(
877874
Allocator.Allocate<Symbol>(),
878-
createBlock(Section, Section.getNextBlockOrdinal(), Address, Size,
879-
Alignment, 0),
880-
Name, Size, S, IsLive);
875+
createBlock(Section, Address, Size, Alignment, 0), Name, Size, S,
876+
IsLive);
881877
Section.addSymbol(Sym);
882878
return Sym;
883879
}
@@ -1019,6 +1015,145 @@ class LinkGraph {
10191015
ExternalSymbolSet AbsoluteSymbols;
10201016
};
10211017

1018+
/// Enables easy lookup of blocks by addresses.
1019+
class BlockAddressMap {
1020+
public:
1021+
using AddrToBlockMap = std::map<JITTargetAddress, Block *>;
1022+
using const_iterator = AddrToBlockMap::const_iterator;
1023+
1024+
/// A block predicate that always adds all blocks.
1025+
static bool includeAllBlocks(const Block &B) { return true; }
1026+
1027+
/// A block predicate that always includes blocks with non-null addresses.
1028+
static bool includeNonNull(const Block &B) { return B.getAddress(); }
1029+
1030+
BlockAddressMap() = default;
1031+
1032+
/// Add a block to the map. Returns an error if the block overlaps with any
1033+
/// existing block.
1034+
template <typename PredFn = decltype(includeAllBlocks)>
1035+
Error addBlock(Block &B, PredFn Pred = includeAllBlocks) {
1036+
if (!Pred(B))
1037+
return Error::success();
1038+
1039+
auto I = AddrToBlock.upper_bound(B.getAddress());
1040+
1041+
// If we're not at the end of the map, check for overlap with the next
1042+
// element.
1043+
if (I != AddrToBlock.end()) {
1044+
if (B.getAddress() + B.getSize() > I->second->getAddress())
1045+
return overlapError(B, *I->second);
1046+
}
1047+
1048+
// If we're not at the start of the map, check for overlap with the previous
1049+
// element.
1050+
if (I != AddrToBlock.begin()) {
1051+
auto &PrevBlock = *std::prev(I)->second;
1052+
if (PrevBlock.getAddress() + PrevBlock.getSize() > B.getAddress())
1053+
return overlapError(B, PrevBlock);
1054+
}
1055+
1056+
AddrToBlock.insert(I, std::make_pair(B.getAddress(), &B));
1057+
return Error::success();
1058+
}
1059+
1060+
/// Add a block to the map without checking for overlap with existing blocks.
1061+
/// The client is responsible for ensuring that the block added does not
1062+
/// overlap with any existing block.
1063+
void addBlockWithoutChecking(Block &B) { AddrToBlock[B.getAddress()] = &B; }
1064+
1065+
/// Add a range of blocks to the map. Returns an error if any block in the
1066+
/// range overlaps with any other block in the range, or with any existing
1067+
/// block in the map.
1068+
template <typename BlockPtrRange,
1069+
typename PredFn = decltype(includeAllBlocks)>
1070+
Error addBlocks(BlockPtrRange &&Blocks, PredFn Pred = includeAllBlocks) {
1071+
for (auto *B : Blocks)
1072+
if (auto Err = addBlock(*B, Pred))
1073+
return Err;
1074+
return Error::success();
1075+
}
1076+
1077+
/// Add a range of blocks to the map without checking for overlap with
1078+
/// existing blocks. The client is responsible for ensuring that the block
1079+
/// added does not overlap with any existing block.
1080+
template <typename BlockPtrRange>
1081+
void addBlocksWithoutChecking(BlockPtrRange &&Blocks) {
1082+
for (auto *B : Blocks)
1083+
addBlockWithoutChecking(*B);
1084+
}
1085+
1086+
/// Iterates over (Address, Block*) pairs in ascending order of address.
1087+
const_iterator begin() const { return AddrToBlock.begin(); }
1088+
const_iterator end() const { return AddrToBlock.end(); }
1089+
1090+
/// Returns the block starting at the given address, or nullptr if no such
1091+
/// block exists.
1092+
Block *getBlockAt(JITTargetAddress Addr) const {
1093+
auto I = AddrToBlock.find(Addr);
1094+
if (I == AddrToBlock.end())
1095+
return nullptr;
1096+
return I->second;
1097+
}
1098+
1099+
/// Returns the block covering the given address, or nullptr if no such block
1100+
/// exists.
1101+
Block *getBlockCovering(JITTargetAddress Addr) const {
1102+
auto I = AddrToBlock.upper_bound(Addr);
1103+
if (I == AddrToBlock.begin())
1104+
return nullptr;
1105+
auto *B = std::prev(I)->second;
1106+
if (Addr < B->getAddress() + B->getSize())
1107+
return B;
1108+
return nullptr;
1109+
}
1110+
1111+
private:
1112+
Error overlapError(Block &NewBlock, Block &ExistingBlock) {
1113+
auto NewBlockEnd = NewBlock.getAddress() + NewBlock.getSize();
1114+
auto ExistingBlockEnd =
1115+
ExistingBlock.getAddress() + ExistingBlock.getSize();
1116+
return make_error<JITLinkError>(
1117+
"Block at " +
1118+
formatv("{0:x16} -- {1:x16}", NewBlock.getAddress(), NewBlockEnd) +
1119+
" overlaps " +
1120+
formatv("{0:x16} -- {1:x16}", ExistingBlock.getAddress(),
1121+
ExistingBlockEnd));
1122+
}
1123+
1124+
AddrToBlockMap AddrToBlock;
1125+
};
1126+
1127+
/// A map of addresses to Symbols.
1128+
class SymbolAddressMap {
1129+
public:
1130+
using SymbolVector = SmallVector<Symbol *, 1>;
1131+
1132+
/// Add a symbol to the SymbolAddressMap.
1133+
void addSymbol(Symbol &Sym) {
1134+
AddrToSymbols[Sym.getAddress()].push_back(&Sym);
1135+
}
1136+
1137+
/// Add all symbols in a given range to the SymbolAddressMap.
1138+
template <typename SymbolPtrCollection>
1139+
void addSymbols(SymbolPtrCollection &&Symbols) {
1140+
for (auto *Sym : Symbols)
1141+
addSymbol(*Sym);
1142+
}
1143+
1144+
/// Returns the list of symbols that start at the given address, or nullptr if
1145+
/// no such symbols exist.
1146+
const SymbolVector *getSymbolsAt(JITTargetAddress Addr) const {
1147+
auto I = AddrToSymbols.find(Addr);
1148+
if (I == AddrToSymbols.end())
1149+
return nullptr;
1150+
return &I->second;
1151+
}
1152+
1153+
private:
1154+
std::map<JITTargetAddress, SymbolVector> AddrToSymbols;
1155+
};
1156+
10221157
/// A function for mutating LinkGraphs.
10231158
using LinkGraphPassFunction = std::function<Error(LinkGraph &)>;
10241159

0 commit comments

Comments
 (0)