Adds utilities for creating anonymous pointers and jump stubs to x86_64.h. These
are used by the GOT and Stubs builder, but may also be used by pass writers who
want to create pointer stubs for indirection.
This patch also switches the underlying type for LinkGraph content from
StringRef to ArrayRef<char>. This avoids any confusion when working with buffers
that contain null bytes in the middle like, for example, a newly added null
pointer content array. ;)
}
/// Create a defined addressable for the given content.
- Block(Section &Parent, StringRef Content, JITTargetAddress Address,
+ Block(Section &Parent, ArrayRef<char> Content, JITTargetAddress Address,
uint64_t Alignment, uint64_t AlignmentOffset)
: Addressable(Address, true), Parent(Parent), Data(Content.data()),
Size(Content.size()) {
size_t getSize() const { return Size; }
/// Get the content for this block. Block must not be a zero-fill block.
- StringRef getContent() const {
+ ArrayRef<char> getContent() const {
assert(Data && "Section does not contain content");
- return StringRef(Data, Size);
+ return ArrayRef<char>(Data, Size);
}
/// Set the content for this block.
/// Caller is responsible for ensuring the underlying bytes are not
/// deallocated while pointed to by this block.
- void setContent(StringRef Content) {
+ void setContent(ArrayRef<char> Content) {
Data = Content.data();
Size = Content.size();
}
/// Returns the content in the underlying block covered by this symbol.
/// This method may only be called on defined non-zero-fill symbols.
- StringRef getSymbolContent() const {
- return getBlock().getContent().substr(Offset, Size);
+ ArrayRef<char> getSymbolContent() const {
+ return getBlock().getContent().slice(Offset, Size);
}
/// Get the linkage for this Symbol.
/// Allocate a copy of the given string using the LinkGraph's allocator.
/// This can be useful when renaming symbols or adding new content to the
/// graph.
- StringRef allocateString(StringRef Source) {
+ ArrayRef<char> allocateString(ArrayRef<char> Source) {
auto *AllocatedBuffer = Allocator.Allocate<char>(Source.size());
llvm::copy(Source, AllocatedBuffer);
- return StringRef(AllocatedBuffer, Source.size());
+ return ArrayRef<char>(AllocatedBuffer, Source.size());
}
/// Allocate a copy of the given string using the LinkGraph's allocator.
/// graph.
///
/// Note: This Twine-based overload requires an extra string copy and an
- /// extra heap allocation for large strings. The StringRef overload should
- /// be preferred where possible.
- StringRef allocateString(Twine Source) {
+ /// extra heap allocation for large strings. The ArrayRef<char> overload
+ /// should be preferred where possible.
+ ArrayRef<char> allocateString(Twine Source) {
SmallString<256> TmpBuffer;
auto SourceStr = Source.toStringRef(TmpBuffer);
auto *AllocatedBuffer = Allocator.Allocate<char>(SourceStr.size());
llvm::copy(SourceStr, AllocatedBuffer);
- return StringRef(AllocatedBuffer, SourceStr.size());
+ return ArrayRef<char>(AllocatedBuffer, SourceStr.size());
}
/// Create a section with the given name, protection flags, and alignment.
}
/// Create a content block.
- Block &createContentBlock(Section &Parent, StringRef Content,
+ Block &createContentBlock(Section &Parent, ArrayRef<char> Content,
uint64_t Address, uint64_t Alignment,
uint64_t AlignmentOffset) {
return createBlock(Parent, Content, Address, Alignment, AlignmentOffset);
return Error::success();
}
+/// x86-64 null pointer content.
+extern const char NullPointerContent[8];
+
+/// x86-64 pointer jump stub content.
+///
+/// Contains the instruction sequence for an indirect jump via an in-memory
+/// pointer:
+/// jmpq *ptr(%rip)
+extern const char PointerJumpStubContent[6];
+
+/// Creates a new pointer block in the given section and returns an anonymous
+/// symbol pointing to it.
+///
+/// If InitialTarget is given then an Pointer64 relocation will be added to the
+/// block pointing at InitialTarget.
+///
+/// The pointer block will have the following default values:
+/// alignment: 64-bit
+/// alignment-offset: 0
+/// address: highest allowable (~7U)
+inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
+ Symbol *InitialTarget = nullptr,
+ uint64_t InitialAddend = 0) {
+ auto &B =
+ G.createContentBlock(PointerSection, NullPointerContent, ~7ULL, 8, 0);
+ if (InitialTarget)
+ B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
+ return G.addAnonymousSymbol(B, 0, 8, false, false);
+}
+
+/// Create a jump stub that jumps via the pointer at the given symbol, returns
+/// an anonymous symbol pointing to it.
+///
+/// The stub block will have the following default values:
+/// alignment: 8-bit
+/// alignment-offset: 0
+/// address: highest allowable: (~5U)
+inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
+ Section &StubSection,
+ Symbol &PointerSymbol) {
+ auto &B =
+ G.createContentBlock(StubSection, PointerJumpStubContent, ~5ULL, 1, 0);
+ B.addEdge(Delta32, 2, PointerSymbol, -4);
+ return G.addAnonymousSymbol(B, 0, 6, true, false);
+}
+
} // namespace x86_64
} // end namespace jitlink
} // end namespace llvm
MemoryRegionInfo() = default;
/// Constructor for symbols/sections with content.
- MemoryRegionInfo(StringRef Content, JITTargetAddress TargetAddress)
+ MemoryRegionInfo(ArrayRef<char> Content, JITTargetAddress TargetAddress)
: ContentPtr(Content.data()), Size(Content.size()),
TargetAddress(TargetAddress) {}
}
/// Set the content for this memory region.
- void setContent(StringRef Content) {
+ void setContent(ArrayRef<char> Content) {
assert(!ContentPtr && !Size && "Content/zero-fill already set");
ContentPtr = Content.data();
Size = Content.size();
}
/// Returns the content for this section if there is any.
- StringRef getContent() const {
+ ArrayRef<char> getContent() const {
assert(!isZeroFill() && "Can't get content for a zero-fill section");
- return StringRef(ContentPtr, static_cast<size_t>(Size));
+ return {ContentPtr, static_cast<size_t>(Size)};
}
/// Returns the zero-fill length for this section.
return Error::success();
}
- BinaryStreamReader BlockReader(B.getContent(), G.getEndianness());
+ BinaryStreamReader BlockReader(
+ StringRef(B.getContent().data(), B.getContent().size()),
+ G.getEndianness());
while (true) {
uint64_t RecordStartOffset = BlockReader.getOffset();
}
CIEInfosMap CIEInfos;
- BinaryStreamReader BlockReader(B.getContent(), PC.G.getEndianness());
+ BinaryStreamReader BlockReader(
+ StringRef(B.getContent().data(), B.getContent().size()),
+ PC.G.getEndianness());
while (!BlockReader.empty()) {
size_t RecordStartOffset = BlockReader.getOffset();
LLVM_DEBUG(dbgs() << " Record is CIE\n");
- auto RecordContent = B.getContent().substr(RecordOffset, RecordLength);
- BinaryStreamReader RecordReader(RecordContent, PC.G.getEndianness());
+ auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
+ BinaryStreamReader RecordReader(
+ StringRef(RecordContent.data(), RecordContent.size()),
+ PC.G.getEndianness());
// Skip past the CIE delta field: we've already processed this far.
RecordReader.setOffset(CIEDeltaFieldOffset + 4);
JITTargetAddress RecordAddress = B.getAddress() + RecordOffset;
- auto RecordContent = B.getContent().substr(RecordOffset, RecordLength);
- BinaryStreamReader RecordReader(RecordContent, PC.G.getEndianness());
+ auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
+ BinaryStreamReader RecordReader(
+ StringRef(RecordContent.data(), RecordContent.size()),
+ PC.G.getEndianness());
// Skip past the CIE delta field: we've already read this far.
RecordReader.setOffset(CIEDeltaFieldOffset + 4);
return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
}
-char EHFrameNullTerminator::NullTerminatorBlockContent[] = {0, 0, 0, 0};
+char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)
: EHFrameSectionName(EHFrameSectionName) {}
<< EHFrameSectionName << "\n";
});
- auto &NullTerminatorBlock =
- G.createContentBlock(*EHFrame, StringRef(NullTerminatorBlockContent, 4),
- 0xfffffffffffffffc, 1, 0);
+ auto &NullTerminatorBlock = G.createContentBlock(
+ *EHFrame, NullTerminatorBlockContent, 0xfffffffffffffffc, 1, 0);
G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);
return Error::success();
}
return *StubsSection;
}
- StringRef getGOTEntryBlockContent() {
- return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent),
- sizeof(NullGOTEntryContent));
+ ArrayRef<char> getGOTEntryBlockContent() {
+ return {reinterpret_cast<const char *>(NullGOTEntryContent),
+ sizeof(NullGOTEntryContent)};
}
- StringRef getStubBlockContent() {
- return StringRef(reinterpret_cast<const char *>(StubContent),
- sizeof(StubContent));
+ ArrayRef<char> getStubBlockContent() {
+ return {reinterpret_cast<const char *>(StubContent), sizeof(StubContent)};
}
mutable Section *GOTSection = nullptr;
// for now everything is
auto §ion = G->createSection(*Name, Prot);
// Do this here because we have it, but move it into graphify later
- G->createContentBlock(section, StringRef(Data, Size), Address,
+ G->createContentBlock(section, ArrayRef<char>(Data, Size), Address,
Alignment, 0);
if (SecRef.sh_type == ELF::SHT_SYMTAB)
// TODO: Dynamic?
? createZeroFillBlock(B.getSection(), SplitIndex, B.getAddress(),
B.getAlignment(), B.getAlignmentOffset())
: createContentBlock(
- B.getSection(), B.getContent().substr(0, SplitIndex),
+ B.getSection(), B.getContent().slice(0, SplitIndex),
B.getAddress(), B.getAlignment(), B.getAlignmentOffset());
// Modify B to cover [ SplitIndex, B.size() ).
B.setAddress(B.getAddress() + SplitIndex);
- B.setContent(B.getContent().substr(SplitIndex));
+ B.setContent(B.getContent().slice(SplitIndex));
B.setAlignmentOffset((B.getAlignmentOffset() + SplitIndex) %
B.getAlignment());
memcpy(BlockDataPtr, B->getContent().data(), B->getContent().size());
// Point the block's content to the fixed up buffer.
- B->setContent(StringRef(BlockDataPtr, B->getContent().size()));
+ B->setContent({BlockDataPtr, B->getContent().size()});
// Update block end pointer.
LastBlockEnd = BlockDataPtr + B->getContent().size();
Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
sys::Memory::MF_WRITE);
- if (!isDebugSection(NSec))
+ if (!isDebugSection(NSec)) {
+ auto FullyQualifiedName =
+ G->allocateString(StringRef(NSec.SegName) + "," + NSec.SectName);
NSec.GraphSection = &G->createSection(
- G->allocateString(StringRef(NSec.SegName) + "," + NSec.SectName),
+ StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()),
Prot);
- else
+ } else
LLVM_DEBUG({
dbgs() << " " << NSec.SegName << "," << NSec.SectName
<< " is a debug section: No graph section will be created.\n";
Section &GraphSec, uint64_t Address, const char *Data, uint64_t Size,
uint32_t Alignment, bool IsLive) {
Block &B =
- Data ? G->createContentBlock(GraphSec, StringRef(Data, Size), Address,
- Alignment, 0)
+ Data ? G->createContentBlock(GraphSec, ArrayRef<char>(Data, Size),
+ Address, Alignment, 0)
: G->createZeroFillBlock(GraphSec, Size, Address, Alignment, 0);
auto &Sym = G->addAnonymousSymbol(B, 0, Size, false, IsLive);
assert(!AddrToCanonicalSymbol.count(Sym.getAddress()) &&
NSec.Data
? G->createContentBlock(
*NSec.GraphSection,
- StringRef(NSec.Data + BlockOffset, BlockSize), BlockStart,
- NSec.Alignment, BlockStart % NSec.Alignment)
+ ArrayRef<char>(NSec.Data + BlockOffset, BlockSize),
+ BlockStart, NSec.Alignment, BlockStart % NSec.Alignment)
: G->createZeroFillBlock(*NSec.GraphSection, BlockSize,
BlockStart, NSec.Alignment,
BlockStart % NSec.Alignment);
return *StubsSection;
}
- StringRef getGOTEntryBlockContent() {
- return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent),
- sizeof(NullGOTEntryContent));
+ ArrayRef<char> getGOTEntryBlockContent() {
+ return {reinterpret_cast<const char *>(NullGOTEntryContent),
+ sizeof(NullGOTEntryContent)};
}
- StringRef getStubBlockContent() {
- return StringRef(reinterpret_cast<const char *>(StubContent),
- sizeof(StubContent));
+ ArrayRef<char> getStubBlockContent() {
+ return {reinterpret_cast<const char *>(StubContent), sizeof(StubContent)};
}
static const uint8_t NullGOTEntryContent[8];
: public PerGraphGOTAndPLTStubsBuilder<
PerGraphGOTAndPLTStubsBuilder_MachO_x86_64> {
public:
- static const uint8_t NullGOTEntryContent[8];
- static const uint8_t StubContent[6];
using PerGraphGOTAndPLTStubsBuilder<
PerGraphGOTAndPLTStubsBuilder_MachO_x86_64>::
}
Symbol &createGOTEntry(Symbol &Target) {
- auto &GOTEntryBlock = G.createContentBlock(
- getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0);
- GOTEntryBlock.addEdge(x86_64::Pointer64, 0, Target, 0);
- return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
+ return x86_64::createAnonymousPointer(G, getGOTSection(), &Target);
}
void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
}
Symbol &createPLTStub(Symbol &Target) {
- auto &StubContentBlock =
- G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
- // Re-use GOT entries for stub targets.
- auto &GOTEntrySymbol = getGOTEntry(Target);
- StubContentBlock.addEdge(x86_64::Delta32, 2, GOTEntrySymbol, -4);
- return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false);
+ return x86_64::createAnonymousPointerJumpStub(G, getStubsSection(),
+ getGOTEntry(Target));
}
void fixPLTEdge(Edge &E, Symbol &Stub) {
return *StubsSection;
}
- StringRef getGOTEntryBlockContent() {
- return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent),
- sizeof(NullGOTEntryContent));
- }
-
- StringRef getStubBlockContent() {
- return StringRef(reinterpret_cast<const char *>(StubContent),
- sizeof(StubContent));
- }
-
Section *GOTSection = nullptr;
Section *StubsSection = nullptr;
};
-const uint8_t
- PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::NullGOTEntryContent[8] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::StubContent[6] = {
- 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
} // namespace
static Error optimizeMachO_x86_64_GOTAndStubs(LinkGraph &G) {
}
} else if (E.getKind() == x86_64::BranchPCRel32ToPtrJumpStubRelaxable) {
auto &StubBlock = E.getTarget().getBlock();
- assert(
- StubBlock.getSize() ==
- sizeof(
- PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::StubContent) &&
- "Stub block should be stub sized");
+ assert(StubBlock.getSize() == sizeof(x86_64::PointerJumpStubContent) &&
+ "Stub block should be stub sized");
assert(StubBlock.edges_size() == 1 &&
"Stub block should only have one outgoing edge");
}
}
+const char NullPointerContent[8] = {0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+const char PointerJumpStubContent[6] = {
+ static_cast<char>(0xFF), 0x25, 0x00, 0x00, 0x00, 0x00};
+
} // end namespace x86_64
} // end namespace jitlink
} // end namespace llvm
logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
return StringRef();
}
- return SymInfo->getContent();
+ return {SymInfo->getContent().data(), SymInfo->getContent().size()};
}
std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr};
else
FileInfo.SectionInfos[Sec.getName()] = {
- StringRef(FirstSym->getBlock().getContent().data(), SecSize),
+ ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
SecAddr};
}
FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr};
else
FileInfo.SectionInfos[Sec.getName()] = {
- StringRef(FirstSym->getBlock().getContent().data(), SecSize),
+ ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
SecAddr};
}
JITTargetAddress SymStart = Sym->getAddress();
JITTargetAddress SymSize = Sym->getSize();
JITTargetAddress SymEnd = SymStart + SymSize;
- const uint8_t *SymData =
- IsZeroFill ? nullptr : Sym->getSymbolContent().bytes_begin();
+ const uint8_t *SymData = IsZeroFill ? nullptr
+ : reinterpret_cast<const uint8_t *>(
+ Sym->getSymbolContent().data());
// Pad any space before the symbol starts.
while (NextAddr != SymStart) {
return Err;
// Register the absolute symbol with the session symbol infos.
- S.SymbolInfos[Name] = { StringRef(), Addr };
+ S.SymbolInfos[Name] = {ArrayRef<char>(), Addr};
}
LLVM_DEBUG({
char *CSymAddr = static_cast<char *>(SymAddr);
StringRef SecContent = Dyld.getSectionContent(SectionID);
uint64_t SymSize = SecContent.size() - (CSymAddr - SecContent.data());
- SymInfo.setContent(StringRef(CSymAddr, SymSize));
+ SymInfo.setContent(ArrayRef<char>(CSymAddr, SymSize));
}
}
return SymInfo;
return SectionID.takeError();
RuntimeDyldChecker::MemoryRegionInfo SecInfo;
SecInfo.setTargetAddress(Dyld.getSectionLoadAddress(*SectionID));
- SecInfo.setContent(Dyld.getSectionContent(*SectionID));
+ StringRef SecContent = Dyld.getSectionContent(*SectionID);
+ SecInfo.setContent(ArrayRef<char>(SecContent.data(), SecContent.size()));
return SecInfo;
};
RuntimeDyldChecker::MemoryRegionInfo StubMemInfo;
StubMemInfo.setTargetAddress(Dyld.getSectionLoadAddress(SI.SectionID) +
SI.Offset);
+ StringRef SecContent =
+ Dyld.getSectionContent(SI.SectionID).substr(SI.Offset);
StubMemInfo.setContent(
- Dyld.getSectionContent(SI.SectionID).substr(SI.Offset));
+ ArrayRef<char>(SecContent.data(), SecContent.size()));
return StubMemInfo;
};
static const char BlockContentBytes[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
0x1C, 0x1D, 0x1E, 0x1F, 0x00};
-static StringRef BlockContent(BlockContentBytes);
+ArrayRef<char> BlockContent(BlockContentBytes);
TEST(LinkGraphTest, Construction) {
// Check that LinkGraph construction works as expected.
// Check that the block addresses and content matches what we would expect.
EXPECT_EQ(B1.getAddress(), 0x1008U);
- EXPECT_EQ(B1.getContent(), BlockContent.substr(8));
+ EXPECT_EQ(B1.getContent(), BlockContent.slice(8));
EXPECT_EQ(B2.getAddress(), 0x1000U);
- EXPECT_EQ(B2.getContent(), BlockContent.substr(0, 8));
+ EXPECT_EQ(B2.getContent(), BlockContent.slice(0, 8));
// Check that symbols in B1 were transferred as expected:
// We expect S1 and S2 to have been transferred to B2, and S3 and S4 to have