Index: llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -128,6 +128,12 @@ virtual const MCSection * SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const; + + /// emitModuleFlags - Emit Obj-C garbage collection and linker options. Only + /// linker option emission is implemented for COFF. + virtual void emitModuleFlags(MCStreamer &Streamer, + ArrayRef ModuleFlags, + Mangler *Mang, const TargetMachine &TM) const; }; } // end namespace llvm Index: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -782,3 +782,49 @@ return getDataSection(); } +void TargetLoweringObjectFileCOFF:: +emitModuleFlags(MCStreamer &Streamer, + ArrayRef ModuleFlags, + Mangler *Mang, const TargetMachine &TM) const { + MDNode *LinkerOptions = 0; + + // Look for the "Linker Options" flag, since it's the only one we support. + for (ArrayRef::iterator + i = ModuleFlags.begin(), e = ModuleFlags.end(); i != e; ++i) { + const Module::ModuleFlagEntry &MFE = *i; + StringRef Key = MFE.Key->getString(); + Value *Val = MFE.Val; + if (Key == "Linker Options") { + LinkerOptions = cast(Val); + break; + } + } + if (!LinkerOptions) + return; + + // Emit the linker options to the linker .drectve section. According to the + // spec, this section is a space-separated string containing flags for linker. + const MCSection *Sec = getDrectveSection(); + Streamer.SwitchSection(Sec); + for (unsigned i = 0, e = LinkerOptions->getNumOperands(); i != e; ++i) { + MDNode *MDOptions = cast(LinkerOptions->getOperand(i)); + for (unsigned ii = 0, ie = MDOptions->getNumOperands(); ii != ie; ++ii) { + MDString *MDOption = cast(MDOptions->getOperand(ii)); + StringRef Op = MDOption->getString(); + // Lead with a space for consistency with our dllexport implementation. + std::string Escaped(" "); + if (Op.find(" ") != StringRef::npos) { + // The PE-COFF spec says args with spaces must be quoted. It doesn't say + // how to escape quotes, but it probably uses this algorithm: + // http://msdn.microsoft.com/en-us/library/17w5ykft(v=vs.85).aspx + // FIXME: Reuse escaping code from Support/Windows/Program.inc + Escaped.push_back('\"'); + Escaped.append(Op); + Escaped.push_back('\"'); + } else { + Escaped.append(Op); + } + Streamer.EmitBytes(Escaped); + } + } +} Index: llvm/trunk/test/MC/COFF/linker-options.ll =================================================================== --- llvm/trunk/test/MC/COFF/linker-options.ll +++ llvm/trunk/test/MC/COFF/linker-options.ll @@ -0,0 +1,21 @@ +; RUN: llc -O0 -mtriple=i386-pc-win32 -filetype=asm -o - %s | FileCheck %s + +!0 = metadata !{ i32 6, metadata !"Linker Options", + metadata !{ + metadata !{ metadata !"/DEFAULTLIB:msvcrt.lib" }, + metadata !{ metadata !"/DEFAULTLIB:msvcrt.lib", + metadata !"/DEFAULTLIB:secur32.lib" }, + metadata !{ metadata !"/with spaces" } } } + +!llvm.module.flags = !{ !0 } + +define dllexport void @foo() { + ret void +} + +; CHECK: .section .drectve,"r" +; CHECK: .ascii " /DEFAULTLIB:msvcrt.lib" +; CHECK: .ascii " /DEFAULTLIB:msvcrt.lib" +; CHECK: .ascii " /DEFAULTLIB:secur32.lib" +; CHECK: .ascii " \"/with spaces\"" +; CHECK: .ascii " /EXPORT:_foo"