diff --git a/llvm/test/tools/llvm-ml/feat00.test b/llvm/test/tools/llvm-ml/feat00.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/feat00.test @@ -0,0 +1,24 @@ +; RUN: llvm-ml -m32 -filetype=obj %s | llvm-readobj --syms - | FileCheck %s --check-prefix=CHECK-OBJ --check-prefix=CHECK-OBJ-NOSAFESEH +; RUN: llvm-ml -m64 -filetype=obj %s | llvm-readobj --syms - | FileCheck %s --check-prefix=CHECK-OBJ --check-prefix=CHECK-OBJ-NOSAFESEH + +; RUN: llvm-ml -m32 -safeseh -filetype=obj %s | llvm-readobj --syms - | FileCheck %s --check-prefix=CHECK-OBJ --check-prefix=CHECK-OBJ-SAFESEH +; RUN: llvm-ml -m64 -safeseh -filetype=obj %s -o %t.obj 2>&1 | FileCheck %s --check-prefix=CHECK-SAFESEH64 +; RUN: llvm-readobj --syms %t.obj | FileCheck %s --check-prefix=CHECK-OBJ --check-prefix=CHECK-OBJ-NOSAFESEH + +; CHECK-SAFESEH64: warning: /safeseh applies only to 32-bit X86 platforms; ignoring. + +.code +noop: + ret +end + +; CHECK-OBJ: Symbol { +; CHECK-OBJ: Name: @feat.00 +; CHECK-OBJ-NOSAFESEH: Value: 2 +; CHECK-OBJ-SAFESEH: Value: 3 +; CHECK-OBJ-NEXT: Section: IMAGE_SYM_ABSOLUTE +; CHECK-OBJ-NEXT: BaseType: Null +; CHECK-OBJ-NEXT: ComplexType: Null +; CHECK-OBJ-NEXT: StorageClass: External +; CHECK-OBJ-NEXT: AuxSymbolCount: 0 +; CHECK-OBJ-NEXT: } diff --git a/llvm/test/tools/llvm-ml/feat00_override.test b/llvm/test/tools/llvm-ml/feat00_override.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/feat00_override.test @@ -0,0 +1,21 @@ +; RUN: llvm-ml -m32 -filetype=obj %s | llvm-readobj --syms - | FileCheck %s +; RUN: llvm-ml -m64 -filetype=obj %s | llvm-readobj --syms - | FileCheck %s +; RUN: llvm-ml -m32 -safeseh -filetype=obj %s | llvm-readobj --syms - | FileCheck %s + +.code + +@feat.00 = 99 + +noop: + ret +end + +; CHECK: Symbol { +; CHECK: Name: @feat.00 +; CHECK: Value: 99 +; CHECK-NEXT: Section: IMAGE_SYM_ABSOLUTE +; CHECK-NEXT: BaseType: Null +; CHECK-NEXT: ComplexType: Null +; CHECK-NEXT: StorageClass: Static +; CHECK-NEXT: AuxSymbolCount: 0 +; CHECK-NEXT: } diff --git a/llvm/tools/llvm-ml/llvm-ml.cpp b/llvm/tools/llvm-ml/llvm-ml.cpp --- a/llvm/tools/llvm-ml/llvm-ml.cpp +++ b/llvm/tools/llvm-ml/llvm-ml.cpp @@ -99,6 +99,12 @@ cl::values(clEnumVal(m32, "32-bit"), clEnumVal(m64, "64-bit (default)"))); +static cl::opt SafeSEH( + "safeseh", + cl::desc("Mark resulting object files as either containing no " + "exception handlers or containing exception handlers that " + "are all declared with .SAFESEH. Only available in 32-bit.")); + static cl::opt TripleName("triple", cl::desc("Target triple to assemble for, " "see -version for available targets")); @@ -195,7 +201,7 @@ MCAsmInfo &MAI, MCSubtargetInfo &STI, MCInstrInfo &MCII, MCTargetOptions &MCOptions) { std::unique_ptr Parser( - createMCMasmParser(SrcMgr, Ctx, Str, MAI)); + createMCMasmParser(SrcMgr, Ctx, Str, MAI, 0)); std::unique_ptr TAP( TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions)); @@ -240,6 +246,12 @@ // construct the Triple object. Triple TheTriple(TripleName); + if (SafeSEH && !(TheTriple.isArch32Bit() && TheTriple.isX86())) { + WithColor::warning() + << "/safeseh applies only to 32-bit X86 platforms; ignoring.\n"; + SafeSEH = false; + } + ErrorOr> BufferPtr = MemoryBuffer::getFileOrSTDIN(InputFilename); if (std::error_code EC = BufferPtr.getError()) { @@ -354,6 +366,23 @@ /*DWARFMustBeAtTheEnd*/ false)); } + if (TheTriple.isOSBinFormatCOFF()) { + // Emit an absolute @feat.00 symbol. This is a features bitfield read by + // link.exe. + int64_t Feat00Flags = 0x2; + if (SafeSEH) { + // 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. + Feat00Flags |= 0x1; + } + MCSymbol *Feat00Sym = Ctx.getOrCreateSymbol("@feat.00"); + Feat00Sym->setRedefinable(true); + Str->emitSymbolAttribute(Feat00Sym, MCSA_Global); + Str->emitAssignment(Feat00Sym, MCConstantExpr::create(Feat00Flags, Ctx)); + } + // Use Assembler information for parsing. Str->setUseAssemblerInfoForParsing(true);