diff --git a/include/llvm/Object/COFFModuleDefinition.h b/include/llvm/Object/COFFModuleDefinition.h index a0e8eacdb7a..17491b81d5b 100644 --- a/include/llvm/Object/COFFModuleDefinition.h +++ b/include/llvm/Object/COFFModuleDefinition.h @@ -16,7 +16,6 @@ // //===----------------------------------------------------------------------===// - #ifndef LLVM_OBJECT_COFF_MODULE_DEFINITION_H #define LLVM_OBJECT_COFF_MODULE_DEFINITION_H @@ -40,8 +39,12 @@ struct COFFModuleDefinition { uint32_t MinorOSVersion = 0; }; +// mingw and wine def files do not mangle _ for x86 which +// is a consequence of legacy binutils' dlltool functionality. +// This MingwDef flag should be removed once mingw stops this pratice. Expected -parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine); +parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine, + bool MingwDef = false); } // End namespace object. } // End namespace llvm. diff --git a/include/llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h b/include/llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h new file mode 100644 index 00000000000..964b0f7620a --- /dev/null +++ b/include/llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h @@ -0,0 +1,24 @@ +//===- DlltoolDriver.h - dlltool.exe-compatible driver ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines an interface to a dlltool.exe-compatible driver. +// Used by llvm-dlltool. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLDRIVERS_LLVM_DLLTOOL_DLLTOOLDRIVER_H +#define LLVM_TOOLDRIVERS_LLVM_DLLTOOL_DLLTOOLDRIVER_H + +namespace llvm { +template class ArrayRef; + +int dlltoolDriverMain(ArrayRef ArgsArr); +} // namespace llvm + +#endif diff --git a/lib/Object/ArchiveWriter.cpp b/lib/Object/ArchiveWriter.cpp index 4034f9039dd..b052c76d1fe 100644 --- a/lib/Object/ArchiveWriter.cpp +++ b/lib/Object/ArchiveWriter.cpp @@ -318,7 +318,8 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; - if (Symflags & object::SymbolRef::SF_Undefined) + if (Symflags & object::SymbolRef::SF_Undefined && + !(Symflags & object::SymbolRef::SF_Indirect)) continue; unsigned NameOffset = NameOS.tell(); diff --git a/lib/Object/COFFImportFile.cpp b/lib/Object/COFFImportFile.cpp index 740bf94d40e..8769ec1691d 100644 --- a/lib/Object/COFFImportFile.cpp +++ b/lib/Object/COFFImportFile.cpp @@ -162,14 +162,17 @@ public: // Library Format. NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, ImportType Type, ImportNameType NameType); + + // Create a weak external file which is described in PE/COFF Aux Format 3. + NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp); }; } // namespace NewArchiveMember ObjectFactory::createImportDescriptor(std::vector &Buffer) { - static const uint32_t NumberOfSections = 2; - static const uint32_t NumberOfSymbols = 7; - static const uint32_t NumberOfRelocations = 3; + const uint32_t NumberOfSections = 2; + const uint32_t NumberOfSymbols = 7; + const uint32_t NumberOfRelocations = 3; // COFF Header coff_file_header Header{ @@ -189,7 +192,7 @@ ObjectFactory::createImportDescriptor(std::vector &Buffer) { append(Buffer, Header); // Section Header Table - static const coff_section SectionTable[NumberOfSections] = { + const coff_section SectionTable[NumberOfSections] = { {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, u32(0), u32(0), @@ -219,12 +222,12 @@ ObjectFactory::createImportDescriptor(std::vector &Buffer) { append(Buffer, SectionTable); // .idata$2 - static const coff_import_directory_table_entry ImportDescriptor{ + const coff_import_directory_table_entry ImportDescriptor{ u32(0), u32(0), u32(0), u32(0), u32(0), }; append(Buffer, ImportDescriptor); - static const coff_relocation RelocationTable[NumberOfRelocations] = { + const coff_relocation RelocationTable[NumberOfRelocations] = { {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), u16(getImgRelRelocation(Machine))}, {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), @@ -307,8 +310,8 @@ ObjectFactory::createImportDescriptor(std::vector &Buffer) { NewArchiveMember ObjectFactory::createNullImportDescriptor(std::vector &Buffer) { - static const uint32_t NumberOfSections = 1; - static const uint32_t NumberOfSymbols = 1; + const uint32_t NumberOfSections = 1; + const uint32_t NumberOfSymbols = 1; // COFF Header coff_file_header Header{ @@ -325,7 +328,7 @@ ObjectFactory::createNullImportDescriptor(std::vector &Buffer) { append(Buffer, Header); // Section Header Table - static const coff_section SectionTable[NumberOfSections] = { + const coff_section SectionTable[NumberOfSections] = { {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, u32(0), u32(0), @@ -342,7 +345,7 @@ ObjectFactory::createNullImportDescriptor(std::vector &Buffer) { append(Buffer, SectionTable); // .idata$3 - static const coff_import_directory_table_entry ImportDescriptor{ + const coff_import_directory_table_entry ImportDescriptor{ u32(0), u32(0), u32(0), u32(0), u32(0), }; append(Buffer, ImportDescriptor); @@ -367,8 +370,8 @@ ObjectFactory::createNullImportDescriptor(std::vector &Buffer) { } NewArchiveMember ObjectFactory::createNullThunk(std::vector &Buffer) { - static const uint32_t NumberOfSections = 2; - static const uint32_t NumberOfSymbols = 1; + const uint32_t NumberOfSections = 2; + const uint32_t NumberOfSymbols = 1; uint32_t VASize = is32bit(Machine) ? 4 : 8; // COFF Header @@ -388,7 +391,7 @@ NewArchiveMember ObjectFactory::createNullThunk(std::vector &Buffer) { append(Buffer, Header); // Section Header Table - static const coff_section SectionTable[NumberOfSections] = { + const coff_section SectionTable[NumberOfSections] = { {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, u32(0), u32(0), @@ -476,6 +479,85 @@ NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, return {MemoryBufferRef(StringRef(Buf, Size), DLLName)}; } +NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, + StringRef Weak, bool Imp) { + std::vector Buffer; + const uint32_t NumberOfSections = 1; + const uint32_t NumberOfSymbols = 5; + + // COFF Header + coff_file_header Header{ + u16(0), + u16(NumberOfSections), + u32(0), + u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), + u32(NumberOfSymbols), + u16(0), + u16(0), + }; + append(Buffer, Header); + + // Section Header Table + const coff_section SectionTable[NumberOfSections] = { + {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'}, + u32(0), + u32(0), + u32(0), + u32(0), + u32(0), + u32(0), + u16(0), + u16(0), + u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}}; + append(Buffer, SectionTable); + + // Symbol Table + coff_symbol16 SymbolTable[NumberOfSymbols] = { + {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}}, + u32(0), + u16(0xFFFF), + u16(0), + IMAGE_SYM_CLASS_STATIC, + 0}, + {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}}, + u32(0), + u16(0xFFFF), + u16(0), + IMAGE_SYM_CLASS_STATIC, + 0}, + {{{0, 0, 0, 0, 0, 0, 0, 0}}, + u32(0), + u16(0), + u16(0), + IMAGE_SYM_CLASS_EXTERNAL, + 0}, + {{{0, 0, 0, 0, 0, 0, 0, 0}}, + u32(0), + u16(0), + u16(0), + IMAGE_SYM_CLASS_WEAK_EXTERNAL, + 1}, + {{{2, 0, 0, 0, 3, 0, 0, 0}}, u32(0), u16(0), u16(0), uint8_t(0), 0}, + }; + SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t); + + //__imp_ String Table + if (Imp) { + SymbolTable[3].Name.Offset.Offset = sizeof(uint32_t) + Sym.size() + 7; + writeStringTable(Buffer, {std::string("__imp_").append(Sym), + std::string("__imp_").append(Weak)}); + } else { + SymbolTable[3].Name.Offset.Offset = sizeof(uint32_t) + Sym.size() + 1; + writeStringTable(Buffer, {Sym, Weak}); + } + append(Buffer, SymbolTable); + + // Copied here so we can still use writeStringTable + char *Buf = Alloc.Allocate(Buffer.size()); + memcpy(Buf, Buffer.data(), Buffer.size()); + return {MemoryBufferRef(StringRef(Buf, Buffer.size()), DLLName)}; +} + std::error_code writeImportLibrary(StringRef DLLName, StringRef Path, ArrayRef Exports, MachineTypes Machine) { @@ -496,6 +578,12 @@ std::error_code writeImportLibrary(StringRef DLLName, StringRef Path, if (E.Private) continue; + if (E.isWeak()) { + Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, false)); + Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, true)); + continue; + } + ImportType ImportType = IMPORT_CODE; if (E.Data) ImportType = IMPORT_DATA; diff --git a/lib/Object/COFFModuleDefinition.cpp b/lib/Object/COFFModuleDefinition.cpp index 0d69cb6b709..d6729684e20 100644 --- a/lib/Object/COFFModuleDefinition.cpp +++ b/lib/Object/COFFModuleDefinition.cpp @@ -55,8 +55,10 @@ struct Token { StringRef Value; }; -static bool isDecorated(StringRef Sym) { - return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); +static bool isDecorated(StringRef Sym, bool MingwDef) { + // mingw does not prepend "_". + return (!MingwDef && Sym.startswith("_")) || Sym.startswith("@") || + Sym.startswith("?"); } static Error createError(const Twine &Err) { @@ -83,6 +85,9 @@ public: } case '=': Buf = Buf.drop_front(); + // GNU dlltool accepts both = and ==. + if (Buf.startswith("=")) + Buf = Buf.drop_front(); return Token(Equal, "="); case ',': Buf = Buf.drop_front(); @@ -120,7 +125,8 @@ private: class Parser { public: - explicit Parser(StringRef S, MachineTypes M) : Lex(S), Machine(M) {} + explicit Parser(StringRef S, MachineTypes M, bool B) + : Lex(S), Machine(M), MingwDef(B) {} Expected parse() { do { @@ -213,9 +219,9 @@ private: } if (Machine == IMAGE_FILE_MACHINE_I386) { - if (!isDecorated(E.Name)) + if (!isDecorated(E.Name, MingwDef)) E.Name = (std::string("_").append(E.Name)); - if (!E.ExtName.empty() && !isDecorated(E.ExtName)) + if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef)) E.ExtName = (std::string("_").append(E.ExtName)); } @@ -308,11 +314,13 @@ private: std::vector Stack; MachineTypes Machine; COFFModuleDefinition Info; + bool MingwDef; }; Expected parseCOFFModuleDefinition(MemoryBufferRef MB, - MachineTypes Machine) { - return Parser(MB.getBuffer(), Machine).parse(); + MachineTypes Machine, + bool MingwDef) { + return Parser(MB.getBuffer(), Machine, MingwDef).parse(); } } // namespace object diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index 1e9b0c5b045..0a2053477ca 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -227,8 +227,11 @@ uint32_t COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const { if (Symb.isExternal() || Symb.isWeakExternal()) Result |= SymbolRef::SF_Global; - if (Symb.isWeakExternal()) + if (Symb.isWeakExternal()) { Result |= SymbolRef::SF_Weak; + // We use indirect to allow the archiver to write weak externs + Result |= SymbolRef::SF_Indirect; + } if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE) Result |= SymbolRef::SF_Absolute; diff --git a/lib/ToolDrivers/CMakeLists.txt b/lib/ToolDrivers/CMakeLists.txt index ad458450fda..28da36bba20 100644 --- a/lib/ToolDrivers/CMakeLists.txt +++ b/lib/ToolDrivers/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(llvm-dlltool) add_subdirectory(llvm-lib) diff --git a/lib/ToolDrivers/LLVMBuild.txt b/lib/ToolDrivers/LLVMBuild.txt index 7da9a5c0100..a49e04bdf3c 100644 --- a/lib/ToolDrivers/LLVMBuild.txt +++ b/lib/ToolDrivers/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = llvm-lib +subdirectories = llvm-dlltool llvm-lib [component_0] type = Group diff --git a/lib/ToolDrivers/llvm-dlltool/CMakeLists.txt b/lib/ToolDrivers/llvm-dlltool/CMakeLists.txt new file mode 100644 index 00000000000..52bd5cba86f --- /dev/null +++ b/lib/ToolDrivers/llvm-dlltool/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_TARGET_DEFINITIONS Options.td) +tablegen(LLVM Options.inc -gen-opt-parser-defs) +add_public_tablegen_target(DllOptionsTableGen) + +add_llvm_library(LLVMDlltoolDriver + DlltoolDriver.cpp + ) + +add_dependencies(LLVMDlltoolDriver DllOptionsTableGen) diff --git a/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp b/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp new file mode 100644 index 00000000000..a7de7930607 --- /dev/null +++ b/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp @@ -0,0 +1,160 @@ +//===- DlltoolDriver.cpp - dlltool.exe-compatible driver ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines an interface to a dlltool.exe-compatible driver. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" +#include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/COFFModuleDefinition.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/Path.h" + +#include +#include + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::COFF; + +namespace { + +enum { + OPT_INVALID = 0, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, +#include "Options.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Options.inc" +#undef PREFIX + +static const llvm::opt::OptTable::Info infoTable[] = { +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ + {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ + X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, +#include "Options.inc" +#undef OPTION +}; + +class DllOptTable : public llvm::opt::OptTable { +public: + DllOptTable() : OptTable(infoTable, false) {} +}; + +} // namespace + +std::vector> OwningMBs; + +// Opens a file. Path has to be resolved already. +// Newly created memory buffers are owned by this driver. +MemoryBufferRef openFile(StringRef Path) { + ErrorOr> MB = MemoryBuffer::getFile(Path); + + if (std::error_code EC = MB.getError()) + llvm::errs() << "fail openFile: " << EC.message() << "\n"; + + MemoryBufferRef MBRef = MB.get()->getMemBufferRef(); + OwningMBs.push_back(std::move(MB.get())); // take ownership + return MBRef; +} + +static MachineTypes getEmulation(StringRef S) { + return StringSwitch(S) + .Case("i386", IMAGE_FILE_MACHINE_I386) + .Case("i386:x86-64", IMAGE_FILE_MACHINE_AMD64) + .Case("arm", IMAGE_FILE_MACHINE_ARMNT) + .Default(IMAGE_FILE_MACHINE_UNKNOWN); +} + +static std::string getImplibPath(std::string Path) { + SmallString<128> Out = StringRef("lib"); + Out.append(Path); + sys::path::replace_extension(Out, ".a"); + return Out.str(); +} + +int llvm::dlltoolDriverMain(llvm::ArrayRef ArgsArr) { + DllOptTable Table; + unsigned MissingIndex; + unsigned MissingCount; + llvm::opt::InputArgList Args = + Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount); + if (MissingCount) { + llvm::errs() << Args.getArgString(MissingIndex) << ": missing argument\n"; + return 1; + } + + // Handle when no input or output is specified + if (Args.hasArgNoClaim(OPT_INPUT) || + (!Args.hasArgNoClaim(OPT_d) && !Args.hasArgNoClaim(OPT_l))) { + Table.PrintHelp(outs(), ArgsArr[0], "dlltool", false); + llvm::outs() << "\nTARGETS: i386, i386:x86-64, arm\n"; + return 1; + } + + if (!Args.hasArgNoClaim(OPT_m) && Args.hasArgNoClaim(OPT_d)) { + llvm::errs() << "error: no target machine specified\n" + << "supported targets: i386, i386:x86-64, arm\n"; + return 1; + } + + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) + llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n"; + + MemoryBufferRef MB; + if (auto *Arg = Args.getLastArg(OPT_d)) + MB = openFile(Arg->getValue()); + + if (!MB.getBufferSize()) { + llvm::errs() << "definition file empty\n"; + return 1; + } + + COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; + if (auto *Arg = Args.getLastArg(OPT_m)) + Machine = getEmulation(Arg->getValue()); + + if (Machine == IMAGE_FILE_MACHINE_UNKNOWN) { + llvm::errs() << "unknown target\n"; + return 1; + } + + Expected Def = + parseCOFFModuleDefinition(MB, Machine, true); + + if (!Def) { + llvm::errs() << "error parsing definition\n" + << errorToErrorCode(Def.takeError()).message(); + return 1; + } + + // Do this after the parser because parseCOFFModuleDefinition sets OutputFile. + if (auto *Arg = Args.getLastArg(OPT_D)) + Def->OutputFile = Arg->getValue(); + + if (Def->OutputFile.empty()) { + llvm::errs() << "no output file specified\n"; + return 1; + } + + std::string Path = Args.getLastArgValue(OPT_l); + if (Path.empty()) + Path = getImplibPath(Def->OutputFile); + + if (writeImportLibrary(Def->OutputFile, Path, Def->Exports, Machine)) + return 1; + return 0; +} diff --git a/lib/ToolDrivers/llvm-dlltool/LLVMBuild.txt b/lib/ToolDrivers/llvm-dlltool/LLVMBuild.txt new file mode 100644 index 00000000000..11736eb47bc --- /dev/null +++ b/lib/ToolDrivers/llvm-dlltool/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./lib/ToolDrivers/llvm-dlltool/LLVMBuild.txt -------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = DlltoolDriver +parent = Libraries +required_libraries = Object Option Support diff --git a/lib/ToolDrivers/llvm-dlltool/Options.td b/lib/ToolDrivers/llvm-dlltool/Options.td new file mode 100644 index 00000000000..213c6a4d767 --- /dev/null +++ b/lib/ToolDrivers/llvm-dlltool/Options.td @@ -0,0 +1,26 @@ +include "llvm/Option/OptParser.td" + +def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target machine">; +def m_long : JoinedOrSeparate<["--"], "machine">, Alias; + +def l: JoinedOrSeparate<["-"], "l">, HelpText<"Generate an import lib">; +def l_long : JoinedOrSeparate<["--"], "output-lib">, Alias; + +def D: JoinedOrSeparate<["-"], "D">, HelpText<"Specify the input DLL Name">; +def D_long : JoinedOrSeparate<["--"], "dllname">, Alias; + +def d: JoinedOrSeparate<["-"], "d">, HelpText<"Input .def File">; +def d_long : JoinedOrSeparate<["--"], "input-def">, Alias; + +//============================================================================== +// The flags below do nothing. They are defined only for dlltool compatibility. +//============================================================================== + +def k: Flag<["-"], "k">, HelpText<"Kill @n Symbol from export">; +def k_alias: Flag<["--"], "kill-at">, Alias; + +def S: JoinedOrSeparate<["-"], "S">, HelpText<"Assembler">; +def S_alias: JoinedOrSeparate<["--"], "as">, Alias; + +def f: JoinedOrSeparate<["-"], "f">, HelpText<"Assembler Flags">; +def f_alias: JoinedOrSeparate<["--"], "as-flags">, Alias; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f9780bb258c..fa28120d096 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -48,6 +48,7 @@ set(LLVM_TEST_DEPENDS llvm-cvtres llvm-diff llvm-dis + llvm-dlltool llvm-dsymutil llvm-dwarfdump llvm-dwp diff --git a/test/DllTool/coff-exports.def b/test/DllTool/coff-exports.def new file mode 100644 index 00000000000..0226886a523 --- /dev/null +++ b/test/DllTool/coff-exports.def @@ -0,0 +1,13 @@ +; RUN: llvm-dlltool -m i386:x86-64 --input-def %s --output-lib %t.a +; RUN: llvm-readobj -coff-exports %t.a | FileCheck %s + +LIBRARY test.dll +EXPORTS +TestFunction + +; CHECK: File: test.dll +; CHECK: Format: COFF-import-file +; CHECK: Type: code +; CHECK: Name type: name +; CHECK: Symbol: __imp_TestFunction +; CHECK: Symbol: TestFunction diff --git a/test/DllTool/coff-weak-exports.def b/test/DllTool/coff-weak-exports.def new file mode 100644 index 00000000000..511d947d839 --- /dev/null +++ b/test/DllTool/coff-weak-exports.def @@ -0,0 +1,19 @@ +; RUN: llvm-dlltool -m i386:x86-64 --input-def %s --output-lib %t.a +; RUN: llvm-readobj -coff-exports %t.a | FileCheck %s + +LIBRARY test.dll +EXPORTS +TestFunction==AltTestFunction + +; CHECK: File: test.dll +; CHECK: Format: COFF-x86-64 +; CHECK: Arch: x86_64 +; CHECK: AddressSize: 64bit +; CHECK: File: test.dll +; CHECK: Format: COFF-x86-64 +; CHECK: Arch: x86_64 +; CHECK: AddressSize: 64bit +; CHECK: File: test.dll +; CHECK: Format: COFF-x86-64 +; CHECK: Arch: x86_64 +; CHECK: AddressSize: 64bit diff --git a/test/DllTool/lit.local.cfg b/test/DllTool/lit.local.cfg new file mode 100644 index 00000000000..482608486d2 --- /dev/null +++ b/test/DllTool/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.def'] diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index 3bb0c8f7b7c..731bcbd8ac9 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} Core + DlltoolDriver LibDriver Object Support @@ -15,3 +16,4 @@ add_llvm_tool(llvm-ar add_llvm_tool_symlink(llvm-ranlib llvm-ar) add_llvm_tool_symlink(llvm-lib llvm-ar) +add_llvm_tool_symlink(llvm-dlltool llvm-ar) diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 500507fd496..af4d3efa52f 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" @@ -863,6 +864,9 @@ int main(int argc, char **argv) { llvm::InitializeAllAsmParsers(); StringRef Stem = sys::path::stem(ToolName); + if (Stem.find("dlltool") != StringRef::npos) + return dlltoolDriverMain(makeArrayRef(argv, argc)); + if (Stem.find("ranlib") == StringRef::npos && Stem.find("lib") != StringRef::npos) return libDriverMain(makeArrayRef(argv, argc)); @@ -878,5 +882,5 @@ int main(int argc, char **argv) { return ranlib_main(); if (Stem.find("ar") != StringRef::npos) return ar_main(); - fail("Not ranlib, ar or lib!"); + fail("Not ranlib, ar, lib or dlltool!"); }