From c1e7621e012ddb936ee96ee3955bfb9311bff7cc Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 17 Sep 2013 23:18:05 +0000 Subject: [PATCH] COFF: Ensure that objects produced by LLVM link with /safeseh Summary: We indicate that the object files are safe by emitting a @feat.00 absolute address symbol. The address is presumably interpreted as a bitfield of features that the compiler would like to enable. Bit 0 is documented in the PE COFF spec to opt in to "registered SEH", which is what /safeseh enables. LLVM's object files are safe by default because LLVM doesn't know how to produce SEH handlers. Reviewers: Bigcheese CC: llvm-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1691 llvm-svn: 190898 --- llvm/lib/MC/WinCOFFObjectWriter.cpp | 19 ++++++++++++++----- llvm/lib/Target/X86/X86AsmPrinter.cpp | 20 ++++++++++++++++++++ llvm/test/CodeGen/X86/coff-feat00.ll | 7 +++++++ llvm/test/MC/COFF/feat00.s | 13 +++++++++++++ 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 llvm/test/CodeGen/X86/coff-feat00.ll create mode 100644 llvm/test/MC/COFF/feat00.s diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp index 263151c6afa6..32523173ee6e 100644 --- a/llvm/lib/MC/WinCOFFObjectWriter.cpp +++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -148,8 +148,8 @@ public: object_t *createCOFFEntity(StringRef Name, list_t &List); void DefineSection(MCSectionData const &SectionData); - void DefineSymbol(MCSymbolData const &SymbolData, - MCAssembler &Assembler); + void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler, + const MCAsmLayout &Layout); void MakeSymbolReal(COFFSymbol &S, size_t Index); void MakeSectionReal(COFFSection &S, size_t Number); @@ -397,7 +397,8 @@ void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { /// This function takes a section data object from the assembler /// and creates the associated COFF symbol staging object. void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, - MCAssembler &Assembler) { + MCAssembler &Assembler, + const MCAsmLayout &Layout) { MCSymbol const &Symbol = SymbolData.getSymbol(); COFFSymbol *coff_symbol = GetOrCreateCOFFSymbol(&Symbol); SymbolMap[&Symbol] = coff_symbol; @@ -438,6 +439,12 @@ void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, const MCSymbolData &ResSymData = Assembler.getSymbolData(Symbol.AliasedSymbol()); + if (Symbol.isVariable()) { + int64_t Addr; + if (Symbol.getVariableValue()->EvaluateAsAbsolute(Addr, Layout)) + coff_symbol->Data.Value = Addr; + } + coff_symbol->Data.Type = (ResSymData.getFlags() & 0x0000FFFF) >> 0; coff_symbol->Data.StorageClass = (ResSymData.getFlags() & 0x00FF0000) >> 16; @@ -449,7 +456,9 @@ void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC; } - if (ResSymData.Fragment != NULL) + if (Symbol.isAbsolute() || Symbol.AliasedSymbol().isVariable()) + coff_symbol->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; + else if (ResSymData.Fragment != NULL) coff_symbol->Section = SectionMap[&ResSymData.Fragment->getParent()->getSection()]; @@ -597,7 +606,7 @@ void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, for (MCAssembler::const_symbol_iterator i = Asm.symbol_begin(), e = Asm.symbol_end(); i != e; i++) - DefineSymbol(*i, Asm); + DefineSymbol(*i, Asm, Layout); } void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp index 9e0ab820715d..7d7a1add2219 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.cpp +++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -518,6 +518,26 @@ bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, void X86AsmPrinter::EmitStartOfAsmFile(Module &M) { if (Subtarget->isTargetEnvMacho()) OutStreamer.SwitchSection(getObjFileLowering().getTextSection()); + + if (Subtarget->isTargetCOFF()) { + // Emit an absolute @feat.00 symbol. This appears to be some kind of + // compiler features bitfield read by link.exe. + if (!Subtarget->is64Bit()) { + MCSymbol *S = MMI->getContext().GetOrCreateSymbol(StringRef("@feat.00")); + OutStreamer.BeginCOFFSymbolDef(S); + OutStreamer.EmitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC); + OutStreamer.EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_NULL); + OutStreamer.EndCOFFSymbolDef(); + // According to the PE-COFF spec, the LSB of this value marks the object + // for "registered SEH". This means that all SEH handler entry points + // must be registered in .sxdata. Use of any unregistered handlers will + // cause the process to terminate immediately. LLVM does not know how to + // register any SEH handlers, so its object files should be safe. + S->setAbsolute(); + OutStreamer.EmitAssignment( + S, MCConstantExpr::Create(int64_t(1), MMI->getContext())); + } + } } diff --git a/llvm/test/CodeGen/X86/coff-feat00.ll b/llvm/test/CodeGen/X86/coff-feat00.ll new file mode 100644 index 000000000000..1dcd4276399a --- /dev/null +++ b/llvm/test/CodeGen/X86/coff-feat00.ll @@ -0,0 +1,7 @@ +; RUN: llc -O0 -mtriple=i386-pc-win32 -filetype=asm -o - %s | FileCheck %s + +define i32 @foo() { + ret i32 0 +} + +; CHECK: @feat.00 = 1 diff --git a/llvm/test/MC/COFF/feat00.s b/llvm/test/MC/COFF/feat00.s new file mode 100644 index 000000000000..b8862de1983e --- /dev/null +++ b/llvm/test/MC/COFF/feat00.s @@ -0,0 +1,13 @@ +// RUN: llvm-mc -filetype=obj -triple i686-pc-win32 %s -o - | llvm-readobj -t | FileCheck %s + +"@feat.00" = 123 + +// CHECK: Symbol { +// CHECK: Name: @feat.00 +// CHECK: Value: 123 +// CHECK: Section: (-1) +// CHECK: BaseType: Null (0x0) +// CHECK: ComplexType: Null (0x0) +// CHECK: StorageClass: External (0x2) +// CHECK: AuxSymbolCount: 0 +// CHECK: }