Files
llvm-mingw/patches/llvm-0004.patch
T

1447 lines
43 KiB
Diff

From e809b3e41dd5d4ba55c1b941f2b4f72b408b4c2e Mon Sep 17 00:00:00 2001
From: Martell Malone <martellmalone@gmail.com>
Date: Tue, 9 Aug 2016 17:52:46 -0700
Subject: [PATCH 4/6] genlib: named as llvm-dlltool
A PE COFF spec compliant import library generator.
Intended to be used with mingw-w64.
Supports:
PE COFF spec (section 8, Import Library Format)
PE COFF spec (Aux Format 3: Weak Externals)
---
include/llvm/DllDriver/DllDriver.h | 24 ++
lib/CMakeLists.txt | 1 +
lib/DLLDriver/CMakeLists.txt | 11 +
lib/DLLDriver/Config.h | 119 ++++++++
lib/DLLDriver/DllDriver.cpp | 185 ++++++++++++
lib/DLLDriver/LLVMBuild.txt | 22 ++
lib/DLLDriver/Librarian.cpp | 603 +++++++++++++++++++++++++++++++++++++
lib/DLLDriver/ModuleDef.cpp | 321 ++++++++++++++++++++
lib/DLLDriver/Options.td | 5 +
lib/Object/ArchiveWriter.cpp | 3 +-
tools/llvm-ar/CMakeLists.txt | 2 +
tools/llvm-ar/llvm-ar.cpp | 6 +-
12 files changed, 1300 insertions(+), 2 deletions(-)
create mode 100644 include/llvm/DllDriver/DllDriver.h
create mode 100644 lib/DLLDriver/CMakeLists.txt
create mode 100644 lib/DLLDriver/Config.h
create mode 100644 lib/DLLDriver/DllDriver.cpp
create mode 100644 lib/DLLDriver/LLVMBuild.txt
create mode 100644 lib/DLLDriver/Librarian.cpp
create mode 100644 lib/DLLDriver/ModuleDef.cpp
create mode 100644 lib/DLLDriver/Options.td
diff --git a/include/llvm/DllDriver/DllDriver.h b/include/llvm/DllDriver/DllDriver.h
new file mode 100644
index 0000000..79fb7b7
--- /dev/null
+++ b/include/llvm/DllDriver/DllDriver.h
@@ -0,0 +1,24 @@
+//===- llvm/DLLDriver/DLLDriver.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 that also understands
+// bitcode files. Used by llvm-dlltool and lld.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DLLDRIVER_DLLDRIVER_H
+#define LLVM_DLLDRIVER_DLLDRIVER_H
+
+namespace llvm {
+template <typename T> class ArrayRef;
+
+int dllToolDriverMain(ArrayRef<const char *> ARgs);
+}
+
+#endif
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 9449421..03988a6 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -20,4 +20,5 @@ add_subdirectory(LineEditor)
add_subdirectory(ProfileData)
add_subdirectory(Fuzzer)
add_subdirectory(Passes)
+add_subdirectory(DLLDriver)
add_subdirectory(LibDriver)
diff --git a/lib/DLLDriver/CMakeLists.txt b/lib/DLLDriver/CMakeLists.txt
new file mode 100644
index 0000000..91fb2f0
--- /dev/null
+++ b/lib/DLLDriver/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(DllOptionsTableGen)
+
+add_llvm_library(LLVMDllDriver
+ DllDriver.cpp
+ ModuleDef.cpp
+ Librarian.cpp
+ )
+
+add_dependencies(LLVMDllDriver DllOptionsTableGen)
diff --git a/lib/DLLDriver/Config.h b/lib/DLLDriver/Config.h
new file mode 100644
index 0000000..d5a3d26
--- /dev/null
+++ b/lib/DLLDriver/Config.h
@@ -0,0 +1,119 @@
+#ifndef LLVM_COFF_CONFIG_H
+#define LLVM_COFF_CONFIG_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include <cstdint>
+#include <map>
+#include <set>
+#include <string>
+
+namespace llvm {
+
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::WindowsSubsystem;
+using llvm::StringRef;
+
+// Short aliases.
+static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
+static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
+static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
+
+struct Export {
+ StringRef Name; // N in N or E=N
+ StringRef ExtName; // E in E=N
+
+ uint16_t Ordinal = 0;
+ bool Noname = false;
+ bool Data = false;
+ bool Private = false;
+
+ // True if this /export option was in .drectves section.
+ bool Directives = false;
+ StringRef SymbolName;
+ StringRef ExportName; // Name in DLL
+
+ bool isWeak() {
+ if(ExtName.size() && Name != ExtName)
+ return true;
+ return false;
+ }
+};
+
+// Global configuration.
+struct Configuration {
+ enum ManifestKind { SideBySide, Embed, No };
+ bool is64() { return Machine == AMD64; }
+ std::vector<Export> Exports;
+
+ llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
+ bool Verbose = false;
+ WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
+ bool NoEntry = false;
+ std::string OutputFile;
+ bool DoGC = true;
+ bool DoICF = true;
+ bool Relocatable = true;
+ bool Force = false;
+ bool Debug = false;
+ bool WriteSymtab = true;
+
+ std::set<StringRef> NoDefaultLibs;
+ bool NoDefaultLibAll = false;
+
+ // True if we are creating a DLL.
+ bool DLL = false;
+ StringRef Implib;
+ std::set<std::string> DelayLoads;
+ std::map<std::string, int> DLLOrder;
+
+ // Used for /opt:lldlto=N
+ unsigned LTOOptLevel = 2;
+
+ // Used for /opt:lldltojobs=N
+ unsigned LTOJobs = 1;
+
+ // Used for /merge:from=to (e.g. /merge:.rdata=.text)
+ std::map<StringRef, StringRef> Merge;
+
+ // Used for /section=.name,{DEKPRSW} to set section attributes.
+ std::map<StringRef, uint32_t> Section;
+
+ // Options for manifest files.
+ ManifestKind Manifest = SideBySide;
+ int ManifestID = 1;
+ StringRef ManifestDependency;
+ bool ManifestUAC = true;
+ std::vector<std::string> ManifestInput;
+ StringRef ManifestLevel = "'asInvoker'";
+ StringRef ManifestUIAccess = "'false'";
+ StringRef ManifestFile;
+
+ // Used for /failifmismatch.
+ std::map<StringRef, StringRef> MustMatch;
+
+ // Used for /alternatename.
+ std::map<StringRef, StringRef> AlternateNames;
+
+ uint64_t ImageBase = -1;
+ uint64_t StackReserve = 1024 * 1024;
+ uint64_t StackCommit = 4096;
+ uint64_t HeapReserve = 1024 * 1024;
+ uint64_t HeapCommit = 4096;
+ uint32_t MajorImageVersion = 0;
+ uint32_t MinorImageVersion = 0;
+ uint32_t MajorOSVersion = 6;
+ uint32_t MinorOSVersion = 0;
+ bool DynamicBase = true;
+ bool AllowBind = true;
+ bool NxCompat = true;
+ bool AllowIsolation = true;
+ bool TerminalServerAware = true;
+ bool LargeAddressAware = false;
+ bool HighEntropyVA = false;
+};
+
+extern Configuration *Config;
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/lib/DLLDriver/DllDriver.cpp b/lib/DLLDriver/DllDriver.cpp
new file mode 100644
index 0000000..aa9adc8
--- /dev/null
+++ b/lib/DLLDriver/DllDriver.cpp
@@ -0,0 +1,185 @@
+//===- DllDriver.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 that also understands
+// bitcode files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DllDriver/DllDriver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cstdint>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "Config.h"
+
+using namespace llvm;
+
+namespace llvm{
+Configuration *Config;
+void parseModuleDefs(MemoryBufferRef MB, StringSaver *Alloc);
+}
+
+namespace {
+
+enum {
+ OPT_INVALID = 0,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) 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, X6, X7, X8, X9, X10) \
+ { \
+ X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \
+ OPT_##GROUP, OPT_##ALIAS, X6 \
+ },
+#include "Options.inc"
+#undef OPTION
+};
+
+class DllOptTable : public llvm::opt::OptTable {
+public:
+ DllOptTable() : OptTable(infoTable, false) {}
+};
+
+}
+
+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) {
+ llvm::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;
+}
+
+#include "llvm/Support/raw_ostream.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/StringSaver.h"
+
+static llvm::COFF::MachineTypes getEmulation(StringRef S) {
+ return StringSwitch<llvm::COFF::MachineTypes>(S)
+ .Case("x86", llvm::COFF::IMAGE_FILE_MACHINE_I386)
+ .Case("x86_64", llvm::COFF::IMAGE_FILE_MACHINE_AMD64)
+ .Case("arm", llvm::COFF::IMAGE_FILE_MACHINE_ARMNT)
+ .Default(llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN);
+}
+
+static std::string getImplibPath() {
+ if (!Config->Implib.empty())
+ return Config->Implib;
+ SmallString<128> Out = StringRef(Config->OutputFile);
+ sys::path::replace_extension(Out, ".lib");
+ return Out.str();
+}
+
+int writeImportLibrary(std::string &Path);
+
+int llvm::dllToolDriverMain(llvm::ArrayRef<const char*> ArgsArr) {
+ SmallVector<const char *, 20> NewArgs(ArgsArr.begin(), ArgsArr.end());
+ BumpPtrAllocator Alloc;
+ StringSaver Saver(Alloc);
+ cl::ExpandResponseFiles(Saver, cl::TokenizeWindowsCommandLine, NewArgs);
+ ArgsArr = NewArgs;
+
+ Configuration C;
+ Config = &C;
+
+ DllOptTable Table;
+ unsigned MissingIndex;
+ unsigned MissingCount;
+ llvm::opt::InputArgList Args =
+ Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
+ if (MissingCount) {
+ llvm::errs() << "missing arg value for \""
+ << Args.getArgString(MissingIndex) << "\", expected "
+ << MissingCount
+ << (MissingCount == 1 ? " argument.\n" : " arguments.\n");
+ return 1;
+ }
+ for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+ llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
+
+ if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end()) {
+ llvm::outs() << "NO ARGS" << "\n";
+ return 0;
+ }
+
+ if (Args.filtered_begin(OPT_emu) == Args.filtered_end()) {
+ llvm::outs() << "Need to set an emulation mode" << "\n";
+ return -1;
+ }
+
+ std::string Path;
+ MemoryBufferRef MB;
+ int i=0;
+ for (auto *Arg : Args.filtered(OPT_INPUT)) {
+ if(i==0)
+ MB = openFile(Arg->getValue());
+ if(i==1)
+ Path = Arg->getValue();
+ i++;
+ }
+
+ if (auto *Arg = Args.getLastArg(OPT_out))
+ Path = Arg->getValue();
+
+ if(!Path.length())
+ Path = getImplibPath();
+
+ llvm::outs() << Path << "\n";
+
+ Config->Machine = IMAGE_FILE_MACHINE_UNKNOWN;
+ if (auto *Arg = Args.getLastArg(OPT_emu))
+ Config->Machine = getEmulation(Arg->getValue());
+
+ if(Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+ llvm::outs() << "Need to set a valid emulation mode" << "\n";
+ return -2;
+ }
+
+ llvm::parseModuleDefs(MB, &Saver);
+
+ // has to happen after the parser
+ if (auto *Arg = Args.getLastArg(OPT_dll))
+ Config->OutputFile = Arg->getValue();
+
+ return writeImportLibrary(Path);
+
+}
diff --git a/lib/DLLDriver/LLVMBuild.txt b/lib/DLLDriver/LLVMBuild.txt
new file mode 100644
index 0000000..8e2b1d65
--- /dev/null
+++ b/lib/DLLDriver/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./lib/LibDriver/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 = DllDriver
+parent = Libraries
+required_libraries = Object Option Support
diff --git a/lib/DLLDriver/Librarian.cpp b/lib/DLLDriver/Librarian.cpp
new file mode 100644
index 0000000..486733e
--- /dev/null
+++ b/lib/DLLDriver/Librarian.cpp
@@ -0,0 +1,603 @@
+//===- Librarian.cpp ------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains functions for the Librarian. The librarian creates and
+// manages libraries of the Common Object File Format (COFF) object files. It
+// primarily is used for creating static libraries and import libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Path.h"
+
+#include <cstdint>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "Config.h"
+
+using namespace llvm;
+using namespace llvm::COFF;
+using namespace llvm::object;
+
+static bool is32bit() {
+ switch (Config->Machine) {
+ default:
+ llvm_unreachable("unsupported machine");
+ case IMAGE_FILE_MACHINE_AMD64:
+ return false;
+ case IMAGE_FILE_MACHINE_ARMNT:
+ case IMAGE_FILE_MACHINE_I386:
+ return true;
+ }
+}
+
+static uint16_t getImgRelRelocation() {
+ switch (Config->Machine) {
+ default:
+ llvm_unreachable("unsupported machine");
+ case IMAGE_FILE_MACHINE_AMD64:
+ return IMAGE_REL_AMD64_ADDR32NB;
+ case IMAGE_FILE_MACHINE_ARMNT:
+ return IMAGE_REL_ARM_ADDR32NB;
+ case IMAGE_FILE_MACHINE_I386:
+ return IMAGE_REL_I386_DIR32NB;
+ }
+}
+
+template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
+ size_t S = B.size();
+ B.resize(S + sizeof(T));
+ memcpy(&B[S], &Data, sizeof(T));
+}
+
+static void writeStringTable(std::vector<uint8_t> &B,
+ ArrayRef<const std::string> Strings) {
+ // The COFF string table consists of a 4-byte value which is the size of the
+ // table, including the length field itself. This value is followed by the
+ // string content itself, which is an array of null-terminated C-style
+ // strings. The termination is important as they are referenced to by offset
+ // by the symbol entity in the file format.
+
+ std::vector<uint8_t>::size_type Pos = B.size();
+ std::vector<uint8_t>::size_type Offset = B.size();
+
+ // Skip over the length field, we will fill it in later as we will have
+ // computed the length while emitting the string content itself.
+ Pos += sizeof(uint32_t);
+
+ for (const auto &S : Strings) {
+ B.resize(Pos + S.length() + 1);
+ strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
+ Pos += S.length() + 1;
+ }
+
+ // Backfill the length of the table now that it has been computed.
+ support::ulittle32_t Length(B.size() - Offset);
+ memcpy(&B[Offset], &Length, sizeof(Length));
+}
+
+static ImportNameType getNameType(StringRef Sym, StringRef ExtName) {
+ if (Sym != ExtName)
+ return IMPORT_NAME_UNDECORATE;
+ if (Config->Machine == I386 && Sym.startswith("_"))
+ return IMPORT_NAME_NOPREFIX;
+ return IMPORT_NAME;
+}
+
+static const std::string NullImportDescriptorSymbolName =
+ "__NULL_IMPORT_DESCRIPTOR";
+
+namespace {
+// This class constructs various small object files necessary to support linking
+// symbols imported from a DLL. The contents are pretty strictly defined and
+// nearly entirely static. The details of the structures files are defined in
+// WINNT.h and the PE/COFF specification.
+class ObjectFactory {
+ using u16 = support::ulittle16_t;
+ using u32 = support::ulittle32_t;
+
+ BumpPtrAllocator Alloc;
+ StringRef DLLName;
+ StringRef Library;
+ std::string ImportDescriptorSymbolName;
+ std::string NullThunkSymbolName;
+
+public:
+ ObjectFactory(StringRef S)
+ : DLLName(S), Library(S.drop_back(4)),
+ ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
+ NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
+
+ // Creates an Import Descriptor. This is a small object file which contains a
+ // reference to the terminators and contains the library name (entry) for the
+ // import name table. It will force the linker to construct the necessary
+ // structure to import symbols from the DLL.
+ NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
+
+ // Creates a NULL import descriptor. This is a small object file whcih
+ // contains a NULL import descriptor. It is used to terminate the imports
+ // from a specific DLL.
+ NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
+
+ // Create a NULL Thunk Entry. This is a small object file which contains a
+ // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
+ // is used to terminate the IAT and ILT.
+ NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
+
+ // Create a short import file which is described in PE/COFF spec 7. Import
+ // Library Format.
+ NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
+ ImportNameType NameType, bool isData);
+
+ // Create a weak external file which is described in PE/COFF Aux Format 3.
+ NewArchiveMember createWeakExternal(std::vector<uint8_t> &Buffer, StringRef Sym, StringRef Weak, bool imp);
+};
+}
+
+NewArchiveMember
+ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
+ static const uint32_t NumberOfSections = 2;
+ static const uint32_t NumberOfSymbols = 8;
+ static const uint32_t NumberOfRelocations = 3;
+
+ // COFF Header
+ coff_file_header Header{
+ u16(Config->Machine), u16(NumberOfSections), u32(0),
+ u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+ // .idata$2
+ sizeof(coff_import_directory_table_entry) +
+ NumberOfRelocations * sizeof(coff_relocation) +
+ // .idata$6
+ (DLLName.size() + 1)),
+ u32(NumberOfSymbols), u16(0),
+ u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
+ };
+ append(Buffer, Header);
+
+ // Section Header Table
+ static const coff_section SectionTable[NumberOfSections] = {
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
+ u32(0),
+ u32(0),
+ u32(sizeof(coff_import_directory_table_entry)),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+ sizeof(coff_import_directory_table_entry)),
+ u32(0),
+ u16(NumberOfRelocations),
+ u16(0),
+ u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
+ u32(0),
+ u32(0),
+ u32(DLLName.size() + 1),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+ sizeof(coff_import_directory_table_entry) +
+ NumberOfRelocations * sizeof(coff_relocation)),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+ sizeof(coff_import_directory_table_entry)),
+ u32(0),
+ u16(0),
+ u16(0),
+ u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+ };
+ append(Buffer, SectionTable);
+
+ // .idata$2
+ static 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] = {
+ {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(3),
+ u16(getImgRelRelocation())},
+ {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
+ u32(4), u16(getImgRelRelocation())},
+ {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
+ u32(5), u16(getImgRelRelocation())},
+ };
+ append(Buffer, RelocationTable);
+
+ // .idata$6
+ auto S = Buffer.size();
+ Buffer.resize(S + DLLName.size() + 1);
+ memcpy(&Buffer[S], DLLName.data(), DLLName.size());
+ Buffer[S + DLLName.size()] = '\0';
+
+ // Symbol Table
+ coff_symbol16 SymbolTable[NumberOfSymbols] = {
+ {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
+ u32(0),
+ u16(0xFFFF),
+ u16(0),
+ IMAGE_SYM_CLASS_STATIC,
+ 0},
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(2),
+ u16(0),
+ IMAGE_SYM_CLASS_EXTERNAL,
+ 0},
+ {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
+ u32(0),
+ u16(2),
+ u16(0),
+ IMAGE_SYM_CLASS_SECTION,
+ 0},
+ {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
+ u32(0),
+ u16(3),
+ u16(0),
+ IMAGE_SYM_CLASS_STATIC,
+ 0},
+ {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
+ u32(0),
+ u16(0),
+ u16(0),
+ IMAGE_SYM_CLASS_SECTION,
+ 0},
+ {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
+ u32(0),
+ u16(0),
+ u16(0),
+ IMAGE_SYM_CLASS_SECTION,
+ 0},
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(2),
+ u16(0),
+ IMAGE_SYM_CLASS_NULL,
+ 0},
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(2),
+ u16(0),
+ IMAGE_SYM_CLASS_NULL,
+ 0},
+ };
+ reinterpret_cast<StringTableOffset &>(SymbolTable[1].Name).Offset =
+ sizeof(uint32_t);
+ reinterpret_cast<StringTableOffset &>(SymbolTable[6].Name).Offset =
+ sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
+ reinterpret_cast<StringTableOffset &>(SymbolTable[7].Name).Offset =
+ sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
+ NullImportDescriptorSymbolName.length() + 1;
+ append(Buffer, SymbolTable);
+
+ // String Table
+ writeStringTable(Buffer,
+ {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
+ NullThunkSymbolName});
+
+ StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+ return {MemoryBufferRef(F, DLLName)};
+}
+
+NewArchiveMember
+ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
+ static const uint32_t NumberOfSections = 1;
+ static const uint32_t NumberOfSymbols = 2;
+
+ // COFF Header
+ coff_file_header Header{
+ u16(Config->Machine), u16(NumberOfSections), u32(0),
+ u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+ // .idata$3
+ sizeof(coff_import_directory_table_entry)),
+ u32(NumberOfSymbols), u16(0),
+ u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
+ };
+ append(Buffer, Header);
+
+ // Section Header Table
+ static const coff_section SectionTable[NumberOfSections] = {
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
+ u32(0),
+ u32(0),
+ u32(sizeof(coff_import_directory_table_entry)),
+ u32(sizeof(coff_file_header) +
+ (NumberOfSections * sizeof(coff_section))),
+ u32(0),
+ u32(0),
+ u16(0),
+ u16(0),
+ u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+ };
+ append(Buffer, SectionTable);
+
+ // .idata$3
+ static const coff_import_directory_table_entry ImportDescriptor{
+ u32(0), u32(0), u32(0), u32(0), u32(0),
+ };
+ append(Buffer, ImportDescriptor);
+
+ // Symbol Table
+ coff_symbol16 SymbolTable[NumberOfSymbols] = {
+ {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
+ u32(0),
+ u16(0xFFFF),
+ u16(0),
+ IMAGE_SYM_CLASS_STATIC,
+ 0},
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(2),
+ u16(0),
+ IMAGE_SYM_CLASS_EXTERNAL,
+ 0},
+ };
+ reinterpret_cast<StringTableOffset &>(SymbolTable[1].Name).Offset =
+ sizeof(uint32_t);
+ append(Buffer, SymbolTable);
+
+ // String Table
+ writeStringTable(Buffer, {NullImportDescriptorSymbolName});
+
+ StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+ return {MemoryBufferRef(F, DLLName)};
+}
+
+NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
+ static const uint32_t NumberOfSections = 2;
+ static const uint32_t NumberOfSymbols = 2;
+
+ // COFF Header
+ coff_file_header Header{
+ u16(Config->Machine), u16(NumberOfSections), u32(0),
+ u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+ // .idata$5
+ sizeof(export_address_table_entry) +
+ // .idata$4
+ sizeof(export_address_table_entry)),
+ u32(NumberOfSymbols), u16(0),
+ u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
+ };
+ append(Buffer, Header);
+
+ // Section Header Table
+ static const coff_section SectionTable[NumberOfSections] = {
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
+ u32(0),
+ u32(0),
+ u32(sizeof(export_address_table_entry)),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
+ u32(0),
+ u32(0),
+ u16(0),
+ u16(0),
+ u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
+ u32(0),
+ u32(0),
+ u32(sizeof(export_address_table_entry)),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+ sizeof(export_address_table_entry)),
+ u32(0),
+ u32(0),
+ u16(0),
+ u16(0),
+ u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+ };
+ append(Buffer, SectionTable);
+
+ // .idata$5
+ static const export_address_table_entry ILT{u32(0)};
+ append(Buffer, ILT);
+
+ // .idata$4
+ static const export_address_table_entry IAT{u32(0)};
+ append(Buffer, IAT);
+
+ // Symbol Table
+ coff_symbol16 SymbolTable[NumberOfSymbols] = {
+ {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
+ u32(0),
+ u16(0xFFFF),
+ u16(0),
+ IMAGE_SYM_CLASS_STATIC,
+ 0},
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(2),
+ u16(0),
+ IMAGE_SYM_CLASS_EXTERNAL,
+ 0},
+ };
+ reinterpret_cast<StringTableOffset &>(SymbolTable[1].Name).Offset =
+ sizeof(uint32_t);
+ append(Buffer, SymbolTable);
+
+ // String Table
+ writeStringTable(Buffer, {NullThunkSymbolName});
+
+ StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+ return {MemoryBufferRef{F, DLLName}};
+}
+
+NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
+ uint16_t Ordinal,
+ ImportNameType NameType,
+ bool isData) {
+ size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs
+ size_t Size = sizeof(coff_import_header) + ImpSize;
+ char *Buf = Alloc.Allocate<char>(Size);
+ memset(Buf, 0, Size);
+ char *P = Buf;
+
+ // Write short import library.
+ auto *Imp = reinterpret_cast<coff_import_header *>(P);
+ P += sizeof(*Imp);
+ Imp->Sig2 = 0xFFFF;
+ Imp->Machine = Config->Machine;
+ Imp->SizeOfData = ImpSize;
+ if (Ordinal > 0)
+ Imp->OrdinalHint = Ordinal;
+ Imp->TypeInfo = (isData ? IMPORT_DATA : IMPORT_CODE);
+
+ if(Config->Machine == IMAGE_FILE_MACHINE_I386) {
+ if(Sym.find('@') != StringRef::npos)
+ Imp->TypeInfo |= IMPORT_NAME_UNDECORATE << 2;
+ else
+ Imp->TypeInfo |= IMPORT_NAME_NOPREFIX << 2;
+ }
+ else
+ Imp->TypeInfo |= IMPORT_NAME << 2;
+
+ // Write symbol name and DLL name.
+ memcpy(P, Sym.data(), Sym.size());
+ P += Sym.size() + 1;
+ memcpy(P, DLLName.data(), DLLName.size());
+
+ return {MemoryBufferRef(StringRef(Buf, Size), DLLName)};
+}
+
+NewArchiveMember ObjectFactory::createWeakExternal(std::vector<uint8_t> &Buffer,
+ StringRef Sym, StringRef Weak, bool imp) {
+ static const uint32_t NumberOfSections = 1;
+ static 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
+ static 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},
+ };
+ reinterpret_cast<StringTableOffset &>(SymbolTable[2].Name).Offset =
+ sizeof(uint32_t);
+
+ if(imp)
+ reinterpret_cast<StringTableOffset &>(SymbolTable[3].Name).Offset =
+ sizeof(uint32_t) + Sym.size() + 1 + 6; //__imp_
+ else
+ reinterpret_cast<StringTableOffset &>(SymbolTable[3].Name).Offset =
+ sizeof(uint32_t) + Sym.size() + 1;// + 6; //__imp_
+
+ append(Buffer, SymbolTable);
+
+ // String Table
+ if(imp)
+ writeStringTable(Buffer, {std::string("__imp_").append(Sym), std::string("__imp_").append(Weak)});
+ else
+ writeStringTable(Buffer, {Sym, Weak});
+
+ StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+ return {MemoryBufferRef{F, DLLName}};
+
+}
+
+// Creates an import library for a DLL. In this function, we first
+// create an empty import library using lib.exe and then adds short
+// import files to that file.
+int writeImportLibrary(std::string &Path) {
+
+ std::vector<NewArchiveMember> Members;
+
+ ObjectFactory OF(llvm::sys::path::filename(Config->OutputFile));
+
+ std::vector<uint8_t> ImportDescriptor;
+ Members.push_back(OF.createImportDescriptor(ImportDescriptor));
+
+ std::vector<uint8_t> NullImportDescriptor;
+ Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
+
+ std::vector<uint8_t> NullThunk;
+ Members.push_back(OF.createNullThunk(NullThunk));
+
+ for (Export &E : Config->Exports) {
+ if (E.Private)
+ continue;
+
+ if (E.isWeak()) {
+ std::vector<uint8_t> *WeakBuffer1 = new std::vector<uint8_t>();
+ std::vector<uint8_t> *WeakBuffer2 = new std::vector<uint8_t>();
+ Members.push_back(OF.createWeakExternal(*WeakBuffer1, E.Name, E.ExtName, false));
+ Members.push_back(OF.createWeakExternal(*WeakBuffer2, E.Name, E.ExtName, true));
+ continue;
+ }
+
+ if(E.ExtName.size() == 0) {
+ E.ExtName = E.Name;
+ }
+
+ ImportNameType Type = getNameType(E.SymbolName, E.Name);
+ Members.push_back(OF.createShortImport(E.Name, E.Ordinal, Type, E.Data));
+ }
+
+ std::pair<StringRef, std::error_code> Result =
+ writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU,
+ /*Deterministic*/ true, /*Thin*/ false);
+
+ if (Result.second)
+ return -1;
+
+ return 0;
+}
diff --git a/lib/DLLDriver/ModuleDef.cpp b/lib/DLLDriver/ModuleDef.cpp
new file mode 100644
index 0000000..428049a
--- /dev/null
+++ b/lib/DLLDriver/ModuleDef.cpp
@@ -0,0 +1,321 @@
+//===- COFF/ModuleDef.cpp -------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Windows-specific.
+// A parser for the module-definition file (.def file).
+// Parsed results are directly written to Config global variable.
+//
+// The format of module-definition files are described in this document:
+// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+//#include "Error.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cstdint>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <system_error>
+
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::WindowsSubsystem;
+using llvm::StringRef;
+
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm;
+
+#include "llvm/Support/Error.h"
+
+void fatal(const Twine &Msg) {
+ llvm::errs() << Msg << "\n";
+ exit(1);
+}
+
+void fatal(std::error_code EC, const Twine &Msg) {
+ fatal(Msg + ": " + EC.message());
+}
+
+void fatal(llvm::Error &Err, const Twine &Msg) {
+ fatal(errorToErrorCode(std::move(Err)), Msg);
+}
+
+namespace llvm {
+namespace {
+
+enum Kind {
+ Unknown,
+ Eof,
+ Identifier,
+ Comma,
+ Equal,
+ KwBase,
+ KwData,
+ KwExports,
+ KwHeapsize,
+ KwLibrary,
+ KwName,
+ KwNoname,
+ KwPrivate,
+ KwStacksize,
+ KwVersion,
+};
+
+struct Token {
+ explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
+ Kind K;
+ StringRef Value;
+};
+
+static bool isDecorated(StringRef Sym) {
+ // Disable Sym.startswith("_") because mingw-w64 is weird about this
+ return Sym.startswith("@") || Sym.startswith("?");
+}
+
+class Lexer {
+public:
+ explicit Lexer(StringRef S) : Buf(S) {}
+
+ Token lex() {
+ Buf = Buf.trim();
+ if (Buf.empty())
+ return Token(Eof);
+
+ switch (Buf[0]) {
+ case '\0':
+ return Token(Eof);
+ case ';': {
+ size_t End = Buf.find('\n');
+ Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
+ return lex();
+ }
+ case '=':
+ // TODO: Fix HACK TO WORK AROUND "==" in mingw-w64
+ if(Buf[1] == '=')
+ Buf = Buf.drop_front();
+ Buf = Buf.drop_front();
+ return Token(Equal, "=");
+ case ',':
+ Buf = Buf.drop_front();
+ return Token(Comma, ",");
+ case '"': {
+ StringRef S;
+ std::tie(S, Buf) = Buf.substr(1).split('"');
+ return Token(Identifier, S);
+ }
+ default: {
+ size_t End = Buf.find_first_of("=,\r\n \t\v");
+ StringRef Word = Buf.substr(0, End);
+ Kind K = llvm::StringSwitch<Kind>(Word)
+ .Case("BASE", KwBase)
+ .Case("DATA", KwData)
+ .Case("EXPORTS", KwExports)
+ .Case("HEAPSIZE", KwHeapsize)
+ .Case("LIBRARY", KwLibrary)
+ .Case("NAME", KwName)
+ .Case("NONAME", KwNoname)
+ .Case("PRIVATE", KwPrivate)
+ .Case("STACKSIZE", KwStacksize)
+ .Case("VERSION", KwVersion)
+ .Default(Identifier);
+ Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
+ return Token(K, Word);
+ }
+ }
+ }
+
+private:
+ StringRef Buf;
+};
+
+class Parser {
+public:
+ explicit Parser(StringRef S, StringSaver *A) : Lex(S), Alloc(A) {}
+
+ void parse() {
+ do {
+ parseOne();
+ } while (Tok.K != Eof);
+ }
+
+private:
+ void read() {
+ if (Stack.empty()) {
+ Tok = Lex.lex();
+ return;
+ }
+ Tok = Stack.back();
+ Stack.pop_back();
+ }
+
+ void readAsInt(uint64_t *I) {
+ read();
+ if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
+ fatal("integer expected");
+ }
+
+ void expect(Kind Expected, StringRef Msg) {
+ read();
+ if (Tok.K != Expected)
+ fatal(Msg);
+ }
+
+ void unget() { Stack.push_back(Tok); }
+
+ void parseOne() {
+ read();
+ switch (Tok.K) {
+ case Eof:
+ return;
+ case KwExports:
+ for (;;) {
+ read();
+ if (Tok.K != Identifier) {
+ unget();
+ return;
+ }
+ parseExport();
+ }
+ case KwHeapsize:
+ parseNumbers(&Config->HeapReserve, &Config->HeapCommit);
+ return;
+ case KwLibrary:
+ parseName(&Config->OutputFile, &Config->ImageBase);
+ if (!StringRef(Config->OutputFile).endswith_lower(".dll"))
+ Config->OutputFile += ".dll";
+ return;
+ case KwStacksize:
+ parseNumbers(&Config->StackReserve, &Config->StackCommit);
+ return;
+ case KwName:
+ parseName(&Config->OutputFile, &Config->ImageBase);
+ return;
+ case KwVersion:
+ parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
+ return;
+ default:
+ fatal("unknown directive: " + Tok.Value);
+ }
+ }
+
+ void parseExport() {
+ Export E;
+ E.Name = Tok.Value;
+ read();
+ if (Tok.K == Equal) {
+ read();
+ if (Tok.K != Identifier)
+ fatal("identifier expected, but got " + Tok.Value);
+ E.ExtName = E.Name;
+ E.Name = Tok.Value;
+ } else {
+ unget();
+ }
+
+ if (Config->Machine == I386) {
+ if (!isDecorated(E.Name))
+ E.Name = Alloc->save("_" + E.Name);
+ if (!E.ExtName.empty() && !isDecorated(E.ExtName))
+ E.ExtName = Alloc->save("_" + E.ExtName);
+ }
+
+ for (;;) {
+ read();
+ if (Tok.K == Identifier && Tok.Value[0] == '@') {
+ Tok.Value.drop_front().getAsInteger(10, E.Ordinal);
+ read();
+ if (Tok.K == KwNoname) {
+ E.Noname = true;
+ } else {
+ unget();
+ }
+ continue;
+ }
+ if (Tok.K == KwData) {
+ E.Data = true;
+ continue;
+ }
+ if (Tok.K == KwPrivate) {
+ E.Private = true;
+ continue;
+ }
+ unget();
+ Config->Exports.push_back(E);
+ return;
+ }
+ }
+
+ // HEAPSIZE/STACKSIZE reserve[,commit]
+ void parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
+ readAsInt(Reserve);
+ read();
+ if (Tok.K != Comma) {
+ unget();
+ Commit = nullptr;
+ return;
+ }
+ readAsInt(Commit);
+ }
+
+ // NAME outputPath [BASE=address]
+ void parseName(std::string *Out, uint64_t *Baseaddr) {
+ read();
+ if (Tok.K == Identifier) {
+ *Out = Tok.Value;
+ } else {
+ *Out = "";
+ unget();
+ return;
+ }
+ read();
+ if (Tok.K == KwBase) {
+ expect(Equal, "'=' expected");
+ readAsInt(Baseaddr);
+ } else {
+ unget();
+ *Baseaddr = 0;
+ }
+ }
+
+ // VERSION major[.minor]
+ void parseVersion(uint32_t *Major, uint32_t *Minor) {
+ read();
+ if (Tok.K != Identifier)
+ fatal("identifier expected, but got " + Tok.Value);
+ StringRef V1, V2;
+ std::tie(V1, V2) = Tok.Value.split('.');
+ if (V1.getAsInteger(10, *Major))
+ fatal("integer expected, but got " + Tok.Value);
+ if (V2.empty())
+ *Minor = 0;
+ else if (V2.getAsInteger(10, *Minor))
+ fatal("integer expected, but got " + Tok.Value);
+ }
+
+ Lexer Lex;
+ Token Tok;
+ std::vector<Token> Stack;
+ StringSaver *Alloc;
+};
+
+} // anonymous namespace
+
+void parseModuleDefs(MemoryBufferRef MB, StringSaver *Alloc) {
+ Parser(MB.getBuffer(), Alloc).parse();
+}
+
+} // namespace llvm
diff --git a/lib/DLLDriver/Options.td b/lib/DLLDriver/Options.td
new file mode 100644
index 0000000..62f33f3
--- /dev/null
+++ b/lib/DLLDriver/Options.td
@@ -0,0 +1,5 @@
+include "llvm/Option/OptParser.td"
+
+def emu: JoinedOrSeparate<["-"], "a">, HelpText<"Set target arch">;
+def out: JoinedOrSeparate<["-"], "o">, HelpText<"Set output file">;
+def dll: JoinedOrSeparate<["-"], "d">, HelpText<"Set dll name">;
diff --git a/lib/Object/ArchiveWriter.cpp b/lib/Object/ArchiveWriter.cpp
index 5357326..46b9d97 100644
--- a/lib/Object/ArchiveWriter.cpp
+++ b/lib/Object/ArchiveWriter.cpp
@@ -273,7 +273,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_Weak))
continue;
unsigned NameOffset = NameOS.tell();
diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt
index 86233df..94cc205 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
+ DllDriver
LibDriver
Object
Support
@@ -12,3 +13,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 865152b..936c417 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/DllDriver/DllDriver.h"
#include "llvm/LibDriver/LibDriver.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
@@ -827,6 +828,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));
@@ -842,5 +846,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!");
}
--
2.7.4