From 56afa6e6600151858649d12e4360746918a7978b Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Mon, 21 Dec 2015 22:09:27 +0000 Subject: [PATCH] [MC, COFF] Support link /incremental conditionally Today, we always take into account the possibility that object files produced by MC may be consumed by an incremental linker. This results in us initialing fields which vary with time (TimeDateStamp) which harms hermetic builds (e.g. verifying a self-host went well) and produces sub-optimal code because we cannot assume anything about the relative position of functions within a section (call sites can get redirected through incremental linker thunks). Let's provide an MCTargetOption which controls this behavior so that we can disable this functionality if we know a-priori that the build will not rely on /incremental. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256203 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCAssembler.h | 8 ++++++++ include/llvm/MC/MCTargetOptions.h | 2 ++ include/llvm/MC/MCTargetOptionsCommandFlags.h | 7 +++++++ include/llvm/Support/TargetRegistry.h | 7 +++++-- lib/CodeGen/LLVMTargetMachine.cpp | 2 ++ lib/MC/MCAssembler.cpp | 3 ++- lib/MC/MCTargetOptions.cpp | 5 +++-- lib/MC/WinCOFFObjectWriter.cpp | 17 ++++++++++++----- lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h | 3 ++- .../ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp | 12 ++++++------ lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h | 2 +- .../X86/MCTargetDesc/X86WinCOFFStreamer.cpp | 4 +++- test/MC/ARM/Windows/invalid-relocation.s | 2 +- test/MC/COFF/simple-fixups.s | 4 ++-- test/MC/COFF/timestamp.s | 2 +- tools/dsymutil/DwarfLinker.cpp | 9 ++++++--- tools/llvm-dwp/llvm-dwp.cpp | 5 ++++- tools/llvm-mc/llvm-mc.cpp | 7 ++++--- 18 files changed, 71 insertions(+), 30 deletions(-) diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 745d8ba6815..87430cd59ec 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -609,6 +609,7 @@ private: unsigned RelaxAll : 1; unsigned SubsectionsViaSymbols : 1; + unsigned IncrementalLinkerCompatible : 1; /// ELF specific e_header flags // It would be good if there were an MCELFAssembler class to hold this. @@ -750,6 +751,13 @@ public: bool getSubsectionsViaSymbols() const { return SubsectionsViaSymbols; } void setSubsectionsViaSymbols(bool Value) { SubsectionsViaSymbols = Value; } + bool isIncrementalLinkerCompatible() const { + return IncrementalLinkerCompatible; + } + void setIncrementalLinkerCompatible(bool Value) { + IncrementalLinkerCompatible = Value; + } + bool getRelaxAll() const { return RelaxAll; } void setRelaxAll(bool Value) { RelaxAll = Value; } diff --git a/include/llvm/MC/MCTargetOptions.h b/include/llvm/MC/MCTargetOptions.h index 00a74de9d06..4b66a750cb7 100644 --- a/include/llvm/MC/MCTargetOptions.h +++ b/include/llvm/MC/MCTargetOptions.h @@ -32,6 +32,7 @@ public: bool MCNoWarn : 1; bool MCSaveTempLabels : 1; bool MCUseDwarfDirectory : 1; + bool MCIncrementalLinkerCompatible : 1; bool ShowMCEncoding : 1; bool ShowMCInst : 1; bool AsmVerbose : 1; @@ -53,6 +54,7 @@ inline bool operator==(const MCTargetOptions &LHS, const MCTargetOptions &RHS) { ARE_EQUAL(MCNoWarn) && ARE_EQUAL(MCSaveTempLabels) && ARE_EQUAL(MCUseDwarfDirectory) && + ARE_EQUAL(MCIncrementalLinkerCompatible) && ARE_EQUAL(ShowMCEncoding) && ARE_EQUAL(ShowMCInst) && ARE_EQUAL(AsmVerbose) && diff --git a/include/llvm/MC/MCTargetOptionsCommandFlags.h b/include/llvm/MC/MCTargetOptionsCommandFlags.h index 1240e135ea0..5180208d33b 100644 --- a/include/llvm/MC/MCTargetOptionsCommandFlags.h +++ b/include/llvm/MC/MCTargetOptionsCommandFlags.h @@ -33,6 +33,12 @@ cl::opt RelaxAll("mc-relax-all", cl::desc("When used with filetype=obj, " "relax all fixups in the emitted object file")); +cl::opt IncrementalLinkerCompatible( + "incremental-linker-compatible", + cl::desc( + "When used with filetype=obj, " + "emit an object file which can be used with an incremental linker")); + cl::opt DwarfVersion("dwarf-version", cl::desc("Dwarf version"), cl::init(0)); @@ -56,6 +62,7 @@ static inline MCTargetOptions InitMCTargetOptionsFromFlags() { Options.SanitizeAddress = (AsmInstrumentation == MCTargetOptions::AsmInstrumentationAddress); Options.MCRelaxAll = RelaxAll; + Options.MCIncrementalLinkerCompatible = IncrementalLinkerCompatible; Options.DwarfVersion = DwarfVersion; Options.ShowMCInst = ShowMCInst; Options.ABIName = ABIName; diff --git a/include/llvm/Support/TargetRegistry.h b/include/llvm/Support/TargetRegistry.h index 3a9711cea38..aec181b1d26 100644 --- a/include/llvm/Support/TargetRegistry.h +++ b/include/llvm/Support/TargetRegistry.h @@ -141,7 +141,8 @@ public: typedef MCStreamer *(*COFFStreamerCtorTy)(MCContext &Ctx, MCAsmBackend &TAB, raw_pwrite_stream &OS, MCCodeEmitter *Emitter, - bool RelaxAll); + bool RelaxAll, + bool IncrementalLinkerCompatible); typedef MCTargetStreamer *(*NullTargetStreamerCtorTy)(MCStreamer &S); typedef MCTargetStreamer *(*AsmTargetStreamerCtorTy)( MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint, @@ -437,6 +438,7 @@ public: MCAsmBackend &TAB, raw_pwrite_stream &OS, MCCodeEmitter *Emitter, const MCSubtargetInfo &STI, bool RelaxAll, + bool IncrementalLinkerCompatible, bool DWARFMustBeAtTheEnd) const { MCStreamer *S; switch (T.getObjectFormat()) { @@ -444,7 +446,8 @@ public: llvm_unreachable("Unknown object format"); case Triple::COFF: assert(T.isOSWindows() && "only Windows COFF is supported"); - S = COFFStreamerCtorFn(Ctx, TAB, OS, Emitter, RelaxAll); + S = COFFStreamerCtorFn(Ctx, TAB, OS, Emitter, RelaxAll, + IncrementalLinkerCompatible); break; case Triple::MachO: if (MachOStreamerCtorFn) diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp index da24cb17918..1c27377feee 100644 --- a/lib/CodeGen/LLVMTargetMachine.cpp +++ b/lib/CodeGen/LLVMTargetMachine.cpp @@ -203,6 +203,7 @@ bool LLVMTargetMachine::addPassesToEmitFile( Triple T(getTargetTriple().str()); AsmStreamer.reset(getTarget().createMCObjectStreamer( T, *Context, *MAB, Out, MCE, STI, Options.MCOptions.MCRelaxAll, + Options.MCOptions.MCIncrementalLinkerCompatible, /*DWARFMustBeAtTheEnd*/ true)); break; } @@ -255,6 +256,7 @@ bool LLVMTargetMachine::addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx, const MCSubtargetInfo &STI = *getMCSubtargetInfo(); std::unique_ptr AsmStreamer(getTarget().createMCObjectStreamer( T, *Ctx, *MAB, Out, MCE, STI, Options.MCOptions.MCRelaxAll, + Options.MCOptions.MCIncrementalLinkerCompatible, /*DWARFMustBeAtTheEnd*/ true)); // Create the AsmPrinter, which takes ownership of AsmStreamer if successful. diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 9f3ab18a40b..297db86e00c 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -337,7 +337,7 @@ MCAssembler::MCAssembler(MCContext &Context_, MCAsmBackend &Backend_, MCCodeEmitter &Emitter_, MCObjectWriter &Writer_) : Context(Context_), Backend(Backend_), Emitter(Emitter_), Writer(Writer_), BundleAlignSize(0), RelaxAll(false), SubsectionsViaSymbols(false), - ELFHeaderEFlags(0) { + IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) { VersionMinInfo.Major = 0; // Major version == 0 for "none specified" } @@ -355,6 +355,7 @@ void MCAssembler::reset() { BundleAlignSize = 0; RelaxAll = false; SubsectionsViaSymbols = false; + IncrementalLinkerCompatible = false; ELFHeaderEFlags = 0; LOHContainer.reset(); VersionMinInfo.Major = 0; diff --git a/lib/MC/MCTargetOptions.cpp b/lib/MC/MCTargetOptions.cpp index 64796af10c8..46562271552 100644 --- a/lib/MC/MCTargetOptions.cpp +++ b/lib/MC/MCTargetOptions.cpp @@ -15,8 +15,9 @@ namespace llvm { MCTargetOptions::MCTargetOptions() : SanitizeAddress(false), MCRelaxAll(false), MCNoExecStack(false), MCFatalWarnings(false), MCNoWarn(false), MCSaveTempLabels(false), - MCUseDwarfDirectory(false), ShowMCEncoding(false), ShowMCInst(false), - AsmVerbose(false), DwarfVersion(0), ABIName() {} + MCUseDwarfDirectory(false), MCIncrementalLinkerCompatible(false), + ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false), + DwarfVersion(0), ABIName() {} StringRef MCTargetOptions::getABIName() const { return ABIName; diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index ffb636a5932..a3820906b76 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -621,7 +621,8 @@ bool WinCOFFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( // thunk to implement their /INCREMENTAL feature. Make sure we don't optimize // away any relocations to functions. uint16_t Type = cast(SymA).getType(); - if ((Type >> COFF::SCT_COMPLEX_TYPE_SHIFT) == COFF::IMAGE_SYM_DTYPE_FUNCTION) + if (Asm.isIncrementalLinkerCompatible() && + (Type >> COFF::SCT_COMPLEX_TYPE_SHIFT) == COFF::IMAGE_SYM_DTYPE_FUNCTION) return false; return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB, InSet, IsPCRel); @@ -968,13 +969,19 @@ void WinCOFFObjectWriter::writeObject(MCAssembler &Asm, Header.PointerToSymbolTable = offset; + // FIXME: Remove the #else branch and make the #if branch unconditional once + // LLVM's self host configuration is aware of /Brepro. #if (ENABLE_TIMESTAMPS == 1) // MS LINK expects to be able to use this timestamp to implement their // /INCREMENTAL feature. - std::time_t Now = time(nullptr); - if (Now < 0 || !isUInt<32>(Now)) - Now = UINT32_MAX; - Header.TimeDateStamp = Now; + if (Asm.isIncrementalLinkerCompatible()) { + std::time_t Now = time(nullptr); + if (Now < 0 || !isUInt<32>(Now)) + Now = UINT32_MAX; + Header.TimeDateStamp = Now; + } else { + Header.TimeDateStamp = 0; + } #else // We want a deterministic output. It looks like GNU as also writes 0 in here. Header.TimeDateStamp = 0; diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h index fd30623d79a..c2bbc8e828c 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h +++ b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h @@ -86,7 +86,8 @@ MCAsmBackend *createThumbBEAsmBackend(const Target &T, // object file. MCStreamer *createARMWinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB, raw_pwrite_stream &OS, - MCCodeEmitter *Emitter, bool RelaxAll); + MCCodeEmitter *Emitter, bool RelaxAll, + bool IncrementalLinkerCompatible); /// Construct an ELF Mach-O object writer. MCObjectWriter *createARMELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI, diff --git a/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp index b993b1be484..83fa084e60c 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp @@ -37,11 +37,11 @@ void ARMWinCOFFStreamer::EmitThumbFunc(MCSymbol *Symbol) { } } -MCStreamer *llvm::createARMWinCOFFStreamer(MCContext &Context, - MCAsmBackend &MAB, - raw_pwrite_stream &OS, - MCCodeEmitter *Emitter, - bool RelaxAll) { - return new ARMWinCOFFStreamer(Context, MAB, *Emitter, OS); +MCStreamer *llvm::createARMWinCOFFStreamer( + MCContext &Context, MCAsmBackend &MAB, raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, bool RelaxAll, bool IncrementalLinkerCompatible) { + auto *S = new ARMWinCOFFStreamer(Context, MAB, *Emitter, OS); + S->getAssembler().setIncrementalLinkerCompatible(IncrementalLinkerCompatible); + return S; } diff --git a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h index 6221baba179..f8e4e70e53f 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h +++ b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h @@ -79,7 +79,7 @@ MCAsmBackend *createX86_64AsmBackend(const Target &T, const MCRegisterInfo &MRI, /// Takes ownership of \p AB and \p CE. MCStreamer *createX86WinCOFFStreamer(MCContext &C, MCAsmBackend &AB, raw_pwrite_stream &OS, MCCodeEmitter *CE, - bool RelaxAll); + bool RelaxAll, bool IncrementalLinkerCompatible); /// Construct an X86 Mach-O object writer. MCObjectWriter *createX86MachObjectWriter(raw_pwrite_stream &OS, bool Is64Bit, diff --git a/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp b/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp index 92f42b68ae5..d04511873b4 100644 --- a/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp +++ b/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp @@ -50,9 +50,11 @@ void X86WinCOFFStreamer::FinishImpl() { MCStreamer *llvm::createX86WinCOFFStreamer(MCContext &C, MCAsmBackend &AB, raw_pwrite_stream &OS, - MCCodeEmitter *CE, bool RelaxAll) { + MCCodeEmitter *CE, bool RelaxAll, + bool IncrementalLinkerCompatible) { X86WinCOFFStreamer *S = new X86WinCOFFStreamer(C, AB, CE, OS); S->getAssembler().setRelaxAll(RelaxAll); + S->getAssembler().setIncrementalLinkerCompatible(IncrementalLinkerCompatible); return S; } diff --git a/test/MC/ARM/Windows/invalid-relocation.s b/test/MC/ARM/Windows/invalid-relocation.s index 4f4c59839a6..c3e74e97634 100644 --- a/test/MC/ARM/Windows/invalid-relocation.s +++ b/test/MC/ARM/Windows/invalid-relocation.s @@ -1,4 +1,4 @@ -# RUN: not llvm-mc -triple thumbv7-windows -filetype obj -o /dev/null 2>&1 %s \ +# RUN: not llvm-mc -triple thumbv7-windows -incremental-linker-compatible -filetype obj -o /dev/null 2>&1 %s \ # RUN: | FileCheck %s .def invalid_relocation diff --git a/test/MC/COFF/simple-fixups.s b/test/MC/COFF/simple-fixups.s index cb5d7642ee6..9d960084272 100644 --- a/test/MC/COFF/simple-fixups.s +++ b/test/MC/COFF/simple-fixups.s @@ -2,8 +2,8 @@ // references to functions. Failing to do so might cause pointer-to-function // equality to fail if /INCREMENTAL links are used. -// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 %s | llvm-readobj -s | FileCheck %s -// RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s | llvm-readobj -s | FileCheck %s +// RUN: llvm-mc -filetype=obj -incremental-linker-compatible -triple i686-pc-win32 %s | llvm-readobj -s | FileCheck %s +// RUN: llvm-mc -filetype=obj -incremental-linker-compatible -triple x86_64-pc-win32 %s | llvm-readobj -s | FileCheck %s .def _foo; .scl 2; diff --git a/test/MC/COFF/timestamp.s b/test/MC/COFF/timestamp.s index ae982b4309e..a2761575789 100644 --- a/test/MC/COFF/timestamp.s +++ b/test/MC/COFF/timestamp.s @@ -1,4 +1,4 @@ -// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 %s -o - | llvm-readobj -h | FileCheck %s +// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 -incremental-linker-compatible %s -o - | llvm-readobj -h | FileCheck %s // REQUIRES: timestamps // CHECK: ImageFileHeader { diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp index e8877a5da89..8c5f7946a42 100644 --- a/tools/dsymutil/DwarfLinker.cpp +++ b/tools/dsymutil/DwarfLinker.cpp @@ -31,6 +31,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptionsCommandFlags.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/LEB128.h" @@ -618,9 +619,11 @@ bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) { if (EC) return error(Twine(OutputFilename) + ": " + EC.message(), Context); - MS = TheTarget->createMCObjectStreamer(TheTriple, *MC, *MAB, *OutFile, MCE, - *MSTI, false, - /*DWARFMustBeAtTheEnd*/ false); + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); + MS = TheTarget->createMCObjectStreamer( + TheTriple, *MC, *MAB, *OutFile, MCE, *MSTI, MCOptions.MCRelaxAll, + MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false); if (!MS) return error("no object streamer for target " + TripleName, Context); diff --git a/tools/llvm-dwp/llvm-dwp.cpp b/tools/llvm-dwp/llvm-dwp.cpp index 5fb1c52330f..570854b849c 100644 --- a/tools/llvm-dwp/llvm-dwp.cpp +++ b/tools/llvm-dwp/llvm-dwp.cpp @@ -10,6 +10,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCTargetOptionsCommandFlags.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/FileSystem.h" @@ -404,8 +405,10 @@ int main(int argc, char **argv) { if (EC) return error(Twine(OutputFilename) + ": " + EC.message(), Context); + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); std::unique_ptr MS(TheTarget->createMCObjectStreamer( - TheTriple, MC, *MAB, OutFile, MCE, *MSTI, false, + TheTriple, MC, *MAB, OutFile, MCE, *MSTI, MCOptions.MCRelaxAll, + MCOptions.MCIncrementalLinkerCompatible, /*DWARFMustBeAtTheEnd*/ false)); if (!MS) return error("no object streamer for target " + TripleName, Context); diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index f3b34e2502f..96e3f7c21a5 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -511,9 +511,10 @@ int main(int argc, char **argv) { MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); - Str.reset(TheTarget->createMCObjectStreamer(TheTriple, Ctx, *MAB, *OS, CE, - *STI, RelaxAll, - /*DWARFMustBeAtTheEnd*/ false)); + Str.reset(TheTarget->createMCObjectStreamer( + TheTriple, Ctx, *MAB, *OS, CE, *STI, MCOptions.MCRelaxAll, + MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false)); if (NoExecStack) Str->InitSections(true); } -- 2.34.1