//
//===----------------------------------------------------------------------===//
-
#ifndef LLVM_OBJECT_COFF_MODULE_DEFINITION_H
#define LLVM_OBJECT_COFF_MODULE_DEFINITION_H
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<COFFModuleDefinition>
-parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine);
+parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine,
+ bool MingwDef = false);
} // End namespace object.
} // End namespace llvm.
--- /dev/null
+//===- 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 <typename T> class ArrayRef;
+
+int dlltoolDriverMain(ArrayRef<const char *> ArgsArr);
+} // namespace llvm
+
+#endif
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();
// 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<uint8_t> &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{
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),
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)),
NewArchiveMember
ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &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{
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),
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);
}
NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &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
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),
return {MemoryBufferRef(StringRef(Buf, Size), DLLName)};
}
+NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
+ StringRef Weak, bool Imp) {
+ std::vector<uint8_t> 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<char>(Buffer.size());
+ memcpy(Buf, Buffer.data(), Buffer.size());
+ return {MemoryBufferRef(StringRef(Buf, Buffer.size()), DLLName)};
+}
+
std::error_code writeImportLibrary(StringRef DLLName, StringRef Path,
ArrayRef<COFFShortExport> Exports,
MachineTypes Machine) {
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;
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) {
}
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();
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<COFFModuleDefinition> parse() {
do {
}
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));
}
std::vector<Token> Stack;
MachineTypes Machine;
COFFModuleDefinition Info;
+ bool MingwDef;
};
Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
- MachineTypes Machine) {
- return Parser(MB.getBuffer(), Machine).parse();
+ MachineTypes Machine,
+ bool MingwDef) {
+ return Parser(MB.getBuffer(), Machine, MingwDef).parse();
}
} // namespace object
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;
+add_subdirectory(llvm-dlltool)
add_subdirectory(llvm-lib)
;===------------------------------------------------------------------------===;
[common]
-subdirectories = llvm-lib
+subdirectories = llvm-dlltool llvm-lib
[component_0]
type = Group
--- /dev/null
+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)
--- /dev/null
+//===- 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 <string>
+#include <vector>
+
+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<std::unique_ptr<MemoryBuffer>> OwningMBs;
+
+// Opens a file. Path has to be resolved already.
+// Newly created memory buffers are owned by this driver.
+MemoryBufferRef openFile(StringRef Path) {
+ ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> 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<MachineTypes>(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<const char *> 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<COFFModuleDefinition> 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;
+}
--- /dev/null
+;===- ./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
--- /dev/null
+include "llvm/Option/OptParser.td"
+
+def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target machine">;
+def m_long : JoinedOrSeparate<["--"], "machine">, Alias<m>;
+
+def l: JoinedOrSeparate<["-"], "l">, HelpText<"Generate an import lib">;
+def l_long : JoinedOrSeparate<["--"], "output-lib">, Alias<l>;
+
+def D: JoinedOrSeparate<["-"], "D">, HelpText<"Specify the input DLL Name">;
+def D_long : JoinedOrSeparate<["--"], "dllname">, Alias<D>;
+
+def d: JoinedOrSeparate<["-"], "d">, HelpText<"Input .def File">;
+def d_long : JoinedOrSeparate<["--"], "input-def">, Alias<d>;
+
+//==============================================================================
+// 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<k>;
+
+def S: JoinedOrSeparate<["-"], "S">, HelpText<"Assembler">;
+def S_alias: JoinedOrSeparate<["--"], "as">, Alias<S>;
+
+def f: JoinedOrSeparate<["-"], "f">, HelpText<"Assembler Flags">;
+def f_alias: JoinedOrSeparate<["--"], "as-flags">, Alias<f>;
llvm-cvtres
llvm-diff
llvm-dis
+ llvm-dlltool
llvm-dsymutil
llvm-dwarfdump
llvm-dwp
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+config.suffixes = ['.def']
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
Core
+ DlltoolDriver
LibDriver
Object
Support
add_llvm_tool_symlink(llvm-ranlib llvm-ar)
add_llvm_tool_symlink(llvm-lib llvm-ar)
+add_llvm_tool_symlink(llvm-dlltool llvm-ar)
#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"
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));
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!");
}