1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[JITLink] Switch from StringRef to ArrayRef<char>, add some generic x86-64 utils

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. ;)
This commit is contained in:
Lang Hames 2021-03-30 20:56:03 -07:00
parent 47152cc5ef
commit 49d6de165d
17 changed files with 130 additions and 94 deletions

View File

@ -158,7 +158,7 @@ private:
}
/// 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()) {
@ -194,15 +194,15 @@ public:
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();
}
@ -500,8 +500,8 @@ public:
/// 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.
@ -849,10 +849,10 @@ public:
/// 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.
@ -860,14 +860,14 @@ public:
/// 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.
@ -883,7 +883,7 @@ public:
}
/// 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);

View File

@ -336,6 +336,52 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
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

View File

@ -78,7 +78,7 @@ public:
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) {}
@ -93,7 +93,7 @@ public:
}
/// 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();
@ -106,9 +106,9 @@ public:
}
/// 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.

View File

@ -81,7 +81,9 @@ Error EHFrameSplitter::processBlock(LinkGraph &G, Block &B,
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();
@ -203,7 +205,9 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
}
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();
@ -267,8 +271,10 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
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);
@ -397,8 +403,10 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
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);
@ -730,7 +738,7 @@ Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
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) {}
@ -746,9 +754,8 @@ Error EHFrameNullTerminator::operator()(LinkGraph &G) {
<< 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();
}

View File

@ -125,14 +125,13 @@ private:
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;
@ -406,7 +405,7 @@ private:
// for now everything is
auto &section = 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?

View File

@ -193,12 +193,12 @@ Block &LinkGraph::splitBlock(Block &B, size_t SplitIndex,
? 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());

View File

@ -404,7 +404,7 @@ void JITLinkerBase::copyBlockContentToWorkingMemory(
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();

View File

@ -178,11 +178,13 @@ Error MachOLinkGraphBuilder::createNormalizedSections() {
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";
@ -316,8 +318,8 @@ void MachOLinkGraphBuilder::addSectionStartSymAndBlock(
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()) &&
@ -508,8 +510,8 @@ Error MachOLinkGraphBuilder::graphifyRegularSymbols() {
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);

View File

@ -471,14 +471,13 @@ private:
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];

View File

@ -416,8 +416,6 @@ class PerGraphGOTAndPLTStubsBuilder_MachO_x86_64
: 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>::
@ -430,10 +428,7 @@ public:
}
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) {
@ -457,12 +452,8 @@ public:
}
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) {
@ -493,25 +484,10 @@ private:
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) {
@ -557,10 +533,7 @@ 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) &&
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");

View File

@ -53,6 +53,12 @@ const char *getEdgeKindName(Edge::Kind K) {
}
}
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

View File

@ -796,7 +796,7 @@ StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const {
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(

View File

@ -164,7 +164,7 @@ Error registerELFGraphInfo(Session &S, LinkGraph &G) {
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};
}

View File

@ -159,7 +159,7 @@ Error registerMachOGraphInfo(Session &S, LinkGraph &G) {
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};
}

View File

@ -301,8 +301,9 @@ static void dumpSectionContents(raw_ostream &OS, LinkGraph &G) {
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) {
@ -1214,7 +1215,7 @@ static Error loadObjects(Session &S) {
return Err;
// Register the absolute symbol with the session symbol infos.
S.SymbolInfos[Name] = { StringRef(), Addr };
S.SymbolInfos[Name] = {ArrayRef<char>(), Addr};
}
LLVM_DEBUG({

View File

@ -840,7 +840,7 @@ static int linkAndVerify() {
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;
@ -867,7 +867,8 @@ static int linkAndVerify() {
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;
};
@ -886,8 +887,10 @@ static int linkAndVerify() {
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;
};

View File

@ -21,7 +21,7 @@ static auto RWFlags =
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.
@ -232,10 +232,10 @@ TEST(LinkGraphTest, SplitBlock) {
// 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