2020-03-06 15:06:37 -08:00
|
|
|
//===--- BinaryEmitter.cpp - collection of functions to emit code and data ===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "BinaryContext.h"
|
|
|
|
#include "BinaryEmitter.h"
|
|
|
|
#include "BinaryFunction.h"
|
|
|
|
#include "llvm/MC/MCSection.h"
|
|
|
|
#include "llvm/Support/LEB128.h"
|
|
|
|
#include "llvm/Support/SMLoc.h"
|
|
|
|
|
|
|
|
#undef DEBUG_TYPE
|
|
|
|
#define DEBUG_TYPE "bolt"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace bolt;
|
|
|
|
|
|
|
|
extern cl::opt<uint32_t> X86AlignBranchBoundary;
|
|
|
|
|
|
|
|
namespace opts {
|
|
|
|
|
|
|
|
extern bool shouldProcess(const BinaryFunction &);
|
|
|
|
|
|
|
|
extern cl::OptionCategory BoltCategory;
|
|
|
|
extern cl::OptionCategory BoltOptCategory;
|
|
|
|
extern cl::OptionCategory BoltRelocCategory;
|
|
|
|
|
2020-04-19 15:02:50 -07:00
|
|
|
extern cl::opt<unsigned> AlignText;
|
2020-03-06 15:06:37 -08:00
|
|
|
extern cl::opt<bool> HotText;
|
|
|
|
extern cl::opt<bool> Instrument;
|
|
|
|
extern cl::opt<JumpTableSupportLevel> JumpTables;
|
|
|
|
extern cl::opt<bool> PreserveBlocksAlignment;
|
|
|
|
extern cl::opt<bool> PrintCacheMetrics;
|
|
|
|
extern cl::opt<bool> UpdateDebugSections;
|
|
|
|
extern cl::opt<bool> UpdateEnd;
|
|
|
|
extern cl::opt<unsigned> Verbosity;
|
|
|
|
|
|
|
|
cl::opt<bool>
|
|
|
|
AlignBlocks("align-blocks",
|
|
|
|
cl::desc("align basic blocks"),
|
|
|
|
cl::init(false),
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
cl::cat(BoltOptCategory));
|
|
|
|
|
|
|
|
cl::opt<MacroFusionType>
|
|
|
|
AlignMacroOpFusion("align-macro-fusion",
|
|
|
|
cl::desc("fix instruction alignment for macro-fusion (x86 relocation mode)"),
|
|
|
|
cl::init(MFT_HOT),
|
|
|
|
cl::values(clEnumValN(MFT_NONE, "none",
|
|
|
|
"do not insert alignment no-ops for macro-fusion"),
|
|
|
|
clEnumValN(MFT_HOT, "hot",
|
|
|
|
"only insert alignment no-ops on hot execution paths (default)"),
|
|
|
|
clEnumValN(MFT_ALL, "all",
|
|
|
|
"always align instructions to allow macro-fusion")),
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
cl::cat(BoltRelocCategory));
|
|
|
|
|
|
|
|
static cl::list<std::string>
|
|
|
|
BreakFunctionNames("break-funcs",
|
|
|
|
cl::CommaSeparated,
|
|
|
|
cl::desc("list of functions to core dump on (debugging)"),
|
|
|
|
cl::value_desc("func1,func2,func3,..."),
|
|
|
|
cl::Hidden,
|
|
|
|
cl::cat(BoltCategory));
|
|
|
|
|
|
|
|
static cl::list<std::string>
|
|
|
|
FunctionPadSpec("pad-funcs",
|
|
|
|
cl::CommaSeparated,
|
|
|
|
cl::desc("list of functions to pad with amount of bytes"),
|
|
|
|
cl::value_desc("func1:pad1,func2:pad2,func3:pad3,..."),
|
|
|
|
cl::Hidden,
|
|
|
|
cl::cat(BoltCategory));
|
|
|
|
|
|
|
|
static cl::opt<bool>
|
|
|
|
MarkFuncs("mark-funcs",
|
|
|
|
cl::desc("mark function boundaries with break instruction to make "
|
|
|
|
"sure we accidentally don't cross them"),
|
|
|
|
cl::ReallyHidden,
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
cl::cat(BoltCategory));
|
|
|
|
|
|
|
|
static cl::opt<bool>
|
|
|
|
PrintJumpTables("print-jump-tables",
|
|
|
|
cl::desc("print jump tables"),
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
cl::Hidden,
|
|
|
|
cl::cat(BoltCategory));
|
|
|
|
|
|
|
|
static cl::opt<bool>
|
|
|
|
X86AlignBranchBoundaryHotOnly("x86-align-branch-boundary-hot-only",
|
|
|
|
cl::desc("only apply branch boundary alignment in hot code"),
|
|
|
|
cl::init(true),
|
|
|
|
cl::cat(BoltOptCategory));
|
|
|
|
|
|
|
|
size_t padFunction(const BinaryFunction &Function) {
|
|
|
|
static std::map<std::string, size_t> FunctionPadding;
|
|
|
|
|
|
|
|
if (FunctionPadding.empty() && !FunctionPadSpec.empty()) {
|
|
|
|
for (auto &Spec : FunctionPadSpec) {
|
|
|
|
auto N = Spec.find(':');
|
|
|
|
if (N == std::string::npos)
|
|
|
|
continue;
|
|
|
|
auto Name = Spec.substr(0, N);
|
|
|
|
auto Padding = std::stoull(Spec.substr(N+1));
|
|
|
|
FunctionPadding[Name] = Padding;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &FPI : FunctionPadding) {
|
|
|
|
auto Name = FPI.first;
|
|
|
|
auto Padding = FPI.second;
|
|
|
|
if (Function.hasNameRegex(Name)) {
|
|
|
|
return Padding;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace opts
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class BinaryEmitter {
|
|
|
|
private:
|
|
|
|
BinaryEmitter(const BinaryEmitter &) = delete;
|
|
|
|
BinaryEmitter &operator=(const BinaryEmitter &) = delete;
|
|
|
|
|
|
|
|
MCStreamer &Streamer;
|
|
|
|
BinaryContext &BC;
|
|
|
|
|
|
|
|
public:
|
|
|
|
BinaryEmitter(MCStreamer &Streamer, BinaryContext &BC)
|
|
|
|
: Streamer(Streamer),
|
|
|
|
BC(BC) {}
|
|
|
|
|
|
|
|
/// Emit all code and data.
|
|
|
|
void emitAll(StringRef OrgSecPrefix);
|
|
|
|
|
|
|
|
/// Emit function code. The caller is responsible for emitting function
|
|
|
|
/// symbol(s) and setting the section to emit the code to.
|
|
|
|
void emitFunctionBody(BinaryFunction &BF, bool EmitColdPart,
|
|
|
|
bool EmitCodeOnly = false);
|
|
|
|
|
|
|
|
private:
|
|
|
|
/// Emit function code.
|
|
|
|
void emitFunctions();
|
|
|
|
|
|
|
|
/// Emit a single function.
|
|
|
|
bool emitFunction(BinaryFunction &BF, bool EmitColdPart);
|
|
|
|
|
|
|
|
/// Helper for emitFunctionBody to write data inside a function
|
|
|
|
/// (used for AArch64)
|
|
|
|
void emitConstantIslands(BinaryFunction &BF, bool EmitColdPart,
|
|
|
|
BinaryFunction *OnBehalfOf = nullptr);
|
|
|
|
|
|
|
|
/// Emit jump tables for the function.
|
|
|
|
void emitJumpTables(const BinaryFunction &BF);
|
|
|
|
|
|
|
|
/// Emit jump table data. Callee supplies sections for the data.
|
|
|
|
void emitJumpTable(const JumpTable &JT, MCSection *HotSection,
|
|
|
|
MCSection *ColdSection);
|
|
|
|
|
|
|
|
/// Emit exception handling ranges for the function.
|
|
|
|
void emitLSDA(BinaryFunction &BF, bool EmitColdPart);
|
|
|
|
|
|
|
|
/// Emit line number information corresponding to \p NewLoc. \p PrevLoc
|
|
|
|
/// provides a context for de-duplication of line number info.
|
|
|
|
/// \p FirstInstr indicates if \p NewLoc represents the first instruction
|
|
|
|
/// in a sequence, such as a function fragment.
|
|
|
|
///
|
|
|
|
/// Return new current location which is either \p NewLoc or \p PrevLoc.
|
|
|
|
SMLoc emitLineInfo(const BinaryFunction &BF, SMLoc NewLoc, SMLoc PrevLoc,
|
|
|
|
bool FirstInstr);
|
|
|
|
|
|
|
|
/// Emit debug line information for functions that were not emitted.
|
|
|
|
void emitDebugLineInfoForNonSimpleFunctions();
|
|
|
|
|
|
|
|
/// Emit function as a blob with relocations and labels for relocations.
|
|
|
|
void emitFunctionBodyRaw(BinaryFunction &BF) LLVM_ATTRIBUTE_UNUSED;
|
|
|
|
|
|
|
|
/// Emit data sections that have code references in them.
|
|
|
|
void emitDataSections(StringRef OrgSecPrefix);
|
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
void BinaryEmitter::emitAll(StringRef OrgSecPrefix) {
|
|
|
|
Streamer.InitSections(false);
|
|
|
|
|
2020-04-19 15:02:50 -07:00
|
|
|
BC.getTextSection()->setAlignment(opts::AlignText);
|
2020-03-06 15:06:37 -08:00
|
|
|
|
|
|
|
emitFunctions();
|
|
|
|
|
|
|
|
if (!BC.HasRelocations && opts::UpdateDebugSections)
|
|
|
|
emitDebugLineInfoForNonSimpleFunctions();
|
|
|
|
|
|
|
|
emitDataSections(OrgSecPrefix);
|
|
|
|
|
|
|
|
// Update _end if needed.
|
|
|
|
if (opts::UpdateEnd) {
|
|
|
|
Streamer.EmitLabel(BC.Ctx->getOrCreateSymbol("_end"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinaryEmitter::emitFunctions() {
|
|
|
|
auto emit = [&](const std::vector<BinaryFunction *> &Functions) {
|
|
|
|
const auto HasProfile = BC.NumProfiledFuncs > 0;
|
|
|
|
const uint32_t OriginalBranchBoundaryAlign = X86AlignBranchBoundary;
|
|
|
|
for (auto *Function : Functions) {
|
|
|
|
if (!BC.HasRelocations &&
|
|
|
|
(!Function->isSimple() || !opts::shouldProcess(*Function)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "BOLT: generating code for function \""
|
|
|
|
<< *Function << "\" : "
|
|
|
|
<< Function->getFunctionNumber() << '\n');
|
|
|
|
|
|
|
|
// Was any part of the function emitted.
|
|
|
|
bool Emitted{false};
|
|
|
|
|
|
|
|
// Turn off Intel JCC Erratum mitigation for cold code if requested
|
|
|
|
if (HasProfile && opts::X86AlignBranchBoundaryHotOnly &&
|
|
|
|
!Function->hasValidProfile())
|
|
|
|
X86AlignBranchBoundary = 0;
|
|
|
|
|
|
|
|
Emitted |= emitFunction(*Function, /*EmitColdPart=*/false);
|
|
|
|
|
|
|
|
if (Function->isSplit()) {
|
|
|
|
if (opts::X86AlignBranchBoundaryHotOnly)
|
|
|
|
X86AlignBranchBoundary = 0;
|
|
|
|
Emitted |= emitFunction(*Function, /*EmitColdPart=*/true);
|
|
|
|
}
|
|
|
|
X86AlignBranchBoundary = OriginalBranchBoundaryAlign;
|
|
|
|
|
|
|
|
if (Emitted)
|
|
|
|
Function->setEmitted(/*KeepCFG=*/opts::PrintCacheMetrics);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Mark the start of hot text.
|
|
|
|
if (opts::HotText) {
|
|
|
|
Streamer.SwitchSection(BC.getTextSection());
|
|
|
|
Streamer.EmitLabel(BC.getHotTextStartSymbol());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit functions in sorted order.
|
|
|
|
std::vector<BinaryFunction *> SortedFunctions = BC.getSortedFunctions();
|
|
|
|
emit(SortedFunctions);
|
|
|
|
|
|
|
|
// Emit functions added by BOLT.
|
|
|
|
emit(BC.getInjectedBinaryFunctions());
|
|
|
|
|
|
|
|
// Mark the end of hot text.
|
|
|
|
if (opts::HotText) {
|
|
|
|
Streamer.SwitchSection(BC.getTextSection());
|
|
|
|
Streamer.EmitLabel(BC.getHotTextEndSymbol());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BinaryEmitter::emitFunction(BinaryFunction &Function, bool EmitColdPart) {
|
|
|
|
if (Function.size() == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Function.getState() == BinaryFunction::State::Empty)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
auto *Section =
|
|
|
|
BC.getCodeSection(EmitColdPart ? Function.getColdCodeSectionName()
|
|
|
|
: Function.getCodeSectionName());
|
|
|
|
Streamer.SwitchSection(Section);
|
|
|
|
Section->setHasInstructions(true);
|
|
|
|
BC.Ctx->addGenDwarfSection(Section);
|
|
|
|
|
|
|
|
if (BC.HasRelocations) {
|
|
|
|
Streamer.EmitCodeAlignment(BinaryFunction::MinAlign);
|
|
|
|
auto MaxAlignBytes = EmitColdPart
|
|
|
|
? Function.getMaxColdAlignmentBytes()
|
|
|
|
: Function.getMaxAlignmentBytes();
|
|
|
|
if (MaxAlignBytes > 0)
|
|
|
|
Streamer.EmitCodeAlignment(Function.getAlignment(), MaxAlignBytes);
|
|
|
|
} else {
|
|
|
|
Streamer.EmitCodeAlignment(Function.getAlignment());
|
|
|
|
}
|
|
|
|
|
|
|
|
MCContext &Context = Streamer.getContext();
|
|
|
|
const MCAsmInfo *MAI = Context.getAsmInfo();
|
|
|
|
|
|
|
|
// Emit all symbols associated with the main function entry.
|
|
|
|
if (!EmitColdPart) {
|
|
|
|
for (auto *Symbol : Function.getSymbols()) {
|
|
|
|
Streamer.EmitSymbolAttribute(Symbol, MCSA_ELF_TypeFunction);
|
|
|
|
Streamer.EmitLabel(Symbol);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
auto *Symbol = Function.getColdSymbol();
|
|
|
|
Streamer.EmitSymbolAttribute(Symbol, MCSA_ELF_TypeFunction);
|
|
|
|
Streamer.EmitLabel(Symbol);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit CFI start
|
|
|
|
if (Function.hasCFI()) {
|
|
|
|
Streamer.EmitCFIStartProc(/*IsSimple=*/false);
|
|
|
|
if (Function.getPersonalityFunction() != nullptr) {
|
|
|
|
Streamer.EmitCFIPersonality(Function.getPersonalityFunction(),
|
|
|
|
Function.getPersonalityEncoding());
|
|
|
|
}
|
|
|
|
auto *LSDASymbol = EmitColdPart ? Function.getColdLSDASymbol()
|
|
|
|
: Function.getLSDASymbol();
|
|
|
|
if (LSDASymbol) {
|
|
|
|
Streamer.EmitCFILsda(LSDASymbol, BC.MOFI->getLSDAEncoding());
|
|
|
|
} else {
|
|
|
|
Streamer.EmitCFILsda(0, dwarf::DW_EH_PE_omit);
|
|
|
|
}
|
|
|
|
// Emit CFI instructions relative to the CIE
|
|
|
|
for (const auto &CFIInstr : Function.cie()) {
|
|
|
|
// Only write CIE CFI insns that LLVM will not already emit
|
|
|
|
const std::vector<MCCFIInstruction> &FrameInstrs =
|
|
|
|
MAI->getInitialFrameState();
|
|
|
|
if (std::find(FrameInstrs.begin(), FrameInstrs.end(), CFIInstr) ==
|
|
|
|
FrameInstrs.end())
|
|
|
|
Streamer.EmitCFIInstruction(CFIInstr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert((Function.empty() || !(*Function.begin()).isCold()) &&
|
|
|
|
"first basic block should never be cold");
|
|
|
|
|
|
|
|
// Emit UD2 at the beginning if requested by user.
|
|
|
|
if (!opts::BreakFunctionNames.empty()) {
|
|
|
|
for (auto &Name : opts::BreakFunctionNames) {
|
|
|
|
if (Function.hasNameRegex(Name)) {
|
|
|
|
Streamer.EmitIntValue(0x0B0F, 2); // UD2: 0F 0B
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit code.
|
|
|
|
emitFunctionBody(Function, EmitColdPart, /*EmitCodeOnly=*/false);
|
|
|
|
|
|
|
|
// Emit padding if requested.
|
|
|
|
if (auto Padding = opts::padFunction(Function)) {
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: padding function " << Function << " with "
|
|
|
|
<< Padding << " bytes\n");
|
|
|
|
Streamer.emitFill(Padding, MAI->getTextAlignFillValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts::MarkFuncs) {
|
|
|
|
Streamer.EmitIntValue(MAI->getTrapFillValue(), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit CFI end
|
|
|
|
if (Function.hasCFI())
|
|
|
|
Streamer.EmitCFIEndProc();
|
|
|
|
|
|
|
|
Streamer.EmitLabel(EmitColdPart ? Function.getFunctionColdEndLabel()
|
|
|
|
: Function.getFunctionEndLabel());
|
|
|
|
|
|
|
|
// Exception handling info for the function.
|
|
|
|
emitLSDA(Function, EmitColdPart);
|
|
|
|
|
|
|
|
if (!EmitColdPart && opts::JumpTables > JTS_NONE)
|
|
|
|
emitJumpTables(Function);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, bool EmitColdPart,
|
|
|
|
bool EmitCodeOnly) {
|
|
|
|
if (!EmitCodeOnly && EmitColdPart && BF.hasConstantIsland())
|
|
|
|
BF.duplicateConstantIslands();
|
|
|
|
|
|
|
|
// Track the first emitted instruction with debug info.
|
|
|
|
bool FirstInstr = true;
|
|
|
|
for (auto BB : BF.layout()) {
|
|
|
|
if (EmitColdPart != BB->isCold())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((opts::AlignBlocks || opts::PreserveBlocksAlignment)
|
|
|
|
&& BB->getAlignment() > 1) {
|
|
|
|
Streamer.EmitCodeAlignment(BB->getAlignment(),
|
|
|
|
BB->getAlignmentMaxBytes());
|
|
|
|
}
|
|
|
|
Streamer.EmitLabel(BB->getLabel());
|
|
|
|
|
|
|
|
// Check if special alignment for macro-fusion is needed.
|
|
|
|
bool MayNeedMacroFusionAlignment =
|
|
|
|
(opts::AlignMacroOpFusion == MFT_ALL) ||
|
|
|
|
(opts::AlignMacroOpFusion == MFT_HOT &&
|
|
|
|
BB->getKnownExecutionCount());
|
|
|
|
BinaryBasicBlock::const_iterator MacroFusionPair;
|
|
|
|
if (MayNeedMacroFusionAlignment) {
|
|
|
|
MacroFusionPair = BB->getMacroOpFusionPair();
|
|
|
|
if (MacroFusionPair == BB->end())
|
|
|
|
MayNeedMacroFusionAlignment = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SMLoc LastLocSeen;
|
|
|
|
// Remember if the last instruction emitted was a prefix.
|
|
|
|
bool LastIsPrefix = false;
|
|
|
|
for (auto I = BB->begin(), E = BB->end(); I != E; ++I) {
|
|
|
|
auto &Instr = *I;
|
|
|
|
|
|
|
|
if (EmitCodeOnly && BC.MII->get(Instr.getOpcode()).isPseudo())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Handle pseudo instructions.
|
|
|
|
if (BC.MIB->isEHLabel(Instr)) {
|
|
|
|
const auto *Label = BC.MIB->getTargetSymbol(Instr);
|
|
|
|
assert(Instr.getNumOperands() >= 1 && Label &&
|
|
|
|
"bad EH_LABEL instruction");
|
|
|
|
Streamer.EmitLabel(const_cast<MCSymbol *>(Label));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (BC.MIB->isCFI(Instr)) {
|
|
|
|
Streamer.EmitCFIInstruction(*BF.getCFIFor(Instr));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle macro-fusion alignment. If we emitted a prefix as
|
|
|
|
// the last instruction, we should've already emitted the associated
|
|
|
|
// alignment hint, so don't emit it twice.
|
|
|
|
if (MayNeedMacroFusionAlignment && !LastIsPrefix && I == MacroFusionPair){
|
|
|
|
// This assumes the second instruction in the macro-op pair will get
|
|
|
|
// assigned to its own MCRelaxableFragment. Since all JCC instructions
|
|
|
|
// are relaxable, we should be safe.
|
|
|
|
Streamer.EmitNeverAlignCodeAtEnd(/*Alignment to avoid=*/64);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!EmitCodeOnly && opts::UpdateDebugSections &&
|
|
|
|
BF.getDWARFUnitLineTable().first) {
|
|
|
|
LastLocSeen = emitLineInfo(BF, Instr.getLoc(), LastLocSeen, FirstInstr);
|
|
|
|
FirstInstr = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare to tag this location with a label if we need to keep track of
|
|
|
|
// the location of calls/returns for BOLT address translation maps
|
|
|
|
if (!EmitCodeOnly && BF.requiresAddressTranslation() &&
|
|
|
|
BC.MIB->hasAnnotation(Instr, "Offset")) {
|
|
|
|
const auto Offset = BC.MIB->getAnnotationAs<uint32_t>(Instr, "Offset");
|
|
|
|
MCSymbol *LocSym = BC.Ctx->createTempSymbol(/*CanBeUnnamed=*/true);
|
|
|
|
Streamer.EmitLabel(LocSym);
|
|
|
|
BB->getLocSyms().emplace_back(std::make_pair(Offset, LocSym));
|
|
|
|
}
|
|
|
|
|
|
|
|
Streamer.EmitInstruction(Instr, *BC.STI);
|
|
|
|
LastIsPrefix = BC.MIB->isPrefix(Instr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!EmitCodeOnly)
|
|
|
|
emitConstantIslands(BF, EmitColdPart);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinaryEmitter::emitConstantIslands(BinaryFunction &BF, bool EmitColdPart,
|
|
|
|
BinaryFunction *OnBehalfOf) {
|
|
|
|
BinaryFunction::IslandInfo &Islands = BF.getIslandInfo();
|
|
|
|
if (Islands.DataOffsets.empty() && Islands.Dependency.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!OnBehalfOf) {
|
|
|
|
if (!EmitColdPart)
|
|
|
|
Streamer.EmitLabel(BF.getFunctionConstantIslandLabel());
|
|
|
|
else
|
|
|
|
Streamer.EmitLabel(BF.getFunctionColdConstantIslandLabel());
|
|
|
|
}
|
|
|
|
|
|
|
|
assert((!OnBehalfOf || Islands.Proxies[OnBehalfOf].size() > 0) &&
|
|
|
|
"spurious OnBehalfOf constant island emission");
|
|
|
|
|
|
|
|
assert(!BF.isInjected() &&
|
|
|
|
"injected functions should not have constant islands");
|
|
|
|
// Raw contents of the function.
|
|
|
|
StringRef SectionContents = BF.getSection().getContents();
|
|
|
|
|
|
|
|
// Raw contents of the function.
|
|
|
|
StringRef FunctionContents =
|
|
|
|
SectionContents.substr(
|
|
|
|
BF.getAddress() - BF.getSection().getAddress(),
|
|
|
|
BF.getMaxSize());
|
|
|
|
|
|
|
|
if (opts::Verbosity && !OnBehalfOf)
|
|
|
|
outs() << "BOLT-INFO: emitting constant island for function " << BF << "\n";
|
|
|
|
|
|
|
|
// We split the island into smaller blocks and output labels between them.
|
|
|
|
auto IS = Islands.Offsets.begin();
|
|
|
|
for (auto DataIter = Islands.DataOffsets.begin();
|
|
|
|
DataIter != Islands.DataOffsets.end();
|
|
|
|
++DataIter) {
|
|
|
|
uint64_t FunctionOffset = *DataIter;
|
|
|
|
uint64_t EndOffset = 0ULL;
|
|
|
|
|
|
|
|
// Determine size of this data chunk
|
|
|
|
auto NextData = std::next(DataIter);
|
|
|
|
auto CodeIter = Islands.CodeOffsets.lower_bound(*DataIter);
|
|
|
|
if (CodeIter == Islands.CodeOffsets.end() &&
|
|
|
|
NextData == Islands.DataOffsets.end()) {
|
|
|
|
EndOffset = BF.getMaxSize();
|
|
|
|
} else if (CodeIter == Islands.CodeOffsets.end()) {
|
|
|
|
EndOffset = *NextData;
|
|
|
|
} else if (NextData == Islands.DataOffsets.end()) {
|
|
|
|
EndOffset = *CodeIter;
|
|
|
|
} else {
|
|
|
|
EndOffset = (*CodeIter > *NextData) ? *NextData : *CodeIter;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FunctionOffset == EndOffset)
|
|
|
|
continue; // Size is zero, nothing to emit
|
|
|
|
|
|
|
|
// Emit labels, relocs and data
|
|
|
|
auto RI = BF.getMoveRelocations().lower_bound(FunctionOffset);
|
|
|
|
while ((IS != Islands.Offsets.end() && IS->first < EndOffset) ||
|
|
|
|
(RI != BF.getMoveRelocations().end() && RI->first < EndOffset)) {
|
|
|
|
auto NextLabelOffset =
|
|
|
|
IS == Islands.Offsets.end() ? EndOffset : IS->first;
|
|
|
|
auto NextRelOffset =
|
|
|
|
RI == BF.getMoveRelocations().end() ? EndOffset : RI->first;
|
|
|
|
auto NextStop = std::min(NextLabelOffset, NextRelOffset);
|
|
|
|
assert(NextStop <= EndOffset && "internal overflow error");
|
|
|
|
if (FunctionOffset < NextStop) {
|
|
|
|
Streamer.EmitBytes(FunctionContents.slice(FunctionOffset, NextStop));
|
|
|
|
FunctionOffset = NextStop;
|
|
|
|
}
|
|
|
|
if (IS != Islands.Offsets.end() && FunctionOffset == IS->first) {
|
|
|
|
// This is a slightly complex code to decide which label to emit. We
|
|
|
|
// have 4 cases to handle: regular symbol, cold symbol, regular or cold
|
|
|
|
// symbol being emitted on behalf of an external function.
|
|
|
|
if (!OnBehalfOf) {
|
|
|
|
if (!EmitColdPart) {
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitted label "
|
|
|
|
<< IS->second->getName() << " at offset 0x"
|
|
|
|
<< Twine::utohexstr(IS->first) << '\n');
|
|
|
|
if (IS->second->isUndefined())
|
|
|
|
Streamer.EmitLabel(IS->second);
|
|
|
|
else
|
|
|
|
assert(BF.hasName(IS->second->getName()));
|
|
|
|
} else if (Islands.ColdSymbols.count(IS->second) != 0) {
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitted label "
|
|
|
|
<< Islands.ColdSymbols[IS->second]->getName()
|
|
|
|
<< '\n');
|
|
|
|
if (Islands.ColdSymbols[IS->second]->isUndefined())
|
|
|
|
Streamer.EmitLabel(Islands.ColdSymbols[IS->second]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!EmitColdPart) {
|
|
|
|
if (MCSymbol *Sym = Islands.Proxies[OnBehalfOf][IS->second]) {
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitted label " << Sym->getName()
|
|
|
|
<< '\n');
|
|
|
|
Streamer.EmitLabel(Sym);
|
|
|
|
}
|
|
|
|
} else if (MCSymbol *Sym =
|
|
|
|
Islands.ColdProxies[OnBehalfOf][IS->second]) {
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitted label " << Sym->getName()
|
|
|
|
<< '\n');
|
|
|
|
Streamer.EmitLabel(Sym);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++IS;
|
|
|
|
}
|
|
|
|
if (RI != BF.getMoveRelocations().end() && FunctionOffset == RI->first) {
|
|
|
|
auto RelocationSize = RI->second.emit(&Streamer);
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitted relocation for symbol "
|
|
|
|
<< RI->second.Symbol->getName() << " at offset 0x"
|
|
|
|
<< Twine::utohexstr(RI->first)
|
|
|
|
<< " with size " << RelocationSize << '\n');
|
|
|
|
FunctionOffset += RelocationSize;
|
|
|
|
++RI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(FunctionOffset <= EndOffset && "overflow error");
|
|
|
|
if (FunctionOffset < EndOffset) {
|
|
|
|
Streamer.EmitBytes(FunctionContents.slice(FunctionOffset, EndOffset));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(IS == Islands.Offsets.end() && "some symbols were not emitted!");
|
|
|
|
|
|
|
|
if (OnBehalfOf)
|
|
|
|
return;
|
|
|
|
// Now emit constant islands from other functions that we may have used in
|
|
|
|
// this function.
|
|
|
|
for (auto *ExternalFunc : Islands.Dependency) {
|
|
|
|
emitConstantIslands(*ExternalFunc, EmitColdPart, &BF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SMLoc BinaryEmitter::emitLineInfo(const BinaryFunction &BF, SMLoc NewLoc,
|
|
|
|
SMLoc PrevLoc, bool FirstInstr) {
|
|
|
|
auto *FunctionCU = BF.getDWARFUnitLineTable().first;
|
|
|
|
const auto *FunctionLineTable = BF.getDWARFUnitLineTable().second;
|
|
|
|
assert(FunctionCU && "cannot emit line info for function without CU");
|
|
|
|
|
|
|
|
auto RowReference = DebugLineTableRowRef::fromSMLoc(NewLoc);
|
|
|
|
|
|
|
|
// Check if no new line info needs to be emitted.
|
|
|
|
if (RowReference == DebugLineTableRowRef::NULL_ROW ||
|
|
|
|
NewLoc.getPointer() == PrevLoc.getPointer())
|
|
|
|
return PrevLoc;
|
|
|
|
|
|
|
|
unsigned CurrentFilenum = 0;
|
|
|
|
const auto *CurrentLineTable = FunctionLineTable;
|
|
|
|
|
|
|
|
// If the CU id from the current instruction location does not
|
|
|
|
// match the CU id from the current function, it means that we
|
|
|
|
// have come across some inlined code. We must look up the CU
|
|
|
|
// for the instruction's original function and get the line table
|
|
|
|
// from that.
|
|
|
|
const auto FunctionUnitIndex = FunctionCU->getOffset();
|
|
|
|
const auto CurrentUnitIndex = RowReference.DwCompileUnitIndex;
|
|
|
|
if (CurrentUnitIndex != FunctionUnitIndex) {
|
|
|
|
CurrentLineTable = BC.DwCtx->getLineTableForUnit(
|
|
|
|
BC.DwCtx->getCompileUnitForOffset(CurrentUnitIndex));
|
|
|
|
// Add filename from the inlined function to the current CU.
|
|
|
|
CurrentFilenum =
|
|
|
|
BC.addDebugFilenameToUnit(FunctionUnitIndex, CurrentUnitIndex,
|
|
|
|
CurrentLineTable->Rows[RowReference.RowIndex - 1].File);
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto &CurrentRow = CurrentLineTable->Rows[RowReference.RowIndex - 1];
|
|
|
|
if (!CurrentFilenum)
|
|
|
|
CurrentFilenum = CurrentRow.File;
|
|
|
|
|
|
|
|
unsigned Flags = (DWARF2_FLAG_IS_STMT * CurrentRow.IsStmt) |
|
|
|
|
(DWARF2_FLAG_BASIC_BLOCK * CurrentRow.BasicBlock) |
|
|
|
|
(DWARF2_FLAG_PROLOGUE_END * CurrentRow.PrologueEnd) |
|
|
|
|
(DWARF2_FLAG_EPILOGUE_BEGIN * CurrentRow.EpilogueBegin);
|
|
|
|
|
|
|
|
// Always emit is_stmt at the beginning of function fragment.
|
|
|
|
if (FirstInstr)
|
|
|
|
Flags |= DWARF2_FLAG_IS_STMT;
|
|
|
|
|
|
|
|
BC.Ctx->setCurrentDwarfLoc(
|
|
|
|
CurrentFilenum,
|
|
|
|
CurrentRow.Line,
|
|
|
|
CurrentRow.Column,
|
|
|
|
Flags,
|
|
|
|
CurrentRow.Isa,
|
|
|
|
CurrentRow.Discriminator);
|
|
|
|
BC.Ctx->setDwarfCompileUnitID(FunctionUnitIndex);
|
|
|
|
|
|
|
|
return NewLoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinaryEmitter::emitJumpTables(const BinaryFunction &BF) {
|
|
|
|
if (!BF.hasJumpTables())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (opts::PrintJumpTables) {
|
|
|
|
outs() << "BOLT-INFO: jump tables for function " << BF << ":\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &JTI : BF.jumpTables()) {
|
|
|
|
auto &JT = *JTI.second;
|
|
|
|
if (opts::PrintJumpTables)
|
|
|
|
JT.print(outs());
|
|
|
|
if ((opts::JumpTables == JTS_BASIC || !BF.isSimple()) &&
|
|
|
|
BC.HasRelocations) {
|
|
|
|
JT.updateOriginal();
|
|
|
|
} else {
|
|
|
|
MCSection *HotSection, *ColdSection;
|
|
|
|
if (opts::JumpTables == JTS_BASIC) {
|
|
|
|
std::string Name = ".local." + JT.Labels[0]->getName().str();
|
|
|
|
std::replace(Name.begin(), Name.end(), '/', '.');
|
|
|
|
auto &Section = BC.registerOrUpdateSection(Name,
|
|
|
|
ELF::SHT_PROGBITS,
|
|
|
|
ELF::SHF_ALLOC);
|
|
|
|
Section.setAnonymous(true);
|
|
|
|
JT.setOutputSection(Section);
|
|
|
|
HotSection = BC.getDataSection(Name);
|
|
|
|
ColdSection = HotSection;
|
|
|
|
} else {
|
|
|
|
if (BF.isSimple()) {
|
|
|
|
HotSection = BC.MOFI->getReadOnlySection();
|
|
|
|
ColdSection = BC.MOFI->getReadOnlyColdSection();
|
|
|
|
} else {
|
|
|
|
HotSection = BF.hasProfile() ? BC.MOFI->getReadOnlySection()
|
|
|
|
: BC.MOFI->getReadOnlyColdSection();
|
|
|
|
ColdSection = HotSection;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
emitJumpTable(JT, HotSection, ColdSection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinaryEmitter::emitJumpTable(const JumpTable &JT, MCSection *HotSection,
|
|
|
|
MCSection *ColdSection) {
|
|
|
|
// Pre-process entries for aggressive splitting.
|
|
|
|
// Each label represents a separate switch table and gets its own count
|
|
|
|
// determining its destination.
|
|
|
|
std::map<MCSymbol *, uint64_t> LabelCounts;
|
|
|
|
if (opts::JumpTables > JTS_SPLIT && !JT.Counts.empty()) {
|
|
|
|
MCSymbol *CurrentLabel = JT.Labels.at(0);
|
|
|
|
uint64_t CurrentLabelCount = 0;
|
|
|
|
for (unsigned Index = 0; Index < JT.Entries.size(); ++Index) {
|
|
|
|
auto LI = JT.Labels.find(Index * JT.EntrySize);
|
|
|
|
if (LI != JT.Labels.end()) {
|
|
|
|
LabelCounts[CurrentLabel] = CurrentLabelCount;
|
|
|
|
CurrentLabel = LI->second;
|
|
|
|
CurrentLabelCount = 0;
|
|
|
|
}
|
|
|
|
CurrentLabelCount += JT.Counts[Index].Count;
|
|
|
|
}
|
|
|
|
LabelCounts[CurrentLabel] = CurrentLabelCount;
|
|
|
|
} else {
|
|
|
|
Streamer.SwitchSection(JT.Count > 0 ? HotSection : ColdSection);
|
|
|
|
Streamer.EmitValueToAlignment(JT.EntrySize);
|
|
|
|
}
|
|
|
|
MCSymbol *LastLabel = nullptr;
|
|
|
|
uint64_t Offset = 0;
|
|
|
|
for (auto *Entry : JT.Entries) {
|
|
|
|
auto LI = JT.Labels.find(Offset);
|
|
|
|
if (LI != JT.Labels.end()) {
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitting jump table "
|
|
|
|
<< LI->second->getName() << " (originally was at address 0x"
|
|
|
|
<< Twine::utohexstr(JT.getAddress() + Offset)
|
|
|
|
<< (Offset ? "as part of larger jump table\n" : "\n"));
|
|
|
|
if (!LabelCounts.empty()) {
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: jump table count: "
|
|
|
|
<< LabelCounts[LI->second] << '\n');
|
|
|
|
if (LabelCounts[LI->second] > 0) {
|
|
|
|
Streamer.SwitchSection(HotSection);
|
|
|
|
} else {
|
|
|
|
Streamer.SwitchSection(ColdSection);
|
|
|
|
}
|
|
|
|
Streamer.EmitValueToAlignment(JT.EntrySize);
|
|
|
|
}
|
|
|
|
Streamer.EmitLabel(LI->second);
|
|
|
|
LastLabel = LI->second;
|
|
|
|
}
|
|
|
|
if (JT.Type == JumpTable::JTT_NORMAL) {
|
|
|
|
Streamer.EmitSymbolValue(Entry, JT.OutputEntrySize);
|
|
|
|
} else { // JTT_PIC
|
|
|
|
auto JTExpr = MCSymbolRefExpr::create(LastLabel, Streamer.getContext());
|
|
|
|
auto E = MCSymbolRefExpr::create(Entry, Streamer.getContext());
|
|
|
|
auto Value = MCBinaryExpr::createSub(E, JTExpr, Streamer.getContext());
|
|
|
|
Streamer.EmitValue(Value, JT.EntrySize);
|
|
|
|
}
|
|
|
|
Offset += JT.EntrySize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The code is based on EHStreamer::emitExceptionTable().
|
|
|
|
void BinaryEmitter::emitLSDA(BinaryFunction &BF, bool EmitColdPart) {
|
|
|
|
const auto *Sites =
|
|
|
|
EmitColdPart ? &BF.getColdCallSites() : &BF.getCallSites();
|
|
|
|
if (Sites->empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate callsite table size. Size of each callsite entry is:
|
|
|
|
//
|
|
|
|
// sizeof(start) + sizeof(length) + sizeof(LP) + sizeof(uleb128(action))
|
|
|
|
//
|
|
|
|
// or
|
|
|
|
//
|
|
|
|
// sizeof(dwarf::DW_EH_PE_data4) * 3 + sizeof(uleb128(action))
|
|
|
|
uint64_t CallSiteTableLength = Sites->size() * 4 * 3;
|
|
|
|
for (const auto &CallSite : *Sites) {
|
|
|
|
CallSiteTableLength += getULEB128Size(CallSite.Action);
|
|
|
|
}
|
|
|
|
|
|
|
|
Streamer.SwitchSection(BC.MOFI->getLSDASection());
|
|
|
|
|
|
|
|
const auto TTypeEncoding = BC.MOFI->getTTypeEncoding();
|
|
|
|
const auto TTypeEncodingSize = BC.getDWARFEncodingSize(TTypeEncoding);
|
|
|
|
const auto TTypeAlignment = 4;
|
|
|
|
|
|
|
|
// Type tables have to be aligned at 4 bytes.
|
|
|
|
Streamer.EmitValueToAlignment(TTypeAlignment);
|
|
|
|
|
|
|
|
// Emit the LSDA label.
|
|
|
|
auto *LSDASymbol = EmitColdPart ? BF.getColdLSDASymbol() : BF.getLSDASymbol();
|
|
|
|
assert(LSDASymbol && "no LSDA symbol set");
|
|
|
|
Streamer.EmitLabel(LSDASymbol);
|
|
|
|
|
|
|
|
// Corresponding FDE start.
|
|
|
|
const auto *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,
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// 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);
|
|
|
|
};
|
|
|
|
|
|
|
|
Streamer.EmitIntValue(TTypeEncoding, 1); // TType format
|
|
|
|
|
|
|
|
// See the comment in EHStreamer::emitExceptionTable() on to use
|
|
|
|
// uleb128 encoding (which can use variable number of bytes to encode the same
|
|
|
|
// value) to ensure type info table is properly aligned at 4 bytes without
|
|
|
|
// iteratively fixing sizes of the tables.
|
|
|
|
unsigned CallSiteTableLengthSize = getULEB128Size(CallSiteTableLength);
|
|
|
|
unsigned TTypeBaseOffset =
|
|
|
|
sizeof(int8_t) + // Call site format
|
|
|
|
CallSiteTableLengthSize + // Call site table length size
|
|
|
|
CallSiteTableLength + // Call site table length
|
|
|
|
BF.getLSDAActionTable().size() + // Actions table size
|
|
|
|
BF.getLSDATypeTable().size() * TTypeEncodingSize; // Types table size
|
|
|
|
unsigned TTypeBaseOffsetSize = getULEB128Size(TTypeBaseOffset);
|
|
|
|
unsigned TotalSize =
|
|
|
|
sizeof(int8_t) + // LPStart format
|
|
|
|
sizeof(int8_t) + // TType format
|
|
|
|
TTypeBaseOffsetSize + // TType base offset size
|
|
|
|
TTypeBaseOffset; // TType base offset
|
|
|
|
unsigned SizeAlign = (4 - TotalSize) & 3;
|
|
|
|
|
|
|
|
// Account for any extra padding that will be added to the call site table
|
|
|
|
// length.
|
|
|
|
Streamer.EmitPaddedULEB128IntValue(TTypeBaseOffset,
|
|
|
|
TTypeBaseOffsetSize + SizeAlign);
|
|
|
|
|
|
|
|
// Emit the landing pad call site table. We use signed data4 since we can emit
|
|
|
|
// a landing pad in a different part of the split function that could appear
|
|
|
|
// earlier in the address space than LPStart.
|
|
|
|
Streamer.EmitIntValue(dwarf::DW_EH_PE_sdata4, 1);
|
|
|
|
Streamer.EmitULEB128IntValue(CallSiteTableLength);
|
|
|
|
|
|
|
|
for (const auto &CallSite : *Sites) {
|
|
|
|
const auto *BeginLabel = CallSite.Start;
|
|
|
|
const auto *EndLabel = CallSite.End;
|
|
|
|
|
|
|
|
assert(BeginLabel && "start EH label expected");
|
|
|
|
assert(EndLabel && "end EH label expected");
|
|
|
|
|
|
|
|
// Start of the range is emitted relative to the start of current
|
|
|
|
// function split part.
|
|
|
|
Streamer.emitAbsoluteSymbolDiff(BeginLabel, StartSymbol, 4);
|
|
|
|
Streamer.emitAbsoluteSymbolDiff(EndLabel, BeginLabel, 4);
|
|
|
|
emitLandingPad(CallSite.LP);
|
|
|
|
Streamer.EmitULEB128IntValue(CallSite.Action);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write out action, type, and type index tables at the end.
|
|
|
|
//
|
|
|
|
// For action and type index tables there's no need to change the original
|
|
|
|
// table format unless we are doing function splitting, in which case we can
|
|
|
|
// split and optimize the tables.
|
|
|
|
//
|
|
|
|
// For type table we (re-)encode the table using TTypeEncoding matching
|
|
|
|
// the current assembler mode.
|
|
|
|
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];
|
|
|
|
switch (TTypeEncoding & 0x70) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unsupported TTypeEncoding");
|
|
|
|
case 0:
|
|
|
|
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();
|
|
|
|
Streamer.EmitLabel(DotSymbol);
|
|
|
|
const auto *SubDotExpr = MCBinaryExpr::createSub(
|
|
|
|
MCSymbolRefExpr::create(TypeSymbol, *BC.Ctx),
|
|
|
|
MCSymbolRefExpr::create(DotSymbol, *BC.Ctx),
|
|
|
|
*BC.Ctx);
|
|
|
|
Streamer.EmitValue(SubDotExpr, TTypeEncodingSize);
|
|
|
|
} else {
|
|
|
|
Streamer.EmitIntValue(0, TTypeEncodingSize);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto const &Byte : BF.getLSDATypeIndexTable()) {
|
|
|
|
Streamer.EmitIntValue(Byte, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinaryEmitter::emitDebugLineInfoForNonSimpleFunctions() {
|
|
|
|
for (auto &It : BC.getBinaryFunctions()) {
|
|
|
|
const auto &Function = It.second;
|
|
|
|
|
|
|
|
if (Function.isSimple())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
auto ULT = Function.getDWARFUnitLineTable();
|
|
|
|
auto Unit = ULT.first;
|
|
|
|
auto LineTable = ULT.second;
|
|
|
|
|
|
|
|
if (!LineTable)
|
|
|
|
continue; // nothing to update for this function
|
|
|
|
|
|
|
|
std::vector<uint32_t> Results;
|
|
|
|
MCSection *FunctionSection =
|
|
|
|
BC.getCodeSection(Function.getCodeSectionName());
|
|
|
|
|
|
|
|
uint64_t Address = It.first;
|
|
|
|
if (LineTable->lookupAddressRange(Address, Function.getMaxSize(),
|
|
|
|
Results)) {
|
|
|
|
auto &OutputLineTable =
|
|
|
|
BC.Ctx->getMCDwarfLineTable(Unit->getOffset()).getMCLineSections();
|
|
|
|
for (auto RowIndex : Results) {
|
|
|
|
const auto &Row = LineTable->Rows[RowIndex];
|
|
|
|
BC.Ctx->setCurrentDwarfLoc(
|
|
|
|
Row.File,
|
|
|
|
Row.Line,
|
|
|
|
Row.Column,
|
|
|
|
(DWARF2_FLAG_IS_STMT * Row.IsStmt) |
|
|
|
|
(DWARF2_FLAG_BASIC_BLOCK * Row.BasicBlock) |
|
|
|
|
(DWARF2_FLAG_PROLOGUE_END * Row.PrologueEnd) |
|
|
|
|
(DWARF2_FLAG_EPILOGUE_BEGIN * Row.EpilogueBegin),
|
|
|
|
Row.Isa,
|
|
|
|
Row.Discriminator,
|
|
|
|
Row.Address);
|
|
|
|
auto Loc = BC.Ctx->getCurrentDwarfLoc();
|
|
|
|
BC.Ctx->clearDwarfLocSeen();
|
|
|
|
OutputLineTable.addLineEntry(MCDwarfLineEntry{nullptr, Loc},
|
|
|
|
FunctionSection);
|
|
|
|
}
|
|
|
|
// Add an empty entry past the end of the function
|
|
|
|
// for end_sequence mark.
|
|
|
|
BC.Ctx->setCurrentDwarfLoc(0, 0, 0, 0, 0, 0,
|
|
|
|
Address + Function.getMaxSize());
|
|
|
|
auto Loc = BC.Ctx->getCurrentDwarfLoc();
|
|
|
|
BC.Ctx->clearDwarfLocSeen();
|
|
|
|
OutputLineTable.addLineEntry(MCDwarfLineEntry{nullptr, Loc},
|
|
|
|
FunctionSection);
|
|
|
|
} else {
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: function " << Function
|
|
|
|
<< " has no associated line number information\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinaryEmitter::emitFunctionBodyRaw(BinaryFunction &BF) {
|
|
|
|
// #14998851: Fix gold linker's '--emit-relocs'.
|
|
|
|
llvm_unreachable(
|
|
|
|
"cannot emit raw body unless relocation accuracy is guaranteed");
|
|
|
|
|
|
|
|
assert(!BF.isInjected() && "cannot emit raw body of injected function");
|
|
|
|
|
|
|
|
// Raw contents of the function.
|
|
|
|
StringRef SectionContents = BF.getSection().getContents();
|
|
|
|
|
|
|
|
// Raw contents of the function.
|
|
|
|
StringRef FunctionContents = SectionContents.substr(
|
|
|
|
BF.getAddress() - BF.getSection().getAddress(), BF.getSize());
|
|
|
|
|
|
|
|
if (opts::Verbosity)
|
|
|
|
outs() << "BOLT-INFO: emitting function " << BF << " in raw ("
|
|
|
|
<< BF.getSize() << " bytes)\n";
|
|
|
|
|
|
|
|
// We split the function blob into smaller blocks and output relocations
|
|
|
|
// and/or labels between them.
|
|
|
|
uint64_t FunctionOffset = 0;
|
|
|
|
auto LI = BF.getLabels().begin();
|
|
|
|
auto RI = BF.getMoveRelocations().begin();
|
|
|
|
while (LI != BF.getLabels().end() ||
|
|
|
|
RI != BF.getMoveRelocations().end()) {
|
|
|
|
uint64_t NextLabelOffset =
|
|
|
|
(LI == BF.getLabels().end() ? BF.getSize() : LI->first);
|
|
|
|
uint64_t NextRelocationOffset =
|
|
|
|
(RI == BF.getMoveRelocations().end() ? BF.getSize() : RI->first);
|
|
|
|
auto NextStop = std::min(NextLabelOffset, NextRelocationOffset);
|
|
|
|
assert(NextStop <= BF.getSize() && "internal overflow error");
|
|
|
|
if (FunctionOffset < NextStop) {
|
|
|
|
Streamer.EmitBytes(FunctionContents.slice(FunctionOffset, NextStop));
|
|
|
|
FunctionOffset = NextStop;
|
|
|
|
}
|
|
|
|
if (LI != BF.getLabels().end() && FunctionOffset == LI->first) {
|
|
|
|
Streamer.EmitLabel(LI->second);
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitted label " << LI->second->getName()
|
|
|
|
<< " at offset 0x" << Twine::utohexstr(LI->first) << '\n');
|
|
|
|
++LI;
|
|
|
|
}
|
|
|
|
if (RI != BF.getMoveRelocations().end() && FunctionOffset == RI->first) {
|
|
|
|
auto RelocationSize = RI->second.emit(&Streamer);
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitted relocation for symbol "
|
|
|
|
<< RI->second.Symbol->getName() << " at offset 0x"
|
|
|
|
<< Twine::utohexstr(RI->first)
|
|
|
|
<< " with size " << RelocationSize << '\n');
|
|
|
|
FunctionOffset += RelocationSize;
|
|
|
|
++RI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(FunctionOffset <= BF.getSize() && "overflow error");
|
|
|
|
if (FunctionOffset < BF.getSize()) {
|
|
|
|
Streamer.EmitBytes(FunctionContents.substr(FunctionOffset));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinaryEmitter::emitDataSections(StringRef OrgSecPrefix) {
|
|
|
|
for (const auto &Section : BC.sections()) {
|
|
|
|
if (!Section.hasRelocations() || !Section.hasSectionRef())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
StringRef SectionName = Section.getName();
|
|
|
|
std::string EmitName = Section.isReordered()
|
|
|
|
? std::string(Section.getOutputName())
|
|
|
|
: OrgSecPrefix.str() + std::string(SectionName);
|
|
|
|
Section.emitAsData(Streamer, EmitName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace bolt {
|
|
|
|
|
|
|
|
void emitBinaryContext(MCStreamer &Streamer, BinaryContext &BC,
|
|
|
|
StringRef OrgSecPrefix) {
|
|
|
|
BinaryEmitter(Streamer, BC).emitAll(OrgSecPrefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
void emitFunctionBody(MCStreamer &Streamer, BinaryFunction &BF,
|
|
|
|
bool EmitColdPart, bool EmitCodeOnly) {
|
|
|
|
BinaryEmitter(Streamer, BF.getBinaryContext()).
|
|
|
|
emitFunctionBody(BF, EmitColdPart, EmitCodeOnly);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace bolt
|
|
|
|
} // namespace llvm
|