mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
llvm: add llvm-dlltool support to the archiver
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) Reviewed By: ruiu Differential Revision: https://reviews.llvm.org/D29892 This reapplies rL308329, which was reverted in rL308374 llvm-svn: 308379
This commit is contained in:
parent
3b9218a913
commit
4ec77fc2c7
@ -16,7 +16,6 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
#ifndef LLVM_OBJECT_COFF_MODULE_DEFINITION_H
|
#ifndef LLVM_OBJECT_COFF_MODULE_DEFINITION_H
|
||||||
#define LLVM_OBJECT_COFF_MODULE_DEFINITION_H
|
#define LLVM_OBJECT_COFF_MODULE_DEFINITION_H
|
||||||
|
|
||||||
@ -40,8 +39,12 @@ struct COFFModuleDefinition {
|
|||||||
uint32_t MinorOSVersion = 0;
|
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>
|
Expected<COFFModuleDefinition>
|
||||||
parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine);
|
parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine,
|
||||||
|
bool MingwDef = false);
|
||||||
|
|
||||||
} // End namespace object.
|
} // End namespace object.
|
||||||
} // End namespace llvm.
|
} // End namespace llvm.
|
||||||
|
24
include/llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h
Normal file
24
include/llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h
Normal file
@ -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 <typename T> class ArrayRef;
|
||||||
|
|
||||||
|
int dlltoolDriverMain(ArrayRef<const char *> ArgsArr);
|
||||||
|
} // namespace llvm
|
||||||
|
|
||||||
|
#endif
|
@ -318,7 +318,8 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
|
|||||||
continue;
|
continue;
|
||||||
if (!(Symflags & object::SymbolRef::SF_Global))
|
if (!(Symflags & object::SymbolRef::SF_Global))
|
||||||
continue;
|
continue;
|
||||||
if (Symflags & object::SymbolRef::SF_Undefined)
|
if (Symflags & object::SymbolRef::SF_Undefined &&
|
||||||
|
!(Symflags & object::SymbolRef::SF_Indirect))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
unsigned NameOffset = NameOS.tell();
|
unsigned NameOffset = NameOS.tell();
|
||||||
|
@ -162,14 +162,17 @@ public:
|
|||||||
// Library Format.
|
// Library Format.
|
||||||
NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
|
NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
|
||||||
ImportType Type, ImportNameType NameType);
|
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
|
} // namespace
|
||||||
|
|
||||||
NewArchiveMember
|
NewArchiveMember
|
||||||
ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
|
ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
|
||||||
static const uint32_t NumberOfSections = 2;
|
const uint32_t NumberOfSections = 2;
|
||||||
static const uint32_t NumberOfSymbols = 7;
|
const uint32_t NumberOfSymbols = 7;
|
||||||
static const uint32_t NumberOfRelocations = 3;
|
const uint32_t NumberOfRelocations = 3;
|
||||||
|
|
||||||
// COFF Header
|
// COFF Header
|
||||||
coff_file_header Header{
|
coff_file_header Header{
|
||||||
@ -189,7 +192,7 @@ ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
|
|||||||
append(Buffer, Header);
|
append(Buffer, Header);
|
||||||
|
|
||||||
// Section Header Table
|
// Section Header Table
|
||||||
static const coff_section SectionTable[NumberOfSections] = {
|
const coff_section SectionTable[NumberOfSections] = {
|
||||||
{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
|
{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
|
||||||
u32(0),
|
u32(0),
|
||||||
u32(0),
|
u32(0),
|
||||||
@ -219,12 +222,12 @@ ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
|
|||||||
append(Buffer, SectionTable);
|
append(Buffer, SectionTable);
|
||||||
|
|
||||||
// .idata$2
|
// .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),
|
u32(0), u32(0), u32(0), u32(0), u32(0),
|
||||||
};
|
};
|
||||||
append(Buffer, ImportDescriptor);
|
append(Buffer, ImportDescriptor);
|
||||||
|
|
||||||
static const coff_relocation RelocationTable[NumberOfRelocations] = {
|
const coff_relocation RelocationTable[NumberOfRelocations] = {
|
||||||
{u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
|
{u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
|
||||||
u16(getImgRelRelocation(Machine))},
|
u16(getImgRelRelocation(Machine))},
|
||||||
{u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
|
{u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
|
||||||
@ -307,8 +310,8 @@ ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
|
|||||||
|
|
||||||
NewArchiveMember
|
NewArchiveMember
|
||||||
ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
|
ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
|
||||||
static const uint32_t NumberOfSections = 1;
|
const uint32_t NumberOfSections = 1;
|
||||||
static const uint32_t NumberOfSymbols = 1;
|
const uint32_t NumberOfSymbols = 1;
|
||||||
|
|
||||||
// COFF Header
|
// COFF Header
|
||||||
coff_file_header Header{
|
coff_file_header Header{
|
||||||
@ -325,7 +328,7 @@ ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
|
|||||||
append(Buffer, Header);
|
append(Buffer, Header);
|
||||||
|
|
||||||
// Section Header Table
|
// Section Header Table
|
||||||
static const coff_section SectionTable[NumberOfSections] = {
|
const coff_section SectionTable[NumberOfSections] = {
|
||||||
{{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
|
{{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
|
||||||
u32(0),
|
u32(0),
|
||||||
u32(0),
|
u32(0),
|
||||||
@ -342,7 +345,7 @@ ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
|
|||||||
append(Buffer, SectionTable);
|
append(Buffer, SectionTable);
|
||||||
|
|
||||||
// .idata$3
|
// .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),
|
u32(0), u32(0), u32(0), u32(0), u32(0),
|
||||||
};
|
};
|
||||||
append(Buffer, ImportDescriptor);
|
append(Buffer, ImportDescriptor);
|
||||||
@ -367,8 +370,8 @@ ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
|
NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
|
||||||
static const uint32_t NumberOfSections = 2;
|
const uint32_t NumberOfSections = 2;
|
||||||
static const uint32_t NumberOfSymbols = 1;
|
const uint32_t NumberOfSymbols = 1;
|
||||||
uint32_t VASize = is32bit(Machine) ? 4 : 8;
|
uint32_t VASize = is32bit(Machine) ? 4 : 8;
|
||||||
|
|
||||||
// COFF Header
|
// COFF Header
|
||||||
@ -388,7 +391,7 @@ NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
|
|||||||
append(Buffer, Header);
|
append(Buffer, Header);
|
||||||
|
|
||||||
// Section Header Table
|
// Section Header Table
|
||||||
static const coff_section SectionTable[NumberOfSections] = {
|
const coff_section SectionTable[NumberOfSections] = {
|
||||||
{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
|
{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
|
||||||
u32(0),
|
u32(0),
|
||||||
u32(0),
|
u32(0),
|
||||||
@ -476,6 +479,85 @@ NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
|
|||||||
return {MemoryBufferRef(StringRef(Buf, Size), DLLName)};
|
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,
|
std::error_code writeImportLibrary(StringRef DLLName, StringRef Path,
|
||||||
ArrayRef<COFFShortExport> Exports,
|
ArrayRef<COFFShortExport> Exports,
|
||||||
MachineTypes Machine) {
|
MachineTypes Machine) {
|
||||||
@ -496,6 +578,12 @@ std::error_code writeImportLibrary(StringRef DLLName, StringRef Path,
|
|||||||
if (E.Private)
|
if (E.Private)
|
||||||
continue;
|
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;
|
ImportType ImportType = IMPORT_CODE;
|
||||||
if (E.Data)
|
if (E.Data)
|
||||||
ImportType = IMPORT_DATA;
|
ImportType = IMPORT_DATA;
|
||||||
|
@ -55,8 +55,10 @@ struct Token {
|
|||||||
StringRef Value;
|
StringRef Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool isDecorated(StringRef Sym) {
|
static bool isDecorated(StringRef Sym, bool MingwDef) {
|
||||||
return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
|
// mingw does not prepend "_".
|
||||||
|
return (!MingwDef && Sym.startswith("_")) || Sym.startswith("@") ||
|
||||||
|
Sym.startswith("?");
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error createError(const Twine &Err) {
|
static Error createError(const Twine &Err) {
|
||||||
@ -83,6 +85,9 @@ public:
|
|||||||
}
|
}
|
||||||
case '=':
|
case '=':
|
||||||
Buf = Buf.drop_front();
|
Buf = Buf.drop_front();
|
||||||
|
// GNU dlltool accepts both = and ==.
|
||||||
|
if (Buf.startswith("="))
|
||||||
|
Buf = Buf.drop_front();
|
||||||
return Token(Equal, "=");
|
return Token(Equal, "=");
|
||||||
case ',':
|
case ',':
|
||||||
Buf = Buf.drop_front();
|
Buf = Buf.drop_front();
|
||||||
@ -120,7 +125,8 @@ private:
|
|||||||
|
|
||||||
class Parser {
|
class Parser {
|
||||||
public:
|
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() {
|
Expected<COFFModuleDefinition> parse() {
|
||||||
do {
|
do {
|
||||||
@ -213,9 +219,9 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Machine == IMAGE_FILE_MACHINE_I386) {
|
if (Machine == IMAGE_FILE_MACHINE_I386) {
|
||||||
if (!isDecorated(E.Name))
|
if (!isDecorated(E.Name, MingwDef))
|
||||||
E.Name = (std::string("_").append(E.Name));
|
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));
|
E.ExtName = (std::string("_").append(E.ExtName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,11 +314,13 @@ private:
|
|||||||
std::vector<Token> Stack;
|
std::vector<Token> Stack;
|
||||||
MachineTypes Machine;
|
MachineTypes Machine;
|
||||||
COFFModuleDefinition Info;
|
COFFModuleDefinition Info;
|
||||||
|
bool MingwDef;
|
||||||
};
|
};
|
||||||
|
|
||||||
Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
|
Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
|
||||||
MachineTypes Machine) {
|
MachineTypes Machine,
|
||||||
return Parser(MB.getBuffer(), Machine).parse();
|
bool MingwDef) {
|
||||||
|
return Parser(MB.getBuffer(), Machine, MingwDef).parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace object
|
} // namespace object
|
||||||
|
@ -227,8 +227,11 @@ uint32_t COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {
|
|||||||
if (Symb.isExternal() || Symb.isWeakExternal())
|
if (Symb.isExternal() || Symb.isWeakExternal())
|
||||||
Result |= SymbolRef::SF_Global;
|
Result |= SymbolRef::SF_Global;
|
||||||
|
|
||||||
if (Symb.isWeakExternal())
|
if (Symb.isWeakExternal()) {
|
||||||
Result |= SymbolRef::SF_Weak;
|
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)
|
if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)
|
||||||
Result |= SymbolRef::SF_Absolute;
|
Result |= SymbolRef::SF_Absolute;
|
||||||
|
@ -1 +1,2 @@
|
|||||||
|
add_subdirectory(llvm-dlltool)
|
||||||
add_subdirectory(llvm-lib)
|
add_subdirectory(llvm-lib)
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
;===------------------------------------------------------------------------===;
|
;===------------------------------------------------------------------------===;
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
subdirectories = llvm-lib
|
subdirectories = llvm-dlltool llvm-lib
|
||||||
|
|
||||||
[component_0]
|
[component_0]
|
||||||
type = Group
|
type = Group
|
||||||
|
9
lib/ToolDrivers/llvm-dlltool/CMakeLists.txt
Normal file
9
lib/ToolDrivers/llvm-dlltool/CMakeLists.txt
Normal file
@ -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)
|
160
lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
Normal file
160
lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
Normal file
@ -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 <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;
|
||||||
|
}
|
22
lib/ToolDrivers/llvm-dlltool/LLVMBuild.txt
Normal file
22
lib/ToolDrivers/llvm-dlltool/LLVMBuild.txt
Normal file
@ -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
|
26
lib/ToolDrivers/llvm-dlltool/Options.td
Normal file
26
lib/ToolDrivers/llvm-dlltool/Options.td
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
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>;
|
@ -48,6 +48,7 @@ set(LLVM_TEST_DEPENDS
|
|||||||
llvm-cvtres
|
llvm-cvtres
|
||||||
llvm-diff
|
llvm-diff
|
||||||
llvm-dis
|
llvm-dis
|
||||||
|
llvm-dlltool
|
||||||
llvm-dsymutil
|
llvm-dsymutil
|
||||||
llvm-dwarfdump
|
llvm-dwarfdump
|
||||||
llvm-dwp
|
llvm-dwp
|
||||||
|
13
test/DllTool/coff-exports.def
Normal file
13
test/DllTool/coff-exports.def
Normal file
@ -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
|
19
test/DllTool/coff-weak-exports.def
Normal file
19
test/DllTool/coff-weak-exports.def
Normal file
@ -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
|
1
test/DllTool/lit.local.cfg
Normal file
1
test/DllTool/lit.local.cfg
Normal file
@ -0,0 +1 @@
|
|||||||
|
config.suffixes = ['.def']
|
@ -1,6 +1,7 @@
|
|||||||
set(LLVM_LINK_COMPONENTS
|
set(LLVM_LINK_COMPONENTS
|
||||||
${LLVM_TARGETS_TO_BUILD}
|
${LLVM_TARGETS_TO_BUILD}
|
||||||
Core
|
Core
|
||||||
|
DlltoolDriver
|
||||||
LibDriver
|
LibDriver
|
||||||
Object
|
Object
|
||||||
Support
|
Support
|
||||||
@ -15,3 +16,4 @@ add_llvm_tool(llvm-ar
|
|||||||
|
|
||||||
add_llvm_tool_symlink(llvm-ranlib llvm-ar)
|
add_llvm_tool_symlink(llvm-ranlib llvm-ar)
|
||||||
add_llvm_tool_symlink(llvm-lib llvm-ar)
|
add_llvm_tool_symlink(llvm-lib llvm-ar)
|
||||||
|
add_llvm_tool_symlink(llvm-dlltool llvm-ar)
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "llvm/ADT/Triple.h"
|
#include "llvm/ADT/Triple.h"
|
||||||
#include "llvm/IR/LLVMContext.h"
|
#include "llvm/IR/LLVMContext.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
|
#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
|
||||||
#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
|
#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
|
||||||
#include "llvm/Object/Archive.h"
|
#include "llvm/Object/Archive.h"
|
||||||
#include "llvm/Object/ArchiveWriter.h"
|
#include "llvm/Object/ArchiveWriter.h"
|
||||||
@ -863,6 +864,9 @@ int main(int argc, char **argv) {
|
|||||||
llvm::InitializeAllAsmParsers();
|
llvm::InitializeAllAsmParsers();
|
||||||
|
|
||||||
StringRef Stem = sys::path::stem(ToolName);
|
StringRef Stem = sys::path::stem(ToolName);
|
||||||
|
if (Stem.find("dlltool") != StringRef::npos)
|
||||||
|
return dlltoolDriverMain(makeArrayRef(argv, argc));
|
||||||
|
|
||||||
if (Stem.find("ranlib") == StringRef::npos &&
|
if (Stem.find("ranlib") == StringRef::npos &&
|
||||||
Stem.find("lib") != StringRef::npos)
|
Stem.find("lib") != StringRef::npos)
|
||||||
return libDriverMain(makeArrayRef(argv, argc));
|
return libDriverMain(makeArrayRef(argv, argc));
|
||||||
@ -878,5 +882,5 @@ int main(int argc, char **argv) {
|
|||||||
return ranlib_main();
|
return ranlib_main();
|
||||||
if (Stem.find("ar") != StringRef::npos)
|
if (Stem.find("ar") != StringRef::npos)
|
||||||
return ar_main();
|
return ar_main();
|
||||||
fail("Not ranlib, ar or lib!");
|
fail("Not ranlib, ar, lib or dlltool!");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user