mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 11:02:04 +08:00
[BOLT] Fix C++ exceptions for shared objects
Summary:
Fix several issues to make C++ exceptions work in shared objects:
* Set MCObjectFileInfo PIC type based on the input binary type.
* Support indirect (DW_EH_PE_indirect) encoding while writing
exception Type Table.
* Use different LPStart value and landing pad encoding for .so's.
* Disable splitting of exception-handling code for .so's because of
the new encoding.
(cherry picked from FBD24698765)
This commit is contained in:
@@ -160,7 +160,7 @@ MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
|
||||
/// Create BinaryContext for a given architecture \p ArchName and
|
||||
/// triple \p TripleName.
|
||||
std::unique_ptr<BinaryContext>
|
||||
BinaryContext::createBinaryContext(ObjectFile *File,
|
||||
BinaryContext::createBinaryContext(ObjectFile *File, bool IsPIC,
|
||||
std::unique_ptr<DWARFContext> DwCtx) {
|
||||
StringRef ArchName = "";
|
||||
StringRef FeaturesStr = "";
|
||||
@@ -223,7 +223,7 @@ BinaryContext::createBinaryContext(ObjectFile *File,
|
||||
llvm::make_unique<MCObjectFileInfo>();
|
||||
std::unique_ptr<MCContext> Ctx =
|
||||
llvm::make_unique<MCContext>(AsmInfo.get(), MRI.get(), MOFI.get());
|
||||
MOFI->InitMCObjectFileInfo(*TheTriple, /*PIC=*/false, *Ctx);
|
||||
MOFI->InitMCObjectFileInfo(*TheTriple, IsPIC, *Ctx);
|
||||
|
||||
std::unique_ptr<MCDisassembler> DisAsm(
|
||||
TheTarget->createMCDisassembler(*STI, *Ctx));
|
||||
@@ -279,6 +279,8 @@ BinaryContext::createBinaryContext(ObjectFile *File,
|
||||
|
||||
BC->setFilename(File->getFileName());
|
||||
|
||||
BC->HasFixedLoadAddress = !IsPIC;
|
||||
|
||||
return BC;
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,8 @@ class BinaryContext {
|
||||
|
||||
public:
|
||||
static std::unique_ptr<BinaryContext>
|
||||
createBinaryContext(ObjectFile *File, std::unique_ptr<DWARFContext> DwCtx);
|
||||
createBinaryContext(ObjectFile *File, bool IsPIC,
|
||||
std::unique_ptr<DWARFContext> DwCtx);
|
||||
|
||||
/// [start memory address] -> [segment info] mapping.
|
||||
std::map<uint64_t, SegmentInfo> SegmentMapInfo;
|
||||
@@ -513,7 +514,9 @@ public:
|
||||
/// Indicates if relocations are available for usage.
|
||||
bool HasRelocations{false};
|
||||
|
||||
/// Is the binary always loaded at a fixed address.
|
||||
/// Is the binary always loaded at a fixed address. Shared objects and
|
||||
/// position-independent executables (PIEs) are examples of binaries that
|
||||
/// will have HasFixedLoadAddress set to false.
|
||||
bool HasFixedLoadAddress{true};
|
||||
|
||||
/// True if the binary has no dynamic dependencies, i.e., if it was statically
|
||||
|
||||
@@ -792,28 +792,49 @@ void BinaryEmitter::emitLSDA(BinaryFunction &BF, bool EmitColdPart) {
|
||||
Streamer.EmitLabel(LSDASymbol);
|
||||
|
||||
// Corresponding FDE start.
|
||||
const auto *StartSymbol = EmitColdPart ? BF.getColdSymbol() : BF.getSymbol();
|
||||
const MCSymbol *StartSymbol = EmitColdPart ? BF.getColdSymbol()
|
||||
: BF.getSymbol();
|
||||
|
||||
// Emit the LSDA header.
|
||||
|
||||
// If LPStart is omitted, then the start of the FDE is used as a base for
|
||||
// landing pad displacements. Then if a cold fragment starts with
|
||||
// a landing pad, this means that the first landing pad offset will be 0.
|
||||
// As a result, an exception handling runtime will ignore this landing pad,
|
||||
// As a result, the exception handling runtime will ignore this landing pad
|
||||
// because zero offset denotes the absence of a landing pad.
|
||||
// For this reason, we emit LPStart value of 0 and output an absolute value
|
||||
// of the landing pad in the table.
|
||||
// For this reason, when the binary has fixed starting address we emit LPStart
|
||||
// as 0 and output the absolute value of the landing pad in the table.
|
||||
//
|
||||
// FIXME: this may break PIEs and DSOs where the base address is not 0.
|
||||
Streamer.EmitIntValue(dwarf::DW_EH_PE_udata4, 1); // LPStart format
|
||||
Streamer.EmitIntValue(0, 4);
|
||||
auto emitLandingPad = [&](const MCSymbol *LPSymbol) {
|
||||
if (!LPSymbol) {
|
||||
Streamer.EmitIntValue(0, 4);
|
||||
return;
|
||||
}
|
||||
Streamer.EmitSymbolValue(LPSymbol, 4);
|
||||
};
|
||||
// If the base address can change, we cannot use absolute addresses for
|
||||
// landing pads (at least not without runtime relocations). Hence, we fall
|
||||
// back to emitting landing pads relative to the FDE start.
|
||||
// As we are emitting label differences, we have to guarantee both labels are
|
||||
// defined in the same section and hence cannot place the landing pad into a
|
||||
// cold fragment when the corresponding call site is in the hot fragment.
|
||||
// Because of this issue and the previously described issue of possible
|
||||
// zero-offset landing pad we disable splitting of exception-handling
|
||||
// code for shared objects.
|
||||
std::function<void(const MCSymbol *)> emitLandingPad;
|
||||
if (BC.HasFixedLoadAddress) {
|
||||
Streamer.EmitIntValue(dwarf::DW_EH_PE_udata4, 1); // LPStart format
|
||||
Streamer.EmitIntValue(0, 4); // LPStart
|
||||
emitLandingPad = [&](const MCSymbol *LPSymbol) {
|
||||
if (!LPSymbol)
|
||||
Streamer.EmitIntValue(0, 4);
|
||||
else
|
||||
Streamer.EmitSymbolValue(LPSymbol, 4);
|
||||
};
|
||||
} else {
|
||||
assert(!EmitColdPart &&
|
||||
"cannot have exceptions in cold fragment for shared object");
|
||||
Streamer.EmitIntValue(dwarf::DW_EH_PE_omit, 1); // LPStart format
|
||||
emitLandingPad = [&](const MCSymbol *LPSymbol) {
|
||||
if (!LPSymbol)
|
||||
Streamer.EmitIntValue(0, 4);
|
||||
else
|
||||
Streamer.emitAbsoluteSymbolDiff(LPSymbol, StartSymbol, 4);
|
||||
};
|
||||
}
|
||||
|
||||
Streamer.EmitIntValue(TTypeEncoding, 1); // TType format
|
||||
|
||||
@@ -873,25 +894,26 @@ void BinaryEmitter::emitLSDA(BinaryFunction &BF, bool EmitColdPart) {
|
||||
for (auto const &Byte : BF.getLSDAActionTable()) {
|
||||
Streamer.EmitIntValue(Byte, 1);
|
||||
}
|
||||
assert(!(TTypeEncoding & dwarf::DW_EH_PE_indirect) &&
|
||||
"indirect type info encoding is not supported yet");
|
||||
for (int Index = BF.getLSDATypeTable().size() - 1; Index >= 0; --Index) {
|
||||
// Note: the address could be an indirect one.
|
||||
const auto TypeAddress = BF.getLSDATypeTable()[Index];
|
||||
|
||||
const auto &TypeTable = (TTypeEncoding & dwarf::DW_EH_PE_indirect)
|
||||
? BF.getLSDATypeAddressTable()
|
||||
: BF.getLSDATypeTable();
|
||||
assert(TypeTable.size() == BF.getLSDATypeTable().size() &&
|
||||
"indirect type table size mismatch");
|
||||
|
||||
for (int Index = TypeTable.size() - 1; Index >= 0; --Index) {
|
||||
const uint64_t TypeAddress = TypeTable[Index];
|
||||
switch (TTypeEncoding & 0x70) {
|
||||
default:
|
||||
llvm_unreachable("unsupported TTypeEncoding");
|
||||
case 0:
|
||||
case dwarf::DW_EH_PE_absptr:
|
||||
Streamer.EmitIntValue(TypeAddress, TTypeEncodingSize);
|
||||
break;
|
||||
case dwarf::DW_EH_PE_pcrel: {
|
||||
if (TypeAddress) {
|
||||
const auto *TypeSymbol =
|
||||
BC.getOrCreateGlobalSymbol(TypeAddress,
|
||||
"TI",
|
||||
TTypeEncodingSize,
|
||||
TTypeAlignment);
|
||||
auto *DotSymbol = BC.Ctx->createTempSymbol();
|
||||
const MCSymbol *TypeSymbol =
|
||||
BC.getOrCreateGlobalSymbol(TypeAddress, "TI", 0, TTypeAlignment);
|
||||
MCSymbol *DotSymbol = BC.Ctx->createTempSymbol();
|
||||
Streamer.EmitLabel(DotSymbol);
|
||||
const auto *SubDotExpr = MCBinaryExpr::createSub(
|
||||
MCSymbolRefExpr::create(TypeSymbol, *BC.Ctx),
|
||||
|
||||
@@ -481,12 +481,20 @@ private:
|
||||
std::vector<CallSite> CallSites;
|
||||
std::vector<CallSite> ColdCallSites;
|
||||
|
||||
/// Binary blobs reprsenting action, type, and type index tables for this
|
||||
/// Binary blobs representing action, type, and type index tables for this
|
||||
/// function' LSDA (exception handling).
|
||||
ArrayRef<uint8_t> LSDAActionTable;
|
||||
std::vector<uint64_t> LSDATypeTable;
|
||||
ArrayRef<uint8_t> LSDATypeIndexTable;
|
||||
|
||||
using LSDATypeTableTy = std::vector<uint64_t>;
|
||||
|
||||
/// Vector of addresses of types referenced by LSDA.
|
||||
LSDATypeTableTy LSDATypeTable;
|
||||
|
||||
/// Vector of addresses of entries in LSDATypeTable used for indirect
|
||||
/// addressing.
|
||||
LSDATypeTableTy LSDATypeAddressTable;
|
||||
|
||||
/// Marking for the beginning of language-specific data area for the function.
|
||||
MCSymbol *LSDASymbol{nullptr};
|
||||
MCSymbol *ColdLSDASymbol{nullptr};
|
||||
@@ -692,6 +700,7 @@ private:
|
||||
clearList(CallSites);
|
||||
clearList(ColdCallSites);
|
||||
clearList(LSDATypeTable);
|
||||
clearList(LSDATypeAddressTable);
|
||||
|
||||
clearList(MoveRelocations);
|
||||
|
||||
@@ -1487,10 +1496,14 @@ public:
|
||||
return LSDAActionTable;
|
||||
}
|
||||
|
||||
const std::vector<uint64_t> &getLSDATypeTable() const {
|
||||
const LSDATypeTableTy &getLSDATypeTable() const {
|
||||
return LSDATypeTable;
|
||||
}
|
||||
|
||||
const LSDATypeTableTy &getLSDATypeAddressTable() const {
|
||||
return LSDATypeAddressTable;
|
||||
}
|
||||
|
||||
const ArrayRef<uint8_t> getLSDATypeIndexTable() const {
|
||||
return LSDATypeIndexTable;
|
||||
}
|
||||
|
||||
@@ -170,11 +170,11 @@ void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
|
||||
outs() << '\n';
|
||||
}
|
||||
|
||||
HasEHRanges = CallSitePtr < CallSiteTableEnd;
|
||||
uint64_t RangeBase = getAddress();
|
||||
this->HasEHRanges = CallSitePtr < CallSiteTableEnd;
|
||||
const uint64_t RangeBase = getAddress();
|
||||
while (CallSitePtr < CallSiteTableEnd) {
|
||||
uint64_t Start = *Data.getEncodedPointer(&CallSitePtr, CallSiteEncoding,
|
||||
CallSitePtr + LSDASectionAddress);
|
||||
CallSitePtr + LSDASectionAddress);
|
||||
uint64_t Length = *Data.getEncodedPointer(
|
||||
&CallSitePtr, CallSiteEncoding, CallSitePtr + LSDASectionAddress);
|
||||
uint64_t LandingPad = *Data.getEncodedPointer(
|
||||
@@ -229,14 +229,13 @@ void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
|
||||
} while (II != IE && II->first < Start + Length);
|
||||
|
||||
if (ActionEntry != 0) {
|
||||
auto printType = [&] (int Index, raw_ostream &OS) {
|
||||
auto printType = [&](int Index, raw_ostream &OS) {
|
||||
assert(Index > 0 && "only positive indices are valid");
|
||||
uint32_t TTEntry = TypeTableStart - Index * TTypeEncodingSize;
|
||||
const auto TTEntryAddress = TTEntry + LSDASectionAddress;
|
||||
uint32_t TypeAddress =
|
||||
const uint64_t TTEntryAddress = TTEntry + LSDASectionAddress;
|
||||
uint64_t TypeAddress =
|
||||
*Data.getEncodedPointer(&TTEntry, TTypeEncoding, TTEntryAddress);
|
||||
if ((TTypeEncoding & DW_EH_PE_pcrel) &&
|
||||
(TypeAddress == TTEntryAddress)) {
|
||||
if ((TTypeEncoding & DW_EH_PE_pcrel) && TypeAddress == TTEntryAddress) {
|
||||
TypeAddress = 0;
|
||||
}
|
||||
if (TypeAddress == 0) {
|
||||
@@ -257,12 +256,12 @@ void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
|
||||
if (opts::PrintExceptions)
|
||||
outs() << " actions: ";
|
||||
uint32_t ActionPtr = ActionTableStart + ActionEntry - 1;
|
||||
long long ActionType;
|
||||
long long ActionNext;
|
||||
int64_t ActionType;
|
||||
int64_t ActionNext;
|
||||
auto Sep = "";
|
||||
do {
|
||||
ActionType = Data.getSLEB128(&ActionPtr);
|
||||
auto Self = ActionPtr;
|
||||
const uint32_t Self = ActionPtr;
|
||||
ActionNext = Data.getSLEB128(&ActionPtr);
|
||||
if (opts::PrintExceptions)
|
||||
outs() << Sep << "(" << ActionType << ", " << ActionNext << ") ";
|
||||
@@ -324,13 +323,15 @@ void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
|
||||
const auto TTEntryAddress = TTEntry + LSDASectionAddress;
|
||||
uint64_t TypeAddress =
|
||||
*Data.getEncodedPointer(&TTEntry, TTypeEncoding, TTEntryAddress);
|
||||
if ((TTypeEncoding & DW_EH_PE_pcrel) && (TypeAddress == TTEntryAddress)) {
|
||||
if ((TTypeEncoding & DW_EH_PE_pcrel) && (TypeAddress == TTEntryAddress))
|
||||
TypeAddress = 0;
|
||||
}
|
||||
if (TypeAddress && (TTypeEncoding & DW_EH_PE_indirect)) {
|
||||
auto PointerOrErr = BC.getPointerAtAddress(TypeAddress);
|
||||
assert(PointerOrErr && "failed to decode indirect address");
|
||||
TypeAddress = *PointerOrErr;
|
||||
if (TTypeEncoding & DW_EH_PE_indirect) {
|
||||
LSDATypeAddressTable.emplace_back(TypeAddress);
|
||||
if (TypeAddress) {
|
||||
auto PointerOrErr = BC.getPointerAtAddress(TypeAddress);
|
||||
assert(PointerOrErr && "failed to decode indirect address");
|
||||
TypeAddress = *PointerOrErr;
|
||||
}
|
||||
}
|
||||
LSDATypeTable.emplace_back(TypeAddress);
|
||||
}
|
||||
|
||||
@@ -58,9 +58,10 @@ MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile,
|
||||
StringRef ToolPath)
|
||||
: InputFile(InputFile), ToolPath(ToolPath),
|
||||
BC(BinaryContext::createBinaryContext(
|
||||
InputFile, DWARFContext::create(*InputFile, nullptr,
|
||||
DWARFContext::defaultErrorHandler, "",
|
||||
false))) {}
|
||||
InputFile, /* IsPIC */ true,
|
||||
DWARFContext::create(*InputFile, nullptr,
|
||||
DWARFContext::defaultErrorHandler, "",
|
||||
false))) {}
|
||||
|
||||
void MachORewriteInstance::readSpecialSections() {
|
||||
for (const auto &Section : InputFile->sections()) {
|
||||
|
||||
@@ -448,18 +448,32 @@ bool refersToReorderedSection(ErrorOr<BinarySection &> Section) {
|
||||
RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc,
|
||||
const char *const *Argv, StringRef ToolPath)
|
||||
: InputFile(File), Argc(Argc), Argv(Argv), ToolPath(ToolPath),
|
||||
BC(BinaryContext::createBinaryContext(
|
||||
File,
|
||||
DWARFContext::create(*File, nullptr,
|
||||
DWARFContext::defaultErrorHandler, "", false))),
|
||||
BAT(llvm::make_unique<BoltAddressTranslation>(*BC)),
|
||||
SHStrTab(StringTableBuilder::ELF) {
|
||||
if (opts::UpdateDebugSections) {
|
||||
auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile);
|
||||
if (!ELF64LEFile) {
|
||||
errs() << "BOLT-ERROR: only 64-bit LE ELF binaries are supported\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool IsPIC = false;
|
||||
const ELFFile<ELF64LE> *Obj = ELF64LEFile->getELFFile();
|
||||
if (Obj->getHeader()->e_type != ELF::ET_EXEC) {
|
||||
outs() << "BOLT-INFO: shared object or position-independent executable "
|
||||
"detected\n";
|
||||
IsPIC = true;
|
||||
}
|
||||
|
||||
BC = BinaryContext::createBinaryContext(File,IsPIC,
|
||||
DWARFContext::create(*File, nullptr,
|
||||
DWARFContext::defaultErrorHandler, "", false));
|
||||
|
||||
BAT = llvm::make_unique<BoltAddressTranslation>(*BC);
|
||||
|
||||
if (opts::UpdateDebugSections)
|
||||
DebugInfoRewriter = llvm::make_unique<DWARFRewriter>(*BC, SectionPatchers);
|
||||
}
|
||||
if (opts::Hugify) {
|
||||
|
||||
if (opts::Hugify)
|
||||
BC->setRuntimeLibrary(llvm::make_unique<HugifyRuntimeLibrary>());
|
||||
}
|
||||
}
|
||||
|
||||
RewriteInstance::~RewriteInstance() {}
|
||||
@@ -509,16 +523,7 @@ void RewriteInstance::discoverStorage() {
|
||||
BC->EFMM.reset(new ExecutableFileMemoryManager(*BC, /*AllowStubs*/ false));
|
||||
|
||||
auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile);
|
||||
if (!ELF64LEFile) {
|
||||
errs() << "BOLT-ERROR: only 64-bit LE ELF binaries are supported\n";
|
||||
exit(1);
|
||||
}
|
||||
auto Obj = ELF64LEFile->getELFFile();
|
||||
if (Obj->getHeader()->e_type != ELF::ET_EXEC) {
|
||||
outs() << "BOLT-INFO: shared object or position-independent executable "
|
||||
"detected\n";
|
||||
BC->HasFixedLoadAddress = false;
|
||||
}
|
||||
const auto *Obj = ELF64LEFile->getELFFile();
|
||||
|
||||
BC->StartFunctionAddress = Obj->getHeader()->e_entry;
|
||||
|
||||
@@ -1650,6 +1655,11 @@ void RewriteInstance::adjustCommandLineOptions() {
|
||||
opts::SplitEH = false;
|
||||
}
|
||||
|
||||
if (opts::SplitEH && !BC->HasFixedLoadAddress) {
|
||||
errs() << "BOLT-WARNING: disabling -split-eh for shared object\n";
|
||||
opts::SplitEH = false;
|
||||
}
|
||||
|
||||
if (opts::StrictMode && !BC->HasRelocations) {
|
||||
errs() << "BOLT-WARNING: disabling strict mode (-strict) in non-relocation "
|
||||
"mode\n";
|
||||
|
||||
Reference in New Issue
Block a user