[BOLT] Fix relocation verification

Summary:
We verify that relocation information matches a value stored in a
binary, i.e. "ExtractedValue == SymbolValue + Addend". However, because
of the size of the relocation, and the fact that an addend is always
of type int64_t, we have to sign-extend the extracted value, and then we
might get mismatch in higher bits in certain scenarios. Hence, we should
only compare values that are truncated to a relocation size.

Discovered while processing hhvm binary with modified compiler flags.

(cherry picked from FBD7462559)
This commit is contained in:
Maksim Panchenko 2018-03-30 15:49:34 -07:00
parent 77f35bd0e9
commit 0d729f218b
1 changed files with 42 additions and 44 deletions

View File

@ -463,6 +463,10 @@ MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
} }
} }
int64_t truncateToSize(int64_t Value, unsigned Bytes) {
return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
}
} }
constexpr const char *RewriteInstance::SectionsToOverwrite[]; constexpr const char *RewriteInstance::SectionsToOverwrite[];
@ -1760,7 +1764,7 @@ void RewriteInstance::readSpecialSections() {
EHFrame = BC->DwCtx->getEHFrame(); EHFrame = BC->DwCtx->getEHFrame();
if (opts::DumpEHFrame) { if (opts::DumpEHFrame) {
outs() << "BOLT-INFO: Dumping original binary .eh_frame\n"; outs() << "BOLT-INFO: Dumping original binary .eh_frame\n";
EHFrame->dump(outs(), NoneType()); EHFrame->dump(outs(), &*BC->MRI, NoneType());
} }
CFIRdWrt.reset(new CFIReaderWriter(*EHFrame)); CFIRdWrt.reset(new CFIReaderWriter(*EHFrame));
} }
@ -1904,7 +1908,9 @@ bool RewriteInstance::analyzeRelocation(const RelocationRef &Rel,
<< "; address = 0x" << Twine::utohexstr(SymbolAddress + Addend) << "; address = 0x" << Twine::utohexstr(SymbolAddress + Addend)
<< '\n'; << '\n';
} }
assert(ExtractedValue == SymbolAddress + Addend && "value mismatch"); assert(truncateToSize(ExtractedValue, RelSize) ==
truncateToSize(SymbolAddress + Addend, RelSize) &&
"value mismatch");
} }
} }
@ -1912,7 +1918,8 @@ bool RewriteInstance::analyzeRelocation(const RelocationRef &Rel,
if (!Relocation::isTLS(Rel.getType()) && if (!Relocation::isTLS(Rel.getType()) &&
SymbolName != "__hot_start" && SymbolName != "__hot_start" &&
SymbolName != "__hot_end" && SymbolName != "__hot_end" &&
ExtractedValue != SymbolAddress + Addend - PCRelOffset) { truncateToSize(ExtractedValue, RelSize) !=
truncateToSize(SymbolAddress + Addend - PCRelOffset, RelSize)) {
auto Section = Symbol.getSection(); auto Section = Symbol.getSection();
SmallString<16> TypeName; SmallString<16> TypeName;
Rel.getTypeName(TypeName); Rel.getTypeName(TypeName);
@ -1939,7 +1946,8 @@ bool RewriteInstance::analyzeRelocation(const RelocationRef &Rel,
Relocation::isTLS(Rel.getType()) || Relocation::isTLS(Rel.getType()) ||
SymbolName == "__hot_start" || SymbolName == "__hot_start" ||
SymbolName == "__hot_end" || SymbolName == "__hot_end" ||
ExtractedValue == SymbolAddress + Addend - PCRelOffset) && truncateToSize(ExtractedValue, RelSize) ==
truncateToSize(SymbolAddress + Addend - PCRelOffset, RelSize)) &&
"extracted relocation value should match relocation components"); "extracted relocation value should match relocation components");
return true; return true;
@ -2718,51 +2726,48 @@ void RewriteInstance::emitFunctions() {
object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()), object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()),
"error creating in-memory object"); "error creating in-memory object");
auto Resolver = orc::createLambdaResolver( auto Resolver = orc::createLegacyLookupResolver(
[&](const std::string &Name) -> JITSymbol { [&](const std::string &Name) -> JITSymbol {
DEBUG(dbgs() << "BOLT: looking for " << Name << "\n"); DEBUG(dbgs() << "BOLT: looking for " << Name << "\n");
if (auto *I = BC->getBinaryDataByName(Name)) if (auto *I = BC->getBinaryDataByName(Name))
return JITSymbol(I->getAddress(), JITSymbolFlags()); return JITSymbol(I->getAddress(), JITSymbolFlags());
return JITSymbol(nullptr); return JITSymbol(nullptr);
}, },
[](const std::string &S) { [](Error Err) { cantFail(std::move(Err), "lookup failed"); });
DEBUG(dbgs() << "BOLT: resolving " << S << "\n");
return nullptr;
}
);
Resolver->setAllowsZeroSymbols(true); Resolver->setAllowsZeroSymbols(true);
MCAsmLayout FinalLayout( MCAsmLayout FinalLayout(
static_cast<MCObjectStreamer *>(Streamer.get())->getAssembler()); static_cast<MCObjectStreamer *>(Streamer.get())->getAssembler());
SSP.reset(new decltype(SSP)::element_type());
ES.reset(new decltype(ES)::element_type(*SSP));
OLT.reset(new decltype(OLT)::element_type( OLT.reset(new decltype(OLT)::element_type(
[this]() { *ES,
[this, &Resolver](orc::VModuleKey Key) {
orc::RTDyldObjectLinkingLayer::Resources R;
R.MemMgr = EFMM;
R.Resolver = Resolver;
// Get memory manager // Get memory manager
return EFMM; return R;
}, },
// Loaded notifier // Loaded notifier
[&](orc::RTDyldObjectLinkingLayerBase::ObjHandleT Handle, [&](orc::VModuleKey Key, const object::ObjectFile &Obj,
const orc::RTDyldObjectLinkingLayer::ObjectPtr &Obj,
const RuntimeDyld::LoadedObjectInfo &) { const RuntimeDyld::LoadedObjectInfo &) {
// Assign addresses to all sections. // Assign addresses to all sections.
mapFileSections(Handle); mapFileSections(Key);
}, },
// Finalized notifier // Finalized notifier
[&](orc::RTDyldObjectLinkingLayerBase::ObjHandleT Handle) { [&](orc::VModuleKey Key) {
// Update output addresses based on the new section map and // Update output addresses based on the new section map and
// layout. // layout.
updateOutputValues(FinalLayout); updateOutputValues(FinalLayout);
})); }));
OLT->setProcessAllSections(true); OLT->setProcessAllSections(true);
auto ObjectsHandle = cantFail( auto K = ES->allocateVModule();
OLT->addObject(std::unique_ptr<OwningBinary<object::ObjectFile>>( cantFail(OLT->addObject(K, std::move(ObjectMemBuffer)));
new OwningBinary<object::ObjectFile>(
std::move(Obj), std::move(ObjectMemBuffer))),
std::move(Resolver)),
"failed in addObject()");
cantFail(OLT->emitAndFinalize(ObjectsHandle)); cantFail(OLT->emitAndFinalize(K));
if (opts::PrintCacheMetrics) { if (opts::PrintCacheMetrics) {
outs() << "BOLT-INFO: cache metrics after emitting functions:\n"; outs() << "BOLT-INFO: cache metrics after emitting functions:\n";
@ -2773,8 +2778,7 @@ void RewriteInstance::emitFunctions() {
TempOut->keep(); TempOut->keep();
} }
void RewriteInstance::mapFileSections( void RewriteInstance::mapFileSections(orc::VModuleKey Key) {
orc::RTDyldObjectLinkingLayer::ObjHandleT &ObjectsHandle) {
NewTextSectionStartAddress = NextAvailableAddress; NewTextSectionStartAddress = NextAvailableAddress;
if (BC->HasRelocations) { if (BC->HasRelocations) {
auto TextSection = BC->getUniqueSectionByName(".text"); auto TextSection = BC->getUniqueSectionByName(".text");
@ -2812,8 +2816,7 @@ void RewriteInstance::mapFileSections(
<< Twine::utohexstr(TextSection->getAllocAddress()) << Twine::utohexstr(TextSection->getAllocAddress())
<< " to 0x" << Twine::utohexstr(NewTextSectionStartAddress) << " to 0x" << Twine::utohexstr(NewTextSectionStartAddress)
<< '\n'); << '\n');
OLT->mapSectionAddress(ObjectsHandle, OLT->mapSectionAddress(Key, TextSection->getSectionID(),
TextSection->getSectionID(),
NewTextSectionStartAddress); NewTextSectionStartAddress);
} else { } else {
for (auto &BFI : BinaryFunctions) { for (auto &BFI : BinaryFunctions) {
@ -2828,8 +2831,7 @@ void RewriteInstance::mapFileSections(
<< Twine::utohexstr(FuncSection->getAllocAddress()) << Twine::utohexstr(FuncSection->getAllocAddress())
<< " to 0x" << Twine::utohexstr(Function.getAddress()) << " to 0x" << Twine::utohexstr(Function.getAddress())
<< '\n'); << '\n');
OLT->mapSectionAddress(ObjectsHandle, OLT->mapSectionAddress(Key, FuncSection->getSectionID(),
FuncSection->getSectionID(),
Function.getAddress()); Function.getAddress());
Function.setImageAddress(FuncSection->getAllocAddress()); Function.setImageAddress(FuncSection->getAllocAddress());
Function.setImageSize(FuncSection->getOutputSize()); Function.setImageSize(FuncSection->getOutputSize());
@ -2849,7 +2851,7 @@ void RewriteInstance::mapFileSections(
DEBUG(dbgs() << "BOLT-DEBUG: mapping " << Section->getName() DEBUG(dbgs() << "BOLT-DEBUG: mapping " << Section->getName()
<< " to 0x" << Twine::utohexstr(JT->getAddress()) << " to 0x" << Twine::utohexstr(JT->getAddress())
<< '\n'); << '\n');
OLT->mapSectionAddress(ObjectsHandle, Section->getSectionID(), OLT->mapSectionAddress(Key, Section->getSectionID(),
JT->getAddress()); JT->getAddress());
} }
} }
@ -2882,8 +2884,7 @@ void RewriteInstance::mapFileSections(
<< Twine::utohexstr(ColdPart.getAddress()) << Twine::utohexstr(ColdPart.getAddress())
<< " with size " << " with size "
<< Twine::utohexstr(ColdPart.getImageSize()) << '\n'); << Twine::utohexstr(ColdPart.getImageSize()) << '\n');
OLT->mapSectionAddress(ObjectsHandle, OLT->mapSectionAddress(Key, ColdSection->getSectionID(),
ColdSection->getSectionID(),
ColdPart.getAddress()); ColdPart.getAddress());
NextAvailableAddress += ColdPart.getImageSize(); NextAvailableAddress += ColdPart.getImageSize();
@ -2927,9 +2928,7 @@ void RewriteInstance::mapFileSections(
<< ") to 0x" << Twine::utohexstr(NextAvailableAddress) << ") to 0x" << Twine::utohexstr(NextAvailableAddress)
<< '\n'); << '\n');
OLT->mapSectionAddress(ObjectsHandle, OLT->mapSectionAddress(Key, Section->getSectionID(), NextAvailableAddress);
Section->getSectionID(),
NextAvailableAddress);
Section->setFileAddress(NextAvailableAddress); Section->setFileAddress(NextAvailableAddress);
Section->setFileOffset(getFileOffsetForAddress(NextAvailableAddress)); Section->setFileOffset(getFileOffsetForAddress(NextAvailableAddress));
@ -2960,8 +2959,7 @@ void RewriteInstance::mapFileSections(
<< ") to 0x" << Twine::utohexstr(Section.getAddress()) << ") to 0x" << Twine::utohexstr(Section.getAddress())
<< '\n'); << '\n');
OLT->mapSectionAddress(ObjectsHandle, OLT->mapSectionAddress(Key, OrgSection->getSectionID(),
OrgSection->getSectionID(),
Section.getAddress()); Section.getAddress());
OrgSection->setFileAddress(Section.getAddress()); OrgSection->setFileAddress(Section.getAddress());
@ -4240,7 +4238,7 @@ void RewriteInstance::rewriteFile() {
auto DwCtx = DWARFContext::create(*E); auto DwCtx = DWARFContext::create(*E);
const auto &EHFrame = DwCtx->getEHFrame(); const auto &EHFrame = DwCtx->getEHFrame();
outs() << "BOLT-INFO: Dumping rewritten .eh_frame\n"; outs() << "BOLT-INFO: Dumping rewritten .eh_frame\n";
EHFrame->dump(outs(), NoneType()); EHFrame->dump(outs(), &*BC->MRI, NoneType());
} }
} }
} }