Skip to content

Commit

Permalink
[BOLT] Support relocations without symbols
Browse files Browse the repository at this point in the history
Summary:
lld may generate relocations without associated symbols. Instead of
rejecting binaries with such relocations, we can re-create the symbol
the relocation is against based on the extracted value.

(cherry picked from FBD10054576)
  • Loading branch information
maksfb committed Sep 21, 2018
1 parent bd0b99c commit ce508b5
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 76 deletions.
4 changes: 2 additions & 2 deletions bolt/src/BinaryContext.cpp
Expand Up @@ -228,9 +228,9 @@ BinaryContext::getSubBinaryData(BinaryData *BD) {
}

MCSymbol *BinaryContext::getOrCreateGlobalSymbol(uint64_t Address,
Twine Prefix,
uint64_t Size,
uint16_t Alignment,
Twine Prefix,
unsigned Flags) {
auto Itr = BinaryDataMap.find(Address);
if (Itr != BinaryDataMap.end()) {
Expand Down Expand Up @@ -536,7 +536,7 @@ void BinaryContext::fixBinaryDataHoles() {
if (BD->getSection() == Section)
setBinaryDataSize(Hole.first, Hole.second);
} else {
getOrCreateGlobalSymbol(Hole.first, Hole.second, 1, "HOLEat");
getOrCreateGlobalSymbol(Hole.first, "HOLEat", Hole.second, 1);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions bolt/src/BinaryContext.h
Expand Up @@ -386,9 +386,9 @@ class BinaryContext {
/// If there are multiple symbols registered at the \p Address, then
/// return the first one.
MCSymbol *getOrCreateGlobalSymbol(uint64_t Address,
uint64_t Size,
uint16_t Alignment,
Twine Prefix,
uint64_t Size = 0,
uint16_t Alignment = 0,
unsigned Flags = 0);

/// Register a symbol with \p Name at a given \p Address and \p Size.
Expand Down
4 changes: 2 additions & 2 deletions bolt/src/BinaryFunction.cpp
Expand Up @@ -1046,7 +1046,7 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
}
// TODO: use DWARF info to get size/alignment here?
auto *TargetSymbol =
BC.getOrCreateGlobalSymbol(TargetAddress, 0, 0, "DATAat");
BC.getOrCreateGlobalSymbol(TargetAddress, "DATAat");
DEBUG(if (opts::Verbosity >= 2) {
auto SectionName = BD ? BD->getSectionName() : "<unknown>";
dbgs() << "Created DATAat sym: " << TargetSymbol->getName()
Expand Down Expand Up @@ -1301,7 +1301,7 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
}

TargetSymbol =
BC.getOrCreateGlobalSymbol(TargetAddress, 0, 0, "FUNCat");
BC.getOrCreateGlobalSymbol(TargetAddress, "FUNCat");
if (TargetAddress == 0) {
// We actually see calls to address 0 in presence of weak
// symbols originating from libraries. This code is never meant
Expand Down
4 changes: 2 additions & 2 deletions bolt/src/BinaryFunction.h
Expand Up @@ -1608,7 +1608,7 @@ class BinaryFunction {

BinaryFunction &setPersonalityFunction(uint64_t Addr) {
assert(!PersonalityFunction && "can't set personality function twice");
PersonalityFunction = BC.getOrCreateGlobalSymbol(Addr, 0, 0, "FUNCat");
PersonalityFunction = BC.getOrCreateGlobalSymbol(Addr, "FUNCat");
return *this;
}

Expand Down Expand Up @@ -1762,7 +1762,7 @@ class BinaryFunction {
return nullptr;

// Register our island at global namespace
Symbol = BC.getOrCreateGlobalSymbol(Address, 0, 0, "ISLANDat");
Symbol = BC.getOrCreateGlobalSymbol(Address, "ISLANDat");
// Internal bookkeeping
const auto Offset = Address - getAddress();
assert((!IslandOffsets.count(Offset) || IslandOffsets[Offset] == Symbol) &&
Expand Down
4 changes: 2 additions & 2 deletions bolt/src/Exceptions.cpp
Expand Up @@ -637,9 +637,9 @@ void BinaryFunction::emitLSDA(MCStreamer *Streamer, bool EmitColdPart) {
if (TypeAddress) {
const auto *TypeSymbol =
BC.getOrCreateGlobalSymbol(TypeAddress,
"TI",
TTypeEncodingSize,
TTypeAlignment,
"TI");
TTypeAlignment);
auto *DotSymbol = BC.Ctx->createTempSymbol();
Streamer->EmitLabel(DotSymbol);
const auto *SubDotExpr = MCBinaryExpr::createSub(
Expand Down
133 changes: 67 additions & 66 deletions bolt/src/RewriteInstance.cpp
Expand Up @@ -1695,7 +1695,7 @@ void RewriteInstance::relocateEHFrameSection() {
if (!Symbol) {
DEBUG(dbgs() << "BOLT-DEBUG: creating symbol for DWARF reference at 0x"
<< Twine::utohexstr(Value) << '\n');
Symbol = BC->getOrCreateGlobalSymbol(Value, 0, 0, "FUNCat");
Symbol = BC->getOrCreateGlobalSymbol(Value, "FUNCat");
}

DEBUG(dbgs() << "BOLT-DEBUG: adding DWARF reference against symbol "
Expand Down Expand Up @@ -1806,8 +1806,7 @@ void RewriteInstance::readSpecialSections() {
}

void RewriteInstance::adjustCommandLineOptions() {
if (BC->isAArch64() && opts::RelocationMode != cl::BOU_TRUE &&
!opts::AggregateOnly) {
if (BC->isAArch64() && !BC->HasRelocations) {
errs() << "BOLT-WARNING: non-relocation mode for AArch64 is not fully "
"supported\n";
}
Expand Down Expand Up @@ -1874,6 +1873,7 @@ int64_t getRelocationAddend(const ELFObjectFileBase *Obj,
bool RewriteInstance::analyzeRelocation(const RelocationRef &Rel,
SectionRef RelocatedSection,
std::string &SymbolName,
bool &IsSectionRelocation,
uint64_t &SymbolAddress,
int64_t &Addend,
uint64_t &ExtractedValue) const {
Expand All @@ -1882,45 +1882,68 @@ bool RewriteInstance::analyzeRelocation(const RelocationRef &Rel,

const bool IsAArch64 = BC->isAArch64();

// For value extraction.
// Extract the value.
StringRef RelocatedSectionContents;
RelocatedSection.getContents(RelocatedSectionContents);
DataExtractor DE(RelocatedSectionContents,
BC->AsmInfo->isLittleEndian(),
BC->AsmInfo->getCodePointerSize());

const bool IsPCRelative = Relocation::isPCRelative(Rel.getType());
auto SymbolIter = Rel.getSymbol();
assert(SymbolIter != InputFile->symbol_end() &&
"relocation symbol must exist");
const auto &Symbol = *SymbolIter;
SymbolName = cantFail(Symbol.getName());
SymbolAddress = cantFail(Symbol.getAddress());
Addend = getRelocationAddend(InputFile, Rel);

uint32_t RelocationOffset =
Rel.getOffset() - RelocatedSection.getAddress();
uint32_t RelocationOffset = Rel.getOffset() - RelocatedSection.getAddress();
const auto RelSize = Relocation::getSizeForType(Rel.getType());
ExtractedValue =
static_cast<uint64_t>(DE.getSigned(&RelocationOffset, RelSize));

ExtractedValue = static_cast<uint64_t>(DE.getSigned(&RelocationOffset,
RelSize));
if (IsAArch64) {
ExtractedValue = Relocation::extractValue(Rel.getType(),
ExtractedValue,
Rel.getOffset());
}

// Section symbols are marked as ST_Debug.
const bool SymbolIsSection =
(cantFail(Symbol.getType()) == SymbolRef::ST_Debug);
Addend = getRelocationAddend(InputFile, Rel);

const bool IsPCRelative = Relocation::isPCRelative(Rel.getType());
const auto PCRelOffset = IsPCRelative && !IsAArch64 ? Rel.getOffset() : 0;
bool SkipVerification = false;
auto SymbolIter = Rel.getSymbol();
if (SymbolIter == InputFile->symbol_end()) {
SymbolAddress = ExtractedValue - Addend;
if (IsPCRelative)
SymbolAddress += PCRelOffset;
auto *RelSymbol = BC->getOrCreateGlobalSymbol(SymbolAddress, "RELSYMat");
SymbolName = RelSymbol->getName();
IsSectionRelocation = false;
} else {
const auto &Symbol = *SymbolIter;
SymbolName = cantFail(Symbol.getName());
SymbolAddress = cantFail(Symbol.getAddress());
SkipVerification = (cantFail(Symbol.getType()) == SymbolRef::ST_Other);
// Section symbols are marked as ST_Debug.
IsSectionRelocation = (cantFail(Symbol.getType()) == SymbolRef::ST_Debug);
if (IsSectionRelocation) {
auto Section = Symbol.getSection();
if (Section && *Section != InputFile->section_end()) {
SymbolName = "section " + std::string(getSectionName(**Section));
if (!IsAArch64) {
assert(SymbolAddress == (*Section)->getAddress() &&
"section symbol address must be the same as section address");
// Convert section symbol relocations to regular relocations inside
// non-section symbols.
if (IsPCRelative) {
Addend = ExtractedValue - (SymbolAddress - PCRelOffset);
} else {
SymbolAddress = ExtractedValue;
Addend = 0;
}
}
}
}
}

// If no symbol has been found or if it is a relocation requiring the
// creation of a GOT entry, do not link against the symbol but against
// whatever address was extracted from the instruction itself. We are
// not creating a GOT entry as this was already processed by the linker.
if (!SymbolAddress || Relocation::isGOT(Rel.getType())) {
assert(!SymbolIsSection);
assert(!IsSectionRelocation);
if (ExtractedValue) {
SymbolAddress = ExtractedValue - Addend + PCRelOffset;
} else {
Expand All @@ -1935,26 +1958,12 @@ bool RewriteInstance::analyzeRelocation(const RelocationRef &Rel,
SymbolAddress += PCRelOffset;
return true;
}
} else if (SymbolIsSection) {
auto Section = Symbol.getSection();
if (Section && *Section != InputFile->section_end()) {
SymbolName = "section " + std::string(getSectionName(**Section));
if (!IsAArch64) {
assert(SymbolAddress == (*Section)->getAddress() &&
"section symbol address must be the same as section address");
// Convert section symbol relocations to regular relocations inside
// non-section symbols.
if (IsPCRelative) {
Addend = ExtractedValue - (SymbolAddress - PCRelOffset);
} else {
SymbolAddress = ExtractedValue;
Addend = 0;
}
}
}
}

auto verifyExtractedValue = [&]() {
if (SkipVerification)
return true;

if (IsAArch64)
return true;

Expand All @@ -1964,9 +1973,6 @@ bool RewriteInstance::analyzeRelocation(const RelocationRef &Rel,
if (Relocation::isTLS(Rel.getType()))
return true;

if (cantFail(Symbol.getType()) == SymbolRef::ST_Other)
return true;

return truncateToSize(ExtractedValue, RelSize) ==
truncateToSize(SymbolAddress + Addend - PCRelOffset, RelSize);
};
Expand All @@ -1981,7 +1987,7 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
Section.getName(SectionName);
DEBUG(dbgs() << "BOLT-DEBUG: relocations for section "
<< SectionName << ":\n");
if (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC) {
if (BinarySection(*BC, Section).isAllocatable()) {
DEBUG(dbgs() << "BOLT-DEBUG: ignoring runtime relocations\n");
return;
}
Expand All @@ -1994,7 +2000,7 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
DEBUG(dbgs() << "BOLT-DEBUG: relocated section is "
<< RelocatedSectionName << '\n');

if (!(ELFSectionRef(RelocatedSection).getFlags() & ELF::SHF_ALLOC)) {
if (!BinarySection(*BC, RelocatedSection).isAllocatable()) {
DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocations against "
<< "non-allocatable section\n");
return;
Expand Down Expand Up @@ -2046,17 +2052,18 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
uint64_t SymbolAddress;
int64_t Addend;
uint64_t ExtractedValue;

bool IsSectionRelocation;
if (!analyzeRelocation(Rel,
RelocatedSection,
SymbolName,
IsSectionRelocation,
SymbolAddress,
Addend,
ExtractedValue)) {
DEBUG(dbgs() << "BOLT-DEBUG: skipping relocation @ offset = 0x"
<< Twine::utohexstr(Rel.getOffset())
<< "; type name = " << TypeName
<< '\n');
<< Twine::utohexstr(Rel.getOffset())
<< "; type name = " << TypeName
<< '\n');
continue;
}

Expand Down Expand Up @@ -2117,16 +2124,13 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
if (BC->isAArch64() && Rel.getType() == ELF::R_AARCH64_ADR_GOT_PAGE)
ForceRelocation = true;

// TODO: RefSection should be the same as **Rel.getSymbol().getSection()
auto RefSection = BC->getSectionForAddress(SymbolAddress);
if (!RefSection && !ForceRelocation) {
DEBUG(dbgs() << "BOLT-DEBUG: cannot determine referenced section.\n");
continue;
}

const bool IsToCode = RefSection && RefSection->isText();
const bool IsSectionRelocation =
(cantFail(Rel.getSymbol()->getType()) == SymbolRef::ST_Debug);

// Occasionally we may see a reference past the last byte of the function
// typically as a result of __builtin_unreachable(). Check it here.
Expand Down Expand Up @@ -2298,22 +2302,25 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
SymbolAddress = BD->getAddress();
assert(Address == SymbolAddress + Addend);
} else {
auto Symbol = *Rel.getSymbol();
// These are mostly local data symbols but undefined symbols
// in relocation sections can get through here too, from .plt.
assert((IsAArch64 ||
IsSectionRelocation ||
BC->getSectionNameForAddress(SymbolAddress)->startswith(".plt"))
&& "known symbols should not resolve to anonymous locals");

const uint64_t SymbolSize =
IsAArch64 ? 0 : ELFSymbolRef(Symbol).getSize();
const uint64_t SymbolAlignment = IsAArch64 ? 1 : Symbol.getAlignment();
const unsigned SymbolFlags = Symbol.getFlags();

if (!IsSectionRelocation) {
if (IsSectionRelocation) {
ReferencedSymbol = BC->getOrCreateGlobalSymbol(SymbolAddress,
"SYMBOLat");
} else {
auto Symbol = *Rel.getSymbol();
const uint64_t SymbolSize =
IsAArch64 ? 0 : ELFSymbolRef(Symbol).getSize();
const uint64_t SymbolAlignment =
IsAArch64 ? 1 : Symbol.getAlignment();
const auto SymbolFlags = Symbol.getFlags();
std::string Name;
if (Symbol.getFlags() & SymbolRef::SF_Global) {
if (SymbolFlags & SymbolRef::SF_Global) {
Name = SymbolName;
} else {
Name = uniquifyName(*BC, StringRef(SymbolName).startswith(
Expand All @@ -2326,12 +2333,6 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
SymbolSize,
SymbolAlignment,
SymbolFlags);
} else {
ReferencedSymbol = BC->getOrCreateGlobalSymbol(SymbolAddress,
SymbolSize,
SymbolAlignment,
"SYMBOLat",
SymbolFlags);
}

if (!opts::AllowSectionRelocations && IsSectionRelocation) {
Expand Down
1 change: 1 addition & 0 deletions bolt/src/RewriteInstance.h
Expand Up @@ -264,6 +264,7 @@ class RewriteInstance {
bool analyzeRelocation(const RelocationRef &Rel,
SectionRef RelocatedSection,
std::string &SymbolName,
bool &IsSectionRelocation,
uint64_t &SymbolAddress,
int64_t &Addend,
uint64_t &ExtractedValue) const;
Expand Down

0 comments on commit ce508b5

Please sign in to comment.