2015-11-23 17:54:18 -08:00
|
|
|
//===--- RewriteInstance.cpp - Interface for machine-level function -------===//
|
|
|
|
|
//
|
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
|
//
|
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "BinaryBasicBlock.h"
|
|
|
|
|
#include "BinaryContext.h"
|
|
|
|
|
#include "BinaryFunction.h"
|
2016-04-15 15:59:52 -07:00
|
|
|
#include "BinaryPassManager.h"
|
2017-10-16 16:53:50 -07:00
|
|
|
#include "CacheMetrics.h"
|
2017-09-01 18:13:51 -07:00
|
|
|
#include "DataAggregator.h"
|
2015-11-23 17:54:18 -08:00
|
|
|
#include "DataReader.h"
|
|
|
|
|
#include "Exceptions.h"
|
2015-12-18 17:00:46 -08:00
|
|
|
#include "RewriteInstance.h"
|
2017-07-17 11:22:22 -07:00
|
|
|
#include "llvm/ADT/Optional.h"
|
2015-11-23 17:54:18 -08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
2016-03-02 18:40:10 -08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
2015-11-23 17:54:18 -08:00
|
|
|
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
|
|
|
|
|
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
|
|
|
|
|
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
|
|
|
|
#include "llvm/MC/MCAsmBackend.h"
|
2016-03-28 17:45:22 -07:00
|
|
|
#include "llvm/MC/MCAsmLayout.h"
|
2015-11-23 17:54:18 -08:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
|
|
|
#include "llvm/MC/MCContext.h"
|
|
|
|
|
#include "llvm/MC/MCDisassembler.h"
|
2016-03-02 18:40:10 -08:00
|
|
|
#include "llvm/MC/MCDwarf.h"
|
2015-11-23 17:54:18 -08:00
|
|
|
#include "llvm/MC/MCInstPrinter.h"
|
|
|
|
|
#include "llvm/MC/MCInstrAnalysis.h"
|
|
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
|
|
|
|
#include "llvm/MC/MCObjectFileInfo.h"
|
|
|
|
|
#include "llvm/MC/MCObjectStreamer.h"
|
|
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
|
|
|
#include "llvm/MC/MCSection.h"
|
|
|
|
|
#include "llvm/MC/MCSectionELF.h"
|
|
|
|
|
#include "llvm/MC/MCStreamer.h"
|
|
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
|
|
|
#include "llvm/MC/MCSymbol.h"
|
|
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2016-09-29 11:19:06 -07:00
|
|
|
#include "llvm/Object/SymbolicFile.h"
|
2015-11-23 17:54:18 -08:00
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
2016-11-11 14:33:34 -08:00
|
|
|
#include "llvm/Support/Dwarf.h"
|
2016-09-27 19:09:38 -07:00
|
|
|
#include "llvm/Support/DataExtractor.h"
|
2015-11-23 17:54:18 -08:00
|
|
|
#include "llvm/Support/Errc.h"
|
|
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
|
|
|
#include "llvm/Support/TargetSelect.h"
|
|
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
|
|
|
#include "llvm/Support/ToolOutputFile.h"
|
2017-05-24 14:14:16 -07:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2015-11-23 17:54:18 -08:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
|
#include <algorithm>
|
2016-01-26 16:03:58 -08:00
|
|
|
#include <fstream>
|
2015-11-23 17:54:18 -08:00
|
|
|
#include <stack>
|
|
|
|
|
#include <system_error>
|
|
|
|
|
|
|
|
|
|
#undef DEBUG_TYPE
|
2016-02-05 14:42:04 -08:00
|
|
|
#define DEBUG_TYPE "bolt"
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
using namespace object;
|
2016-02-05 14:42:04 -08:00
|
|
|
using namespace bolt;
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
namespace opts {
|
|
|
|
|
|
2017-03-28 14:40:20 -07:00
|
|
|
extern cl::OptionCategory BoltCategory;
|
|
|
|
|
extern cl::OptionCategory BoltOptCategory;
|
2017-09-01 18:13:51 -07:00
|
|
|
extern cl::OptionCategory BoltOutputCategory;
|
|
|
|
|
extern cl::OptionCategory AggregatorCategory;
|
2017-03-28 14:40:20 -07:00
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
extern cl::opt<JumpTableSupportLevel> JumpTables;
|
2017-03-03 11:35:41 -08:00
|
|
|
extern cl::opt<BinaryFunction::ReorderType> ReorderFunctions;
|
2016-09-27 19:09:38 -07:00
|
|
|
|
2017-06-13 16:29:39 -07:00
|
|
|
static cl::opt<bool>
|
2017-10-16 16:53:50 -07:00
|
|
|
PrintCacheMetrics("print-cache-metrics",
|
|
|
|
|
cl::desc("calculate and print various metrics for instruction cache"),
|
2017-06-13 16:29:39 -07:00
|
|
|
cl::init(false),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltOptCategory));
|
|
|
|
|
|
2017-09-01 18:13:51 -07:00
|
|
|
cl::opt<std::string>
|
2017-03-28 14:40:20 -07:00
|
|
|
OutputFilename("o",
|
|
|
|
|
cl::desc("<output file>"),
|
|
|
|
|
cl::Required,
|
2017-09-01 18:13:51 -07:00
|
|
|
cl::cat(BoltOutputCategory));
|
2016-09-02 14:15:29 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
static cl::opt<unsigned>
|
|
|
|
|
AlignFunctions("align-functions",
|
2017-03-28 14:40:20 -07:00
|
|
|
cl::desc("align functions at a given value (relocation mode)"),
|
|
|
|
|
cl::init(64),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltOptCategory));
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
static cl::opt<unsigned>
|
|
|
|
|
AlignFunctionsMaxBytes("align-functions-max-bytes",
|
2017-03-28 14:40:20 -07:00
|
|
|
cl::desc("maximum number of bytes to use to align functions"),
|
2017-10-10 16:36:01 -07:00
|
|
|
cl::init(32),
|
2017-03-28 14:40:20 -07:00
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltOptCategory));
|
2016-04-21 09:54:33 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
AllowStripped("allow-stripped",
|
|
|
|
|
cl::desc("allow processing of stripped binaries"),
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
BoostMacroops("boost-macroops",
|
|
|
|
|
cl::desc("try to boost macro-op fusions by avoiding the cache-line boundary"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltOptCategory));
|
2016-09-27 19:09:38 -07:00
|
|
|
|
2017-03-28 14:40:20 -07:00
|
|
|
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));
|
2016-08-29 21:11:22 -07:00
|
|
|
|
2016-09-09 12:37:37 -07:00
|
|
|
cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
DumpDotAll("dump-dot-all",
|
|
|
|
|
cl::desc("dump function CFGs to graphviz format after each stage"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-09-09 12:37:37 -07:00
|
|
|
|
2017-03-28 14:40:20 -07:00
|
|
|
static cl::opt<bool>
|
|
|
|
|
DumpEHFrame("dump-eh-frame",
|
|
|
|
|
cl::desc("dump parsed .eh_frame (debugging)"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2017-02-22 11:29:52 -08:00
|
|
|
|
2017-03-28 14:40:20 -07:00
|
|
|
static cl::opt<bool>
|
|
|
|
|
FixDebugInfoLargeFunctions("fix-debuginfo-large-functions",
|
|
|
|
|
cl::init(true),
|
|
|
|
|
cl::desc("do another pass if we encounter large functions, to correct their "
|
|
|
|
|
"debug info."),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::ReallyHidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-09-27 19:09:38 -07:00
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
static cl::list<std::string>
|
|
|
|
|
FunctionNames("funcs",
|
2017-03-28 14:40:20 -07:00
|
|
|
cl::CommaSeparated,
|
|
|
|
|
cl::desc("list of functions to optimize"),
|
|
|
|
|
cl::value_desc("func1,func2,func3,..."),
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-01-26 16:03:58 -08:00
|
|
|
static cl::opt<std::string>
|
2016-04-21 09:54:33 -07:00
|
|
|
FunctionNamesFile("funcs-file",
|
2017-03-28 14:40:20 -07:00
|
|
|
cl::desc("file with list of functions to optimize"),
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
static cl::list<std::string>
|
|
|
|
|
FunctionPadSpec("pad-funcs",
|
2017-03-28 14:40:20 -07:00
|
|
|
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));
|
2016-09-27 19:09:38 -07:00
|
|
|
|
2017-03-28 14:40:20 -07:00
|
|
|
cl::opt<bool>
|
|
|
|
|
HotText("hot-text",
|
|
|
|
|
cl::desc("hot text symbols support (relocation mode)"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltCategory));
|
|
|
|
|
|
|
|
|
|
static cl::opt<bool>
|
|
|
|
|
KeepTmp("keep-tmp",
|
|
|
|
|
cl::desc("preserve intermediate .o file"),
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
static cl::opt<bool>
|
|
|
|
|
MarkFuncs("mark-funcs",
|
2017-03-28 14:40:20 -07:00
|
|
|
cl::desc("mark function boundaries with break instruction to make "
|
|
|
|
|
"sure we accidentally don't cross them"),
|
|
|
|
|
cl::ReallyHidden,
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-04-08 19:30:27 -07:00
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
static cl::opt<unsigned>
|
2016-04-21 09:54:33 -07:00
|
|
|
MaxFunctions("max-funcs",
|
2017-03-28 14:40:20 -07:00
|
|
|
cl::desc("maximum number of functions to overwrite"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
PrintAll("print-all",
|
|
|
|
|
cl::desc("print functions after each stage"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-02-25 16:57:07 -08:00
|
|
|
|
2016-04-11 17:46:18 -07:00
|
|
|
static cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
PrintCFG("print-cfg",
|
|
|
|
|
cl::desc("print functions after CFG construction"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-04-11 17:46:18 -07:00
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
static cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
PrintDisasm("print-disasm",
|
|
|
|
|
cl::desc("print function after disassembly"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
static cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
PrintLoopInfo("print-loops",
|
|
|
|
|
cl::desc("print loop related information"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-05-02 12:47:18 -07:00
|
|
|
cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
Relocs("relocs",
|
|
|
|
|
cl::desc("relocation mode - use relocations to move functions in the binary"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltCategory));
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2017-03-28 14:40:20 -07:00
|
|
|
static cl::list<std::string>
|
|
|
|
|
SkipFunctionNames("skip-funcs",
|
|
|
|
|
cl::CommaSeparated,
|
|
|
|
|
cl::desc("list of functions to skip"),
|
|
|
|
|
cl::value_desc("func1,func2,func3,..."),
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-07-01 08:40:56 -07:00
|
|
|
|
2017-03-28 14:40:20 -07:00
|
|
|
static cl::opt<std::string>
|
|
|
|
|
SkipFunctionNamesFile("skip-funcs-file",
|
|
|
|
|
cl::desc("file with list of functions to skip"),
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2017-03-28 14:40:20 -07:00
|
|
|
cl::opt<BinaryFunction::SplittingType>
|
|
|
|
|
SplitFunctions("split-functions",
|
|
|
|
|
cl::desc("split functions into hot and cold regions"),
|
|
|
|
|
cl::init(BinaryFunction::ST_NONE),
|
|
|
|
|
cl::values(clEnumValN(BinaryFunction::ST_NONE, "0",
|
|
|
|
|
"do not split any function"),
|
|
|
|
|
clEnumValN(BinaryFunction::ST_EH, "1",
|
|
|
|
|
"split all landing pads"),
|
|
|
|
|
clEnumValN(BinaryFunction::ST_LARGE, "2",
|
|
|
|
|
"also split if function too large to fit"),
|
|
|
|
|
clEnumValN(BinaryFunction::ST_ALL, "3",
|
|
|
|
|
"split all functions"),
|
|
|
|
|
clEnumValEnd),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltOptCategory));
|
2016-05-26 10:58:01 -07:00
|
|
|
|
2017-03-28 14:40:20 -07:00
|
|
|
static cl::opt<unsigned>
|
|
|
|
|
TopCalledLimit("top-called-limit",
|
|
|
|
|
cl::desc("maximum number of functions to print in top called "
|
|
|
|
|
"functions section"),
|
|
|
|
|
cl::init(100),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
|
|
|
|
|
|
|
|
|
cl::opt<bool>
|
|
|
|
|
TrapOldCode("trap-old-code",
|
|
|
|
|
cl::desc("insert traps in old function bodies (relocation mode)"),
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(BoltCategory));
|
|
|
|
|
|
|
|
|
|
cl::opt<bool>
|
|
|
|
|
UpdateDebugSections("update-debug-sections",
|
|
|
|
|
cl::desc("update DWARF debug sections of the executable"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltCategory));
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-02-08 10:08:28 -08:00
|
|
|
static cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
UseGnuStack("use-gnu-stack",
|
|
|
|
|
cl::desc("use GNU_STACK program header for new segment (workaround for "
|
|
|
|
|
"issues with strip/objcopy)"),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltCategory));
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-07-11 18:51:13 -07:00
|
|
|
cl::opt<bool>
|
2017-03-28 14:40:20 -07:00
|
|
|
UseOldText("use-old-text",
|
|
|
|
|
cl::desc("re-use space in old .text if possible (relocation mode)"),
|
|
|
|
|
cl::cat(BoltCategory));
|
|
|
|
|
|
|
|
|
|
// The default verbosity level (0) is pretty terse, level 1 is fairly
|
|
|
|
|
// verbose and usually prints some informational message for every
|
|
|
|
|
// function processed. Level 2 is for the noisiest of messages and
|
|
|
|
|
// often prints a message per basic block.
|
|
|
|
|
// Error messages should never be suppressed by the verbosity level.
|
|
|
|
|
// Only warnings and info messages should be affected.
|
|
|
|
|
//
|
|
|
|
|
// The rational behind stream usage is as follows:
|
|
|
|
|
// outs() for info and debugging controlled by command line flags.
|
|
|
|
|
// errs() for errors and warnings.
|
|
|
|
|
// dbgs() for output within DEBUG().
|
|
|
|
|
cl::opt<unsigned>
|
|
|
|
|
Verbosity("v",
|
|
|
|
|
cl::desc("set verbosity level for diagnostic output"),
|
|
|
|
|
cl::init(0),
|
|
|
|
|
cl::ZeroOrMore,
|
|
|
|
|
cl::cat(BoltCategory));
|
2016-07-11 18:51:13 -07:00
|
|
|
|
2017-05-24 14:14:16 -07:00
|
|
|
static cl::opt<bool>
|
|
|
|
|
AddBoltInfo("add-bolt-info",
|
|
|
|
|
cl::desc("add BOLT version and command line argument information to "
|
|
|
|
|
"processed binaries"),
|
|
|
|
|
cl::init(true),
|
|
|
|
|
cl::cat(BoltCategory));
|
|
|
|
|
|
2017-09-01 18:13:51 -07:00
|
|
|
cl::opt<bool>
|
|
|
|
|
AggregateOnly("aggregate-only",
|
|
|
|
|
cl::desc("exit after writing aggregated data file"),
|
|
|
|
|
cl::Hidden,
|
|
|
|
|
cl::cat(AggregatorCategory));
|
|
|
|
|
|
2017-10-06 14:42:46 -07:00
|
|
|
static cl::opt<bool>
|
|
|
|
|
IgnoreBuildID("ignore-build-id",
|
|
|
|
|
cl::desc("continue even if build-ids in input binary and perf.data mismatch"),
|
|
|
|
|
cl::init(false),
|
|
|
|
|
cl::cat(AggregatorCategory));
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
// Check against lists of functions from options if we should
|
|
|
|
|
// optimize the function with a given name.
|
2015-12-18 17:00:46 -08:00
|
|
|
bool shouldProcess(const BinaryFunction &Function) {
|
2016-01-21 14:18:30 -08:00
|
|
|
if (opts::MaxFunctions && Function.getFunctionNumber() > opts::MaxFunctions)
|
2015-12-18 17:00:46 -08:00
|
|
|
return false;
|
|
|
|
|
|
2016-04-08 19:30:27 -07:00
|
|
|
auto populateFunctionNames = [](cl::opt<std::string> &FunctionNamesFile,
|
|
|
|
|
cl::list<std::string> &FunctionNames) {
|
|
|
|
|
assert(!FunctionNamesFile.empty() && "unexpected empty file name");
|
2016-01-26 16:03:58 -08:00
|
|
|
std::ifstream FuncsFile(FunctionNamesFile, std::ios::in);
|
|
|
|
|
std::string FuncName;
|
|
|
|
|
while (std::getline(FuncsFile, FuncName)) {
|
|
|
|
|
FunctionNames.push_back(FuncName);
|
|
|
|
|
}
|
|
|
|
|
FunctionNamesFile = "";
|
2016-04-08 19:30:27 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!FunctionNamesFile.empty())
|
|
|
|
|
populateFunctionNames(FunctionNamesFile, FunctionNames);
|
|
|
|
|
|
|
|
|
|
if (!SkipFunctionNamesFile.empty())
|
|
|
|
|
populateFunctionNames(SkipFunctionNamesFile, SkipFunctionNames);
|
2016-01-26 16:03:58 -08:00
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
bool IsValid = true;
|
|
|
|
|
if (!FunctionNames.empty()) {
|
|
|
|
|
IsValid = false;
|
|
|
|
|
for (auto &Name : FunctionNames) {
|
2016-06-10 17:13:05 -07:00
|
|
|
if (Function.hasName(Name)) {
|
2015-11-23 17:54:18 -08:00
|
|
|
IsValid = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!IsValid)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!SkipFunctionNames.empty()) {
|
|
|
|
|
for (auto &Name : SkipFunctionNames) {
|
2016-06-10 17:13:05 -07:00
|
|
|
if (Function.hasName(Name)) {
|
2015-11-23 17:54:18 -08:00
|
|
|
IsValid = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IsValid;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
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.hasName(Name)) {
|
|
|
|
|
return Padding;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
} // namespace opts
|
|
|
|
|
|
2017-05-16 09:27:34 -07:00
|
|
|
constexpr const char *RewriteInstance::SectionsToOverwrite[];
|
2017-06-27 16:25:59 -07:00
|
|
|
constexpr const char *RewriteInstance::SectionsToOverwriteRelocMode[];
|
2016-07-22 20:52:57 -07:00
|
|
|
|
2017-02-07 12:20:46 -08:00
|
|
|
const std::string RewriteInstance::OrgSecPrefix = ".bolt.org";
|
|
|
|
|
|
2017-02-07 15:31:14 -08:00
|
|
|
const std::string RewriteInstance::BOLTSecPrefix = ".bolt";
|
|
|
|
|
|
2017-05-24 14:14:16 -07:00
|
|
|
namespace llvm {
|
|
|
|
|
namespace bolt {
|
|
|
|
|
extern const char *BoltRevision;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
static void report_error(StringRef Message, std::error_code EC) {
|
|
|
|
|
assert(EC);
|
2016-02-05 14:42:04 -08:00
|
|
|
errs() << "BOLT-ERROR: '" << Message << "': " << EC.message() << ".\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_error(std::error_code EC, StringRef Message) {
|
|
|
|
|
if (!EC)
|
|
|
|
|
return;
|
|
|
|
|
report_error(Message, EC);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-18 17:00:46 -08:00
|
|
|
uint8_t *ExecutableFileMemoryManager::allocateSection(intptr_t Size,
|
|
|
|
|
unsigned Alignment,
|
|
|
|
|
unsigned SectionID,
|
|
|
|
|
StringRef SectionName,
|
|
|
|
|
bool IsCode,
|
|
|
|
|
bool IsReadOnly) {
|
|
|
|
|
uint8_t *ret;
|
|
|
|
|
if (IsCode) {
|
|
|
|
|
ret = SectionMemoryManager::allocateCodeSection(Size, Alignment,
|
|
|
|
|
SectionID, SectionName);
|
|
|
|
|
} else {
|
|
|
|
|
ret = SectionMemoryManager::allocateDataSection(Size, Alignment,
|
|
|
|
|
SectionID, SectionName,
|
|
|
|
|
IsReadOnly);
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
bool IsLocal = false;
|
|
|
|
|
if (SectionName.startswith(".local."))
|
|
|
|
|
IsLocal = true;
|
|
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "BOLT: allocating " << (IsLocal ? "local " : "")
|
2016-09-14 16:45:40 -07:00
|
|
|
<< (IsCode ? "code" : (IsReadOnly ? "read-only data" : "data"))
|
2015-12-18 17:00:46 -08:00
|
|
|
<< " section : " << SectionName
|
|
|
|
|
<< " with size " << Size << ", alignment " << Alignment
|
|
|
|
|
<< " at 0x" << ret << "\n");
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2015-12-18 17:00:46 -08:00
|
|
|
SectionMapInfo[SectionName] = SectionInfo(reinterpret_cast<uint64_t>(ret),
|
|
|
|
|
Size,
|
|
|
|
|
Alignment,
|
2016-02-08 10:02:48 -08:00
|
|
|
IsCode,
|
2016-03-28 22:39:48 -07:00
|
|
|
IsReadOnly,
|
2017-01-17 15:49:59 -08:00
|
|
|
IsLocal,
|
2016-03-28 22:39:48 -07:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
SectionID);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2015-12-18 17:00:46 -08:00
|
|
|
return ret;
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-05-16 17:02:17 -07:00
|
|
|
/// Notifier for non-allocatable (note) section.
|
2016-03-09 16:06:41 -08:00
|
|
|
uint8_t *ExecutableFileMemoryManager::recordNoteSection(
|
2016-03-03 10:13:11 -08:00
|
|
|
const uint8_t *Data,
|
|
|
|
|
uintptr_t Size,
|
|
|
|
|
unsigned Alignment,
|
|
|
|
|
unsigned SectionID,
|
|
|
|
|
StringRef SectionName) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT: note section "
|
|
|
|
|
<< SectionName
|
|
|
|
|
<< " with size " << Size << ", alignment " << Alignment
|
|
|
|
|
<< " at 0x"
|
|
|
|
|
<< Twine::utohexstr(reinterpret_cast<uint64_t>(Data)) << '\n');
|
|
|
|
|
// We need to make a copy of the section contents if we'll need it for
|
2017-04-05 09:29:24 -07:00
|
|
|
// a future reference. RuntimeDyld will not allocate the space forus.
|
|
|
|
|
uint8_t *DataCopy = new uint8_t[Size];
|
|
|
|
|
memcpy(DataCopy, Data, Size);
|
|
|
|
|
NoteSectionInfo[SectionName] =
|
|
|
|
|
SectionInfo(reinterpret_cast<uint64_t>(DataCopy),
|
|
|
|
|
Size,
|
|
|
|
|
Alignment,
|
|
|
|
|
/*IsCode=*/false,
|
|
|
|
|
/*IsReadOnly=*/true,
|
|
|
|
|
/*IsLocal=*/false,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
SectionID);
|
|
|
|
|
return DataCopy;
|
2016-03-03 10:13:11 -08:00
|
|
|
}
|
|
|
|
|
|
2015-12-18 17:00:46 -08:00
|
|
|
bool ExecutableFileMemoryManager::finalizeMemory(std::string *ErrMsg) {
|
2016-02-05 14:42:04 -08:00
|
|
|
DEBUG(dbgs() << "BOLT: finalizeMemory()\n");
|
2015-12-18 17:00:46 -08:00
|
|
|
return SectionMemoryManager::finalizeMemory(ErrMsg);
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
ExecutableFileMemoryManager::~ExecutableFileMemoryManager() {
|
|
|
|
|
for (auto &SII : NoteSectionInfo) {
|
|
|
|
|
delete[] reinterpret_cast<uint8_t *>(SII.second.AllocAddress);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-11 14:23:54 -07:00
|
|
|
namespace {
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
/// Create BinaryContext for a given architecture \p ArchName and
|
|
|
|
|
/// triple \p TripleName.
|
2017-07-25 09:11:42 -07:00
|
|
|
std::unique_ptr<BinaryContext>
|
2017-08-02 18:14:01 -07:00
|
|
|
createBinaryContext(ELFObjectFileBase *File, DataReader &DR,
|
2017-07-25 09:11:42 -07:00
|
|
|
std::unique_ptr<DWARFContext> DwCtx) {
|
|
|
|
|
std::string ArchName;
|
|
|
|
|
std::string TripleName;
|
|
|
|
|
llvm::Triple::ArchType Arch = (llvm::Triple::ArchType)File->getArch();
|
|
|
|
|
if (Arch == llvm::Triple::x86_64) {
|
|
|
|
|
ArchName = "x86-64";
|
|
|
|
|
TripleName = "x86_64-unknown-linux";
|
|
|
|
|
} else if (Arch == llvm::Triple::aarch64) {
|
|
|
|
|
ArchName = "aarch64";
|
|
|
|
|
TripleName = "aarch64-unknown-linux";
|
|
|
|
|
} else {
|
|
|
|
|
errs() << "BOLT-ERROR: Unrecognized machine in ELF file.\n";
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
std::string Error;
|
|
|
|
|
std::unique_ptr<Triple> TheTriple = llvm::make_unique<Triple>(TripleName);
|
|
|
|
|
const Target *TheTarget = TargetRegistry::lookupTarget(ArchName,
|
|
|
|
|
*TheTriple,
|
|
|
|
|
Error);
|
|
|
|
|
if (!TheTarget) {
|
2016-09-02 14:15:29 -07:00
|
|
|
errs() << "BOLT-ERROR: " << Error;
|
2015-11-23 17:54:18 -08:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<const MCRegisterInfo> MRI(
|
|
|
|
|
TheTarget->createMCRegInfo(TripleName));
|
|
|
|
|
if (!MRI) {
|
2016-09-02 14:15:29 -07:00
|
|
|
errs() << "BOLT-ERROR: no register info for target " << TripleName << "\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set up disassembler.
|
|
|
|
|
std::unique_ptr<const MCAsmInfo> AsmInfo(
|
|
|
|
|
TheTarget->createMCAsmInfo(*MRI, TripleName));
|
|
|
|
|
if (!AsmInfo) {
|
2016-09-02 14:15:29 -07:00
|
|
|
errs() << "BOLT-ERROR: no assembly info for target " << TripleName << "\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<const MCSubtargetInfo> STI(
|
|
|
|
|
TheTarget->createMCSubtargetInfo(TripleName, "", ""));
|
|
|
|
|
if (!STI) {
|
2016-09-02 14:15:29 -07:00
|
|
|
errs() << "BOLT-ERROR: no subtarget info for target " << TripleName << "\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
|
|
|
|
|
if (!MII) {
|
2016-09-02 14:15:29 -07:00
|
|
|
errs() << "BOLT-ERROR: no instruction info for target " << TripleName << "\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<MCObjectFileInfo> MOFI =
|
|
|
|
|
llvm::make_unique<MCObjectFileInfo>();
|
|
|
|
|
std::unique_ptr<MCContext> Ctx =
|
|
|
|
|
llvm::make_unique<MCContext>(AsmInfo.get(), MRI.get(), MOFI.get());
|
|
|
|
|
MOFI->InitMCObjectFileInfo(*TheTriple, Reloc::Default,
|
2017-08-27 17:04:06 -07:00
|
|
|
CodeModel::Small, *Ctx);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
std::unique_ptr<MCDisassembler> DisAsm(
|
|
|
|
|
TheTarget->createMCDisassembler(*STI, *Ctx));
|
|
|
|
|
|
|
|
|
|
if (!DisAsm) {
|
2016-09-02 14:15:29 -07:00
|
|
|
errs() << "BOLT-ERROR: no disassembler for target " << TripleName << "\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<const MCInstrAnalysis> MIA(
|
|
|
|
|
TheTarget->createMCInstrAnalysis(MII.get()));
|
|
|
|
|
if (!MIA) {
|
2016-09-02 14:15:29 -07:00
|
|
|
errs() << "BOLT-ERROR: failed to create instruction analysis for target"
|
2015-11-23 17:54:18 -08:00
|
|
|
<< TripleName << "\n";
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
|
|
|
|
|
std::unique_ptr<MCInstPrinter> InstructionPrinter(
|
|
|
|
|
TheTarget->createMCInstPrinter(Triple(TripleName), AsmPrinterVariant,
|
|
|
|
|
*AsmInfo, *MII, *MRI));
|
|
|
|
|
if (!InstructionPrinter) {
|
2016-09-02 14:15:29 -07:00
|
|
|
errs() << "BOLT-ERROR: no instruction printer for target " << TripleName
|
2015-11-23 17:54:18 -08:00
|
|
|
<< '\n';
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
InstructionPrinter->setPrintImmHex(true);
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<MCCodeEmitter> MCE(
|
|
|
|
|
TheTarget->createMCCodeEmitter(*MII, *MRI, *Ctx));
|
|
|
|
|
|
|
|
|
|
// Make sure we don't miss any output on core dumps.
|
|
|
|
|
outs().SetUnbuffered();
|
|
|
|
|
errs().SetUnbuffered();
|
|
|
|
|
dbgs().SetUnbuffered();
|
|
|
|
|
|
|
|
|
|
auto BC =
|
|
|
|
|
llvm::make_unique<BinaryContext>(std::move(Ctx),
|
2016-02-25 16:57:07 -08:00
|
|
|
std::move(DwCtx),
|
2015-11-23 17:54:18 -08:00
|
|
|
std::move(TheTriple),
|
|
|
|
|
TheTarget,
|
|
|
|
|
TripleName,
|
|
|
|
|
std::move(MCE),
|
|
|
|
|
std::move(MOFI),
|
|
|
|
|
std::move(AsmInfo),
|
|
|
|
|
std::move(MII),
|
|
|
|
|
std::move(STI),
|
|
|
|
|
std::move(InstructionPrinter),
|
|
|
|
|
std::move(MIA),
|
|
|
|
|
std::move(MRI),
|
|
|
|
|
std::move(DisAsm),
|
2016-03-14 18:48:05 -07:00
|
|
|
DR);
|
2016-03-02 18:40:10 -08:00
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
return BC;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-11 14:23:54 -07:00
|
|
|
} // namespace
|
|
|
|
|
|
2017-08-02 18:14:01 -07:00
|
|
|
RewriteInstance::RewriteInstance(ELFObjectFileBase *File, DataReader &DR,
|
2017-09-01 18:13:51 -07:00
|
|
|
DataAggregator &DA, const int Argc,
|
|
|
|
|
const char *const *Argv)
|
|
|
|
|
: InputFile(File), Argc(Argc), Argv(Argv), DA(DA),
|
2017-07-25 09:11:42 -07:00
|
|
|
BC(createBinaryContext(
|
|
|
|
|
File, DR,
|
|
|
|
|
std::unique_ptr<DWARFContext>(
|
|
|
|
|
new DWARFContextInMemory(*InputFile, nullptr, true)))) {}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
RewriteInstance::~RewriteInstance() {}
|
|
|
|
|
|
2015-11-24 09:29:41 -08:00
|
|
|
void RewriteInstance::reset() {
|
|
|
|
|
BinaryFunctions.clear();
|
|
|
|
|
FileSymRefs.clear();
|
|
|
|
|
auto &DR = BC->DR;
|
2017-07-25 09:11:42 -07:00
|
|
|
BC = createBinaryContext(
|
|
|
|
|
InputFile, DR,
|
|
|
|
|
std::unique_ptr<DWARFContext>(
|
|
|
|
|
new DWARFContextInMemory(*InputFile, nullptr, true)));
|
2015-11-24 09:29:41 -08:00
|
|
|
CFIRdWrt.reset(nullptr);
|
2017-01-17 15:49:59 -08:00
|
|
|
EFMM.reset(nullptr);
|
2015-11-24 09:29:41 -08:00
|
|
|
Out.reset(nullptr);
|
|
|
|
|
EHFrame = nullptr;
|
|
|
|
|
FailedAddresses.clear();
|
2016-04-05 19:35:45 -07:00
|
|
|
RangesSectionsWriter.reset();
|
2017-05-16 09:27:34 -07:00
|
|
|
LocationListWriter.reset();
|
2015-11-24 09:29:41 -08:00
|
|
|
TotalScore = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-01 18:13:51 -07:00
|
|
|
void RewriteInstance::aggregateData() {
|
|
|
|
|
DA.aggregate(*BC.get(), BinaryFunctions);
|
|
|
|
|
|
|
|
|
|
if (!opts::AggregateOnly)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (std::error_code EC = DA.writeAggregatedFile()) {
|
|
|
|
|
check_error(EC, "cannot create output data file");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-08 10:02:48 -08:00
|
|
|
void RewriteInstance::discoverStorage() {
|
2017-01-17 15:49:59 -08:00
|
|
|
|
|
|
|
|
EFMM.reset(new ExecutableFileMemoryManager());
|
|
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile);
|
2016-02-08 10:02:48 -08:00
|
|
|
if (!ELF64LEFile) {
|
|
|
|
|
errs() << "BOLT-ERROR: only 64-bit LE ELF binaries are supported\n";
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
auto Obj = ELF64LEFile->getELFFile();
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
EntryPoint = Obj->getHeader()->e_entry;
|
|
|
|
|
|
2016-02-08 10:02:48 -08:00
|
|
|
// This is where the first segment and ELF header were allocated.
|
|
|
|
|
uint64_t FirstAllocAddress = std::numeric_limits<uint64_t>::max();
|
|
|
|
|
|
|
|
|
|
NextAvailableAddress = 0;
|
2016-02-12 19:01:53 -08:00
|
|
|
uint64_t NextAvailableOffset = 0;
|
2016-02-08 10:02:48 -08:00
|
|
|
for (const auto &Phdr : Obj->program_headers()) {
|
|
|
|
|
if (Phdr.p_type == ELF::PT_LOAD) {
|
|
|
|
|
FirstAllocAddress = std::min(FirstAllocAddress,
|
|
|
|
|
static_cast<uint64_t>(Phdr.p_vaddr));
|
|
|
|
|
NextAvailableAddress = std::max(NextAvailableAddress,
|
|
|
|
|
Phdr.p_vaddr + Phdr.p_memsz);
|
2016-02-12 19:01:53 -08:00
|
|
|
NextAvailableOffset = std::max(NextAvailableOffset,
|
|
|
|
|
Phdr.p_offset + Phdr.p_filesz);
|
2017-01-17 15:49:59 -08:00
|
|
|
|
|
|
|
|
EFMM->SegmentMapInfo[Phdr.p_vaddr] = SegmentInfo{Phdr.p_vaddr,
|
|
|
|
|
Phdr.p_memsz,
|
|
|
|
|
Phdr.p_offset,
|
|
|
|
|
Phdr.p_filesz};
|
2016-02-08 10:02:48 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
for (const auto &Section : InputFile->sections()) {
|
|
|
|
|
StringRef SectionName;
|
|
|
|
|
Section.getName(SectionName);
|
|
|
|
|
StringRef SectionContents;
|
|
|
|
|
Section.getContents(SectionContents);
|
|
|
|
|
if (SectionName == ".text") {
|
|
|
|
|
OldTextSectionAddress = Section.getAddress();
|
|
|
|
|
OldTextSectionSize = Section.getSize();
|
|
|
|
|
OldTextSectionOffset =
|
|
|
|
|
SectionContents.data() - InputFile->getData().data();
|
2017-02-07 15:31:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SectionName.startswith(OrgSecPrefix) ||
|
|
|
|
|
SectionName.startswith(BOLTSecPrefix)) {
|
|
|
|
|
errs() << "BOLT-ERROR: input file was processed by BOLT. "
|
|
|
|
|
"Cannot re-optimize.\n";
|
|
|
|
|
exit(1);
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
assert(NextAvailableAddress && NextAvailableOffset &&
|
|
|
|
|
"no PT_LOAD pheader seen");
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2016-09-02 14:15:29 -07:00
|
|
|
outs() << "BOLT-INFO: first alloc address is 0x"
|
2016-02-08 10:02:48 -08:00
|
|
|
<< Twine::utohexstr(FirstAllocAddress) << '\n';
|
|
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
FirstNonAllocatableOffset = NextAvailableOffset;
|
|
|
|
|
|
|
|
|
|
NextAvailableAddress = RoundUpToAlignment(NextAvailableAddress, PageAlign);
|
|
|
|
|
NextAvailableOffset = RoundUpToAlignment(NextAvailableOffset, PageAlign);
|
|
|
|
|
|
|
|
|
|
if (!opts::UseGnuStack) {
|
|
|
|
|
// This is where the black magic happens. Creating PHDR table in a segment
|
|
|
|
|
// other than that containing ELF header is tricky. Some loaders and/or
|
|
|
|
|
// parts of loaders will apply e_phoff from ELF header assuming both are in
|
|
|
|
|
// the same segment, while others will do the proper calculation.
|
|
|
|
|
// We create the new PHDR table in such a way that both of the methods
|
|
|
|
|
// of loading and locating the table work. There's a slight file size
|
|
|
|
|
// overhead because of that.
|
2016-03-03 10:13:11 -08:00
|
|
|
//
|
|
|
|
|
// NB: bfd's strip command cannot do the above and will corrupt the
|
|
|
|
|
// binary during the process of stripping non-allocatable sections.
|
2016-02-12 19:01:53 -08:00
|
|
|
if (NextAvailableOffset <= NextAvailableAddress - FirstAllocAddress) {
|
|
|
|
|
NextAvailableOffset = NextAvailableAddress - FirstAllocAddress;
|
|
|
|
|
} else {
|
|
|
|
|
NextAvailableAddress = NextAvailableOffset + FirstAllocAddress;
|
|
|
|
|
}
|
|
|
|
|
assert(NextAvailableOffset == NextAvailableAddress - FirstAllocAddress &&
|
|
|
|
|
"PHDR table address calculation error");
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2016-09-02 14:15:29 -07:00
|
|
|
outs() << "BOLT-INFO: creating new program header table at address 0x"
|
2016-02-12 19:01:53 -08:00
|
|
|
<< Twine::utohexstr(NextAvailableAddress) << ", offset 0x"
|
|
|
|
|
<< Twine::utohexstr(NextAvailableOffset) << '\n';
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
PHDRTableAddress = NextAvailableAddress;
|
|
|
|
|
PHDRTableOffset = NextAvailableOffset;
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
// Reserve space for 3 extra pheaders.
|
|
|
|
|
unsigned Phnum = Obj->getHeader()->e_phnum;
|
|
|
|
|
Phnum += 3;
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
NextAvailableAddress += Phnum * sizeof(ELFFile<ELF64LE>::Elf_Phdr);
|
|
|
|
|
NextAvailableOffset += Phnum * sizeof(ELFFile<ELF64LE>::Elf_Phdr);
|
|
|
|
|
}
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
// Align at cache line.
|
|
|
|
|
NextAvailableAddress = RoundUpToAlignment(NextAvailableAddress, 64);
|
|
|
|
|
NextAvailableOffset = RoundUpToAlignment(NextAvailableOffset, 64);
|
2016-02-08 10:02:48 -08:00
|
|
|
|
|
|
|
|
NewTextSegmentAddress = NextAvailableAddress;
|
|
|
|
|
NewTextSegmentOffset = NextAvailableOffset;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-06 14:42:46 -07:00
|
|
|
Optional<std::string>
|
|
|
|
|
RewriteInstance::getBuildID() {
|
|
|
|
|
for (auto &Section : InputFile->sections()) {
|
|
|
|
|
StringRef SectionName;
|
|
|
|
|
Section.getName(SectionName);
|
|
|
|
|
|
|
|
|
|
if (SectionName != ".note.gnu.build-id")
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
StringRef SectionContents;
|
|
|
|
|
Section.getContents(SectionContents);
|
|
|
|
|
|
|
|
|
|
// Reading notes section (see Portable Formats Specification, Version 1.1,
|
|
|
|
|
// pg 2-5, section "Note Section").
|
|
|
|
|
DataExtractor DE = DataExtractor(SectionContents, true, 8);
|
|
|
|
|
uint32_t Offset = 0;
|
|
|
|
|
if (!DE.isValidOffset(Offset))
|
|
|
|
|
return NoneType();
|
|
|
|
|
uint32_t NameSz = DE.getU32(&Offset);
|
|
|
|
|
if (!DE.isValidOffset(Offset))
|
|
|
|
|
return NoneType();
|
|
|
|
|
uint32_t DescSz = DE.getU32(&Offset);
|
|
|
|
|
if (!DE.isValidOffset(Offset))
|
|
|
|
|
return NoneType();
|
|
|
|
|
uint32_t Type = DE.getU32(&Offset);
|
|
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "NameSz = " << NameSz << "; DescSz = " << DescSz
|
|
|
|
|
<< "; Type = " << Type << "\n");
|
|
|
|
|
|
|
|
|
|
// Type 3 is a GNU build-id note section
|
|
|
|
|
if (Type != 3)
|
|
|
|
|
return NoneType();
|
|
|
|
|
|
|
|
|
|
StringRef Name = SectionContents.slice(Offset, Offset + NameSz);
|
|
|
|
|
Offset = RoundUpToAlignment(Offset + NameSz, 4);
|
|
|
|
|
StringRef BinaryBuildID = SectionContents.slice(Offset, Offset + DescSz);
|
|
|
|
|
if (Name.substr(0, 3) != "GNU")
|
|
|
|
|
return NoneType();
|
|
|
|
|
|
|
|
|
|
std::string Str;
|
|
|
|
|
raw_string_ostream OS(Str);
|
|
|
|
|
auto CharIter = BinaryBuildID.bytes_begin();
|
|
|
|
|
while (CharIter != BinaryBuildID.bytes_end()) {
|
|
|
|
|
if (*CharIter < 0x10)
|
|
|
|
|
OS << "0";
|
|
|
|
|
OS << Twine::utohexstr(*CharIter);
|
|
|
|
|
++CharIter;
|
|
|
|
|
}
|
|
|
|
|
outs() << "BOLT-INFO: Binary build-id is: " << OS.str() << "\n";
|
|
|
|
|
return OS.str();
|
|
|
|
|
}
|
|
|
|
|
return NoneType();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RewriteInstance::checkBuildID() {
|
|
|
|
|
auto FileBuildID = getBuildID();
|
|
|
|
|
if (!FileBuildID) {
|
|
|
|
|
outs() << "BOLT-WARNING: Build ID will not be checked because we could not "
|
|
|
|
|
"read one from input binary\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto PerfBuildID = DA.getPerfBuildID();
|
|
|
|
|
if (!PerfBuildID) {
|
|
|
|
|
outs() << "BOLT-WARNING: Build ID will not be checked because we could not "
|
|
|
|
|
"read one from perf.data\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (*FileBuildID == *PerfBuildID)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
outs() << "BOLT-ERROR: Build ID mismatch! This indicates the input binary "
|
|
|
|
|
"supplied for data aggregation is not the same recorded by perf "
|
|
|
|
|
"when collecting profiling data.\n";
|
|
|
|
|
|
|
|
|
|
if (!opts::IgnoreBuildID) {
|
|
|
|
|
DA.abort();
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
void RewriteInstance::run() {
|
|
|
|
|
if (!BC) {
|
2016-09-02 14:15:29 -07:00
|
|
|
errs() << "BOLT-ERROR: failed to create a binary context\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-17 11:22:22 -07:00
|
|
|
auto executeRewritePass = [&](const std::set<uint64_t> &NonSimpleFunctions) {
|
|
|
|
|
discoverStorage();
|
|
|
|
|
readSpecialSections();
|
|
|
|
|
discoverFileObjects();
|
|
|
|
|
readDebugInfo();
|
|
|
|
|
readProfileData();
|
|
|
|
|
disassembleFunctions();
|
2017-09-01 18:13:51 -07:00
|
|
|
if (DA.started()) {
|
|
|
|
|
aggregateData();
|
|
|
|
|
if (opts::AggregateOnly)
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-07-17 11:22:22 -07:00
|
|
|
for (uint64_t Address : NonSimpleFunctions) {
|
|
|
|
|
auto FI = BinaryFunctions.find(Address);
|
|
|
|
|
assert(FI != BinaryFunctions.end() && "bad non-simple function address");
|
|
|
|
|
FI->second.setSimple(false);
|
|
|
|
|
}
|
|
|
|
|
runOptimizationPasses();
|
|
|
|
|
emitFunctions();
|
|
|
|
|
};
|
2016-04-11 17:46:18 -07:00
|
|
|
|
2017-07-25 09:11:42 -07:00
|
|
|
outs() << "BOLT-INFO: Target architecture: "
|
|
|
|
|
<< Triple::getArchTypeName(
|
|
|
|
|
(llvm::Triple::ArchType)InputFile->getArch())
|
|
|
|
|
<< "\n";
|
|
|
|
|
|
2017-10-06 14:42:46 -07:00
|
|
|
if (DA.started())
|
|
|
|
|
checkBuildID();
|
2017-07-17 11:22:22 -07:00
|
|
|
unsigned PassNumber = 1;
|
|
|
|
|
executeRewritePass({});
|
2017-09-01 18:13:51 -07:00
|
|
|
if (opts::AggregateOnly)
|
|
|
|
|
return;
|
2016-03-31 16:38:49 -07:00
|
|
|
|
|
|
|
|
if (opts::SplitFunctions == BinaryFunction::ST_LARGE &&
|
2016-04-11 17:46:18 -07:00
|
|
|
checkLargeFunctions()) {
|
|
|
|
|
++PassNumber;
|
2016-03-31 16:38:49 -07:00
|
|
|
// Emit again because now some functions have been split
|
2016-04-11 17:46:18 -07:00
|
|
|
outs() << "BOLT: split-functions: starting pass " << PassNumber << "...\n";
|
2016-03-31 16:38:49 -07:00
|
|
|
reset();
|
2017-07-17 11:22:22 -07:00
|
|
|
executeRewritePass({});
|
2016-03-31 16:38:49 -07:00
|
|
|
}
|
|
|
|
|
|
2016-04-11 17:46:18 -07:00
|
|
|
// Emit functions again ignoring functions which still didn't fit in their
|
|
|
|
|
// original space, so that we don't generate incorrect debugging information
|
|
|
|
|
// for them (information that would reflect the optimized version).
|
|
|
|
|
if (opts::UpdateDebugSections && opts::FixDebugInfoLargeFunctions &&
|
|
|
|
|
checkLargeFunctions()) {
|
|
|
|
|
++PassNumber;
|
2016-05-27 20:19:19 -07:00
|
|
|
outs() << "BOLT: starting pass (ignoring large functions) "
|
2016-04-11 17:46:18 -07:00
|
|
|
<< PassNumber << "...\n";
|
|
|
|
|
reset();
|
2017-07-17 11:22:22 -07:00
|
|
|
executeRewritePass(LargeFunctions);
|
2016-04-11 17:46:18 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-31 19:12:26 -07:00
|
|
|
if (opts::UpdateDebugSections)
|
|
|
|
|
updateDebugInfo();
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2017-05-24 14:14:16 -07:00
|
|
|
addBoltInfoSection();
|
|
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
// Copy allocatable part of the input.
|
2015-11-23 17:54:18 -08:00
|
|
|
std::error_code EC;
|
|
|
|
|
Out = llvm::make_unique<tool_output_file>(opts::OutputFilename, EC,
|
|
|
|
|
sys::fs::F_None, 0777);
|
|
|
|
|
check_error(EC, "cannot create output executable file");
|
2016-03-03 10:13:11 -08:00
|
|
|
Out->os() << InputFile->getData().substr(0, FirstNonAllocatableOffset);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
// Rewrite allocatable contents and copy non-allocatable parts with mods.
|
2015-11-23 17:54:18 -08:00
|
|
|
rewriteFile();
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 11:09:34 -08:00
|
|
|
void RewriteInstance::discoverFileObjects() {
|
2015-11-23 17:54:18 -08:00
|
|
|
FileSymRefs.clear();
|
|
|
|
|
BinaryFunctions.clear();
|
|
|
|
|
BC->GlobalAddresses.clear();
|
|
|
|
|
|
2016-09-29 11:19:06 -07:00
|
|
|
// For local symbols we want to keep track of associated FILE symbol name for
|
|
|
|
|
// disambiguation by combined name.
|
|
|
|
|
StringRef FileSymbolName;
|
|
|
|
|
bool SeenFileName = false;
|
|
|
|
|
struct SymbolRefHash {
|
|
|
|
|
std::size_t operator()(SymbolRef const &S) const {
|
|
|
|
|
return std::hash<decltype(DataRefImpl::p)>{}(S.getRawDataRefImpl().p);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
std::unordered_map<SymbolRef, StringRef, SymbolRefHash> SymbolToFileName;
|
|
|
|
|
for (const auto &Symbol : InputFile->symbols()) {
|
2017-02-07 15:56:00 -08:00
|
|
|
ErrorOr<StringRef> NameOrError = Symbol.getName();
|
|
|
|
|
if (NameOrError && NameOrError->startswith("__asan_init")) {
|
|
|
|
|
errs() << "BOLT-ERROR: input file was compiled or linked with sanitizer "
|
|
|
|
|
"support. Cannot optimize.\n";
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2017-03-31 07:51:30 -07:00
|
|
|
if (NameOrError && NameOrError->startswith("__llvm_coverage_mapping")) {
|
|
|
|
|
errs() << "BOLT-ERROR: input file was compiled or linked with coverage "
|
|
|
|
|
"support. Cannot optimize.\n";
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2017-02-07 15:56:00 -08:00
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
if (Symbol.getFlags() & SymbolRef::SF_Undefined)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (Symbol.getType() == SymbolRef::ST_File) {
|
2016-09-29 11:19:06 -07:00
|
|
|
check_error(NameOrError.getError(), "cannot get symbol name for file");
|
2017-09-25 18:05:37 -07:00
|
|
|
// Ignore Clang LTO artificial FILE symbol as it is not always generated,
|
|
|
|
|
// and this uncertainty is causing havoc in function name matching.
|
|
|
|
|
if (*NameOrError == "ld-temp.o")
|
|
|
|
|
continue;
|
2016-07-11 18:51:13 -07:00
|
|
|
FileSymbolName = *NameOrError;
|
|
|
|
|
SeenFileName = true;
|
2015-11-23 17:54:18 -08:00
|
|
|
continue;
|
|
|
|
|
}
|
2016-09-29 11:19:06 -07:00
|
|
|
if (!FileSymbolName.empty() &&
|
|
|
|
|
!(Symbol.getFlags() & SymbolRef::SF_Global)) {
|
|
|
|
|
SymbolToFileName[Symbol] = FileSymbolName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort symbols in the file by value.
|
|
|
|
|
std::vector<SymbolRef> SortedFileSymbols(InputFile->symbol_begin(),
|
|
|
|
|
InputFile->symbol_end());
|
|
|
|
|
std::stable_sort(SortedFileSymbols.begin(), SortedFileSymbols.end(),
|
|
|
|
|
[](const SymbolRef &A, const SymbolRef &B) {
|
2016-09-27 19:09:38 -07:00
|
|
|
// FUNC symbols have higher precedence.
|
2016-09-29 11:19:06 -07:00
|
|
|
if (*(A.getAddress()) == *(B.getAddress())) {
|
2016-09-27 19:09:38 -07:00
|
|
|
return A.getType() == SymbolRef::ST_Function &&
|
|
|
|
|
B.getType() != SymbolRef::ST_Function;
|
2016-09-29 11:19:06 -07:00
|
|
|
}
|
|
|
|
|
return *(A.getAddress()) < *(B.getAddress());
|
|
|
|
|
});
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
BinaryFunction *PreviousFunction = nullptr;
|
2016-09-29 11:19:06 -07:00
|
|
|
for (const auto &Symbol : SortedFileSymbols) {
|
|
|
|
|
// Keep undefined symbols for pretty printing?
|
|
|
|
|
if (Symbol.getFlags() & SymbolRef::SF_Undefined)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (Symbol.getType() == SymbolRef::ST_File)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ErrorOr<StringRef> NameOrError = Symbol.getName();
|
|
|
|
|
check_error(NameOrError.getError(), "cannot get symbol name");
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
ErrorOr<uint64_t> AddressOrErr = Symbol.getAddress();
|
|
|
|
|
check_error(AddressOrErr.getError(), "cannot get symbol address");
|
|
|
|
|
uint64_t Address = *AddressOrErr;
|
|
|
|
|
if (Address == 0) {
|
2016-09-02 14:15:29 -07:00
|
|
|
if (opts::Verbosity >= 1 && Symbol.getType() == SymbolRef::ST_Function)
|
2016-02-05 14:42:04 -08:00
|
|
|
errs() << "BOLT-WARNING: function with 0 address seen\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileSymRefs[Address] = Symbol;
|
|
|
|
|
|
|
|
|
|
// There's nothing horribly wrong with anonymous symbols, but let's
|
|
|
|
|
// ignore them for now.
|
2016-07-11 18:51:13 -07:00
|
|
|
if (NameOrError->empty())
|
2015-11-23 17:54:18 -08:00
|
|
|
continue;
|
|
|
|
|
|
2016-07-11 18:51:13 -07:00
|
|
|
/// It is possible we are seeing a globalized local. LLVM might treat it as
|
|
|
|
|
/// a local if it has a "private global" prefix, e.g. ".L". Thus we have to
|
|
|
|
|
/// change the prefix to enforce global scope of the symbol.
|
|
|
|
|
std::string Name =
|
|
|
|
|
NameOrError->startswith(BC->AsmInfo->getPrivateGlobalPrefix())
|
2017-07-17 11:22:22 -07:00
|
|
|
? "PG" + std::string(*NameOrError)
|
2016-07-11 18:51:13 -07:00
|
|
|
: std::string(*NameOrError);
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
// Disambiguate all local symbols before adding to symbol table.
|
2016-07-11 18:51:13 -07:00
|
|
|
// Since we don't know if we will see a global with the same name,
|
2015-11-23 17:54:18 -08:00
|
|
|
// always modify the local name.
|
2016-07-11 18:51:13 -07:00
|
|
|
//
|
|
|
|
|
// NOTE: the naming convention for local symbols should match
|
|
|
|
|
// the one we use for profile data.
|
2015-11-23 17:54:18 -08:00
|
|
|
std::string UniqueName;
|
2016-07-11 18:51:13 -07:00
|
|
|
std::string AlternativeName;
|
2015-11-23 17:54:18 -08:00
|
|
|
if (Symbol.getFlags() & SymbolRef::SF_Global) {
|
2016-07-11 18:51:13 -07:00
|
|
|
assert(BC->GlobalSymbols.find(Name) == BC->GlobalSymbols.end() &&
|
2015-11-23 17:54:18 -08:00
|
|
|
"global name not unique");
|
2016-07-11 18:51:13 -07:00
|
|
|
UniqueName = Name;
|
2015-11-23 17:54:18 -08:00
|
|
|
} else {
|
2016-07-11 18:51:13 -07:00
|
|
|
// If we have a local file name, we should create 2 variants for the
|
|
|
|
|
// function name. The reason is that perf profile might have been
|
|
|
|
|
// collected on a binary that did not have the local file name (e.g. as
|
|
|
|
|
// a side effect of stripping debug info from the binary):
|
|
|
|
|
//
|
|
|
|
|
// primary: <function>/<id>
|
|
|
|
|
// alternative: <function>/<file>/<id2>
|
|
|
|
|
//
|
|
|
|
|
// The <id> field is used for disambiguation of local symbols since there
|
|
|
|
|
// could be identical function names coming from identical file names
|
|
|
|
|
// (e.g. from different directories).
|
|
|
|
|
std::string Prefix = Name + "/";
|
|
|
|
|
std::string AltPrefix;
|
2016-09-29 11:19:06 -07:00
|
|
|
auto SFI = SymbolToFileName.find(Symbol);
|
|
|
|
|
if (SFI != SymbolToFileName.end()) {
|
|
|
|
|
AltPrefix = Prefix + std::string(SFI->second) + "/";
|
|
|
|
|
}
|
2016-07-11 18:51:13 -07:00
|
|
|
|
|
|
|
|
auto uniquifyName = [&] (std::string NamePrefix) {
|
|
|
|
|
unsigned LocalID = 1;
|
|
|
|
|
while (BC->GlobalSymbols.find(NamePrefix + std::to_string(LocalID))
|
|
|
|
|
!= BC->GlobalSymbols.end())
|
|
|
|
|
++LocalID;
|
|
|
|
|
return NamePrefix + std::to_string(LocalID);
|
|
|
|
|
};
|
|
|
|
|
UniqueName = uniquifyName(Prefix);
|
|
|
|
|
if (!AltPrefix.empty())
|
|
|
|
|
AlternativeName = uniquifyName(AltPrefix);
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
2017-08-04 11:21:05 -07:00
|
|
|
// Register names even if it's not a function, e.g. for an entry point.
|
2016-07-11 18:51:13 -07:00
|
|
|
BC->registerNameAtAddress(UniqueName, Address);
|
|
|
|
|
if (!AlternativeName.empty())
|
|
|
|
|
BC->registerNameAtAddress(AlternativeName, Address);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
ErrorOr<section_iterator> SectionOrErr = Symbol.getSection();
|
|
|
|
|
check_error(SectionOrErr.getError(), "cannot get symbol section");
|
|
|
|
|
section_iterator Section = *SectionOrErr;
|
2016-03-03 10:13:11 -08:00
|
|
|
if (Section == InputFile->section_end()) {
|
2015-11-23 17:54:18 -08:00
|
|
|
// Could be an absolute symbol. Could record for pretty printing.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-29 11:19:06 -07:00
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: considering symbol " << UniqueName
|
|
|
|
|
<< " for function\n");
|
|
|
|
|
|
|
|
|
|
if (!Section->isText()) {
|
|
|
|
|
assert(Symbol.getType() != SymbolRef::ST_Function &&
|
|
|
|
|
"unexpected function inside non-code section");
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: rejecting as symbol is not in code\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 15:47:10 -07:00
|
|
|
auto SymbolSize = ELFSymbolRef(Symbol).getSize();
|
|
|
|
|
|
2016-09-29 11:19:06 -07:00
|
|
|
// Assembly functions could be ST_NONE with 0 size. Check that the
|
|
|
|
|
// corresponding section is a code section and they are not inside any
|
|
|
|
|
// other known function to consider them.
|
|
|
|
|
//
|
|
|
|
|
// Sometimes assembly functions are not marked as functions and neither are
|
|
|
|
|
// their local labels. The only way to tell them apart is to look at
|
|
|
|
|
// symbol scope - global vs local.
|
|
|
|
|
if (Symbol.getType() != SymbolRef::ST_Function) {
|
|
|
|
|
if (PreviousFunction) {
|
|
|
|
|
if (PreviousFunction->getSize() == 0) {
|
|
|
|
|
if (PreviousFunction->isSymbolValidInScope(Symbol, SymbolSize)) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: symbol is a function local symbol\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else if (PreviousFunction->containsAddress(Address)) {
|
|
|
|
|
if (PreviousFunction->isSymbolValidInScope(Symbol, SymbolSize)) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: symbol is a function local symbol\n");
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
if (Address == PreviousFunction->getAddress() && SymbolSize == 0) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: ignoring symbol as a marker\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (opts::Verbosity > 1) {
|
|
|
|
|
errs() << "BOLT-WARNING: symbol " << UniqueName
|
|
|
|
|
<< " seen in the middle of function "
|
|
|
|
|
<< *PreviousFunction << ". Could be a new entry.\n";
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PreviousFunction &&
|
|
|
|
|
PreviousFunction->containsAddress(Address) &&
|
2016-09-27 19:09:38 -07:00
|
|
|
PreviousFunction->getAddress() != Address) {
|
|
|
|
|
if (PreviousFunction->isSymbolValidInScope(Symbol, SymbolSize)) {
|
|
|
|
|
if (opts::Verbosity >= 1) {
|
|
|
|
|
outs() << "BOLT-DEBUG: possibly another entry for function "
|
|
|
|
|
<< *PreviousFunction << " : " << UniqueName << '\n';
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
outs() << "BOLT-INFO: using " << UniqueName << " as another entry to "
|
|
|
|
|
<< "function " << *PreviousFunction << '\n';
|
|
|
|
|
|
|
|
|
|
PreviousFunction->
|
|
|
|
|
addEntryPointAtOffset(Address - PreviousFunction->getAddress());
|
|
|
|
|
|
|
|
|
|
if (!opts::Relocs)
|
|
|
|
|
PreviousFunction->setSimple(false);
|
|
|
|
|
|
|
|
|
|
// Remove the symbol from FileSymRefs so that we can skip it from
|
|
|
|
|
// in the future.
|
|
|
|
|
auto SI = FileSymRefs.find(Address);
|
|
|
|
|
assert(SI != FileSymRefs.end() && "symbol expected to be present");
|
|
|
|
|
assert(SI->second == Symbol && "wrong symbol found");
|
|
|
|
|
FileSymRefs.erase(SI);
|
2016-09-29 11:19:06 -07:00
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 11:09:34 -08:00
|
|
|
// Checkout for conflicts with function data from FDEs.
|
|
|
|
|
bool IsSimple = true;
|
|
|
|
|
auto FDEI = CFIRdWrt->getFDEs().lower_bound(Address);
|
|
|
|
|
if (FDEI != CFIRdWrt->getFDEs().end()) {
|
|
|
|
|
auto &FDE = *FDEI->second;
|
|
|
|
|
if (FDEI->first != Address) {
|
|
|
|
|
// There's no matching starting address in FDE. Make sure the previous
|
|
|
|
|
// FDE does not contain this address.
|
|
|
|
|
if (FDEI != CFIRdWrt->getFDEs().begin()) {
|
|
|
|
|
--FDEI;
|
|
|
|
|
auto &PrevFDE = *FDEI->second;
|
|
|
|
|
auto PrevStart = PrevFDE.getInitialLocation();
|
|
|
|
|
auto PrevLength = PrevFDE.getAddressRange();
|
2016-09-15 15:47:10 -07:00
|
|
|
if (Address > PrevStart && Address < PrevStart + PrevLength) {
|
2016-09-27 19:09:38 -07:00
|
|
|
errs() << "BOLT-ERROR: function " << UniqueName
|
|
|
|
|
<< " is in conflict with FDE ["
|
|
|
|
|
<< Twine::utohexstr(PrevStart) << ", "
|
|
|
|
|
<< Twine::utohexstr(PrevStart + PrevLength)
|
|
|
|
|
<< "). Skipping.\n";
|
2016-03-11 11:09:34 -08:00
|
|
|
IsSimple = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (FDE.getAddressRange() != SymbolSize) {
|
2016-09-15 15:47:10 -07:00
|
|
|
if (SymbolSize) {
|
|
|
|
|
// Function addresses match but sizes differ.
|
2017-06-02 18:41:31 -07:00
|
|
|
errs() << "BOLT-WARNING: sizes differ for function " << UniqueName
|
2016-09-27 19:09:38 -07:00
|
|
|
<< ". FDE : " << FDE.getAddressRange()
|
2017-06-02 18:41:31 -07:00
|
|
|
<< "; symbol table : " << SymbolSize << ". Using max size.\n";
|
2016-09-02 14:15:29 -07:00
|
|
|
}
|
2016-03-11 11:09:34 -08:00
|
|
|
SymbolSize = std::max(SymbolSize, FDE.getAddressRange());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-11 14:23:54 -07:00
|
|
|
BinaryFunction *BF{nullptr};
|
2016-06-10 17:13:05 -07:00
|
|
|
auto BFI = BinaryFunctions.find(Address);
|
|
|
|
|
if (BFI != BinaryFunctions.end()) {
|
2016-08-11 14:23:54 -07:00
|
|
|
BF = &BFI->second;
|
2016-06-10 17:13:05 -07:00
|
|
|
// Duplicate function name. Make sure everything matches before we add
|
|
|
|
|
// an alternative name.
|
2016-09-15 15:47:10 -07:00
|
|
|
if (SymbolSize != BF->getSize()) {
|
|
|
|
|
if (opts::Verbosity >= 1) {
|
|
|
|
|
if (SymbolSize && BF->getSize()) {
|
|
|
|
|
errs() << "BOLT-WARNING: size mismatch for duplicate entries "
|
|
|
|
|
<< *BF << " and " << UniqueName << '\n';
|
|
|
|
|
}
|
|
|
|
|
outs() << "BOLT-INFO: adjusting size of function " << *BF
|
|
|
|
|
<< " old " << BF->getSize() << " new " << SymbolSize << "\n";
|
|
|
|
|
}
|
|
|
|
|
BF->setSize(std::max(SymbolSize, BF->getSize()));
|
2016-06-10 17:13:05 -07:00
|
|
|
}
|
2016-08-11 14:23:54 -07:00
|
|
|
BF->addAlternativeName(UniqueName);
|
2016-06-10 17:13:05 -07:00
|
|
|
} else {
|
2016-08-11 14:23:54 -07:00
|
|
|
BF = createBinaryFunction(UniqueName, *Section, Address, SymbolSize,
|
|
|
|
|
IsSimple);
|
2016-06-10 17:13:05 -07:00
|
|
|
}
|
2016-07-11 18:51:13 -07:00
|
|
|
if (!AlternativeName.empty())
|
2016-08-11 14:23:54 -07:00
|
|
|
BF->addAlternativeName(AlternativeName);
|
2016-09-29 11:19:06 -07:00
|
|
|
|
|
|
|
|
PreviousFunction = BF;
|
2016-07-11 18:51:13 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-04 11:21:05 -07:00
|
|
|
// Process PLT section.
|
|
|
|
|
disassemblePLT();
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// See if we missed any functions marked by FDE.
|
|
|
|
|
for (const auto &FDEI : CFIRdWrt->getFDEs()) {
|
|
|
|
|
const auto Address = FDEI.first;
|
|
|
|
|
const auto *FDE = FDEI.second;
|
2017-08-04 11:21:05 -07:00
|
|
|
const auto *BF = getBinaryFunctionAtAddress(Address);
|
2016-09-27 19:09:38 -07:00
|
|
|
if (!BF) {
|
2017-08-04 11:21:05 -07:00
|
|
|
if (const auto *PartialBF = getBinaryFunctionContainingAddress(Address)) {
|
2017-07-17 11:22:22 -07:00
|
|
|
errs() << "BOLT-WARNING: FDE [0x" << Twine::utohexstr(Address) << ", 0x"
|
|
|
|
|
<< Twine::utohexstr(Address + FDE->getAddressRange())
|
2017-08-04 11:21:05 -07:00
|
|
|
<< ") conflicts with function " << *PartialBF << '\n';
|
2016-09-27 19:09:38 -07:00
|
|
|
} else {
|
2017-08-04 11:21:05 -07:00
|
|
|
if (opts::Verbosity >= 1) {
|
|
|
|
|
errs() << "BOLT-WARNING: FDE [0x" << Twine::utohexstr(Address)
|
|
|
|
|
<< ", 0x" << Twine::utohexstr(Address + FDE->getAddressRange())
|
|
|
|
|
<< ") has no corresponding symbol table entry\n";
|
|
|
|
|
}
|
|
|
|
|
auto Section = BC->getSectionForAddress(Address);
|
|
|
|
|
assert(Section && "cannot get section for address from FDE");
|
2016-09-27 19:09:38 -07:00
|
|
|
std::string FunctionName =
|
|
|
|
|
"__BOLT_FDE_FUNCat" + Twine::utohexstr(Address).str();
|
|
|
|
|
createBinaryFunction(FunctionName, *Section, Address,
|
|
|
|
|
FDE->getAddressRange(), true);
|
|
|
|
|
}
|
2017-06-02 18:41:31 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-11 18:51:13 -07:00
|
|
|
if (!SeenFileName && BC->DR.hasLocalsWithFileName() && !opts::AllowStripped) {
|
|
|
|
|
errs() << "BOLT-ERROR: input binary does not have local file symbols "
|
|
|
|
|
"but profile data includes function names with embedded file "
|
|
|
|
|
"names. It appears that the input binary was stripped while a "
|
|
|
|
|
"profiled binary was not. If you know what you are doing and "
|
|
|
|
|
"wish to proceed, use -allow-stripped option.\n";
|
|
|
|
|
exit(1);
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
2016-09-29 11:19:06 -07:00
|
|
|
|
|
|
|
|
// Now that all the functions were created - adjust their boundaries.
|
|
|
|
|
adjustFunctionBoundaries();
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
if (!opts::Relocs)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Read all relocations now that we have binary functions mapped.
|
|
|
|
|
for (const auto &Section : InputFile->sections()) {
|
|
|
|
|
if (Section.relocation_begin() != Section.relocation_end()) {
|
|
|
|
|
readRelocations(Section);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-29 11:19:06 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-04 11:21:05 -07:00
|
|
|
void RewriteInstance::disassemblePLT() {
|
|
|
|
|
if (!PLTSection.getObject())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const auto PLTAddress = PLTSection.getAddress();
|
|
|
|
|
StringRef PLTContents;
|
|
|
|
|
PLTSection.getContents(PLTContents);
|
|
|
|
|
ArrayRef<uint8_t> PLTData(
|
|
|
|
|
reinterpret_cast<const uint8_t *>(PLTContents.data()),
|
|
|
|
|
PLTSection.getSize());
|
|
|
|
|
|
|
|
|
|
// Pseudo function for the start of PLT. The table could have a matching
|
|
|
|
|
// FDE that we want to match to pseudo function.
|
|
|
|
|
createBinaryFunction("__BOLT_PLT_PSEUDO" , PLTSection, PLTAddress, 0, false);
|
|
|
|
|
for (uint64_t Offset = 0; Offset < PLTSection.getSize(); Offset += 0x10) {
|
|
|
|
|
uint64_t InstrSize;
|
|
|
|
|
MCInst Instruction;
|
|
|
|
|
const uint64_t InstrAddr = PLTAddress + Offset;
|
|
|
|
|
if (!BC->DisAsm->getInstruction(Instruction,
|
|
|
|
|
InstrSize,
|
|
|
|
|
PLTData.slice(Offset),
|
|
|
|
|
InstrAddr,
|
|
|
|
|
nulls(),
|
|
|
|
|
nulls())) {
|
|
|
|
|
errs() << "BOLT-ERROR: unable to disassemble instruction in .plt "
|
|
|
|
|
<< "at offset 0x" << Twine::utohexstr(Offset) << '\n';
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!BC->MIA->isIndirectBranch(Instruction))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
uint64_t TargetAddress;
|
|
|
|
|
if (!BC->MIA->evaluateMemOperandTarget(Instruction,
|
|
|
|
|
TargetAddress,
|
|
|
|
|
InstrAddr,
|
|
|
|
|
InstrSize)) {
|
|
|
|
|
errs() << "BOLT-ERROR: error evaluating PLT instruction at offset 0x"
|
|
|
|
|
<< Twine::utohexstr(InstrAddr) << '\n';
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// To get the name we have to read a relocation against the address.
|
|
|
|
|
for (const auto &Rel : RelaPLTSection.relocations()) {
|
|
|
|
|
if (Rel.getType() != ELF::R_X86_64_JUMP_SLOT)
|
|
|
|
|
continue;
|
|
|
|
|
if (Rel.getOffset() == TargetAddress) {
|
|
|
|
|
const auto SymbolIter = Rel.getSymbol();
|
|
|
|
|
assert(SymbolIter != InputFile->symbol_end() &&
|
|
|
|
|
"non-null symbol expected");
|
|
|
|
|
const auto SymbolName = *(*SymbolIter).getName();
|
|
|
|
|
std::string Name = SymbolName.str() + "@PLT";
|
|
|
|
|
auto *BF = createBinaryFunction(Name,
|
|
|
|
|
PLTSection,
|
|
|
|
|
InstrAddr,
|
|
|
|
|
0,
|
|
|
|
|
/*IsSimple=*/false);
|
|
|
|
|
auto TargetSymbol = BC->registerNameAtAddress(SymbolName.str() + "@GOT",
|
|
|
|
|
TargetAddress);
|
|
|
|
|
BF->setPLTSymbol(TargetSymbol);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PLTGOTSection.getObject()) {
|
|
|
|
|
// Check if we need to create a function for .plt.got. Some linkers
|
|
|
|
|
// (depending on the version) would mark it with FDE while others wouldn't.
|
|
|
|
|
if (!getBinaryFunctionAtAddress(PLTGOTSection.getAddress())) {
|
|
|
|
|
createBinaryFunction("__BOLT_PLT_GOT_PSEUDO" , PLTGOTSection,
|
|
|
|
|
PLTGOTSection.getAddress(), 0, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-29 11:19:06 -07:00
|
|
|
void RewriteInstance::adjustFunctionBoundaries() {
|
|
|
|
|
for (auto &BFI : BinaryFunctions) {
|
|
|
|
|
auto &Function = BFI.second;
|
|
|
|
|
|
|
|
|
|
// Check if there's a symbol with a larger address in the same section.
|
|
|
|
|
// If there is - it determines the maximum size for the current function,
|
|
|
|
|
// otherwise, it is the size of containing section the defines it.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: ignore some symbols that could be tolerated inside the body
|
|
|
|
|
// of a function.
|
|
|
|
|
auto NextSymRefI = FileSymRefs.upper_bound(Function.getAddress());
|
|
|
|
|
while (NextSymRefI != FileSymRefs.end()) {
|
|
|
|
|
auto &Symbol = NextSymRefI->second;
|
|
|
|
|
auto SymbolSize = ELFSymbolRef(Symbol).getSize();
|
|
|
|
|
|
|
|
|
|
if (!Function.isSymbolValidInScope(Symbol, SymbolSize))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// This is potentially another entry point into the function.
|
|
|
|
|
auto EntryOffset = NextSymRefI->first - Function.getAddress();
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: adding entry point to function "
|
|
|
|
|
<< Function << " at offset 0x"
|
|
|
|
|
<< Twine::utohexstr(EntryOffset) << '\n');
|
|
|
|
|
Function.addEntryPointAtOffset(EntryOffset);
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
// In non-relocation mode there's potentially an external undetectable
|
|
|
|
|
// reference to the entry point and hence we cannot move this entry point.
|
|
|
|
|
// Optimizing without moving could be difficult.
|
|
|
|
|
if (!opts::Relocs)
|
|
|
|
|
Function.setSimple(false);
|
2016-09-29 11:19:06 -07:00
|
|
|
|
|
|
|
|
++NextSymRefI;
|
|
|
|
|
}
|
|
|
|
|
auto NextSymRefSectionI = (NextSymRefI == FileSymRefs.end())
|
|
|
|
|
? InputFile->section_end()
|
|
|
|
|
: NextSymRefI->second.getSection();
|
|
|
|
|
|
|
|
|
|
uint64_t MaxSize;
|
|
|
|
|
if (NextSymRefI != FileSymRefs.end() &&
|
|
|
|
|
NextSymRefI->second.getSection() &&
|
|
|
|
|
*NextSymRefI->second.getSection() != InputFile->section_end() &&
|
|
|
|
|
**NextSymRefI->second.getSection() == Function.getSection()) {
|
|
|
|
|
MaxSize = NextSymRefI->first - Function.getAddress();
|
|
|
|
|
} else {
|
|
|
|
|
// Function runs till the end of the containing section.
|
|
|
|
|
uint64_t SectionEnd = Function.getSection().getAddress() +
|
|
|
|
|
Function.getSection().getSize();
|
|
|
|
|
assert((NextSymRefI == FileSymRefs.end() ||
|
|
|
|
|
NextSymRefI->first >= SectionEnd) &&
|
|
|
|
|
"different sections should not overlap");
|
|
|
|
|
MaxSize = SectionEnd - Function.getAddress();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MaxSize < Function.getSize()) {
|
2016-09-27 19:09:38 -07:00
|
|
|
errs() << "BOLT-ERROR: symbol seen in the middle of the function "
|
|
|
|
|
<< Function << ". Skipping.\n";
|
2016-09-29 11:19:06 -07:00
|
|
|
Function.setSimple(false);
|
2016-09-27 19:09:38 -07:00
|
|
|
Function.setMaxSize(Function.getSize());
|
2016-09-29 11:19:06 -07:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Function.setMaxSize(MaxSize);
|
2016-09-27 19:09:38 -07:00
|
|
|
if (!Function.getSize() && Function.isSimple()) {
|
2016-09-29 11:19:06 -07:00
|
|
|
// Some assembly functions have their size set to 0, use the max
|
|
|
|
|
// size as their real size.
|
|
|
|
|
if (opts::Verbosity >= 1) {
|
|
|
|
|
outs() << "BOLT-INFO: setting size of function " << Function
|
|
|
|
|
<< " to " << Function.getMaxSize() << " (was 0)\n";
|
|
|
|
|
}
|
|
|
|
|
Function.setSize(Function.getMaxSize());
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
2016-11-11 14:33:34 -08:00
|
|
|
void RewriteInstance::relocateEHFrameSection() {
|
|
|
|
|
assert(EHFrameSection.getObject() != nullptr &&
|
|
|
|
|
"non-empty .eh_frame section expected");
|
|
|
|
|
|
|
|
|
|
DWARFFrame EHFrame(EHFrameSection.getAddress());
|
|
|
|
|
StringRef EHFrameSectionContents;
|
|
|
|
|
EHFrameSection.getContents(EHFrameSectionContents);
|
|
|
|
|
DataExtractor DE(EHFrameSectionContents,
|
|
|
|
|
BC->AsmInfo->isLittleEndian(),
|
|
|
|
|
BC->AsmInfo->getPointerSize());
|
|
|
|
|
auto createReloc = [&](uint64_t Value, uint64_t Offset, uint64_t DwarfType) {
|
|
|
|
|
if (DwarfType == dwarf::DW_EH_PE_omit)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!(DwarfType & dwarf::DW_EH_PE_pcrel) &&
|
|
|
|
|
!(DwarfType & dwarf::DW_EH_PE_textrel) &&
|
|
|
|
|
!(DwarfType & dwarf::DW_EH_PE_funcrel) &&
|
|
|
|
|
!(DwarfType & dwarf::DW_EH_PE_datarel)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(DwarfType & dwarf::DW_EH_PE_sdata4))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint64_t RelType;
|
|
|
|
|
switch (DwarfType & 0x0f) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("unsupported DWARF encoding type");
|
|
|
|
|
case dwarf::DW_EH_PE_sdata4:
|
|
|
|
|
case dwarf::DW_EH_PE_udata4:
|
|
|
|
|
RelType = ELF::R_X86_64_PC32;
|
|
|
|
|
break;
|
|
|
|
|
case dwarf::DW_EH_PE_sdata8:
|
|
|
|
|
case dwarf::DW_EH_PE_udata8:
|
|
|
|
|
RelType = ELF::R_X86_64_PC64;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto *Symbol = BC->getGlobalSymbolAtAddress(Value);
|
|
|
|
|
if (!Symbol) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: creating symbol for DWARF reference at 0x"
|
|
|
|
|
<< Twine::utohexstr(Value) << '\n');
|
|
|
|
|
Symbol = BC->getOrCreateGlobalSymbol(Value, "FUNCat");
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: adding DWARF reference against symbol "
|
|
|
|
|
<< Symbol->getName() << '\n');
|
|
|
|
|
|
|
|
|
|
BC->addSectionRelocation(EHFrameSection, Offset, Symbol, RelType);
|
2016-11-11 14:33:34 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EHFrame.parse(DE, createReloc);
|
|
|
|
|
|
|
|
|
|
if (!EHFrame.ParseError.empty()) {
|
|
|
|
|
errs() << "BOLT-ERROR: EHFrame reader failed with message \""
|
|
|
|
|
<< EHFrame.ParseError << '\n';
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-11 14:23:54 -07:00
|
|
|
BinaryFunction *RewriteInstance::createBinaryFunction(
|
|
|
|
|
const std::string &Name, SectionRef Section, uint64_t Address,
|
|
|
|
|
uint64_t Size, bool IsSimple) {
|
|
|
|
|
auto Result = BinaryFunctions.emplace(
|
|
|
|
|
Address, BinaryFunction(Name, Section, Address, Size, *BC, IsSimple));
|
|
|
|
|
assert(Result.second == true && "unexpected duplicate function");
|
|
|
|
|
auto *BF = &Result.first->second;
|
2017-08-04 11:21:05 -07:00
|
|
|
BC->registerNameAtAddress(Name, Address);
|
2016-08-11 14:23:54 -07:00
|
|
|
BC->SymbolToFunctionMap[BF->getSymbol()] = BF;
|
|
|
|
|
return BF;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
void RewriteInstance::readSpecialSections() {
|
2017-03-22 22:05:50 -07:00
|
|
|
bool HasTextRelocations = false;
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
// Process special sections.
|
2016-03-03 10:13:11 -08:00
|
|
|
for (const auto &Section : InputFile->sections()) {
|
2015-11-23 17:54:18 -08:00
|
|
|
StringRef SectionName;
|
|
|
|
|
check_error(Section.getName(SectionName), "cannot get section name");
|
|
|
|
|
StringRef SectionContents;
|
|
|
|
|
check_error(Section.getContents(SectionContents),
|
|
|
|
|
"cannot get section contents");
|
|
|
|
|
ArrayRef<uint8_t> SectionData(
|
|
|
|
|
reinterpret_cast<const uint8_t *>(SectionContents.data()),
|
|
|
|
|
Section.getSize());
|
|
|
|
|
|
|
|
|
|
if (SectionName == ".gcc_except_table") {
|
|
|
|
|
LSDAData = SectionData;
|
|
|
|
|
LSDAAddress = Section.getAddress();
|
2016-04-01 11:37:28 -07:00
|
|
|
} else if (SectionName == ".debug_loc") {
|
|
|
|
|
DebugLocSize = Section.getSize();
|
2016-11-11 14:33:34 -08:00
|
|
|
} else if (SectionName == ".eh_frame") {
|
|
|
|
|
EHFrameSection = Section;
|
2017-03-22 22:05:50 -07:00
|
|
|
} else if (SectionName == ".rela.text") {
|
|
|
|
|
HasTextRelocations = true;
|
2017-05-15 15:21:59 -07:00
|
|
|
} else if (SectionName == ".gdb_index") {
|
|
|
|
|
GdbIndexSection = Section;
|
2017-08-04 11:21:05 -07:00
|
|
|
} else if (SectionName == ".plt") {
|
|
|
|
|
PLTSection = Section;
|
|
|
|
|
} else if (SectionName == ".got.plt") {
|
|
|
|
|
GOTPLTSection = Section;
|
2017-06-02 18:41:31 -07:00
|
|
|
} else if (SectionName == ".plt.got") {
|
|
|
|
|
PLTGOTSection = Section;
|
2017-08-04 11:21:05 -07:00
|
|
|
} else if (SectionName == ".rela.plt") {
|
|
|
|
|
RelaPLTSection = Section;
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
2016-07-21 12:45:35 -07:00
|
|
|
|
2016-08-22 14:24:09 -07:00
|
|
|
// Ignore zero-size allocatable sections as they present no interest to us.
|
2017-06-02 18:41:31 -07:00
|
|
|
// Note that .tbss is marked as having a positive size while in reality it
|
|
|
|
|
// is not taking any allocatable space.
|
2016-09-27 19:09:38 -07:00
|
|
|
if ((ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC) &&
|
2017-06-02 18:41:31 -07:00
|
|
|
Section.getSize() > 0 &&
|
|
|
|
|
SectionName != ".tbss") {
|
2016-07-21 12:45:35 -07:00
|
|
|
BC->AllocatableSections.emplace(std::make_pair(Section.getAddress(),
|
|
|
|
|
Section));
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
2017-03-22 22:05:50 -07:00
|
|
|
if (opts::Relocs && !HasTextRelocations) {
|
|
|
|
|
errs() << "BOLT-ERROR: relocations against code are missing from the input "
|
|
|
|
|
"file. Cannot proceed in relocations mode (-relocs).\n";
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
// Process debug sections.
|
2016-02-25 16:57:07 -08:00
|
|
|
EHFrame = BC->DwCtx->getEHFrame();
|
2015-11-23 17:54:18 -08:00
|
|
|
if (opts::DumpEHFrame) {
|
2016-11-15 10:40:00 -08:00
|
|
|
outs() << "BOLT-INFO: Dumping original binary .eh_frame\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
EHFrame->dump(outs());
|
|
|
|
|
}
|
2016-11-14 16:39:55 -08:00
|
|
|
CFIRdWrt.reset(new CFIReaderWriter(*EHFrame));
|
2015-11-23 17:54:18 -08:00
|
|
|
if (!EHFrame->ParseError.empty()) {
|
2016-02-05 14:42:04 -08:00
|
|
|
errs() << "BOLT-ERROR: EHFrame reader failed with message \""
|
2016-11-14 16:39:55 -08:00
|
|
|
<< EHFrame->ParseError << '\n';
|
2015-11-24 13:55:44 -08:00
|
|
|
exit(1);
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
namespace {
|
|
|
|
|
template <typename ELFT>
|
|
|
|
|
int64_t getRelocationAddend(const ELFObjectFile<ELFT> *Obj,
|
|
|
|
|
const RelocationRef &RelRef) {
|
|
|
|
|
int64_t Addend = 0;
|
|
|
|
|
const ELFFile<ELFT> &EF = *Obj->getELFFile();
|
|
|
|
|
DataRefImpl Rel = RelRef.getRawDataRefImpl();
|
|
|
|
|
const auto *RelocationSection = *(EF.getSection(Rel.d.a));
|
|
|
|
|
switch (RelocationSection->sh_type) {
|
|
|
|
|
default: llvm_unreachable("unexpected relocation section type");
|
|
|
|
|
case ELF::SHT_REL:
|
|
|
|
|
break;
|
|
|
|
|
case ELF::SHT_RELA: {
|
|
|
|
|
const auto *RelA = Obj->getRela(Rel);
|
|
|
|
|
Addend = RelA->r_addend;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Addend;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t getRelocationAddend(const ELFObjectFileBase *Obj,
|
|
|
|
|
const RelocationRef &Rel) {
|
|
|
|
|
if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj))
|
|
|
|
|
return getRelocationAddend(ELF32LE, Rel);
|
|
|
|
|
if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj))
|
|
|
|
|
return getRelocationAddend(ELF64LE, Rel);
|
|
|
|
|
if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj))
|
|
|
|
|
return getRelocationAddend(ELF32BE, Rel);
|
|
|
|
|
auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);
|
|
|
|
|
return getRelocationAddend(ELF64BE, Rel);
|
|
|
|
|
}
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
|
|
void RewriteInstance::readRelocations(const SectionRef &Section) {
|
|
|
|
|
StringRef SectionName;
|
|
|
|
|
Section.getName(SectionName);
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: relocations for section "
|
|
|
|
|
<< SectionName << ":\n");
|
|
|
|
|
if (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: ignoring runtime relocations\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto SecIter = Section.getRelocatedSection();
|
|
|
|
|
assert(SecIter != InputFile->section_end() && "relocated section expected");
|
|
|
|
|
auto RelocatedSection = *SecIter;
|
|
|
|
|
|
|
|
|
|
StringRef RelocatedSectionName;
|
|
|
|
|
RelocatedSection.getName(RelocatedSectionName);
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: relocated section is "
|
|
|
|
|
<< RelocatedSectionName << '\n');
|
|
|
|
|
|
|
|
|
|
if (!(ELFSectionRef(RelocatedSection).getFlags() & ELF::SHF_ALLOC)) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocations against "
|
|
|
|
|
<< "non-allocatable section\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const bool SkipRelocs = StringSwitch<bool>(RelocatedSectionName)
|
|
|
|
|
.Cases(".plt", ".rela.plt", ".got.plt", ".eh_frame", true)
|
|
|
|
|
.Default(false);
|
|
|
|
|
if (SkipRelocs) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocations against known section\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For value extraction.
|
|
|
|
|
StringRef RelocatedSectionContents;
|
|
|
|
|
RelocatedSection.getContents(RelocatedSectionContents);
|
|
|
|
|
DataExtractor DE(RelocatedSectionContents,
|
|
|
|
|
BC->AsmInfo->isLittleEndian(),
|
|
|
|
|
BC->AsmInfo->getPointerSize());
|
|
|
|
|
|
|
|
|
|
bool IsFromCode = RelocatedSection.isText();
|
|
|
|
|
for (const auto &Rel : Section.relocations()) {
|
|
|
|
|
SmallString<16> TypeName;
|
|
|
|
|
Rel.getTypeName(TypeName);
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: offset = 0x"
|
|
|
|
|
<< Twine::utohexstr(Rel.getOffset())
|
|
|
|
|
<< "; type name = " << TypeName
|
|
|
|
|
<< '\n');
|
|
|
|
|
|
2017-09-13 11:21:47 -07:00
|
|
|
if (Rel.getType() == ELF::R_X86_64_TLSGD ||
|
|
|
|
|
Rel.getType() == ELF::R_X86_64_TLSLD ||
|
|
|
|
|
Rel.getType() == ELF::R_X86_64_DTPOFF32) {
|
|
|
|
|
DEBUG(dbgs() << "skipping relocation\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Extract value.
|
|
|
|
|
uint32_t RelocationOffset =
|
|
|
|
|
Rel.getOffset() - RelocatedSection.getAddress();
|
|
|
|
|
auto ExtractedValue = static_cast<uint64_t>(
|
|
|
|
|
DE.getSigned(&RelocationOffset,
|
|
|
|
|
Relocation::getSizeForType(Rel.getType())));
|
|
|
|
|
|
|
|
|
|
bool IsPCRelative = Relocation::isPCRelative(Rel.getType());
|
|
|
|
|
auto Addend = getRelocationAddend(InputFile, Rel);
|
|
|
|
|
uint64_t Address = 0;
|
|
|
|
|
uint64_t SymbolAddress = 0;
|
|
|
|
|
auto SymbolIter = Rel.getSymbol();
|
|
|
|
|
std::string SymbolName = "<no symbol>";
|
|
|
|
|
SymbolAddress = *SymbolIter->getAddress();
|
|
|
|
|
if (!SymbolAddress) {
|
|
|
|
|
Address = ExtractedValue;
|
|
|
|
|
if (IsPCRelative) {
|
|
|
|
|
Address += Rel.getOffset();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Address = SymbolAddress + Addend;
|
|
|
|
|
}
|
2017-02-14 22:55:10 -08:00
|
|
|
bool SymbolIsSection = false;
|
2016-09-27 19:09:38 -07:00
|
|
|
if (SymbolIter != InputFile->symbol_end()) {
|
|
|
|
|
SymbolName = (*(*SymbolIter).getName());
|
|
|
|
|
if (SymbolIter->getType() == SymbolRef::ST_Debug) {
|
|
|
|
|
// Weird stuff - section symbols are marked as ST_Debug.
|
2017-02-14 22:55:10 -08:00
|
|
|
SymbolIsSection = true;
|
2016-09-27 19:09:38 -07:00
|
|
|
auto SymbolSection = SymbolIter->getSection();
|
|
|
|
|
if (SymbolSection && *SymbolSection != InputFile->section_end()) {
|
|
|
|
|
StringRef SymbolSectionName;
|
|
|
|
|
(*SymbolSection)->getName(SymbolSectionName);
|
|
|
|
|
SymbolName = "section " + std::string(SymbolSectionName);
|
|
|
|
|
Address = Addend;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ForceRelocation = false;
|
|
|
|
|
if (opts::HotText &&
|
|
|
|
|
(SymbolName == "__hot_start" || SymbolName == "__hot_end")) {
|
|
|
|
|
ForceRelocation = true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-02 18:41:31 -07:00
|
|
|
bool IsAbsoluteCodeRefWithAddend = false;
|
2017-02-14 22:55:10 -08:00
|
|
|
if (!IsPCRelative && Addend != 0 && IsFromCode && !SymbolIsSection) {
|
|
|
|
|
auto RefSection = BC->getSectionForAddress(SymbolAddress);
|
|
|
|
|
if (RefSection && RefSection->isText()) {
|
2017-07-17 11:22:22 -07:00
|
|
|
if (opts::Verbosity > 1) {
|
|
|
|
|
errs() << "BOLT-WARNING: detected absolute reference from code into "
|
|
|
|
|
<< "a middle of a function:\n"
|
|
|
|
|
<< " offset = 0x" << Twine::utohexstr(Rel.getOffset())
|
|
|
|
|
<< "; symbol = " << SymbolName
|
|
|
|
|
<< "; symbol address = 0x" << Twine::utohexstr(SymbolAddress)
|
|
|
|
|
<< "; addend = 0x" << Twine::utohexstr(Addend)
|
|
|
|
|
<< "; address = 0x" << Twine::utohexstr(Address)
|
|
|
|
|
<< "; type = " << Rel.getType()
|
|
|
|
|
<< "; type name = " << TypeName
|
|
|
|
|
<< '\n';
|
|
|
|
|
}
|
2017-02-14 22:55:10 -08:00
|
|
|
assert(ExtractedValue == SymbolAddress + Addend && "value mismatch");
|
2017-06-02 18:41:31 -07:00
|
|
|
Address = SymbolAddress;
|
|
|
|
|
IsAbsoluteCodeRefWithAddend = true;
|
2017-02-14 22:55:10 -08:00
|
|
|
}
|
2017-06-02 18:41:31 -07:00
|
|
|
} else if (Addend < 0 && IsPCRelative) {
|
2016-09-27 19:09:38 -07:00
|
|
|
Address -= Addend;
|
|
|
|
|
} else {
|
|
|
|
|
Addend = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: offset = 0x"
|
|
|
|
|
<< Twine::utohexstr(Rel.getOffset())
|
|
|
|
|
<< "; symbol = " << SymbolName
|
|
|
|
|
<< "; symbol address = 0x" << Twine::utohexstr(SymbolAddress)
|
|
|
|
|
<< "; addend = 0x" << Twine::utohexstr(Addend)
|
|
|
|
|
<< "; address = 0x" << Twine::utohexstr(Address)
|
|
|
|
|
<< "; type = " << Rel.getType()
|
|
|
|
|
<< "; type name = " << TypeName
|
|
|
|
|
<< '\n');
|
|
|
|
|
|
|
|
|
|
if (Rel.getType() != ELF::R_X86_64_TPOFF32 &&
|
|
|
|
|
Rel.getType() != ELF::R_X86_64_GOTTPOFF &&
|
|
|
|
|
Rel.getType() != ELF::R_X86_64_GOTPCREL) {
|
|
|
|
|
if (!IsPCRelative) {
|
2017-06-02 18:41:31 -07:00
|
|
|
if (!IsAbsoluteCodeRefWithAddend) {
|
|
|
|
|
if (opts::Verbosity > 2 &&
|
|
|
|
|
ExtractedValue != Address) {
|
|
|
|
|
errs() << "BOLT-WARNING: mismatch ExtractedValue = 0x"
|
|
|
|
|
<< Twine::utohexstr(ExtractedValue) << '\n';
|
|
|
|
|
}
|
|
|
|
|
Address = ExtractedValue;
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
} else {
|
2017-05-26 15:46:46 -07:00
|
|
|
if (opts::Verbosity > 2 &&
|
2016-09-27 19:09:38 -07:00
|
|
|
ExtractedValue != Address - Rel.getOffset() + Addend) {
|
|
|
|
|
errs() << "BOLT-WARNING: PC-relative mismatch ExtractedValue = 0x"
|
|
|
|
|
<< Twine::utohexstr(ExtractedValue) << '\n';
|
|
|
|
|
}
|
|
|
|
|
Address = ExtractedValue - Addend;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BinaryFunction *ContainingBF = nullptr;
|
|
|
|
|
if (IsFromCode) {
|
|
|
|
|
ContainingBF = getBinaryFunctionContainingAddress(Rel.getOffset());
|
|
|
|
|
assert(ContainingBF && "cannot find function for address in code");
|
2017-06-02 18:41:31 -07:00
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: relocation belongs to " << *ContainingBF
|
2016-09-27 19:09:38 -07:00
|
|
|
<< '\n');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PC-relative relocations from data to code are tricky since the original
|
|
|
|
|
// information is typically lost after linking even with '--emit-relocs'.
|
|
|
|
|
// They are normally used by PIC-style jump tables and reference both
|
|
|
|
|
// the jump table and jump destination by computing the difference
|
|
|
|
|
// between the two. If we blindly apply the relocation it will appear
|
|
|
|
|
// that it references an arbitrary location in the code, possibly even
|
|
|
|
|
// in a different function from that containing the jump table.
|
|
|
|
|
if (IsPCRelative) {
|
|
|
|
|
// Just register the fact that we have PC-relative relocation at a given
|
|
|
|
|
// address. The actual referenced label/address cannot be determined
|
|
|
|
|
// from linker data alone.
|
|
|
|
|
if (IsFromCode) {
|
|
|
|
|
ContainingBF->addPCRelativeRelocationAddress(Rel.getOffset());
|
|
|
|
|
}
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: not creating PC-relative relocation\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto RefSection = BC->getSectionForAddress(Address);
|
|
|
|
|
if (!RefSection && !ForceRelocation) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: cannot determine referenced section.\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ToCode = RefSection && RefSection->isText();
|
|
|
|
|
|
|
|
|
|
// Occasionally we may see a reference past the last byte of the function
|
|
|
|
|
// typically as a result of __builtin_unreachable(). Check it here.
|
|
|
|
|
auto *ReferencedBF =
|
|
|
|
|
getBinaryFunctionContainingAddress(Address, /*CheckPastEnd*/ true);
|
|
|
|
|
uint64_t RefFunctionOffset = 0;
|
|
|
|
|
MCSymbol *ReferencedSymbol = nullptr;
|
|
|
|
|
if (ForceRelocation) {
|
|
|
|
|
ReferencedSymbol = BC->registerNameAtAddress(SymbolName, 0);
|
|
|
|
|
Addend = Address;
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: creating relocations for huge pages against"
|
|
|
|
|
" symbol " << SymbolName << " with addend " << Addend
|
|
|
|
|
<< '\n');
|
|
|
|
|
} else if (ReferencedBF) {
|
|
|
|
|
RefFunctionOffset = Address - ReferencedBF->getAddress();
|
|
|
|
|
DEBUG(dbgs() << " referenced function " << *ReferencedBF;
|
|
|
|
|
if (Address != ReferencedBF->getAddress())
|
|
|
|
|
dbgs() << " at offset 0x"
|
|
|
|
|
<< Twine::utohexstr(RefFunctionOffset);
|
|
|
|
|
dbgs() << '\n');
|
|
|
|
|
if (RefFunctionOffset) {
|
|
|
|
|
ReferencedSymbol =
|
|
|
|
|
ReferencedBF->getOrCreateLocalLabel(Address, /*CreatePastEnd*/ true);
|
|
|
|
|
} else {
|
|
|
|
|
ReferencedSymbol = ReferencedBF->getSymbol();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (RefSection && RefSection->isText() && SymbolAddress) {
|
|
|
|
|
// This can happen e.g. with PIC-style jump tables.
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: no corresponding function for "
|
|
|
|
|
"relocation against code\n");
|
|
|
|
|
}
|
|
|
|
|
ReferencedSymbol = BC->getOrCreateGlobalSymbol(Address, "SYMBOLat");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsFromCode) {
|
|
|
|
|
if (ReferencedBF || ForceRelocation) {
|
|
|
|
|
ContainingBF->addRelocation(Rel.getOffset(), ReferencedSymbol,
|
2017-06-02 18:41:31 -07:00
|
|
|
Rel.getType(), Addend, ExtractedValue);
|
2016-09-27 19:09:38 -07:00
|
|
|
} else {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocation from code to data\n");
|
|
|
|
|
}
|
|
|
|
|
} else if (ToCode) {
|
|
|
|
|
assert(Addend == 0 && "did not expect addend");
|
2017-02-21 16:15:15 -08:00
|
|
|
BC->addRelocation(Rel.getOffset(), ReferencedSymbol, Rel.getType());
|
2016-09-27 19:09:38 -07:00
|
|
|
} else {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocation from data to data\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-14 18:48:05 -07:00
|
|
|
void RewriteInstance::readDebugInfo() {
|
|
|
|
|
if (!opts::UpdateDebugSections)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-05-27 20:19:19 -07:00
|
|
|
BC->preprocessDebugInfo(BinaryFunctions);
|
2016-03-14 18:48:05 -07:00
|
|
|
}
|
|
|
|
|
|
2017-07-17 11:22:22 -07:00
|
|
|
void RewriteInstance::readProfileData() {
|
|
|
|
|
if (BC->DR.getAllFuncsData().empty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (auto &BFI : BinaryFunctions) {
|
|
|
|
|
auto &Function = BFI.second;
|
2017-08-02 18:14:01 -07:00
|
|
|
auto *FuncData = BC->DR.getFuncBranchData(Function.getNames());
|
2017-07-17 11:22:22 -07:00
|
|
|
if (!FuncData)
|
|
|
|
|
continue;
|
|
|
|
|
Function.BranchData = FuncData;
|
|
|
|
|
Function.ExecutionCount = FuncData->ExecutionCount;
|
|
|
|
|
FuncData->Used = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
void RewriteInstance::disassembleFunctions() {
|
|
|
|
|
// Disassemble every function and build it's control flow graph.
|
|
|
|
|
TotalScore = 0;
|
2017-05-01 16:52:54 -07:00
|
|
|
BC->SumExecutionCount = 0;
|
2015-11-23 17:54:18 -08:00
|
|
|
for (auto &BFI : BinaryFunctions) {
|
|
|
|
|
BinaryFunction &Function = BFI.second;
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// If we have to relocate the code we have to disassemble all functions.
|
|
|
|
|
if (!opts::Relocs && !opts::shouldProcess(Function)) {
|
2016-03-03 10:13:11 -08:00
|
|
|
DEBUG(dbgs() << "BOLT: skipping processing function "
|
2016-08-07 12:35:23 -07:00
|
|
|
<< Function << " per user request.\n");
|
2015-11-23 17:54:18 -08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SectionRef Section = Function.getSection();
|
2015-12-17 12:59:15 -08:00
|
|
|
assert(Section.getAddress() <= Function.getAddress() &&
|
2016-02-08 10:02:48 -08:00
|
|
|
Section.getAddress() + Section.getSize()
|
2015-12-17 12:59:15 -08:00
|
|
|
>= Function.getAddress() + Function.getSize() &&
|
|
|
|
|
"wrong section for function");
|
2015-11-23 17:54:18 -08:00
|
|
|
if (!Section.isText() || Section.isVirtual() || !Section.getSize()) {
|
2015-12-17 12:59:15 -08:00
|
|
|
// When could it happen?
|
2016-09-27 19:09:38 -07:00
|
|
|
errs() << "BOLT-ERROR: corresponding section is non-executable or "
|
|
|
|
|
<< "empty for function " << Function << '\n';
|
2015-11-23 17:54:18 -08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 15:47:10 -07:00
|
|
|
// Treat zero-sized functions as non-simple ones.
|
|
|
|
|
if (Function.getSize() == 0) {
|
|
|
|
|
Function.setSimple(false);
|
|
|
|
|
continue;
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StringRef SectionContents;
|
|
|
|
|
check_error(Section.getContents(SectionContents),
|
|
|
|
|
"cannot get section contents");
|
|
|
|
|
|
|
|
|
|
assert(SectionContents.size() == Section.getSize() &&
|
|
|
|
|
"section size mismatch");
|
|
|
|
|
|
|
|
|
|
// Function offset from the section start.
|
|
|
|
|
auto FunctionOffset = Function.getAddress() - Section.getAddress();
|
|
|
|
|
|
|
|
|
|
// Offset of the function in the file.
|
|
|
|
|
Function.setFileOffset(
|
2016-03-03 10:13:11 -08:00
|
|
|
SectionContents.data() - InputFile->getData().data() + FunctionOffset);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
ArrayRef<uint8_t> FunctionData(
|
|
|
|
|
reinterpret_cast<const uint8_t *>
|
|
|
|
|
(SectionContents.data()) + FunctionOffset,
|
|
|
|
|
Function.getSize());
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
Function.disassemble(FunctionData);
|
|
|
|
|
|
|
|
|
|
if (!Function.isSimple() && opts::Relocs) {
|
|
|
|
|
errs() << "BOLT-ERROR: function " << Function << " cannot be properly "
|
|
|
|
|
<< "disassembled. Unable to continue in relocation mode.\n";
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
if (opts::PrintAll || opts::PrintDisasm)
|
2016-09-02 14:15:29 -07:00
|
|
|
Function.print(outs(), "after disassembly", true);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Post-process inter-procedural references ASAP as it may affect
|
|
|
|
|
// functions we are about to disassemble next.
|
2017-02-21 14:18:09 -08:00
|
|
|
for (const auto Addr : BC->InterproceduralReferences) {
|
2016-09-27 19:09:38 -07:00
|
|
|
auto *ContainingFunction = getBinaryFunctionContainingAddress(Addr);
|
|
|
|
|
if (ContainingFunction && ContainingFunction->getAddress() != Addr) {
|
|
|
|
|
ContainingFunction->addEntryPoint(Addr);
|
|
|
|
|
if (!opts::Relocs) {
|
|
|
|
|
if (opts::Verbosity >= 1) {
|
|
|
|
|
errs() << "BOLT-WARNING: Function " << *ContainingFunction
|
|
|
|
|
<< " has internal BBs that are target of a reference located"
|
|
|
|
|
<< " in another function. Skipping the function.\n";
|
|
|
|
|
}
|
|
|
|
|
ContainingFunction->setSimple(false);
|
|
|
|
|
}
|
2017-02-21 14:18:09 -08:00
|
|
|
} else if (!ContainingFunction && Addr) {
|
|
|
|
|
// Check if address falls in function padding space - this could be
|
|
|
|
|
// unmarked data in code. In this case adjust the padding space size.
|
|
|
|
|
auto Section = BC->getSectionForAddress(Addr);
|
|
|
|
|
assert(Section && "cannot get section for referenced address");
|
|
|
|
|
|
|
|
|
|
if (!Section->isText())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// PLT requires special handling and could be ignored in this context.
|
|
|
|
|
StringRef SectionName;
|
|
|
|
|
Section->getName(SectionName);
|
2017-06-02 18:41:31 -07:00
|
|
|
if (SectionName == ".plt" || SectionName == ".plt.got")
|
2017-02-21 14:18:09 -08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (opts::Relocs) {
|
|
|
|
|
errs() << "BOLT-ERROR: cannot process binaries with unmarked "
|
|
|
|
|
<< "object in code at address 0x"
|
|
|
|
|
<< Twine::utohexstr(Addr) << " belonging to section "
|
|
|
|
|
<< SectionName << " in relocation mode.\n";
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContainingFunction =
|
|
|
|
|
getBinaryFunctionContainingAddress(Addr,
|
|
|
|
|
/*CheckPastEnd=*/false,
|
|
|
|
|
/*UseMaxSize=*/true);
|
2017-03-07 14:22:15 -08:00
|
|
|
// We are not going to overwrite non-simple functions, but for simple
|
|
|
|
|
// ones - adjust the padding size.
|
|
|
|
|
if (ContainingFunction && ContainingFunction->isSimple()) {
|
2017-02-21 14:18:09 -08:00
|
|
|
errs() << "BOLT-WARNING: function " << *ContainingFunction
|
|
|
|
|
<< " has an object detected in a padding region at address 0x"
|
|
|
|
|
<< Twine::utohexstr(Addr) << '\n';
|
|
|
|
|
ContainingFunction->setMaxSize(
|
|
|
|
|
Addr - ContainingFunction->getAddress());
|
|
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BC->InterproceduralReferences.clear();
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2017-09-01 18:13:51 -07:00
|
|
|
if (opts::AggregateOnly)
|
|
|
|
|
continue;
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
// Fill in CFI information for this function
|
2016-09-27 19:09:38 -07:00
|
|
|
if (Function.isSimple()) {
|
|
|
|
|
if (!CFIRdWrt->fillCFIInfoFor(Function)) {
|
|
|
|
|
errs() << "BOLT-ERROR: unable to fill CFI for function "
|
|
|
|
|
<< Function << ".\n";
|
|
|
|
|
if (opts::Relocs)
|
|
|
|
|
abort();
|
|
|
|
|
Function.setSimple(false);
|
|
|
|
|
continue;
|
2016-02-22 18:25:43 -08:00
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse LSDA.
|
2016-09-27 19:09:38 -07:00
|
|
|
if (Function.isSimple() && Function.getLSDAAddress() != 0)
|
2015-11-23 17:54:18 -08:00
|
|
|
Function.parseLSDA(LSDAData, LSDAAddress);
|
|
|
|
|
|
|
|
|
|
if (!Function.buildCFG())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (opts::PrintAll || opts::PrintCFG)
|
2016-09-02 14:15:29 -07:00
|
|
|
Function.print(outs(), "after building cfg", true);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-07-01 08:40:56 -07:00
|
|
|
if (opts::DumpDotAll)
|
|
|
|
|
Function.dumpGraphForPass("build-cfg");
|
|
|
|
|
|
2016-05-26 10:58:01 -07:00
|
|
|
if (opts::PrintLoopInfo) {
|
|
|
|
|
Function.calculateLoopInfo();
|
2016-09-02 14:15:29 -07:00
|
|
|
Function.printLoopInfo(outs());
|
2016-05-26 10:58:01 -07:00
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
TotalScore += Function.getFunctionScore();
|
2017-05-01 16:52:54 -07:00
|
|
|
BC->SumExecutionCount += Function.getKnownExecutionCount();
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
} // Iterate over all functions
|
2015-12-03 13:29:52 -08:00
|
|
|
|
2017-09-01 18:13:51 -07:00
|
|
|
if (opts::AggregateOnly)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-01-16 14:58:22 -08:00
|
|
|
uint64_t NumSimpleFunctions{0};
|
2016-06-15 18:36:16 -07:00
|
|
|
uint64_t NumStaleProfileFunctions{0};
|
2016-01-16 14:58:22 -08:00
|
|
|
std::vector<BinaryFunction *> ProfiledFunctions;
|
|
|
|
|
for (auto &BFI : BinaryFunctions) {
|
2016-06-15 18:36:16 -07:00
|
|
|
auto &Function = BFI.second;
|
|
|
|
|
if (!Function.isSimple())
|
2016-01-16 14:58:22 -08:00
|
|
|
continue;
|
|
|
|
|
++NumSimpleFunctions;
|
2016-06-15 18:36:16 -07:00
|
|
|
if (Function.getExecutionCount() == BinaryFunction::COUNT_NO_PROFILE)
|
|
|
|
|
continue;
|
|
|
|
|
if (Function.hasValidProfile())
|
|
|
|
|
ProfiledFunctions.push_back(&Function);
|
|
|
|
|
else
|
|
|
|
|
++NumStaleProfileFunctions;
|
2016-01-16 14:58:22 -08:00
|
|
|
}
|
2017-05-01 16:52:54 -07:00
|
|
|
BC->NumProfiledFuncs = ProfiledFunctions.size();
|
2016-01-16 14:58:22 -08:00
|
|
|
|
2017-01-23 13:08:40 -08:00
|
|
|
const auto NumAllProfiledFunctions =
|
|
|
|
|
ProfiledFunctions.size() + NumStaleProfileFunctions;
|
2016-09-02 14:15:29 -07:00
|
|
|
outs() << "BOLT-INFO: "
|
2017-01-23 13:08:40 -08:00
|
|
|
<< NumAllProfiledFunctions
|
2016-06-15 18:36:16 -07:00
|
|
|
<< " functions out of " << NumSimpleFunctions << " simple functions ("
|
2017-01-23 13:08:40 -08:00
|
|
|
<< format("%.1f", NumAllProfiledFunctions /
|
|
|
|
|
(float) NumSimpleFunctions * 100.0f)
|
2016-01-16 14:58:22 -08:00
|
|
|
<< "%) have non-empty execution profile.\n";
|
2016-06-15 18:36:16 -07:00
|
|
|
if (NumStaleProfileFunctions) {
|
2016-09-02 14:15:29 -07:00
|
|
|
outs() << "BOLT-INFO: " << NumStaleProfileFunctions
|
2017-01-23 13:08:40 -08:00
|
|
|
<< format(" (%.1f%% of all profiled)",
|
|
|
|
|
NumStaleProfileFunctions /
|
|
|
|
|
(float) NumAllProfiledFunctions * 100.0f)
|
2016-06-15 18:36:16 -07:00
|
|
|
<< " function" << (NumStaleProfileFunctions == 1 ? "" : "s")
|
|
|
|
|
<< " have invalid (possibly stale) profile.\n";
|
|
|
|
|
}
|
2016-01-16 14:58:22 -08:00
|
|
|
|
2017-07-17 11:22:22 -07:00
|
|
|
// Profile is marked as 'Used' if it either matches a function name
|
|
|
|
|
// exactly or if it 100% matches any of functions with matching common
|
|
|
|
|
// LTO names.
|
|
|
|
|
auto getUnusedObjects = [this]() -> Optional<std::vector<StringRef>> {
|
|
|
|
|
std::vector<StringRef> UnusedObjects;
|
|
|
|
|
for (const auto &Func : BC->DR.getAllFuncsData()) {
|
|
|
|
|
if (!Func.getValue().Used) {
|
|
|
|
|
UnusedObjects.emplace_back(Func.getKey());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (UnusedObjects.empty())
|
|
|
|
|
return NoneType();
|
|
|
|
|
return UnusedObjects;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (const auto UnusedObjects = getUnusedObjects()) {
|
|
|
|
|
outs() << "BOLT-INFO: profile for " << UnusedObjects->size()
|
|
|
|
|
<< " objects was ignored\n";
|
|
|
|
|
if (opts::Verbosity >= 1) {
|
|
|
|
|
for (auto Name : *UnusedObjects) {
|
|
|
|
|
outs() << " " << Name << '\n';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-16 14:58:22 -08:00
|
|
|
if (ProfiledFunctions.size() > 10) {
|
2016-09-02 14:15:29 -07:00
|
|
|
if (opts::Verbosity >= 1) {
|
|
|
|
|
outs() << "BOLT-INFO: top called functions are:\n";
|
|
|
|
|
std::sort(ProfiledFunctions.begin(), ProfiledFunctions.end(),
|
|
|
|
|
[](BinaryFunction *A, BinaryFunction *B) {
|
|
|
|
|
return B->getExecutionCount() < A->getExecutionCount();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
auto SFI = ProfiledFunctions.begin();
|
Indirect call promotion optimization.
Summary:
Perform indirect call promotion optimization in BOLT.
The code scans the instructions during CFG creation for all
indirect calls. Right now indirect tail calls are not handled
since the functions are marked not simple. The offsets of the
indirect calls are stored for later use by the ICP pass.
The indirect call promotion pass visits each indirect call and
examines the BranchData for each. If the most frequent targets
from that callsite exceed the specified threshold (default 90%),
the call is promoted. Otherwise, it is ignored. By default,
only one target is considered at each callsite.
When an candiate callsite is processed, we modify the callsite
to test for the most common call targets before calling through
the original generic call mechanism.
The CFG and layout are modified by ICP.
A few new command line options have been added:
-indirect-call-promotion
-indirect-call-promotion-threshold=<percentage>
-indirect-call-promotion-topn=<int>
The threshold is the minimum frequency of a call target needed
before ICP is triggered.
The topn option controls the number of targets to consider for
each callsite, e.g. ICP is triggered if topn=2 and the total
requency of the top two call targets exceeds the threshold.
Example of ICP:
C++ code:
int B_count = 0;
int C_count = 0;
struct A { virtual void foo() = 0; }
struct B : public A { virtual void foo() { ++B_count; }; };
struct C : public A { virtual void foo() { ++C_count; }; };
A* a = ...
a->foo();
...
original:
400863: 49 8b 07 mov (%r15),%rax
400866: 4c 89 ff mov %r15,%rdi
400869: ff 10 callq *(%rax)
40086b: 41 83 e6 01 and $0x1,%r14d
40086f: 4d 89 e6 mov %r12,%r14
400872: 4c 0f 44 f5 cmove %rbp,%r14
400876: 4c 89 f7 mov %r14,%rdi
...
after ICP:
40085e: 49 8b 07 mov (%r15),%rax
400861: 4c 89 ff mov %r15,%rdi
400864: 49 ba e0 0b 40 00 00 movabs $0x400be0,%r10
40086b: 00 00 00
40086e: 4c 3b 10 cmp (%rax),%r10
400871: 75 29 jne 40089c <main+0x9c>
400873: 41 ff d2 callq *%r10
400876: 41 83 e6 01 and $0x1,%r14d
40087a: 4d 89 e6 mov %r12,%r14
40087d: 4c 0f 44 f5 cmove %rbp,%r14
400881: 4c 89 f7 mov %r14,%rdi
...
40089c: ff 10 callq *(%rax)
40089e: eb d6 jmp 400876 <main+0x76>
(cherry picked from FBD3612218)
2016-09-07 18:59:23 -07:00
|
|
|
auto SFIend = ProfiledFunctions.end();
|
|
|
|
|
for (auto i = 0u; i < opts::TopCalledLimit && SFI != SFIend; ++SFI, ++i) {
|
2016-09-02 14:15:29 -07:00
|
|
|
outs() << " " << **SFI << " : "
|
|
|
|
|
<< (*SFI)->getExecutionCount() << '\n';
|
|
|
|
|
}
|
2016-01-16 14:58:22 -08:00
|
|
|
}
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RewriteInstance::runOptimizationPasses() {
|
2017-08-10 13:18:44 -07:00
|
|
|
BinaryFunctionPassManager::runAllPasses(*BC, BinaryFunctions, LargeFunctions);
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Helper function to emit the contents of a function via a MCStreamer object.
|
2017-05-24 18:40:29 -07:00
|
|
|
void RewriteInstance::emitFunction(MCStreamer &Streamer, BinaryFunction &Function,
|
|
|
|
|
bool EmitColdPart) {
|
2016-09-27 19:09:38 -07:00
|
|
|
if (Function.getSize() == 0)
|
|
|
|
|
return;
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-12-21 17:13:56 -08:00
|
|
|
if (Function.getState() == BinaryFunction::State::Empty)
|
2016-09-27 19:09:38 -07:00
|
|
|
return;
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
MCSection *Section;
|
|
|
|
|
if (opts::Relocs) {
|
2017-05-24 18:40:29 -07:00
|
|
|
Section = BC->MOFI->getTextSection();
|
2016-09-27 19:09:38 -07:00
|
|
|
} else {
|
|
|
|
|
// Each fuction is emmitted into its own section.
|
2017-01-17 15:49:59 -08:00
|
|
|
Section =
|
2017-05-24 18:40:29 -07:00
|
|
|
BC->Ctx->getELFSection(EmitColdPart ? Function.getColdCodeSectionName()
|
|
|
|
|
: Function.getCodeSectionName(),
|
2017-01-17 15:49:59 -08:00
|
|
|
ELF::SHT_PROGBITS,
|
|
|
|
|
ELF::SHF_EXECINSTR | ELF::SHF_ALLOC);
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
2016-03-02 18:40:10 -08:00
|
|
|
|
|
|
|
|
Section->setHasInstructions(true);
|
2017-05-16 09:27:34 -07:00
|
|
|
|
2017-05-24 18:40:29 -07:00
|
|
|
BC->Ctx->addGenDwarfSection(Section);
|
2016-03-02 18:40:10 -08:00
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
Streamer.SwitchSection(Section);
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (opts::Relocs) {
|
2017-05-24 21:59:01 -07:00
|
|
|
Streamer.EmitCodeAlignment(BinaryFunction::MinAlign);
|
|
|
|
|
Streamer.EmitCodeAlignment(opts::AlignFunctions,
|
|
|
|
|
opts::AlignFunctionsMaxBytes);
|
2016-09-27 19:09:38 -07:00
|
|
|
} else {
|
|
|
|
|
Streamer.EmitCodeAlignment(Function.getAlignment());
|
2017-05-16 09:27:34 -07:00
|
|
|
Streamer.setCodeSkew(EmitColdPart ? 0 : Function.getAddress());
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
|
2016-11-17 14:56:42 -08:00
|
|
|
MCContext &Context = Streamer.getContext();
|
|
|
|
|
const MCAsmInfo *MAI = Context.getAsmInfo();
|
|
|
|
|
|
2016-08-07 12:35:23 -07:00
|
|
|
// Emit all names the function is known under.
|
2016-12-21 17:13:56 -08:00
|
|
|
for (const auto &Name : Function.getNames()) {
|
|
|
|
|
Twine EmitName = EmitColdPart ? Twine(Name).concat(".cold") : Name;
|
2017-05-24 18:40:29 -07:00
|
|
|
auto *EmitSymbol = BC->Ctx->getOrCreateSymbol(EmitName);
|
2016-12-21 17:13:56 -08:00
|
|
|
Streamer.EmitSymbolAttribute(EmitSymbol, MCSA_ELF_TypeFunction);
|
|
|
|
|
DEBUG(dbgs() << "emitting symbol " << EmitSymbol->getName()
|
|
|
|
|
<< " for function " << Function << '\n');
|
|
|
|
|
Streamer.EmitLabel(EmitSymbol);
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Emit CFI start
|
2016-09-27 19:09:38 -07:00
|
|
|
if (Function.hasCFI() && (opts::Relocs || Function.isSimple())) {
|
2015-11-23 17:54:18 -08:00
|
|
|
Streamer.EmitCFIStartProc(/*IsSimple=*/false);
|
|
|
|
|
if (Function.getPersonalityFunction() != nullptr) {
|
|
|
|
|
Streamer.EmitCFIPersonality(Function.getPersonalityFunction(),
|
|
|
|
|
Function.getPersonalityEncoding());
|
|
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
auto *LSDASymbol = EmitColdPart ? Function.getColdLSDASymbol()
|
|
|
|
|
: Function.getLSDASymbol();
|
|
|
|
|
if (LSDASymbol) {
|
2017-05-24 18:40:29 -07:00
|
|
|
Streamer.EmitCFILsda(LSDASymbol, BC->MOFI->getLSDAEncoding());
|
2015-12-18 17:00:46 -08:00
|
|
|
} else {
|
|
|
|
|
Streamer.EmitCFILsda(0, dwarf::DW_EH_PE_omit);
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
// Emit CFI instructions relative to the CIE
|
2016-11-17 14:56:42 -08:00
|
|
|
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);
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
assert((Function.empty() || !(*Function.begin()).isCold()) &&
|
2016-01-26 16:03:58 -08:00
|
|
|
"first basic block should never be cold");
|
|
|
|
|
|
2016-04-21 09:54:33 -07:00
|
|
|
// Emit UD2 at the beginning if requested by user.
|
|
|
|
|
if (!opts::BreakFunctionNames.empty()) {
|
|
|
|
|
for (auto &Name : opts::BreakFunctionNames) {
|
2016-06-10 17:13:05 -07:00
|
|
|
if (Function.hasName(Name)) {
|
2016-04-21 09:54:33 -07:00
|
|
|
Streamer.EmitIntValue(0x0B0F, 2); // UD2: 0F 0B
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
// Emit code.
|
2016-09-27 19:09:38 -07:00
|
|
|
Function.emitBody(Streamer, EmitColdPart);
|
2016-04-19 22:00:29 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// 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());
|
|
|
|
|
}
|
2016-03-28 17:45:22 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (opts::MarkFuncs) {
|
|
|
|
|
Streamer.EmitIntValue(MAI->getTrapFillValue(), 1);
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Emit CFI end
|
2016-09-27 19:09:38 -07:00
|
|
|
if (Function.hasCFI() && (opts::Relocs || Function.isSimple()))
|
2015-11-23 17:54:18 -08:00
|
|
|
Streamer.EmitCFIEndProc();
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
Streamer.EmitLabel(EmitColdPart ? Function.getFunctionColdEndLabel()
|
|
|
|
|
: Function.getFunctionEndLabel());
|
2016-01-22 16:45:39 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Exception handling info for the function.
|
|
|
|
|
Function.emitLSDA(&Streamer, EmitColdPart);
|
2015-12-18 17:00:46 -08:00
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
if (!EmitColdPart && opts::JumpTables > JTS_NONE)
|
2016-09-27 19:09:38 -07:00
|
|
|
Function.emitJumpTables(&Streamer);
|
2017-05-08 22:51:36 -07:00
|
|
|
|
|
|
|
|
Function.setEmitted();
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
2017-05-24 18:40:29 -07:00
|
|
|
namespace {
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
template <typename T>
|
|
|
|
|
std::vector<T> singletonSet(T t) {
|
|
|
|
|
std::vector<T> Vec;
|
|
|
|
|
Vec.push_back(std::move(t));
|
|
|
|
|
return Vec;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
|
|
void RewriteInstance::emitFunctions() {
|
|
|
|
|
std::error_code EC;
|
|
|
|
|
|
|
|
|
|
// This is an object file, which we keep for debugging purposes.
|
|
|
|
|
// Once we decide it's useless, we should create it in memory.
|
|
|
|
|
std::unique_ptr<tool_output_file> TempOut =
|
2016-02-08 10:02:48 -08:00
|
|
|
llvm::make_unique<tool_output_file>(opts::OutputFilename + ".bolt.o",
|
2015-11-23 17:54:18 -08:00
|
|
|
EC, sys::fs::F_None);
|
|
|
|
|
check_error(EC, "cannot create output object file");
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<buffer_ostream> BOS =
|
|
|
|
|
make_unique<buffer_ostream>(TempOut->os());
|
|
|
|
|
raw_pwrite_stream *OS = BOS.get();
|
|
|
|
|
|
|
|
|
|
// Implicitly MCObjectStreamer takes ownership of MCAsmBackend (MAB)
|
|
|
|
|
// and MCCodeEmitter (MCE). ~MCObjectStreamer() will delete these
|
|
|
|
|
// two instances.
|
|
|
|
|
auto MCE = BC->TheTarget->createMCCodeEmitter(*BC->MII, *BC->MRI, *BC->Ctx);
|
|
|
|
|
auto MAB = BC->TheTarget->createMCAsmBackend(*BC->MRI, BC->TripleName, "");
|
|
|
|
|
std::unique_ptr<MCStreamer> Streamer(
|
|
|
|
|
BC->TheTarget->createMCObjectStreamer(*BC->TheTriple,
|
|
|
|
|
*BC->Ctx,
|
|
|
|
|
*MAB,
|
|
|
|
|
*OS,
|
|
|
|
|
MCE,
|
|
|
|
|
*BC->STI,
|
|
|
|
|
/* RelaxAll */ false,
|
|
|
|
|
/* DWARFMustBeAtTheEnd */ false));
|
|
|
|
|
|
|
|
|
|
Streamer->InitSections(false);
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Mark beginning of "hot text".
|
|
|
|
|
if (opts::Relocs && opts::HotText)
|
|
|
|
|
Streamer->EmitLabel(BC->Ctx->getOrCreateSymbol("__hot_start"));
|
|
|
|
|
|
|
|
|
|
// Sort functions for the output.
|
|
|
|
|
std::vector<BinaryFunction *> SortedFunctions(BinaryFunctions.size());
|
|
|
|
|
std::transform(BinaryFunctions.begin(),
|
|
|
|
|
BinaryFunctions.end(),
|
|
|
|
|
SortedFunctions.begin(),
|
|
|
|
|
[](std::pair<const uint64_t, BinaryFunction> &BFI) {
|
|
|
|
|
return &BFI.second;
|
|
|
|
|
});
|
|
|
|
|
|
2017-03-03 11:35:41 -08:00
|
|
|
if (opts::ReorderFunctions != BinaryFunction::RT_NONE) {
|
2016-09-27 19:09:38 -07:00
|
|
|
std::stable_sort(SortedFunctions.begin(), SortedFunctions.end(),
|
2017-03-03 11:35:41 -08:00
|
|
|
[](const BinaryFunction *A, const BinaryFunction *B) {
|
|
|
|
|
if (A->hasValidIndex() && B->hasValidIndex()) {
|
|
|
|
|
return A->getIndex() < B->getIndex();
|
|
|
|
|
} else {
|
|
|
|
|
return A->hasValidIndex();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEBUG(
|
|
|
|
|
if (!opts::Relocs) {
|
|
|
|
|
auto SortedIt = SortedFunctions.begin();
|
|
|
|
|
for (auto &It : BinaryFunctions) {
|
|
|
|
|
assert(&It.second == *SortedIt);
|
|
|
|
|
++SortedIt;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
uint32_t LastHotIndex = -1u;
|
|
|
|
|
uint32_t CurrentIndex = 0;
|
|
|
|
|
for (auto *BF : SortedFunctions) {
|
|
|
|
|
if (!BF->hasValidIndex() && LastHotIndex == -1u) {
|
|
|
|
|
LastHotIndex = CurrentIndex;
|
|
|
|
|
}
|
|
|
|
|
assert(LastHotIndex == -1u || !BF->hasValidIndex());
|
|
|
|
|
assert(!BF->hasValidIndex() || CurrentIndex == BF->getIndex());
|
|
|
|
|
++CurrentIndex;
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
2017-03-03 11:35:41 -08:00
|
|
|
CurrentIndex = 0;
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: LastHotIndex = " << LastHotIndex << "\n");
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
bool ColdFunctionSeen = false;
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
// Output functions one by one.
|
2016-09-27 19:09:38 -07:00
|
|
|
for (auto *FunctionPtr : SortedFunctions) {
|
|
|
|
|
auto &Function = *FunctionPtr;
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Emit all cold function split parts at the border of hot and
|
|
|
|
|
// cold functions.
|
2017-03-03 11:35:41 -08:00
|
|
|
if (opts::Relocs && !ColdFunctionSeen && CurrentIndex >= LastHotIndex) {
|
2016-09-27 19:09:38 -07:00
|
|
|
// Mark the end of "hot" stuff.
|
|
|
|
|
if (opts::HotText) {
|
|
|
|
|
Streamer->SwitchSection(BC->MOFI->getTextSection());
|
|
|
|
|
Streamer->EmitLabel(BC->Ctx->getOrCreateSymbol("__hot_end"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ColdFunctionSeen = true;
|
|
|
|
|
if (opts::SplitFunctions != BinaryFunction::ST_NONE) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: generating code for split functions\n");
|
|
|
|
|
for (auto *FPtr : SortedFunctions) {
|
|
|
|
|
if (!FPtr->isSplit() || !FPtr->isSimple())
|
|
|
|
|
continue;
|
2017-05-24 18:40:29 -07:00
|
|
|
emitFunction(*Streamer, *FPtr, /*EmitColdPart=*/true);
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: first cold function: " << Function << '\n');
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (!opts::Relocs &&
|
|
|
|
|
(!Function.isSimple() || !opts::shouldProcess(Function))) {
|
2017-03-03 11:35:41 -08:00
|
|
|
++CurrentIndex;
|
2015-11-23 17:54:18 -08:00
|
|
|
continue;
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-02-08 10:02:48 -08:00
|
|
|
DEBUG(dbgs() << "BOLT: generating code for function \""
|
2016-08-07 12:35:23 -07:00
|
|
|
<< Function << "\" : "
|
2016-02-08 10:02:48 -08:00
|
|
|
<< Function.getFunctionNumber() << '\n');
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2017-05-24 18:40:29 -07:00
|
|
|
emitFunction(*Streamer, Function, /*EmitColdPart=*/false);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (!opts::Relocs && Function.isSplit())
|
2017-05-24 18:40:29 -07:00
|
|
|
emitFunction(*Streamer, Function, /*EmitColdPart=*/true);
|
2017-03-03 11:35:41 -08:00
|
|
|
|
|
|
|
|
++CurrentIndex;
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (!ColdFunctionSeen && opts::HotText) {
|
|
|
|
|
Streamer->SwitchSection(BC->MOFI->getTextSection());
|
|
|
|
|
Streamer->EmitLabel(BC->Ctx->getOrCreateSymbol("__hot_end"));
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-16 09:27:34 -07:00
|
|
|
if (!opts::Relocs && opts::UpdateDebugSections)
|
2016-05-31 19:12:26 -07:00
|
|
|
updateDebugLineInfoForNonSimpleFunctions();
|
2016-04-05 19:35:45 -07:00
|
|
|
|
2017-04-05 09:29:24 -07:00
|
|
|
emitDataSections(Streamer.get());
|
|
|
|
|
|
2016-11-11 14:33:34 -08:00
|
|
|
// Relocate .eh_frame to .eh_frame_old.
|
|
|
|
|
if (EHFrameSection.getObject() != nullptr) {
|
|
|
|
|
relocateEHFrameSection();
|
|
|
|
|
emitDataSection(Streamer.get(), EHFrameSection, ".eh_frame_old");
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
Streamer->Finish();
|
|
|
|
|
|
2016-02-08 10:02:48 -08:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
2017-05-08 22:51:36 -07:00
|
|
|
// Assign addresses to new sections.
|
2016-02-08 10:02:48 -08:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2016-03-02 18:40:10 -08:00
|
|
|
if (opts::UpdateDebugSections) {
|
|
|
|
|
// Compute offsets of tables in .debug_line for each compile unit.
|
2016-05-27 20:19:19 -07:00
|
|
|
updateLineTableOffsets();
|
2016-03-02 18:40:10 -08:00
|
|
|
}
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
// Get output object as ObjectFile.
|
|
|
|
|
std::unique_ptr<MemoryBuffer> ObjectMemBuffer =
|
|
|
|
|
MemoryBuffer::getMemBuffer(BOS->str(), "in-memory object file", false);
|
|
|
|
|
ErrorOr<std::unique_ptr<object::ObjectFile>> ObjOrErr =
|
|
|
|
|
object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef());
|
|
|
|
|
check_error(ObjOrErr.getError(), "error creating in-memory object");
|
|
|
|
|
|
|
|
|
|
auto Resolver = orc::createLambdaResolver(
|
|
|
|
|
[&](const std::string &Name) {
|
2016-02-05 14:42:04 -08:00
|
|
|
DEBUG(dbgs() << "BOLT: looking for " << Name << "\n");
|
2015-11-23 17:54:18 -08:00
|
|
|
auto I = BC->GlobalSymbols.find(Name);
|
|
|
|
|
if (I == BC->GlobalSymbols.end())
|
|
|
|
|
return RuntimeDyld::SymbolInfo(nullptr);
|
|
|
|
|
return RuntimeDyld::SymbolInfo(I->second,
|
|
|
|
|
JITSymbolFlags::None);
|
|
|
|
|
},
|
|
|
|
|
[](const std::string &S) {
|
2016-02-05 14:42:04 -08:00
|
|
|
DEBUG(dbgs() << "BOLT: resolving " << S << "\n");
|
2015-11-23 17:54:18 -08:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
);
|
2016-09-27 19:09:38 -07:00
|
|
|
Resolver->setAllowsZeroSymbols(true);
|
|
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
auto ObjectsHandle = OLT.addObjectSet(
|
|
|
|
|
singletonSet(std::move(ObjOrErr.get())),
|
2017-01-17 15:49:59 -08:00
|
|
|
EFMM.get(),
|
2016-03-03 10:13:11 -08:00
|
|
|
std::move(Resolver),
|
|
|
|
|
/* ProcessAllSections = */true);
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2017-05-08 22:51:36 -07:00
|
|
|
// Assign addresses to all sections.
|
2016-09-27 19:09:38 -07:00
|
|
|
mapFileSections(ObjectsHandle);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2017-05-08 22:51:36 -07:00
|
|
|
// Update output addresses based on the new section map and layout.
|
|
|
|
|
MCAsmLayout FinalLayout(
|
2016-09-27 19:09:38 -07:00
|
|
|
static_cast<MCObjectStreamer *>(Streamer.get())->getAssembler());
|
2017-05-08 22:51:36 -07:00
|
|
|
updateOutputValues(FinalLayout);
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
OLT.emitAndFinalize(ObjectsHandle);
|
|
|
|
|
|
2017-10-16 16:53:50 -07:00
|
|
|
if (opts::PrintCacheMetrics) {
|
|
|
|
|
outs() << "BOLT-INFO: cache metrics after optimization\n";
|
|
|
|
|
CacheMetrics::printAll(SortedFunctions);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (opts::KeepTmp)
|
|
|
|
|
TempOut->keep();
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
void RewriteInstance::mapFileSections(
|
|
|
|
|
orc::ObjectLinkingLayer<>::ObjSetHandleT &ObjectsHandle) {
|
|
|
|
|
NewTextSectionStartAddress = NextAvailableAddress;
|
|
|
|
|
if (opts::Relocs) {
|
2017-01-17 15:49:59 -08:00
|
|
|
auto SMII = EFMM->SectionMapInfo.find(".text");
|
|
|
|
|
assert(SMII != EFMM->SectionMapInfo.end() &&
|
2016-09-27 19:09:38 -07:00
|
|
|
".text not found in output");
|
|
|
|
|
auto &SI = SMII->second;
|
|
|
|
|
|
|
|
|
|
uint64_t NewTextSectionOffset = 0;
|
|
|
|
|
if (opts::UseOldText && SI.Size <= OldTextSectionSize) {
|
|
|
|
|
outs() << "BOLT-INFO: using original .text for new code\n";
|
|
|
|
|
// Utilize the original .text for storage.
|
|
|
|
|
NewTextSectionStartAddress = OldTextSectionAddress;
|
|
|
|
|
NewTextSectionOffset = OldTextSectionOffset;
|
|
|
|
|
auto Padding = OffsetToAlignment(NewTextSectionStartAddress, PageAlign);
|
|
|
|
|
if (Padding + SI.Size <= OldTextSectionSize) {
|
|
|
|
|
outs() << "BOLT-INFO: using 0x200000 alignment\n";
|
|
|
|
|
NewTextSectionStartAddress += Padding;
|
|
|
|
|
NewTextSectionOffset += Padding;
|
|
|
|
|
}
|
2016-11-09 11:19:02 -08:00
|
|
|
} else {
|
2016-09-27 19:09:38 -07:00
|
|
|
if (opts::UseOldText) {
|
|
|
|
|
errs() << "BOLT-ERROR: original .text too small to fit the new code. "
|
2017-03-03 11:35:41 -08:00
|
|
|
<< SI.Size << " bytes needed, have " << OldTextSectionSize
|
2016-09-27 19:09:38 -07:00
|
|
|
<< " bytes available.\n";
|
|
|
|
|
}
|
|
|
|
|
auto Padding = OffsetToAlignment(NewTextSectionStartAddress, PageAlign);
|
|
|
|
|
NextAvailableAddress += Padding;
|
|
|
|
|
NewTextSectionStartAddress = NextAvailableAddress;
|
2017-01-17 15:49:59 -08:00
|
|
|
NewTextSectionOffset = getFileOffsetForAddress(NextAvailableAddress);
|
2016-09-27 19:09:38 -07:00
|
|
|
NextAvailableAddress += Padding + SI.Size;
|
2016-11-09 11:19:02 -08:00
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
SI.FileAddress = NewTextSectionStartAddress;
|
|
|
|
|
SI.FileOffset = NewTextSectionOffset;
|
2016-11-09 11:19:02 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
DEBUG(dbgs() << "BOLT: mapping .text 0x"
|
|
|
|
|
<< Twine::utohexstr(SMII->second.AllocAddress)
|
|
|
|
|
<< " to 0x" << Twine::utohexstr(NewTextSectionStartAddress)
|
|
|
|
|
<< '\n');
|
2016-10-07 09:34:16 -07:00
|
|
|
OLT.mapSectionAddress(ObjectsHandle,
|
2016-09-27 19:09:38 -07:00
|
|
|
SI.SectionID,
|
|
|
|
|
NewTextSectionStartAddress);
|
|
|
|
|
} else {
|
|
|
|
|
for (auto &BFI : BinaryFunctions) {
|
|
|
|
|
auto &Function = BFI.second;
|
|
|
|
|
if (!Function.isSimple() || !opts::shouldProcess(Function))
|
|
|
|
|
continue;
|
2016-10-07 09:34:16 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
auto TooLarge = false;
|
2017-01-17 15:49:59 -08:00
|
|
|
auto SMII = EFMM->SectionMapInfo.find(Function.getCodeSectionName());
|
|
|
|
|
assert(SMII != EFMM->SectionMapInfo.end() &&
|
2016-09-27 19:09:38 -07:00
|
|
|
"cannot find section for function");
|
|
|
|
|
DEBUG(dbgs() << "BOLT: mapping 0x"
|
|
|
|
|
<< Twine::utohexstr(SMII->second.AllocAddress)
|
|
|
|
|
<< " to 0x" << Twine::utohexstr(Function.getAddress())
|
|
|
|
|
<< '\n');
|
|
|
|
|
OLT.mapSectionAddress(ObjectsHandle,
|
|
|
|
|
SMII->second.SectionID,
|
|
|
|
|
Function.getAddress());
|
|
|
|
|
Function.setImageAddress(SMII->second.AllocAddress);
|
|
|
|
|
Function.setImageSize(SMII->second.Size);
|
|
|
|
|
if (Function.getImageSize() > Function.getMaxSize()) {
|
|
|
|
|
TooLarge = true;
|
|
|
|
|
FailedAddresses.emplace_back(Function.getAddress());
|
|
|
|
|
}
|
2016-03-11 11:30:30 -08:00
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
// Map jump tables if updating in-place.
|
|
|
|
|
if (opts::JumpTables == JTS_BASIC) {
|
|
|
|
|
for (auto &JTI : Function.JumpTables) {
|
|
|
|
|
auto &JT = JTI.second;
|
|
|
|
|
auto SMII = EFMM->SectionMapInfo.find(JT.SectionName);
|
|
|
|
|
assert(SMII != EFMM->SectionMapInfo.end() &&
|
|
|
|
|
"cannot find section for jump table");
|
|
|
|
|
JT.SecInfo = &SMII->second;
|
|
|
|
|
JT.SecInfo->FileAddress = JT.Address;
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: mapping " << JT.SectionName << " to 0x"
|
|
|
|
|
<< Twine::utohexstr(JT.Address) << '\n');
|
|
|
|
|
OLT.mapSectionAddress(ObjectsHandle,
|
|
|
|
|
JT.SecInfo->SectionID,
|
|
|
|
|
JT.Address);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (!Function.isSplit())
|
|
|
|
|
continue;
|
|
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
SMII = EFMM->SectionMapInfo.find(Function.getColdCodeSectionName());
|
|
|
|
|
assert(SMII != EFMM->SectionMapInfo.end() &&
|
2016-09-27 19:09:38 -07:00
|
|
|
"cannot find section for cold part");
|
|
|
|
|
// Cold fragments are aligned at 16 bytes.
|
|
|
|
|
NextAvailableAddress = RoundUpToAlignment(NextAvailableAddress, 16);
|
2017-01-17 15:49:59 -08:00
|
|
|
auto &ColdPart = Function.cold();
|
2016-09-27 19:09:38 -07:00
|
|
|
if (TooLarge) {
|
|
|
|
|
// The corresponding FDE will refer to address 0.
|
2017-01-17 15:49:59 -08:00
|
|
|
ColdPart.setAddress(0);
|
|
|
|
|
ColdPart.setImageAddress(0);
|
|
|
|
|
ColdPart.setImageSize(0);
|
|
|
|
|
ColdPart.setFileOffset(0);
|
2016-09-27 19:09:38 -07:00
|
|
|
} else {
|
2017-01-17 15:49:59 -08:00
|
|
|
ColdPart.setAddress(NextAvailableAddress);
|
|
|
|
|
ColdPart.setImageAddress(SMII->second.AllocAddress);
|
|
|
|
|
ColdPart.setImageSize(SMII->second.Size);
|
|
|
|
|
ColdPart.setFileOffset(getFileOffsetForAddress(NextAvailableAddress));
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "BOLT: mapping cold fragment 0x"
|
2017-01-17 15:49:59 -08:00
|
|
|
<< Twine::utohexstr(ColdPart.getImageAddress())
|
2016-09-27 19:09:38 -07:00
|
|
|
<< " to 0x"
|
2017-01-17 15:49:59 -08:00
|
|
|
<< Twine::utohexstr(ColdPart.getAddress())
|
2016-09-27 19:09:38 -07:00
|
|
|
<< " with size "
|
2017-01-17 15:49:59 -08:00
|
|
|
<< Twine::utohexstr(ColdPart.getImageSize()) << '\n');
|
2016-09-27 19:09:38 -07:00
|
|
|
OLT.mapSectionAddress(ObjectsHandle,
|
|
|
|
|
SMII->second.SectionID,
|
2017-01-17 15:49:59 -08:00
|
|
|
ColdPart.getAddress());
|
2016-09-27 19:09:38 -07:00
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
NextAvailableAddress += ColdPart.getImageSize();
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add the new text section aggregating all existing code sections.
|
2017-01-17 15:49:59 -08:00
|
|
|
// This is pseudo-section that serves a purpose of creating a corresponding
|
|
|
|
|
// entry in section header table.
|
2016-09-27 19:09:38 -07:00
|
|
|
auto NewTextSectionSize = NextAvailableAddress - NewTextSectionStartAddress;
|
|
|
|
|
if (NewTextSectionSize) {
|
2017-02-07 15:31:14 -08:00
|
|
|
EFMM->SectionMapInfo[BOLTSecPrefix + ".text"] =
|
2016-09-27 19:09:38 -07:00
|
|
|
SectionInfo(0,
|
|
|
|
|
NewTextSectionSize,
|
|
|
|
|
16,
|
|
|
|
|
true /*IsCode*/,
|
|
|
|
|
true /*IsReadOnly*/,
|
2017-01-17 15:49:59 -08:00
|
|
|
true /*IsLocal*/,
|
2016-09-27 19:09:38 -07:00
|
|
|
NewTextSectionStartAddress,
|
2017-01-17 15:49:59 -08:00
|
|
|
getFileOffsetForAddress(NewTextSectionStartAddress));
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
2016-02-12 19:01:53 -08:00
|
|
|
}
|
2015-12-18 17:00:46 -08:00
|
|
|
|
|
|
|
|
// Map special sections to their addresses in the output image.
|
2016-09-27 19:09:38 -07:00
|
|
|
// These are the sections that we generate via MCStreamer.
|
|
|
|
|
// The order is important.
|
2016-11-11 14:33:34 -08:00
|
|
|
std::vector<std::string> Sections = { ".eh_frame", ".eh_frame_old",
|
|
|
|
|
".gcc_except_table",
|
2016-09-16 15:54:32 -07:00
|
|
|
".rodata", ".rodata.cold" };
|
2016-02-12 19:01:53 -08:00
|
|
|
for (auto &SectionName : Sections) {
|
2017-01-17 15:49:59 -08:00
|
|
|
auto SMII = EFMM->SectionMapInfo.find(SectionName);
|
|
|
|
|
if (SMII == EFMM->SectionMapInfo.end())
|
2016-09-16 15:54:32 -07:00
|
|
|
continue;
|
|
|
|
|
SectionInfo &SI = SMII->second;
|
|
|
|
|
NextAvailableAddress = RoundUpToAlignment(NextAvailableAddress,
|
|
|
|
|
SI.Alignment);
|
|
|
|
|
DEBUG(dbgs() << "BOLT: mapping section " << SectionName << " (0x"
|
|
|
|
|
<< Twine::utohexstr(SI.AllocAddress)
|
|
|
|
|
<< ") to 0x" << Twine::utohexstr(NextAvailableAddress)
|
|
|
|
|
<< '\n');
|
|
|
|
|
|
|
|
|
|
OLT.mapSectionAddress(ObjectsHandle,
|
|
|
|
|
SI.SectionID,
|
|
|
|
|
NextAvailableAddress);
|
|
|
|
|
SI.FileAddress = NextAvailableAddress;
|
2017-01-17 15:49:59 -08:00
|
|
|
SI.FileOffset = getFileOffsetForAddress(NextAvailableAddress);
|
2016-09-16 15:54:32 -07:00
|
|
|
|
|
|
|
|
NextAvailableAddress += SI.Size;
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
2015-12-18 17:00:46 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Handling for sections with relocations.
|
|
|
|
|
for (auto &SRI : BC->SectionRelocations) {
|
|
|
|
|
auto &Section = SRI.first;
|
|
|
|
|
StringRef SectionName;
|
|
|
|
|
Section.getName(SectionName);
|
2017-02-07 12:20:46 -08:00
|
|
|
auto SMII = EFMM->SectionMapInfo.find(OrgSecPrefix +
|
2017-01-17 15:49:59 -08:00
|
|
|
std::string(SectionName));
|
|
|
|
|
if (SMII == EFMM->SectionMapInfo.end())
|
2016-09-27 19:09:38 -07:00
|
|
|
continue;
|
|
|
|
|
SectionInfo &SI = SMII->second;
|
2016-04-06 18:03:44 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (SI.FileAddress) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: section " << SectionName
|
|
|
|
|
<< " is already mapped at 0x"
|
|
|
|
|
<< Twine::utohexstr(SI.FileAddress) << '\n');
|
|
|
|
|
continue;
|
2016-03-28 17:45:22 -07:00
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
DEBUG(dbgs() << "BOLT: mapping original section " << SectionName << " (0x"
|
|
|
|
|
<< Twine::utohexstr(SI.AllocAddress)
|
|
|
|
|
<< ") to 0x" << Twine::utohexstr(Section.getAddress())
|
|
|
|
|
<< '\n');
|
2016-03-28 17:45:22 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
OLT.mapSectionAddress(ObjectsHandle,
|
|
|
|
|
SI.SectionID,
|
|
|
|
|
Section.getAddress());
|
|
|
|
|
SI.FileAddress = Section.getAddress();
|
|
|
|
|
|
|
|
|
|
StringRef SectionContents;
|
|
|
|
|
Section.getContents(SectionContents);
|
|
|
|
|
SI.FileOffset = SectionContents.data() - InputFile->getData().data();
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
2017-05-08 22:51:36 -07:00
|
|
|
void RewriteInstance::updateOutputValues(const MCAsmLayout &Layout) {
|
|
|
|
|
for (auto &BFI : BinaryFunctions) {
|
|
|
|
|
auto &Function = BFI.second;
|
|
|
|
|
|
2017-05-16 09:27:34 -07:00
|
|
|
if (!Function.isEmitted()) {
|
|
|
|
|
Function.setOutputAddress(Function.getAddress());
|
|
|
|
|
Function.setOutputSize(Function.getSize());
|
2017-05-08 22:51:36 -07:00
|
|
|
continue;
|
2017-05-16 09:27:34 -07:00
|
|
|
}
|
2017-05-08 22:51:36 -07:00
|
|
|
|
|
|
|
|
if (opts::Relocs) {
|
|
|
|
|
const auto BaseAddress = NewTextSectionStartAddress;
|
|
|
|
|
const auto StartOffset = Layout.getSymbolOffset(*Function.getSymbol());
|
|
|
|
|
const auto EndOffset =
|
|
|
|
|
Layout.getSymbolOffset(*Function.getFunctionEndLabel());
|
|
|
|
|
Function.setOutputAddress(BaseAddress + StartOffset);
|
|
|
|
|
Function.setOutputSize(EndOffset - StartOffset);
|
|
|
|
|
if (Function.isSplit()) {
|
|
|
|
|
const auto *ColdStartSymbol = Function.getColdSymbol();
|
|
|
|
|
assert(ColdStartSymbol && ColdStartSymbol->isDefined(false) &&
|
|
|
|
|
"split function should have defined cold symbol");
|
|
|
|
|
const auto *ColdEndSymbol = Function.getFunctionColdEndLabel();
|
|
|
|
|
assert(ColdEndSymbol && ColdEndSymbol->isDefined(false) &&
|
|
|
|
|
"split function should have defined cold end symbol");
|
|
|
|
|
const auto ColdStartOffset = Layout.getSymbolOffset(*ColdStartSymbol);
|
|
|
|
|
const auto ColdEndOffset = Layout.getSymbolOffset(*ColdEndSymbol);
|
|
|
|
|
Function.cold().setAddress(BaseAddress + ColdStartOffset);
|
|
|
|
|
Function.cold().setImageSize(ColdEndOffset - ColdStartOffset);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Function.setOutputAddress(Function.getAddress());
|
|
|
|
|
Function.setOutputSize(
|
|
|
|
|
Layout.getSymbolOffset(*Function.getFunctionEndLabel()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update basic block output ranges only for the debug info.
|
|
|
|
|
if (!opts::UpdateDebugSections)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Output ranges should match the input if the body hasn't changed.
|
2017-05-31 09:36:49 -07:00
|
|
|
if (!Function.isSimple() && !opts::Relocs)
|
2017-05-08 22:51:36 -07:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
BinaryBasicBlock *PrevBB = nullptr;
|
|
|
|
|
for (auto BBI = Function.layout_begin(), BBE = Function.layout_end();
|
|
|
|
|
BBI != BBE; ++BBI) {
|
|
|
|
|
auto *BB = *BBI;
|
|
|
|
|
assert(BB->getLabel()->isDefined(false) && "symbol should be defined");
|
2017-05-31 09:36:49 -07:00
|
|
|
uint64_t BaseAddress;
|
|
|
|
|
if (opts::Relocs) {
|
|
|
|
|
BaseAddress = NewTextSectionStartAddress;
|
|
|
|
|
} else {
|
|
|
|
|
BaseAddress = BB->isCold() ? Function.cold().getAddress()
|
|
|
|
|
: Function.getOutputAddress();
|
|
|
|
|
}
|
2017-05-08 22:51:36 -07:00
|
|
|
uint64_t Address = BaseAddress + Layout.getSymbolOffset(*BB->getLabel());
|
|
|
|
|
BB->setOutputStartAddress(Address);
|
|
|
|
|
|
|
|
|
|
if (PrevBB) {
|
|
|
|
|
auto PrevBBEndAddress = Address;
|
|
|
|
|
if (BB->isCold() != PrevBB->isCold()) {
|
|
|
|
|
PrevBBEndAddress =
|
|
|
|
|
Function.getOutputAddress() + Function.getOutputSize();
|
|
|
|
|
}
|
|
|
|
|
PrevBB->setOutputEndAddress(PrevBBEndAddress);
|
|
|
|
|
}
|
|
|
|
|
PrevBB = BB;
|
|
|
|
|
}
|
2017-10-09 14:15:38 -07:00
|
|
|
PrevBB->setOutputEndAddress(PrevBB->isCold() ?
|
2017-05-08 22:51:36 -07:00
|
|
|
Function.cold().getAddress() + Function.cold().getImageSize() :
|
|
|
|
|
Function.getOutputAddress() + Function.getOutputSize());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-11 14:33:34 -08:00
|
|
|
void RewriteInstance::emitDataSection(MCStreamer *Streamer, SectionRef Section,
|
|
|
|
|
std::string Name) {
|
|
|
|
|
StringRef SectionName;
|
|
|
|
|
if (!Name.empty())
|
|
|
|
|
SectionName = Name;
|
|
|
|
|
else
|
|
|
|
|
Section.getName(SectionName);
|
2017-04-05 09:29:24 -07:00
|
|
|
|
|
|
|
|
const auto SectionFlags = ELFSectionRef(Section).getFlags();
|
|
|
|
|
const auto SectionType = ELFSectionRef(Section).getType();
|
2016-11-11 14:33:34 -08:00
|
|
|
auto *ELFSection = BC->Ctx->getELFSection(SectionName,
|
2017-04-05 09:29:24 -07:00
|
|
|
SectionType,
|
|
|
|
|
SectionFlags);
|
|
|
|
|
|
2016-11-11 14:33:34 -08:00
|
|
|
StringRef SectionContents;
|
|
|
|
|
Section.getContents(SectionContents);
|
|
|
|
|
|
|
|
|
|
Streamer->SwitchSection(ELFSection);
|
|
|
|
|
Streamer->EmitValueToAlignment(Section.getAlignment());
|
|
|
|
|
|
2017-04-05 09:29:24 -07:00
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitting "
|
|
|
|
|
<< (SectionFlags & ELF::SHF_ALLOC ? "" : "non-")
|
|
|
|
|
<< "allocatable data section " << SectionName << '\n');
|
2016-11-11 14:33:34 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
auto SRI = BC->SectionRelocations.find(Section);
|
|
|
|
|
if (SRI == BC->SectionRelocations.end()) {
|
2016-11-11 14:33:34 -08:00
|
|
|
Streamer->EmitBytes(SectionContents);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto &Relocations = SRI->second;
|
|
|
|
|
uint64_t SectionOffset = 0;
|
|
|
|
|
for (auto &Relocation : Relocations) {
|
|
|
|
|
assert(Relocation.Offset < Section.getSize() && "overflow detected");
|
|
|
|
|
if (SectionOffset < Relocation.Offset) {
|
|
|
|
|
Streamer->EmitBytes(
|
|
|
|
|
SectionContents.substr(SectionOffset,
|
|
|
|
|
Relocation.Offset - SectionOffset));
|
|
|
|
|
SectionOffset = Relocation.Offset;
|
|
|
|
|
}
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: emitting relocation for symbol "
|
|
|
|
|
<< Relocation.Symbol->getName() << " at offset 0x"
|
|
|
|
|
<< Twine::utohexstr(Relocation.Offset)
|
|
|
|
|
<< " with size "
|
|
|
|
|
<< Relocation::getSizeForType(Relocation.Type) << '\n');
|
2016-09-27 19:09:38 -07:00
|
|
|
auto RelocationSize = Relocation.emit(Streamer);
|
2016-11-11 14:33:34 -08:00
|
|
|
SectionOffset += RelocationSize;
|
|
|
|
|
}
|
|
|
|
|
assert(SectionOffset <= SectionContents.size() && "overflow error");
|
|
|
|
|
if (SectionOffset < SectionContents.size()) {
|
|
|
|
|
Streamer->EmitBytes(SectionContents.substr(SectionOffset));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
void RewriteInstance::emitDataSections(MCStreamer *Streamer) {
|
|
|
|
|
for (auto &SRI : BC->SectionRelocations) {
|
|
|
|
|
auto &Section = SRI.first;
|
|
|
|
|
|
|
|
|
|
StringRef SectionName;
|
|
|
|
|
Section.getName(SectionName);
|
|
|
|
|
|
|
|
|
|
assert(SectionName != ".eh_frame" && "should not emit .eh_frame as data");
|
|
|
|
|
|
2017-02-07 12:20:46 -08:00
|
|
|
auto EmitName = OrgSecPrefix + std::string(SectionName);
|
2016-09-27 19:09:38 -07:00
|
|
|
emitDataSection(Streamer, Section, EmitName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-11 17:46:18 -07:00
|
|
|
bool RewriteInstance::checkLargeFunctions() {
|
2016-09-27 19:09:38 -07:00
|
|
|
if (opts::Relocs)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-04-11 17:46:18 -07:00
|
|
|
LargeFunctions.clear();
|
2016-03-31 16:38:49 -07:00
|
|
|
for (auto &BFI : BinaryFunctions) {
|
|
|
|
|
auto &Function = BFI.second;
|
|
|
|
|
|
|
|
|
|
// Ignore this function if we failed to map it to the output binary
|
|
|
|
|
if (Function.getImageAddress() == 0 || Function.getImageSize() == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (Function.getImageSize() <= Function.getMaxSize())
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-04-11 17:46:18 -07:00
|
|
|
LargeFunctions.insert(BFI.first);
|
2016-03-31 16:38:49 -07:00
|
|
|
}
|
2016-04-11 17:46:18 -07:00
|
|
|
return !LargeFunctions.empty();
|
2016-03-31 16:38:49 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
void RewriteInstance::patchELFPHDRTable() {
|
|
|
|
|
auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile);
|
2016-02-08 10:02:48 -08:00
|
|
|
if (!ELF64LEFile) {
|
|
|
|
|
errs() << "BOLT-ERROR: only 64-bit LE ELF binaries are supported\n";
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
auto Obj = ELF64LEFile->getELFFile();
|
|
|
|
|
auto &OS = Out->os();
|
|
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
// Write/re-write program headers.
|
2016-03-03 10:13:11 -08:00
|
|
|
Phnum = Obj->getHeader()->e_phnum;
|
2016-02-12 19:01:53 -08:00
|
|
|
if (PHDRTableOffset) {
|
|
|
|
|
// Writing new pheader table.
|
|
|
|
|
Phnum += 1; // only adding one new segment
|
|
|
|
|
// Segment size includes the size of the PHDR area.
|
|
|
|
|
NewTextSegmentSize = NextAvailableAddress - PHDRTableAddress;
|
|
|
|
|
} else {
|
|
|
|
|
assert(!PHDRTableAddress && "unexpected address for program header table");
|
|
|
|
|
// Update existing table.
|
|
|
|
|
PHDRTableOffset = Obj->getHeader()->e_phoff;
|
|
|
|
|
NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress;
|
|
|
|
|
}
|
|
|
|
|
OS.seek(PHDRTableOffset);
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
bool ModdedGnuStack = false;
|
2017-05-25 10:29:38 -07:00
|
|
|
(void)ModdedGnuStack;
|
2016-02-12 19:01:53 -08:00
|
|
|
bool AddedSegment = false;
|
2017-05-25 10:29:38 -07:00
|
|
|
(void)AddedSegment;
|
2016-02-08 10:02:48 -08:00
|
|
|
|
|
|
|
|
// Copy existing program headers with modifications.
|
|
|
|
|
for (auto &Phdr : Obj->program_headers()) {
|
2016-02-12 19:01:53 -08:00
|
|
|
auto NewPhdr = Phdr;
|
|
|
|
|
if (PHDRTableAddress && Phdr.p_type == ELF::PT_PHDR) {
|
2016-02-08 10:02:48 -08:00
|
|
|
NewPhdr.p_offset = PHDRTableOffset;
|
|
|
|
|
NewPhdr.p_vaddr = PHDRTableAddress;
|
|
|
|
|
NewPhdr.p_paddr = PHDRTableAddress;
|
|
|
|
|
NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum;
|
|
|
|
|
NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum;
|
|
|
|
|
} else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {
|
2017-01-17 15:49:59 -08:00
|
|
|
auto SMII = EFMM->SectionMapInfo.find(".eh_frame_hdr");
|
|
|
|
|
if (SMII != EFMM->SectionMapInfo.end()) {
|
2016-07-12 16:43:53 -07:00
|
|
|
auto &EHFrameHdrSecInfo = SMII->second;
|
|
|
|
|
NewPhdr.p_offset = EHFrameHdrSecInfo.FileOffset;
|
|
|
|
|
NewPhdr.p_vaddr = EHFrameHdrSecInfo.FileAddress;
|
|
|
|
|
NewPhdr.p_paddr = EHFrameHdrSecInfo.FileAddress;
|
|
|
|
|
NewPhdr.p_filesz = EHFrameHdrSecInfo.Size;
|
|
|
|
|
NewPhdr.p_memsz = EHFrameHdrSecInfo.Size;
|
|
|
|
|
}
|
2016-02-12 19:01:53 -08:00
|
|
|
} else if (opts::UseGnuStack && Phdr.p_type == ELF::PT_GNU_STACK) {
|
|
|
|
|
NewPhdr.p_type = ELF::PT_LOAD;
|
|
|
|
|
NewPhdr.p_offset = NewTextSegmentOffset;
|
|
|
|
|
NewPhdr.p_vaddr = NewTextSegmentAddress;
|
|
|
|
|
NewPhdr.p_paddr = NewTextSegmentAddress;
|
|
|
|
|
NewPhdr.p_filesz = NewTextSegmentSize;
|
|
|
|
|
NewPhdr.p_memsz = NewTextSegmentSize;
|
|
|
|
|
NewPhdr.p_flags = ELF::PF_X | ELF::PF_R;
|
|
|
|
|
NewPhdr.p_align = PageAlign;
|
|
|
|
|
ModdedGnuStack = true;
|
|
|
|
|
} else if (!opts::UseGnuStack && Phdr.p_type == ELF::PT_DYNAMIC) {
|
|
|
|
|
// Insert new pheader
|
|
|
|
|
ELFFile<ELF64LE>::Elf_Phdr NewTextPhdr;
|
|
|
|
|
NewTextPhdr.p_type = ELF::PT_LOAD;
|
|
|
|
|
NewTextPhdr.p_offset = PHDRTableOffset;
|
|
|
|
|
NewTextPhdr.p_vaddr = PHDRTableAddress;
|
|
|
|
|
NewTextPhdr.p_paddr = PHDRTableAddress;
|
|
|
|
|
NewTextPhdr.p_filesz = NewTextSegmentSize;
|
|
|
|
|
NewTextPhdr.p_memsz = NewTextSegmentSize;
|
|
|
|
|
NewTextPhdr.p_flags = ELF::PF_X | ELF::PF_R;
|
|
|
|
|
NewTextPhdr.p_align = PageAlign;
|
|
|
|
|
OS.write(reinterpret_cast<const char *>(&NewTextPhdr),
|
|
|
|
|
sizeof(NewTextPhdr));
|
|
|
|
|
AddedSegment = true;
|
2016-02-08 10:02:48 -08:00
|
|
|
}
|
2016-02-12 19:01:53 -08:00
|
|
|
OS.write(reinterpret_cast<const char *>(&NewPhdr), sizeof(NewPhdr));
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
assert((!opts::UseGnuStack || ModdedGnuStack) &&
|
|
|
|
|
"could not find GNU_STACK program header to modify");
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
assert((opts::UseGnuStack || AddedSegment) &&
|
|
|
|
|
"could not add program header for the new segment");
|
2016-03-03 10:13:11 -08:00
|
|
|
}
|
|
|
|
|
|
2016-09-16 15:54:32 -07:00
|
|
|
namespace {
|
2017-04-06 10:49:59 -07:00
|
|
|
|
|
|
|
|
/// Write padding to \p OS such that its current \p Offset becomes aligned
|
|
|
|
|
/// at \p Alignment. Return new (aligned) offset.
|
|
|
|
|
uint64_t appendPadding(raw_pwrite_stream &OS,
|
|
|
|
|
uint64_t Offset,
|
|
|
|
|
uint64_t Alignment) {
|
2017-05-16 17:29:31 -07:00
|
|
|
if (!Alignment)
|
|
|
|
|
return Offset;
|
|
|
|
|
|
2017-04-06 10:49:59 -07:00
|
|
|
const auto PaddingSize = OffsetToAlignment(Offset, Alignment);
|
|
|
|
|
for (unsigned I = 0; I < PaddingSize; ++I)
|
2016-09-16 15:54:32 -07:00
|
|
|
OS.write((unsigned char)0);
|
2017-04-06 10:49:59 -07:00
|
|
|
return Offset + PaddingSize;
|
2016-09-16 15:54:32 -07:00
|
|
|
}
|
2017-04-06 10:49:59 -07:00
|
|
|
|
2016-09-16 15:54:32 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
void RewriteInstance::rewriteNoteSections() {
|
|
|
|
|
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();
|
|
|
|
|
auto &OS = Out->os();
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
uint64_t NextAvailableOffset = getFileOffsetForAddress(NextAvailableAddress);
|
2016-02-12 19:01:53 -08:00
|
|
|
assert(NextAvailableOffset >= FirstNonAllocatableOffset &&
|
|
|
|
|
"next available offset calculation failure");
|
2016-03-03 10:13:11 -08:00
|
|
|
OS.seek(NextAvailableOffset);
|
|
|
|
|
|
|
|
|
|
// Copy over non-allocatable section contents and update file offsets.
|
|
|
|
|
for (auto &Section : Obj->sections()) {
|
|
|
|
|
if (Section.sh_type == ELF::SHT_NULL)
|
|
|
|
|
continue;
|
|
|
|
|
if (Section.sh_flags & ELF::SHF_ALLOC)
|
|
|
|
|
continue;
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (Section.sh_type == ELF::SHT_RELA)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
// Insert padding as needed.
|
2017-04-06 10:49:59 -07:00
|
|
|
NextAvailableOffset =
|
|
|
|
|
appendPadding(OS, NextAvailableOffset, Section.sh_addralign);
|
2016-03-03 10:13:11 -08:00
|
|
|
|
2016-03-11 11:30:30 -08:00
|
|
|
ErrorOr<StringRef> SectionName = Obj->getSectionName(&Section);
|
|
|
|
|
check_error(SectionName.getError(), "cannot get section name");
|
|
|
|
|
|
2016-05-16 17:02:17 -07:00
|
|
|
// New section size.
|
2016-03-11 11:30:30 -08:00
|
|
|
uint64_t Size = 0;
|
|
|
|
|
|
2016-11-11 14:33:34 -08:00
|
|
|
// Copy over section contents unless it's one of the sections we overwrite.
|
2017-02-07 12:20:46 -08:00
|
|
|
if (!willOverwriteSection(*SectionName)) {
|
2016-03-11 11:30:30 -08:00
|
|
|
Size = Section.sh_size;
|
Update subroutine address ranges in binary.
Summary:
[WIP] Update DWARF info for function address ranges.
This diff currently does not work for unknown reasons,
but I'm describing here what's the current state.
According to both llvm-dwarf and readelf our output seems correct,
but GDB does not interpret it as expected. All details go below in
hope I missed something.
I couldn't actually track the whole change that introduced support for
what we need in gdb yet, but I think I can get to it
(2007-12-04: Support
lexical bocks and function bodies that occupy non-contiguous address ranges). I have reasons to believe gdb at least at some
nges).
The set of introduced changes was basically this:
- After disassembly, iterate over the DIEs in .debug_info and find the
ones that correspond to each BinaryFunction.
- Refactor DebugArangesWriter to also write addresses of functions to
.debug_ranges and track the offsets of function address ranges there
- Add some infrastructure to facilitate patching the binary in
simple ways (BinaryPatcher.h)
- In RewriteInstance, after writing .debug_ranges already with
function address ranges, for each function do:
-- Find the abbreviation corresponding to the function
-- Patch .debug_abbrev to replace DW_AT_low_pc with DW_AT_ranges and
DW_AT_high_pc with DW_AT_producer (I'll explain this hack below).
Also patch the corresponding forms to DW_FORM_sec_offset and
DW_FORM_string (null-terminated in-place string).
-- Patch debug_info with the .debug_ranges offset in place of
the first 4 bytes of DW_AT_low_pc (DW_AT_ranges only occupies 4
bytes whereas low_pc occupies 8), and write an arbitrary string
in-place in the other 12 bytes that were the 4 MSB of low_pc
and the 8 bytes of high_pc before the patch. This depends on
low_pc and high_pc being put consecutively by the compiler, but
it serves to validate the idea. I tried another way of doing it
that does not rely on this but it didn't work either and I believe
the reason for either not working is the same (and still unknown,
but unrelated to them. I might be wrong though, and if I find yet
another way of doing it I may try it). The other way was to
use a form of DW_FORM_data8 for the section offset. This is
disallowed by the specification, but I doubt gdb validates this,
as it's just easier to store it as 64-bit anyway as this is even
necessary to support 64-bit DWARF (which is not what gcc generates
by default apparently).
I still need to make changes to the diff to make it production-ready,
but first I want to figure out why it doesn't work as expected.
By looking at the output of llvm-dwarfdump or readelf, all of
.debug_ranges, .debug_abbrev and .debug_info seem to have been
correctly updated. However, gdb seems to have serious problems with
what we write.
(In fact, readelf --debug-dump=Ranges shows some funny warning messages
of the form ("Warning: There is a hole [0x100 - 0x120] in .debug_ranges"),
but I played around with this and it seems it's just because no
compile unit was using these ranges. Changing .debug_info apparently
changes these warnings, so they seem to be unrelated to the section
itself. Also looking at the hex dump of the section doesn't help,
as everything seems fine. llvm-dwarfdump doesn't say anything.
So I think .debug_ranges is fine.)
The result is that gdb not only doesn't show the function name as we
wanted, but it also stops showing line number information.
Apparently it's not reading/interpreting the address ranges at all,
and so the functions now have no associated address ranges, only the
symbol value which allows one to put a breakpoint in the function,
but not to show source code.
As this left me without more ideas of what to try to feed gdb with,
I believe the most promising next trial is to try to debug gdb itself,
unless someone spots anything I missed.
I found where the interesting part of the code lies for this
case (gdb/dwarf2read.c and some other related files, but mainly that one).
It seems in some parts gdb uses DW_AT_ranges for only getting
its lowest and highest addresses and setting that as low_pc and
high_pc (see dwarf2_get_pc_bounds in gdb's code and where it's called).
I really hope this is not actually the case for
function address ranges. I'll investigate this further. Otherwise
I don't think any changes we make will make it work as initially
intended, as we'll simply need gdb to support it and in that case it
doesn't.
(cherry picked from FBD3073641)
2016-03-16 18:08:29 -07:00
|
|
|
std::string Data = InputFile->getData().substr(Section.sh_offset, Size);
|
|
|
|
|
auto SectionPatchersIt = SectionPatchers.find(*SectionName);
|
|
|
|
|
if (SectionPatchersIt != SectionPatchers.end()) {
|
|
|
|
|
(*SectionPatchersIt->second).patchBinary(Data);
|
|
|
|
|
}
|
|
|
|
|
OS << Data;
|
2017-04-06 10:49:59 -07:00
|
|
|
|
|
|
|
|
// Add padding as the section extension might rely on the alignment.
|
|
|
|
|
Size = appendPadding(OS, Size, Section.sh_addralign);
|
2016-03-11 11:30:30 -08:00
|
|
|
}
|
2016-03-03 10:13:11 -08:00
|
|
|
|
|
|
|
|
// Address of extension to the section.
|
|
|
|
|
uint64_t Address{0};
|
|
|
|
|
|
2016-03-09 16:06:41 -08:00
|
|
|
// Perform section post-processing.
|
2016-03-11 11:30:30 -08:00
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
auto SII = EFMM->NoteSectionInfo.find(*SectionName);
|
|
|
|
|
if (SII != EFMM->NoteSectionInfo.end()) {
|
2016-03-03 10:13:11 -08:00
|
|
|
auto &SI = SII->second;
|
|
|
|
|
assert(SI.Alignment <= Section.sh_addralign &&
|
|
|
|
|
"alignment exceeds value in file");
|
2016-03-09 16:06:41 -08:00
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
// Write section extension.
|
|
|
|
|
Address = SI.AllocAddress;
|
2016-03-09 16:06:41 -08:00
|
|
|
if (Address) {
|
2017-04-05 09:29:24 -07:00
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: " << (Size ? "appending" : "writing")
|
2016-05-16 17:02:17 -07:00
|
|
|
<< " contents to section "
|
2016-03-09 16:06:41 -08:00
|
|
|
<< *SectionName << '\n');
|
|
|
|
|
OS.write(reinterpret_cast<const char *>(Address), SI.Size);
|
|
|
|
|
Size += SI.Size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!SI.PendingRelocs.empty()) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: processing relocs for section "
|
|
|
|
|
<< *SectionName << '\n');
|
|
|
|
|
for (auto &Reloc : SI.PendingRelocs) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: writing value "
|
|
|
|
|
<< Twine::utohexstr(Reloc.Value)
|
|
|
|
|
<< " of size " << (unsigned)Reloc.Size
|
|
|
|
|
<< " at offset "
|
|
|
|
|
<< Twine::utohexstr(Reloc.Offset) << '\n');
|
|
|
|
|
assert(Reloc.Size == 4 &&
|
|
|
|
|
"only relocations of size 4 are supported at the moment");
|
|
|
|
|
OS.pwrite(reinterpret_cast<const char*>(&Reloc.Value),
|
|
|
|
|
Reloc.Size,
|
|
|
|
|
NextAvailableOffset + Reloc.Offset);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-03 10:13:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set/modify section info.
|
2017-01-17 15:49:59 -08:00
|
|
|
EFMM->NoteSectionInfo[*SectionName] =
|
2016-03-03 10:13:11 -08:00
|
|
|
SectionInfo(Address,
|
|
|
|
|
Size,
|
|
|
|
|
Section.sh_addralign,
|
|
|
|
|
/*IsCode=*/false,
|
|
|
|
|
/*IsReadOnly=*/false,
|
2017-01-17 15:49:59 -08:00
|
|
|
/*IsLocal=*/false,
|
2016-03-03 10:13:11 -08:00
|
|
|
/*FileAddress=*/0,
|
|
|
|
|
NextAvailableOffset);
|
|
|
|
|
|
|
|
|
|
NextAvailableOffset += Size;
|
|
|
|
|
}
|
2017-05-16 17:29:31 -07:00
|
|
|
|
|
|
|
|
// Write new note sections.
|
|
|
|
|
for (auto &SII : EFMM->NoteSectionInfo) {
|
|
|
|
|
auto &SI = SII.second;
|
|
|
|
|
if (SI.FileOffset || !SI.AllocAddress)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
assert(SI.PendingRelocs.empty() && "cannot have pending relocs");
|
|
|
|
|
|
|
|
|
|
NextAvailableOffset = appendPadding(OS, NextAvailableOffset, SI.Alignment);
|
|
|
|
|
SI.FileOffset = NextAvailableOffset;
|
|
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: writing out new section " << SII.first
|
|
|
|
|
<< " of size " << SI.Size << " at offset 0x"
|
|
|
|
|
<< Twine::utohexstr(SI.FileOffset) << '\n');
|
|
|
|
|
|
|
|
|
|
OS.write(reinterpret_cast<const char *>(SI.AllocAddress), SI.Size);
|
|
|
|
|
NextAvailableOffset += SI.Size;
|
|
|
|
|
}
|
2016-03-03 10:13:11 -08:00
|
|
|
}
|
|
|
|
|
|
2017-02-07 12:20:46 -08:00
|
|
|
template <typename ELFT>
|
2017-05-16 17:29:31 -07:00
|
|
|
void RewriteInstance::finalizeSectionStringTable(ELFObjectFile<ELFT> *File) {
|
2017-02-07 12:20:46 -08:00
|
|
|
auto *Obj = File->getELFFile();
|
|
|
|
|
|
|
|
|
|
// Pre-populate section header string table.
|
|
|
|
|
for (auto &Section : Obj->sections()) {
|
|
|
|
|
ErrorOr<StringRef> SectionName = Obj->getSectionName(&Section);
|
|
|
|
|
check_error(SectionName.getError(), "cannot get section name");
|
|
|
|
|
SHStrTab.add(*SectionName);
|
|
|
|
|
if (willOverwriteSection(*SectionName))
|
|
|
|
|
SHStrTab.add(OrgSecPrefix + SectionName->str());
|
|
|
|
|
}
|
|
|
|
|
for (auto &SMII : EFMM->SectionMapInfo) {
|
|
|
|
|
SHStrTab.add(SMII.first);
|
|
|
|
|
}
|
2017-05-16 17:29:31 -07:00
|
|
|
for (auto &SMII : EFMM->NoteSectionInfo) {
|
|
|
|
|
SHStrTab.add(SMII.first);
|
|
|
|
|
}
|
2017-02-07 12:20:46 -08:00
|
|
|
SHStrTab.finalize(StringTableBuilder::ELF);
|
|
|
|
|
|
2017-05-16 17:29:31 -07:00
|
|
|
const auto SHStrTabSize = SHStrTab.data().size();
|
|
|
|
|
uint8_t *DataCopy = new uint8_t[SHStrTabSize];
|
|
|
|
|
memcpy(DataCopy, SHStrTab.data().data(), SHStrTabSize);
|
|
|
|
|
EFMM->NoteSectionInfo[".shstrtab"] =
|
|
|
|
|
SectionInfo(reinterpret_cast<uint64_t>(DataCopy),
|
|
|
|
|
SHStrTabSize,
|
|
|
|
|
/*Alignment*/1,
|
|
|
|
|
/*IsCode=*/false,
|
|
|
|
|
/*IsReadOnly=*/false,
|
|
|
|
|
/*IsLocal=*/false);
|
|
|
|
|
EFMM->NoteSectionInfo[".shstrtab"].IsStrTab = true;
|
2017-02-07 12:20:46 -08:00
|
|
|
}
|
|
|
|
|
|
2017-05-24 14:14:16 -07:00
|
|
|
void RewriteInstance::addBoltInfoSection() {
|
|
|
|
|
if (opts::AddBoltInfo) {
|
2017-10-06 17:54:26 -07:00
|
|
|
std::string DescStr;
|
|
|
|
|
raw_string_ostream DescOS(DescStr);
|
2017-05-24 14:14:16 -07:00
|
|
|
|
2017-10-06 17:54:26 -07:00
|
|
|
DescOS << "BOLT revision: " << BoltRevision << ", " << "command line:";
|
2017-05-24 14:14:16 -07:00
|
|
|
for (auto I = 0; I < Argc; ++I) {
|
2017-10-06 17:54:26 -07:00
|
|
|
DescOS << " " << Argv[I];
|
2017-05-24 14:14:16 -07:00
|
|
|
}
|
2017-10-06 17:54:26 -07:00
|
|
|
DescOS.flush();
|
|
|
|
|
|
|
|
|
|
std::string Str;
|
|
|
|
|
raw_string_ostream OS(Str);
|
|
|
|
|
std::string NameStr = "GNU";
|
|
|
|
|
const uint32_t NameSz = NameStr.size() + 1;
|
2017-10-10 13:30:05 -07:00
|
|
|
const uint32_t DescSz = DescStr.size();
|
2017-10-06 17:54:26 -07:00
|
|
|
const uint32_t Type = 4; // NT_GNU_GOLD_VERSION (gold version)
|
|
|
|
|
OS.write(reinterpret_cast<const char*>(&(NameSz)), 4);
|
|
|
|
|
OS.write(reinterpret_cast<const char*>(&(DescSz)), 4);
|
|
|
|
|
OS.write(reinterpret_cast<const char*>(&(Type)), 4);
|
2017-10-10 13:30:05 -07:00
|
|
|
OS << NameStr;
|
|
|
|
|
for (uint64_t I = NameStr.size();
|
|
|
|
|
I < RoundUpToAlignment(NameStr.size(), 4); ++I) {
|
|
|
|
|
OS << '\0';
|
|
|
|
|
}
|
|
|
|
|
OS << DescStr;
|
|
|
|
|
for (uint64_t I = DescStr.size();
|
|
|
|
|
I < RoundUpToAlignment(DescStr.size(), 4); ++I) {
|
2017-10-06 17:54:26 -07:00
|
|
|
OS << '\0';
|
|
|
|
|
}
|
2017-05-24 14:14:16 -07:00
|
|
|
|
|
|
|
|
const auto BoltInfo = OS.str();
|
|
|
|
|
const auto SectionSize = BoltInfo.size();
|
|
|
|
|
uint8_t *SectionData = new uint8_t[SectionSize];
|
|
|
|
|
memcpy(SectionData, BoltInfo.data(), SectionSize);
|
2017-10-06 17:54:26 -07:00
|
|
|
EFMM->NoteSectionInfo[".note.bolt_info"] =
|
|
|
|
|
SectionInfo(reinterpret_cast<uint64_t>(SectionData), SectionSize,
|
|
|
|
|
/*Alignment=*/1,
|
|
|
|
|
/*IsCode=*/false,
|
|
|
|
|
/*IsReadOnly=*/true,
|
|
|
|
|
/*IsLocal=*/false, 0, 0, 0,
|
|
|
|
|
/*IsELFNote=*/true);
|
2017-05-24 14:14:16 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
// Provide a mapping of the existing input binary sections to the output binary
|
|
|
|
|
// section header table.
|
|
|
|
|
// Return the map from the section header old index to its new index. Optionally
|
|
|
|
|
// return in OutputSections an ordered list of the output sections. This is
|
|
|
|
|
// optional because for reference updating in the symbol table we only need the
|
|
|
|
|
// map of input to output indices, not the real output section list.
|
|
|
|
|
template <typename ELFT, typename ELFShdrTy>
|
|
|
|
|
std::vector<uint32_t>
|
|
|
|
|
RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
|
|
|
|
|
std::vector<ELFShdrTy> *OutputSections) {
|
2016-09-27 19:09:38 -07:00
|
|
|
auto *Obj = File->getELFFile();
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
std::vector<uint32_t> NewSectionIndex(Obj->getNumSections(), 0);
|
|
|
|
|
NewTextSectionIndex = 0;
|
|
|
|
|
uint32_t CurIndex{0};
|
2016-09-16 15:54:32 -07:00
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
// Copy over entries for original allocatable sections with minor
|
|
|
|
|
// modifications (e.g. name).
|
2016-02-12 19:01:53 -08:00
|
|
|
for (auto &Section : Obj->sections()) {
|
|
|
|
|
// Always ignore this section.
|
|
|
|
|
if (Section.sh_type == ELF::SHT_NULL) {
|
2017-06-27 16:25:59 -07:00
|
|
|
NewSectionIndex[0] = CurIndex++;
|
|
|
|
|
if (OutputSections)
|
|
|
|
|
OutputSections->emplace_back(Section);
|
2016-02-12 19:01:53 -08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
// Is this our new text? Then update our pointer indicating the new output
|
|
|
|
|
// text section
|
|
|
|
|
if (opts::UseOldText && Section.sh_flags & ELF::SHF_ALLOC &&
|
|
|
|
|
Section.sh_addr <= NewTextSectionStartAddress &&
|
|
|
|
|
Section.sh_addr + Section.sh_size > NewTextSectionStartAddress) {
|
|
|
|
|
NewTextSectionIndex = CurIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Skip non-allocatable sections.
|
2016-03-03 10:13:11 -08:00
|
|
|
if (!(Section.sh_flags & ELF::SHF_ALLOC))
|
2016-09-27 19:09:38 -07:00
|
|
|
continue;
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
NewSectionIndex[std::distance(Obj->section_begin(), &Section)] =
|
|
|
|
|
CurIndex++;
|
|
|
|
|
|
|
|
|
|
// If only computing the map, we're done with this iteration
|
|
|
|
|
if (!OutputSections)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
ErrorOr<StringRef> SectionName = Obj->getSectionName(&Section);
|
|
|
|
|
check_error(SectionName.getError(), "cannot get section name");
|
|
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
auto NewSection = Section;
|
|
|
|
|
if (*SectionName == ".bss") {
|
|
|
|
|
// .bss section offset matches that of the next section.
|
|
|
|
|
NewSection.sh_offset = NewTextSegmentOffset;
|
|
|
|
|
}
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2017-02-07 12:20:46 -08:00
|
|
|
if (willOverwriteSection(*SectionName)) {
|
|
|
|
|
NewSection.sh_name = SHStrTab.getOffset(OrgSecPrefix +
|
|
|
|
|
SectionName->str());
|
|
|
|
|
} else {
|
|
|
|
|
NewSection.sh_name = SHStrTab.getOffset(*SectionName);
|
2016-03-03 10:13:11 -08:00
|
|
|
}
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
OutputSections->emplace_back(NewSection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we are creating our own .text section, it should be the first section
|
|
|
|
|
// we created in EFMM->SectionMapInfo, so this is the correct index.
|
|
|
|
|
if (!opts::UseOldText) {
|
|
|
|
|
NewTextSectionIndex = CurIndex;
|
2016-03-03 10:13:11 -08:00
|
|
|
}
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
// Process entries for all new allocatable sections.
|
2017-01-17 15:49:59 -08:00
|
|
|
for (auto &SMII : EFMM->SectionMapInfo) {
|
2017-02-07 12:20:46 -08:00
|
|
|
const auto &SectionName = SMII.first;
|
|
|
|
|
const auto &SI = SMII.second;
|
2016-03-03 10:13:11 -08:00
|
|
|
// Ignore function sections.
|
2016-09-27 19:09:38 -07:00
|
|
|
if (SI.FileAddress < NewTextSegmentAddress) {
|
|
|
|
|
if (opts::Verbosity)
|
|
|
|
|
outs() << "BOLT-INFO: not writing section header for existing section "
|
|
|
|
|
<< SMII.first << '\n';
|
2016-03-03 10:13:11 -08:00
|
|
|
continue;
|
2016-09-02 14:15:29 -07:00
|
|
|
}
|
2017-06-27 16:25:59 -07:00
|
|
|
|
|
|
|
|
++CurIndex;
|
|
|
|
|
// If only computing the map, we're done with this iteration
|
|
|
|
|
if (!OutputSections)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (opts::Verbosity >= 1)
|
2017-05-16 17:29:31 -07:00
|
|
|
outs() << "BOLT-INFO: writing section header for " << SectionName << '\n';
|
2017-06-27 16:25:59 -07:00
|
|
|
ELFShdrTy NewSection;
|
2017-02-07 12:20:46 -08:00
|
|
|
NewSection.sh_name = SHStrTab.getOffset(SectionName);
|
2016-03-03 10:13:11 -08:00
|
|
|
NewSection.sh_type = ELF::SHT_PROGBITS;
|
|
|
|
|
NewSection.sh_addr = SI.FileAddress;
|
|
|
|
|
NewSection.sh_offset = SI.FileOffset;
|
|
|
|
|
NewSection.sh_size = SI.Size;
|
|
|
|
|
NewSection.sh_entsize = 0;
|
|
|
|
|
NewSection.sh_flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR;
|
|
|
|
|
NewSection.sh_link = 0;
|
|
|
|
|
NewSection.sh_info = 0;
|
|
|
|
|
NewSection.sh_addralign = SI.Alignment;
|
2017-06-27 16:25:59 -07:00
|
|
|
OutputSections->emplace_back(NewSection);
|
2016-03-03 10:13:11 -08:00
|
|
|
}
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2017-05-16 17:29:31 -07:00
|
|
|
uint64_t LastFileOffset = 0;
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
// Copy over entries for non-allocatable sections performing necessary
|
2016-09-27 19:09:38 -07:00
|
|
|
// adjustments.
|
2016-03-03 10:13:11 -08:00
|
|
|
for (auto &Section : Obj->sections()) {
|
|
|
|
|
if (Section.sh_type == ELF::SHT_NULL)
|
|
|
|
|
continue;
|
|
|
|
|
if (Section.sh_flags & ELF::SHF_ALLOC)
|
|
|
|
|
continue;
|
2017-06-07 20:06:29 -07:00
|
|
|
// Strip non-allocatable relocation sections.
|
|
|
|
|
if (Section.sh_type == ELF::SHT_RELA)
|
2016-09-27 19:09:38 -07:00
|
|
|
continue;
|
|
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
NewSectionIndex[std::distance(Obj->section_begin(), &Section)] =
|
|
|
|
|
CurIndex++;
|
|
|
|
|
|
|
|
|
|
// If only computing the map, we're done with this iteration
|
|
|
|
|
if (!OutputSections)
|
|
|
|
|
continue;
|
|
|
|
|
|
2017-05-16 17:29:31 -07:00
|
|
|
ErrorOr<StringRef> SectionName = Obj->getSectionName(&Section);
|
|
|
|
|
check_error(SectionName.getError(), "cannot get section name");
|
|
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
auto SII = EFMM->NoteSectionInfo.find(*SectionName);
|
|
|
|
|
assert(SII != EFMM->NoteSectionInfo.end() &&
|
2016-03-03 10:13:11 -08:00
|
|
|
"missing section info for non-allocatable section");
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2017-05-16 17:29:31 -07:00
|
|
|
const auto &SI = SII->second;
|
2016-03-03 10:13:11 -08:00
|
|
|
auto NewSection = Section;
|
2017-05-16 17:29:31 -07:00
|
|
|
NewSection.sh_offset = SI.FileOffset;
|
|
|
|
|
NewSection.sh_size = SI.Size;
|
2017-02-07 12:20:46 -08:00
|
|
|
NewSection.sh_name = SHStrTab.getOffset(*SectionName);
|
2016-02-12 19:01:53 -08:00
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
OutputSections->emplace_back(NewSection);
|
2017-05-16 17:29:31 -07:00
|
|
|
|
|
|
|
|
LastFileOffset = SI.FileOffset;
|
2016-02-12 19:01:53 -08:00
|
|
|
}
|
|
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
// Map input -> output is ready. Early return if that's all we need.
|
|
|
|
|
if (!OutputSections)
|
|
|
|
|
return NewSectionIndex;
|
|
|
|
|
|
2017-05-16 17:29:31 -07:00
|
|
|
// Create entries for new non-allocatable sections.
|
|
|
|
|
for (auto &SII : EFMM->NoteSectionInfo) {
|
|
|
|
|
const auto &SectionName = SII.first;
|
|
|
|
|
const auto &SI = SII.second;
|
|
|
|
|
|
|
|
|
|
if (SI.FileOffset <= LastFileOffset)
|
|
|
|
|
continue;
|
2017-02-07 12:20:46 -08:00
|
|
|
|
2017-05-16 17:29:31 -07:00
|
|
|
if (opts::Verbosity >= 1)
|
|
|
|
|
outs() << "BOLT-INFO: writing section header for " << SectionName << '\n';
|
2017-06-27 16:25:59 -07:00
|
|
|
ELFShdrTy NewSection;
|
2017-05-16 17:29:31 -07:00
|
|
|
NewSection.sh_name = SHStrTab.getOffset(SectionName);
|
2017-10-06 17:54:26 -07:00
|
|
|
NewSection.sh_type =
|
|
|
|
|
(SI.IsStrTab ? ELF::SHT_STRTAB
|
|
|
|
|
: SI.IsELFNote ? ELF::SHT_NOTE : ELF::SHT_PROGBITS);
|
2017-05-16 17:29:31 -07:00
|
|
|
NewSection.sh_addr = 0;
|
|
|
|
|
NewSection.sh_offset = SI.FileOffset;
|
|
|
|
|
NewSection.sh_size = SI.Size;
|
|
|
|
|
NewSection.sh_entsize = 0;
|
|
|
|
|
NewSection.sh_flags = 0;
|
|
|
|
|
NewSection.sh_link = 0;
|
|
|
|
|
NewSection.sh_info = 0;
|
|
|
|
|
NewSection.sh_addralign = SI.Alignment ? SI.Alignment : 1;
|
2017-06-27 16:25:59 -07:00
|
|
|
OutputSections->emplace_back(NewSection);
|
2017-05-16 17:29:31 -07:00
|
|
|
}
|
|
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
return NewSectionIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rewrite section header table inserting new entries as needed. The sections
|
|
|
|
|
// header table size itself may affect the offsets of other sections,
|
|
|
|
|
// so we are placing it at the end of the binary.
|
|
|
|
|
//
|
|
|
|
|
// As we rewrite entries we need to track how many sections were inserted
|
|
|
|
|
// as it changes the sh_link value. We map old indices to new ones for
|
|
|
|
|
// existing sections.
|
|
|
|
|
//
|
|
|
|
|
// The following are assumptions about file modifications:
|
|
|
|
|
// * There are no modifications done to address and/or size of existing
|
|
|
|
|
// allocatable sections.
|
|
|
|
|
// * All new allocatable sections are written immediately after existing
|
|
|
|
|
// allocatable sections.
|
|
|
|
|
// * There could be modifications done to non-allocatable sections, e.g.
|
|
|
|
|
// size could be increased.
|
|
|
|
|
// * New non-allocatable sections are added to the end of the file.
|
|
|
|
|
template <typename ELFT>
|
|
|
|
|
void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile<ELFT> *File) {
|
|
|
|
|
using Elf_Shdr = typename ELFObjectFile<ELFT>::Elf_Shdr;
|
|
|
|
|
std::vector<Elf_Shdr> OutputSections;
|
|
|
|
|
auto &OS = Out->os();
|
|
|
|
|
auto *Obj = File->getELFFile();
|
|
|
|
|
|
|
|
|
|
auto NewSectionIndex = getOutputSections(File, &OutputSections);
|
|
|
|
|
|
2017-06-07 20:06:29 -07:00
|
|
|
// Sort sections by their offset prior to writing. Only newly created sections
|
|
|
|
|
// were unsorted, hence this wouldn't ruin indices in NewSectionIndex.
|
2017-06-27 16:25:59 -07:00
|
|
|
std::stable_sort(OutputSections.begin(), OutputSections.end(),
|
2017-05-16 17:29:31 -07:00
|
|
|
[] (Elf_Shdr A, Elf_Shdr B) {
|
|
|
|
|
return A.sh_offset < B.sh_offset;
|
|
|
|
|
});
|
2017-06-07 20:06:29 -07:00
|
|
|
|
|
|
|
|
DEBUG(
|
|
|
|
|
dbgs() << "BOLT-DEBUG: old to new section index mapping:\n";
|
|
|
|
|
for (uint64_t I = 0; I < NewSectionIndex.size(); ++I) {
|
|
|
|
|
dbgs() << " " << I << " -> " << NewSectionIndex[I] << '\n';
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Align starting address for section header table.
|
|
|
|
|
auto SHTOffset = OS.tell();
|
|
|
|
|
SHTOffset = appendPadding(OS, SHTOffset, sizeof(Elf_Shdr));
|
|
|
|
|
|
|
|
|
|
// Write all section header entries while patching section references.
|
2017-06-27 16:25:59 -07:00
|
|
|
for (uint64_t Index = 0; Index < OutputSections.size(); ++Index) {
|
|
|
|
|
auto &Section = OutputSections[Index];
|
2017-06-07 20:06:29 -07:00
|
|
|
Section.sh_link = NewSectionIndex[Section.sh_link];
|
|
|
|
|
if (Section.sh_type == ELF::SHT_REL || Section.sh_type == ELF::SHT_RELA) {
|
|
|
|
|
if (Section.sh_info)
|
|
|
|
|
Section.sh_info = NewSectionIndex[Section.sh_info];
|
|
|
|
|
}
|
|
|
|
|
OS.write(reinterpret_cast<const char *>(&Section), sizeof(Section));
|
2017-05-16 17:29:31 -07:00
|
|
|
}
|
2017-02-22 11:29:52 -08:00
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
// Fix ELF header.
|
|
|
|
|
auto NewEhdr = *Obj->getHeader();
|
2017-05-08 22:51:36 -07:00
|
|
|
|
|
|
|
|
if (opts::Relocs) {
|
|
|
|
|
NewEhdr.e_entry = getNewFunctionAddress(NewEhdr.e_entry);
|
|
|
|
|
assert(NewEhdr.e_entry && "cannot find new address for entry point");
|
|
|
|
|
}
|
2016-02-12 19:01:53 -08:00
|
|
|
NewEhdr.e_phoff = PHDRTableOffset;
|
|
|
|
|
NewEhdr.e_phnum = Phnum;
|
2016-03-03 10:13:11 -08:00
|
|
|
NewEhdr.e_shoff = SHTOffset;
|
2017-06-27 16:25:59 -07:00
|
|
|
NewEhdr.e_shnum = OutputSections.size();
|
2017-06-07 20:06:29 -07:00
|
|
|
NewEhdr.e_shstrndx = NewSectionIndex[NewEhdr.e_shstrndx];
|
2016-02-12 19:01:53 -08:00
|
|
|
OS.pwrite(reinterpret_cast<const char *>(&NewEhdr), sizeof(NewEhdr), 0);
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
|
void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
|
|
|
|
|
if (!opts::Relocs)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
auto *Obj = File->getELFFile();
|
2017-06-27 16:25:59 -07:00
|
|
|
// Set pointer at the end of the output file, so we can pwrite old symbol
|
|
|
|
|
// tables if we need to.
|
|
|
|
|
uint64_t NextAvailableOffset = getFileOffsetForAddress(NextAvailableAddress);
|
|
|
|
|
assert(NextAvailableOffset >= FirstNonAllocatableOffset &&
|
|
|
|
|
"next available offset calculation failure");
|
|
|
|
|
Out->os().seek(NextAvailableOffset);
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
using Elf_Shdr = typename ELFObjectFile<ELFT>::Elf_Shdr;
|
|
|
|
|
using Elf_Sym = typename ELFObjectFile<ELFT>::Elf_Sym;
|
|
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
// Compute a preview of how section indices will change after rewriting, so
|
|
|
|
|
// we can properly update the symbol table.
|
|
|
|
|
auto NewSectionIndex =
|
|
|
|
|
getOutputSections(File, (std::vector<Elf_Shdr> *)nullptr);
|
|
|
|
|
|
|
|
|
|
auto updateSymbolTable = [&](bool PatchExisting, const Elf_Shdr *Section,
|
|
|
|
|
std::function<void(size_t, const char *, size_t)>
|
|
|
|
|
Write,
|
|
|
|
|
std::function<size_t(StringRef)> AddToStrTab) {
|
|
|
|
|
auto StringSection = *Obj->getStringTableForSymtab(*Section);
|
2017-10-10 18:06:45 -07:00
|
|
|
unsigned IsHotTextUpdated = 0;
|
2017-06-27 16:25:59 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
for (const Elf_Sym &Symbol : Obj->symbols(Section)) {
|
|
|
|
|
auto NewSymbol = Symbol;
|
2017-06-27 16:25:59 -07:00
|
|
|
const auto *Function = getBinaryFunctionAtAddress(Symbol.st_value);
|
|
|
|
|
// Some section symbols may be mistakenly associated with the first
|
|
|
|
|
// function emitted in the section. Dismiss if it is a section symbol.
|
2017-08-04 11:21:05 -07:00
|
|
|
if (Function &&
|
|
|
|
|
!Function->getPLTSymbol() &&
|
|
|
|
|
NewSymbol.getType() != ELF::STT_SECTION) {
|
2017-05-08 22:51:36 -07:00
|
|
|
NewSymbol.st_value = Function->getOutputAddress();
|
|
|
|
|
NewSymbol.st_size = Function->getOutputSize();
|
2016-09-27 19:09:38 -07:00
|
|
|
NewSymbol.st_shndx = NewTextSectionIndex;
|
2017-06-27 16:25:59 -07:00
|
|
|
if (!PatchExisting && Function->isSplit()) {
|
|
|
|
|
auto NewColdSym = NewSymbol;
|
|
|
|
|
SmallVector<char, 256> Buf;
|
|
|
|
|
NewColdSym.st_name = AddToStrTab(Twine(*Symbol.getName(StringSection))
|
|
|
|
|
.concat(".cold.0")
|
|
|
|
|
.toStringRef(Buf));
|
|
|
|
|
NewColdSym.st_value = Function->cold().getAddress();
|
|
|
|
|
NewColdSym.st_size = Function->cold().getImageSize();
|
|
|
|
|
Write(0, reinterpret_cast<const char *>(&NewColdSym),
|
|
|
|
|
sizeof(NewColdSym));
|
|
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
} else {
|
|
|
|
|
if (NewSymbol.st_shndx < ELF::SHN_LORESERVE) {
|
|
|
|
|
NewSymbol.st_shndx = NewSectionIndex[NewSymbol.st_shndx];
|
|
|
|
|
}
|
2017-06-27 16:25:59 -07:00
|
|
|
// Detect local syms in the text section that we didn't update
|
2017-06-16 20:04:43 -07:00
|
|
|
// and were preserved by the linker to support relocations against
|
2017-06-27 16:25:59 -07:00
|
|
|
// .text (t15274167). Remove then from the symtab.
|
2017-06-16 20:04:43 -07:00
|
|
|
if (opts::Relocs && NewSymbol.getType() == ELF::STT_NOTYPE &&
|
|
|
|
|
NewSymbol.getBinding() == ELF::STB_LOCAL &&
|
|
|
|
|
NewSymbol.st_size == 0) {
|
|
|
|
|
if (auto SecOrErr =
|
|
|
|
|
File->getELFFile()->getSection(NewSymbol.st_shndx)) {
|
|
|
|
|
auto Section = *SecOrErr;
|
|
|
|
|
if (Section->sh_type == ELF::SHT_PROGBITS &&
|
|
|
|
|
Section->sh_flags & ELF::SHF_ALLOC &&
|
|
|
|
|
Section->sh_flags & ELF::SHF_EXECINSTR) {
|
2017-06-27 16:25:59 -07:00
|
|
|
// This will cause the symbol to not be emitted if we are
|
|
|
|
|
// creating a new symtab from scratch instead of patching one.
|
|
|
|
|
if (!PatchExisting)
|
|
|
|
|
continue;
|
|
|
|
|
// If patching an existing symtab, patch this value to zero.
|
2017-06-16 20:04:43 -07:00
|
|
|
NewSymbol.st_value = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opts::HotText) {
|
|
|
|
|
auto updateSymbolValue = [&](const StringRef Name) {
|
|
|
|
|
NewSymbol.st_value = getNewValueForSymbol(Name);
|
|
|
|
|
NewSymbol.st_shndx = ELF::SHN_ABS;
|
|
|
|
|
outs() << "BOLT-INFO: setting " << Name << " to 0x"
|
|
|
|
|
<< Twine::utohexstr(NewSymbol.st_value) << '\n';
|
2017-10-10 18:06:45 -07:00
|
|
|
++IsHotTextUpdated;
|
2016-09-27 19:09:38 -07:00
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
auto SymbolName = Symbol.getName(StringSection);
|
2016-09-27 19:09:38 -07:00
|
|
|
assert(SymbolName && "cannot get symbol name");
|
|
|
|
|
if (*SymbolName == "__hot_start" || *SymbolName == "__hot_end")
|
|
|
|
|
updateSymbolValue(*SymbolName);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
Write((&Symbol - Obj->symbol_begin(Section)) * sizeof(Elf_Sym),
|
|
|
|
|
reinterpret_cast<const char *>(&NewSymbol), sizeof(NewSymbol));
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
2017-10-10 18:06:45 -07:00
|
|
|
|
|
|
|
|
assert((!IsHotTextUpdated || IsHotTextUpdated == 2) &&
|
|
|
|
|
"either none or both __hot_start/__hot_end symbols were expected");
|
|
|
|
|
if (opts::HotText && !IsHotTextUpdated && !PatchExisting) {
|
|
|
|
|
auto addSymbol = [&](const std::string &Name) {
|
|
|
|
|
Elf_Sym Symbol;
|
|
|
|
|
Symbol.st_value = getNewValueForSymbol(Name);
|
|
|
|
|
Symbol.st_shndx = ELF::SHN_ABS;
|
|
|
|
|
Symbol.st_name = AddToStrTab(Name);
|
|
|
|
|
Symbol.st_size = 0;
|
|
|
|
|
Symbol.st_other = 0;
|
|
|
|
|
Symbol.setBindingAndType(ELF::STB_WEAK, ELF::STT_NOTYPE);
|
|
|
|
|
|
|
|
|
|
outs() << "BOLT-INFO: setting " << Name << " to 0x"
|
|
|
|
|
<< Twine::utohexstr(Symbol.st_value) << '\n';
|
|
|
|
|
|
|
|
|
|
Write(0, reinterpret_cast<const char *>(&Symbol), sizeof(Symbol));
|
|
|
|
|
};
|
|
|
|
|
addSymbol("__hot_start");
|
|
|
|
|
addSymbol("__hot_end");
|
|
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Update dynamic symbol table.
|
|
|
|
|
const Elf_Shdr *DynSymSection = nullptr;
|
|
|
|
|
for (const Elf_Shdr &Section : Obj->sections()) {
|
|
|
|
|
if (Section.sh_type == ELF::SHT_DYNSYM) {
|
|
|
|
|
DynSymSection = &Section;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(DynSymSection && "no dynamic symbol table found");
|
2017-06-27 16:25:59 -07:00
|
|
|
updateSymbolTable(/*patch existing table?*/ true, DynSymSection,
|
|
|
|
|
[&](size_t Offset, const char *Buf, size_t Size) {
|
|
|
|
|
Out->os().pwrite(Buf, Size,
|
|
|
|
|
DynSymSection->sh_offset + Offset);
|
|
|
|
|
},
|
|
|
|
|
[](StringRef) -> size_t { return 0; });
|
|
|
|
|
|
|
|
|
|
// (re)create regular symbol table.
|
2016-09-27 19:09:38 -07:00
|
|
|
const Elf_Shdr *SymTabSection = nullptr;
|
|
|
|
|
for (const auto &Section : Obj->sections()) {
|
|
|
|
|
if (Section.sh_type == ELF::SHT_SYMTAB) {
|
|
|
|
|
SymTabSection = &Section;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!SymTabSection) {
|
|
|
|
|
errs() << "BOLT-WARNING: no symbol table found\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-06-27 16:25:59 -07:00
|
|
|
|
|
|
|
|
const Elf_Shdr *StrTabSection = *Obj->getSection(SymTabSection->sh_link);
|
|
|
|
|
std::string NewContents;
|
|
|
|
|
std::string NewStrTab =
|
|
|
|
|
File->getData().substr(StrTabSection->sh_offset, StrTabSection->sh_size);
|
|
|
|
|
auto SecName = *Obj->getSectionName(SymTabSection);
|
|
|
|
|
auto StrSecName = *Obj->getSectionName(StrTabSection);
|
|
|
|
|
|
|
|
|
|
updateSymbolTable(/*patch existing table?*/false, SymTabSection,
|
|
|
|
|
[&](size_t Offset, const char *Buf, size_t Size) {
|
|
|
|
|
NewContents.append(Buf, Size);
|
|
|
|
|
}, [&](StringRef Str) {
|
|
|
|
|
size_t Idx = NewStrTab.size();
|
|
|
|
|
NewStrTab.append(Str.data(), Str.size());
|
|
|
|
|
NewStrTab.append(1, '\0');
|
|
|
|
|
return Idx;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
uint8_t *DataCopy = new uint8_t[NewContents.size()];
|
|
|
|
|
memcpy(DataCopy, NewContents.data(), NewContents.size());
|
|
|
|
|
EFMM->NoteSectionInfo[SecName] =
|
|
|
|
|
SectionInfo(reinterpret_cast<uint64_t>(DataCopy), NewContents.size(),
|
|
|
|
|
/*Alignment*/ 1,
|
|
|
|
|
/*IsCode=*/false,
|
|
|
|
|
/*IsReadOnly=*/false,
|
|
|
|
|
/*IsLocal=*/false);
|
|
|
|
|
DataCopy = new uint8_t[NewStrTab.size()];
|
|
|
|
|
memcpy(DataCopy, NewStrTab.data(), NewStrTab.size());
|
|
|
|
|
EFMM->NoteSectionInfo[StrSecName] =
|
|
|
|
|
SectionInfo(reinterpret_cast<uint64_t>(DataCopy), NewStrTab.size(),
|
|
|
|
|
/*Alignment*/ 1,
|
|
|
|
|
/*IsCode=*/false,
|
|
|
|
|
/*IsReadOnly=*/false,
|
|
|
|
|
/*IsLocal=*/false);
|
|
|
|
|
EFMM->NoteSectionInfo[StrSecName].IsStrTab = true;
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
|
void RewriteInstance::patchELFRelaPLT(ELFObjectFile<ELFT> *File) {
|
|
|
|
|
auto &OS = Out->os();
|
|
|
|
|
|
|
|
|
|
if (!RelaPLTSection.getObject()) {
|
|
|
|
|
errs() << "BOLT-INFO: no .rela.plt section found\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const auto &Rel : RelaPLTSection.relocations()) {
|
|
|
|
|
if (Rel.getType() == ELF::R_X86_64_IRELATIVE) {
|
|
|
|
|
DataRefImpl DRI = Rel.getRawDataRefImpl();
|
|
|
|
|
const auto *RelA = File->getRela(DRI);
|
|
|
|
|
auto Address = RelA->r_addend;
|
|
|
|
|
auto NewAddress = getNewFunctionAddress(Address);
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: patching IRELATIVE .rela.plt entry 0x"
|
|
|
|
|
<< Twine::utohexstr(Address) << " with 0x"
|
|
|
|
|
<< Twine::utohexstr(NewAddress) << '\n');
|
|
|
|
|
auto NewRelA = *RelA;
|
|
|
|
|
NewRelA.r_addend = NewAddress;
|
|
|
|
|
OS.pwrite(reinterpret_cast<const char *>(&NewRelA), sizeof(NewRelA),
|
|
|
|
|
reinterpret_cast<const char *>(RelA) - File->getData().data());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
|
void RewriteInstance::patchELFGOT(ELFObjectFile<ELFT> *File) {
|
|
|
|
|
auto &OS = Out->os();
|
|
|
|
|
|
|
|
|
|
SectionRef GOTSection;
|
|
|
|
|
for (const auto &Section : File->sections()) {
|
|
|
|
|
StringRef SectionName;
|
|
|
|
|
Section.getName(SectionName);
|
|
|
|
|
if (SectionName == ".got") {
|
|
|
|
|
GOTSection = Section;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!GOTSection.getObject()) {
|
|
|
|
|
errs() << "BOLT-INFO: no .got section found\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StringRef GOTContents;
|
|
|
|
|
GOTSection.getContents(GOTContents);
|
|
|
|
|
for (const uint64_t *GOTEntry =
|
|
|
|
|
reinterpret_cast<const uint64_t *>(GOTContents.data());
|
|
|
|
|
GOTEntry < reinterpret_cast<const uint64_t *>(GOTContents.data() +
|
|
|
|
|
GOTContents.size());
|
|
|
|
|
++GOTEntry) {
|
|
|
|
|
if (auto NewAddress = getNewFunctionAddress(*GOTEntry)) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: patching GOT entry 0x"
|
|
|
|
|
<< Twine::utohexstr(*GOTEntry) << " with 0x"
|
|
|
|
|
<< Twine::utohexstr(NewAddress) << '\n');
|
|
|
|
|
OS.pwrite(reinterpret_cast<const char *>(&NewAddress), sizeof(NewAddress),
|
|
|
|
|
reinterpret_cast<const char *>(GOTEntry) - File->getData().data());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
|
void RewriteInstance::patchELFDynamic(ELFObjectFile<ELFT> *File) {
|
|
|
|
|
auto *Obj = File->getELFFile();
|
|
|
|
|
auto &OS = Out->os();
|
|
|
|
|
|
|
|
|
|
using Elf_Phdr = typename ELFFile<ELFT>::Elf_Phdr;
|
|
|
|
|
using Elf_Dyn = typename ELFFile<ELFT>::Elf_Dyn;
|
|
|
|
|
|
|
|
|
|
// Locate DYNAMIC by looking through program headers.
|
|
|
|
|
uint64_t DynamicOffset = 0;
|
|
|
|
|
const Elf_Phdr *DynamicPhdr = 0;
|
|
|
|
|
for (auto &Phdr : Obj->program_headers()) {
|
|
|
|
|
if (Phdr.p_type == ELF::PT_DYNAMIC) {
|
|
|
|
|
DynamicOffset = Phdr.p_offset;
|
|
|
|
|
DynamicPhdr = &Phdr;
|
|
|
|
|
assert(Phdr.p_memsz == Phdr.p_filesz && "dynamic sizes should match");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(DynamicPhdr && "missing dynamic in ELF binary");
|
|
|
|
|
|
2017-08-04 11:21:05 -07:00
|
|
|
bool ZNowSet = false;
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Go through all dynamic entries and patch functions addresses with
|
|
|
|
|
// new ones.
|
|
|
|
|
ErrorOr<const Elf_Dyn *> DTB = Obj->dynamic_table_begin(DynamicPhdr);
|
|
|
|
|
ErrorOr<const Elf_Dyn *> DTE = Obj->dynamic_table_end(DynamicPhdr);
|
|
|
|
|
assert(DTB && DTE && "error accessing dynamic table");
|
|
|
|
|
for (auto *DE = *DTB; DE != *DTE; ++DE) {
|
|
|
|
|
auto NewDE = *DE;
|
|
|
|
|
bool ShouldPatch = true;
|
|
|
|
|
switch (DE->getTag()) {
|
|
|
|
|
default:
|
|
|
|
|
ShouldPatch = false;
|
|
|
|
|
break;
|
|
|
|
|
case ELF::DT_INIT:
|
|
|
|
|
case ELF::DT_FINI:
|
2017-08-04 11:21:05 -07:00
|
|
|
if (opts::Relocs) {
|
|
|
|
|
if (auto NewAddress = getNewFunctionAddress(DE->getPtr())) {
|
|
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: patching dynamic entry of type "
|
|
|
|
|
<< DE->getTag() << '\n');
|
|
|
|
|
NewDE.d_un.d_ptr = NewAddress;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ELF::DT_FLAGS:
|
|
|
|
|
if (BC->RequiresZNow) {
|
|
|
|
|
NewDE.d_un.d_val |= ELF::DF_BIND_NOW;
|
|
|
|
|
ZNowSet = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ELF::DT_FLAGS_1:
|
|
|
|
|
if (BC->RequiresZNow) {
|
|
|
|
|
NewDE.d_un.d_val |= ELF::DF_1_NOW;
|
|
|
|
|
ZNowSet = true;
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (ShouldPatch) {
|
|
|
|
|
OS.pwrite(reinterpret_cast<const char *>(&NewDE), sizeof(NewDE),
|
|
|
|
|
DynamicOffset + (DE - *DTB) * sizeof(*DE));
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-04 11:21:05 -07:00
|
|
|
|
|
|
|
|
if (BC->RequiresZNow && !ZNowSet) {
|
|
|
|
|
errs() << "BOLT-ERROR: output binary requires immediate relocation "
|
|
|
|
|
"processing which depends on DT_FLAGS or DT_FLAGS_1 presence in "
|
|
|
|
|
".dynamic. Please re-link the binary with -znow.\n";
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t RewriteInstance::getNewFunctionAddress(uint64_t OldAddress) {
|
2016-12-21 17:13:56 -08:00
|
|
|
const auto *Function = getBinaryFunctionAtAddress(OldAddress);
|
2016-09-27 19:09:38 -07:00
|
|
|
if (!Function)
|
|
|
|
|
return 0;
|
2017-05-08 22:51:36 -07:00
|
|
|
return Function->getOutputAddress();
|
2016-02-08 10:02:48 -08:00
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
void RewriteInstance::rewriteFile() {
|
2016-09-27 19:09:38 -07:00
|
|
|
auto &OS = Out->os();
|
|
|
|
|
|
2016-02-08 10:02:48 -08:00
|
|
|
// We obtain an asm-specific writer so that we can emit nops in an
|
|
|
|
|
// architecture-specific way at the end of the function.
|
2015-11-23 17:54:18 -08:00
|
|
|
auto MCE = BC->TheTarget->createMCCodeEmitter(*BC->MII, *BC->MRI, *BC->Ctx);
|
|
|
|
|
auto MAB = BC->TheTarget->createMCAsmBackend(*BC->MRI, BC->TripleName, "");
|
|
|
|
|
std::unique_ptr<MCStreamer> Streamer(
|
|
|
|
|
BC->TheTarget->createMCObjectStreamer(*BC->TheTriple,
|
|
|
|
|
*BC->Ctx,
|
|
|
|
|
*MAB,
|
2016-09-27 19:09:38 -07:00
|
|
|
OS,
|
2015-11-23 17:54:18 -08:00
|
|
|
MCE,
|
|
|
|
|
*BC->STI,
|
|
|
|
|
/* RelaxAll */ false,
|
|
|
|
|
/* DWARFMustBeAtTheEnd */ false));
|
2016-03-11 11:30:30 -08:00
|
|
|
|
2015-11-23 17:54:18 -08:00
|
|
|
auto &Writer = static_cast<MCObjectStreamer *>(Streamer.get())
|
|
|
|
|
->getAssembler()
|
|
|
|
|
.getWriter();
|
|
|
|
|
|
2016-02-12 19:01:53 -08:00
|
|
|
// Make sure output stream has enough reserved space, otherwise
|
|
|
|
|
// pwrite() will fail.
|
2017-01-17 15:49:59 -08:00
|
|
|
auto Offset = OS.seek(getFileOffsetForAddress(NextAvailableAddress));
|
2017-05-25 10:29:38 -07:00
|
|
|
(void)Offset;
|
2017-01-17 15:49:59 -08:00
|
|
|
assert(Offset == getFileOffsetForAddress(NextAvailableAddress) &&
|
2016-02-08 10:02:48 -08:00
|
|
|
"error resizing output file");
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (!opts::Relocs) {
|
|
|
|
|
// Overwrite functions in the output file.
|
|
|
|
|
uint64_t CountOverwrittenFunctions = 0;
|
|
|
|
|
uint64_t OverwrittenScore = 0;
|
|
|
|
|
for (auto &BFI : BinaryFunctions) {
|
|
|
|
|
auto &Function = BFI.second;
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (Function.getImageAddress() == 0 || Function.getImageSize() == 0)
|
|
|
|
|
continue;
|
2016-04-05 19:35:45 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (Function.getImageSize() > Function.getMaxSize()) {
|
|
|
|
|
if (opts::Verbosity >= 1) {
|
|
|
|
|
errs() << "BOLT-WARNING: new function size (0x"
|
|
|
|
|
<< Twine::utohexstr(Function.getImageSize())
|
|
|
|
|
<< ") is larger than maximum allowed size (0x"
|
|
|
|
|
<< Twine::utohexstr(Function.getMaxSize())
|
|
|
|
|
<< ") for function " << Function << '\n';
|
|
|
|
|
}
|
|
|
|
|
FailedAddresses.emplace_back(Function.getAddress());
|
|
|
|
|
continue;
|
2016-09-02 14:15:29 -07:00
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (Function.isSplit() && (Function.cold().getImageAddress() == 0 ||
|
|
|
|
|
Function.cold().getImageSize() == 0))
|
|
|
|
|
continue;
|
2016-09-08 14:52:26 -07:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
OverwrittenScore += Function.getFunctionScore();
|
|
|
|
|
// Overwrite function in the output file.
|
|
|
|
|
if (opts::Verbosity >= 2) {
|
|
|
|
|
outs() << "BOLT: rewriting function \"" << Function << "\"\n";
|
|
|
|
|
}
|
2017-01-17 15:49:59 -08:00
|
|
|
OS.pwrite(reinterpret_cast<char *>(Function.getImageAddress()),
|
2017-05-08 22:51:36 -07:00
|
|
|
Function.getImageSize(),
|
|
|
|
|
Function.getFileOffset());
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
// Write nops at the end of the function.
|
2017-01-17 15:49:59 -08:00
|
|
|
auto Pos = OS.tell();
|
|
|
|
|
OS.seek(Function.getFileOffset() + Function.getImageSize());
|
2016-09-27 19:09:38 -07:00
|
|
|
MAB->writeNopData(Function.getMaxSize() - Function.getImageSize(),
|
|
|
|
|
&Writer);
|
2017-01-17 15:49:59 -08:00
|
|
|
OS.seek(Pos);
|
|
|
|
|
|
|
|
|
|
// Write jump tables if updating in-place.
|
|
|
|
|
if (opts::JumpTables == JTS_BASIC) {
|
|
|
|
|
for (auto &JTI : Function.JumpTables) {
|
|
|
|
|
auto &JT = JTI.second;
|
|
|
|
|
assert(JT.SecInfo && "section info for jump table expected");
|
|
|
|
|
JT.SecInfo->FileOffset =
|
|
|
|
|
getFileOffsetForAddress(JT.Address);
|
|
|
|
|
assert(JT.SecInfo->FileOffset && "no matching offset in file");
|
|
|
|
|
Out->os().pwrite(reinterpret_cast<char *>(JT.SecInfo->AllocAddress),
|
|
|
|
|
JT.SecInfo->Size,
|
|
|
|
|
JT.SecInfo->FileOffset);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
if (!Function.isSplit()) {
|
|
|
|
|
++CountOverwrittenFunctions;
|
|
|
|
|
if (opts::MaxFunctions &&
|
|
|
|
|
CountOverwrittenFunctions == opts::MaxFunctions) {
|
|
|
|
|
outs() << "BOLT: maximum number of functions reached\n";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Write cold part
|
|
|
|
|
if (opts::Verbosity >= 2) {
|
|
|
|
|
outs() << "BOLT: rewriting function \"" << Function
|
|
|
|
|
<< "\" (cold part)\n";
|
|
|
|
|
}
|
2017-05-08 22:51:36 -07:00
|
|
|
OS.pwrite(reinterpret_cast<char*>(Function.cold().getImageAddress()),
|
|
|
|
|
Function.cold().getImageSize(),
|
|
|
|
|
Function.cold().getFileOffset());
|
2016-09-27 19:09:38 -07:00
|
|
|
|
|
|
|
|
// FIXME: write nops after cold part too.
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
++CountOverwrittenFunctions;
|
|
|
|
|
if (opts::MaxFunctions &&
|
|
|
|
|
CountOverwrittenFunctions == opts::MaxFunctions) {
|
2016-02-05 14:42:04 -08:00
|
|
|
outs() << "BOLT: maximum number of functions reached\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
// Print function statistics.
|
|
|
|
|
outs() << "BOLT: " << CountOverwrittenFunctions
|
|
|
|
|
<< " out of " << BinaryFunctions.size()
|
|
|
|
|
<< " functions were overwritten.\n";
|
|
|
|
|
if (TotalScore != 0) {
|
|
|
|
|
double Coverage = OverwrittenScore / (double)TotalScore * 100.0;
|
|
|
|
|
outs() << format("BOLT: Rewritten functions cover %.2lf", Coverage)
|
|
|
|
|
<< "% of the execution count of simple functions of "
|
|
|
|
|
"this binary.\n";
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
|
|
|
|
}
|
2015-12-18 17:00:46 -08:00
|
|
|
|
2016-09-27 19:09:38 -07:00
|
|
|
if (opts::Relocs && opts::TrapOldCode) {
|
2017-01-17 15:49:59 -08:00
|
|
|
auto SavedPos = OS.tell();
|
2016-09-27 19:09:38 -07:00
|
|
|
// Overwrite function body to make sure we never execute these instructions.
|
|
|
|
|
for (auto &BFI : BinaryFunctions) {
|
|
|
|
|
auto &BF = BFI.second;
|
|
|
|
|
if (!BF.getFileOffset())
|
|
|
|
|
continue;
|
2017-01-17 15:49:59 -08:00
|
|
|
OS.seek(BF.getFileOffset());
|
2016-09-27 19:09:38 -07:00
|
|
|
for (unsigned I = 0; I < BF.getMaxSize(); ++I)
|
2017-01-17 15:49:59 -08:00
|
|
|
OS.write((unsigned char)
|
2016-09-27 19:09:38 -07:00
|
|
|
Streamer->getContext().getAsmInfo()->getTrapFillValue());
|
|
|
|
|
}
|
2017-01-17 15:49:59 -08:00
|
|
|
OS.seek(SavedPos);
|
2016-03-03 10:13:11 -08:00
|
|
|
}
|
2015-12-18 17:00:46 -08:00
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
// Write all non-local sections, i.e. those not emitted with the function.
|
|
|
|
|
for (auto &SMII : EFMM->SectionMapInfo) {
|
2016-02-08 10:02:48 -08:00
|
|
|
SectionInfo &SI = SMII.second;
|
2017-01-17 15:49:59 -08:00
|
|
|
if (SI.IsLocal)
|
2016-02-08 10:02:48 -08:00
|
|
|
continue;
|
2016-09-02 14:15:29 -07:00
|
|
|
if (opts::Verbosity >= 1) {
|
|
|
|
|
outs() << "BOLT: writing new section " << SMII.first << '\n';
|
2017-01-17 15:49:59 -08:00
|
|
|
outs() << " data at 0x" << Twine::utohexstr(SI.AllocAddress) << '\n';
|
|
|
|
|
outs() << " of size " << SI.Size << '\n';
|
|
|
|
|
outs() << " at offset " << SI.FileOffset << '\n';
|
2016-09-02 14:15:29 -07:00
|
|
|
}
|
2017-01-17 15:49:59 -08:00
|
|
|
OS.pwrite(reinterpret_cast<const char *>(SI.AllocAddress),
|
2016-02-08 10:02:48 -08:00
|
|
|
SI.Size,
|
|
|
|
|
SI.FileOffset);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-11 14:33:34 -08:00
|
|
|
// If .eh_frame is present create .eh_frame_hdr.
|
2017-01-17 15:49:59 -08:00
|
|
|
auto SMII = EFMM->SectionMapInfo.find(".eh_frame");
|
|
|
|
|
if (SMII != EFMM->SectionMapInfo.end()) {
|
2016-11-11 14:33:34 -08:00
|
|
|
writeEHFrameHeader(SMII->second);
|
2015-12-18 17:00:46 -08:00
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
// Patch program header table.
|
|
|
|
|
patchELFPHDRTable();
|
2016-02-08 10:02:48 -08:00
|
|
|
|
2017-05-16 17:29:31 -07:00
|
|
|
// Finalize memory image of section string table.
|
|
|
|
|
finalizeSectionStringTable();
|
|
|
|
|
|
2017-06-27 16:25:59 -07:00
|
|
|
if (opts::Relocs) {
|
|
|
|
|
// Update symbol tables.
|
|
|
|
|
patchELFSymTabs();
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
// Copy non-allocatable sections once allocatable part is finished.
|
|
|
|
|
rewriteNoteSections();
|
|
|
|
|
|
2017-08-04 11:21:05 -07:00
|
|
|
// Patch dynamic section/segment.
|
|
|
|
|
patchELFDynamic();
|
2016-09-27 19:09:38 -07:00
|
|
|
|
2017-08-04 11:21:05 -07:00
|
|
|
if (opts::Relocs) {
|
2017-01-17 15:49:59 -08:00
|
|
|
patchELFRelaPLT();
|
2016-09-27 19:09:38 -07:00
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
patchELFGOT();
|
|
|
|
|
}
|
2016-09-27 19:09:38 -07:00
|
|
|
|
2016-03-03 10:13:11 -08:00
|
|
|
// Update ELF book-keeping info.
|
|
|
|
|
patchELFSectionHeaderTable();
|
2015-11-23 17:54:18 -08:00
|
|
|
|
|
|
|
|
Out->keep();
|
2016-11-15 10:40:00 -08:00
|
|
|
|
|
|
|
|
// If requested, open again the binary we just wrote to dump its EH Frame
|
|
|
|
|
if (opts::DumpEHFrame) {
|
|
|
|
|
ErrorOr<OwningBinary<Binary>> BinaryOrErr =
|
|
|
|
|
createBinary(opts::OutputFilename);
|
|
|
|
|
if (std::error_code EC = BinaryOrErr.getError())
|
|
|
|
|
report_error(opts::OutputFilename, EC);
|
|
|
|
|
Binary &Binary = *BinaryOrErr.get().getBinary();
|
|
|
|
|
|
|
|
|
|
if (auto *E = dyn_cast<ELFObjectFileBase>(&Binary)) {
|
2016-09-27 19:09:38 -07:00
|
|
|
DWARFContextInMemory DwCtx(*E, nullptr, true);
|
2016-11-15 10:40:00 -08:00
|
|
|
const auto &EHFrame = DwCtx.getEHFrame();
|
|
|
|
|
outs() << "BOLT-INFO: Dumping rewritten .eh_frame\n";
|
|
|
|
|
EHFrame->dump(outs());
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-23 17:54:18 -08:00
|
|
|
}
|
2016-03-02 18:40:10 -08:00
|
|
|
|
2016-11-11 14:33:34 -08:00
|
|
|
void RewriteInstance::writeEHFrameHeader(SectionInfo &EHFrameSecInfo) {
|
|
|
|
|
DWARFFrame NewEHFrame(EHFrameSecInfo.FileAddress);
|
|
|
|
|
NewEHFrame.parse(
|
|
|
|
|
DataExtractor(StringRef(reinterpret_cast<const char *>(
|
|
|
|
|
EHFrameSecInfo.AllocAddress),
|
|
|
|
|
EHFrameSecInfo.Size),
|
|
|
|
|
BC->AsmInfo->isLittleEndian(),
|
|
|
|
|
BC->AsmInfo->getPointerSize()));
|
|
|
|
|
if (!NewEHFrame.ParseError.empty()) {
|
|
|
|
|
errs() << "BOLT-ERROR: EHFrame reader failed with message \""
|
|
|
|
|
<< NewEHFrame.ParseError << '\n';
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
auto OldSMII = EFMM->SectionMapInfo.find(".eh_frame_old");
|
|
|
|
|
assert(OldSMII != EFMM->SectionMapInfo.end() &&
|
2016-11-11 14:33:34 -08:00
|
|
|
"expected .eh_frame_old to be present");
|
|
|
|
|
auto &OldEHFrameSecInfo = OldSMII->second;
|
|
|
|
|
DWARFFrame OldEHFrame(OldEHFrameSecInfo.FileAddress);
|
|
|
|
|
OldEHFrame.parse(
|
|
|
|
|
DataExtractor(StringRef(reinterpret_cast<const char *>(
|
|
|
|
|
OldEHFrameSecInfo.AllocAddress),
|
|
|
|
|
OldEHFrameSecInfo.Size),
|
|
|
|
|
BC->AsmInfo->isLittleEndian(),
|
|
|
|
|
BC->AsmInfo->getPointerSize()));
|
|
|
|
|
if (!OldEHFrame.ParseError.empty()) {
|
|
|
|
|
errs() << "BOLT-ERROR: EHFrame reader failed with message \""
|
|
|
|
|
<< OldEHFrame.ParseError << '\n';
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "BOLT: writing a new .eh_frame_hdr\n");
|
|
|
|
|
|
2017-04-06 10:49:59 -07:00
|
|
|
NextAvailableAddress =
|
|
|
|
|
appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign);
|
2016-11-11 14:33:34 -08:00
|
|
|
|
|
|
|
|
SectionInfo EHFrameHdrSecInfo;
|
|
|
|
|
EHFrameHdrSecInfo.FileAddress = NextAvailableAddress;
|
2017-01-17 15:49:59 -08:00
|
|
|
EHFrameHdrSecInfo.FileOffset = getFileOffsetForAddress(NextAvailableAddress);
|
2016-11-11 14:33:34 -08:00
|
|
|
|
|
|
|
|
auto NewEHFrameHdr =
|
|
|
|
|
CFIRdWrt->generateEHFrameHeader(OldEHFrame,
|
|
|
|
|
NewEHFrame,
|
|
|
|
|
EHFrameHdrSecInfo.FileAddress,
|
|
|
|
|
FailedAddresses);
|
|
|
|
|
|
|
|
|
|
EHFrameHdrSecInfo.Size = NewEHFrameHdr.size();
|
|
|
|
|
|
|
|
|
|
assert(Out->os().tell() == EHFrameHdrSecInfo.FileOffset &&
|
|
|
|
|
"offset mismatch");
|
|
|
|
|
Out->os().write(NewEHFrameHdr.data(), EHFrameHdrSecInfo.Size);
|
|
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
EFMM->SectionMapInfo[".eh_frame_hdr"] = EHFrameHdrSecInfo;
|
2016-11-11 14:33:34 -08:00
|
|
|
|
|
|
|
|
NextAvailableAddress += EHFrameHdrSecInfo.Size;
|
|
|
|
|
|
|
|
|
|
// Merge .eh_frame and .eh_frame_old so that gdb can locate all FDEs.
|
|
|
|
|
EHFrameSecInfo.Size = OldEHFrameSecInfo.FileAddress + OldEHFrameSecInfo.Size
|
|
|
|
|
- EHFrameSecInfo.FileAddress;
|
2017-01-17 15:49:59 -08:00
|
|
|
EFMM->SectionMapInfo.erase(OldSMII);
|
2016-11-11 14:33:34 -08:00
|
|
|
DEBUG(dbgs() << "BOLT-DEBUG: size of .eh_frame after merge is "
|
|
|
|
|
<< EHFrameSecInfo.Size << '\n');
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-17 15:49:59 -08:00
|
|
|
uint64_t RewriteInstance::getFileOffsetForAddress(uint64_t Address) const {
|
|
|
|
|
// Check if it's possibly part of the new segment.
|
|
|
|
|
if (Address >= NewTextSegmentAddress) {
|
|
|
|
|
return Address - NewTextSegmentAddress + NewTextSegmentOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find an existing segment that matches the address.
|
|
|
|
|
const auto SegmentInfoI = EFMM->SegmentMapInfo.upper_bound(Address);
|
|
|
|
|
if (SegmentInfoI == EFMM->SegmentMapInfo.begin())
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
const auto &SegmentInfo = std::prev(SegmentInfoI)->second;
|
|
|
|
|
if (Address < SegmentInfo.Address ||
|
|
|
|
|
Address >= SegmentInfo.Address + SegmentInfo.FileSize)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return SegmentInfo.FileOffset + Address - SegmentInfo.Address;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-07 12:20:46 -08:00
|
|
|
bool RewriteInstance::willOverwriteSection(StringRef SectionName) {
|
2017-06-27 16:25:59 -07:00
|
|
|
if (opts::Relocs) {
|
|
|
|
|
for (auto &OverwriteName : SectionsToOverwriteRelocMode) {
|
|
|
|
|
if (SectionName == OverwriteName)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (auto &OverwriteName : SectionsToOverwrite) {
|
|
|
|
|
if (SectionName == OverwriteName)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-05-16 17:02:17 -07:00
|
|
|
}
|
|
|
|
|
|
2017-02-07 12:20:46 -08:00
|
|
|
auto SMII = EFMM->SectionMapInfo.find(SectionName);
|
|
|
|
|
if (SMII != EFMM->SectionMapInfo.end())
|
|
|
|
|
return true;
|
|
|
|
|
|
2016-05-16 17:02:17 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2016-08-22 14:24:09 -07:00
|
|
|
|
|
|
|
|
BinaryFunction *
|
2016-09-27 19:09:38 -07:00
|
|
|
RewriteInstance::getBinaryFunctionContainingAddress(uint64_t Address,
|
2017-02-21 14:18:09 -08:00
|
|
|
bool CheckPastEnd,
|
|
|
|
|
bool UseMaxSize) {
|
2016-08-22 14:24:09 -07:00
|
|
|
auto FI = BinaryFunctions.upper_bound(Address);
|
|
|
|
|
if (FI == BinaryFunctions.begin())
|
|
|
|
|
return nullptr;
|
|
|
|
|
--FI;
|
2017-02-21 14:18:09 -08:00
|
|
|
|
|
|
|
|
const auto UsedSize = UseMaxSize ? FI->second.getMaxSize()
|
|
|
|
|
: FI->second.getSize();
|
|
|
|
|
|
|
|
|
|
if (Address >= FI->first + UsedSize + (CheckPastEnd ? 1 : 0))
|
2016-08-22 14:24:09 -07:00
|
|
|
return nullptr;
|
|
|
|
|
return &FI->second;
|
|
|
|
|
}
|
2016-12-21 17:13:56 -08:00
|
|
|
|
|
|
|
|
const BinaryFunction *
|
|
|
|
|
RewriteInstance::getBinaryFunctionAtAddress(uint64_t Address) const {
|
|
|
|
|
const auto *Symbol = BC->getGlobalSymbolAtAddress(Address);
|
|
|
|
|
if (!Symbol)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
return BC->getFunctionForSymbol(Symbol);
|
|
|
|
|
}
|
2017-05-16 09:27:34 -07:00
|
|
|
|
|
|
|
|
DWARFAddressRangesVector RewriteInstance::translateModuleAddressRanges(
|
|
|
|
|
const DWARFAddressRangesVector &InputRanges) const {
|
|
|
|
|
DWARFAddressRangesVector OutputRanges;
|
|
|
|
|
|
|
|
|
|
for (const auto Range : InputRanges) {
|
|
|
|
|
auto BFI = BinaryFunctions.lower_bound(Range.first);
|
|
|
|
|
while (BFI != BinaryFunctions.end()) {
|
|
|
|
|
const auto &Function = BFI->second;
|
|
|
|
|
if (Function.getAddress() >= Range.second)
|
|
|
|
|
break;
|
|
|
|
|
const auto FunctionRanges = Function.getOutputAddressRanges();
|
|
|
|
|
std::move(std::begin(FunctionRanges),
|
|
|
|
|
std::end(FunctionRanges),
|
|
|
|
|
std::back_inserter(OutputRanges));
|
|
|
|
|
std::advance(BFI, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OutputRanges;
|
|
|
|
|
}
|