Skip to content

Commit

Permalink
llvm: add llvm-dlltool support to the archiver
Browse files Browse the repository at this point in the history
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
  • Loading branch information
martell committed Jul 18, 2017
1 parent f6b8ac2 commit 1079ef8
Show file tree
Hide file tree
Showing 18 changed files with 411 additions and 26 deletions.
7 changes: 5 additions & 2 deletions llvm/include/llvm/Object/COFFModuleDefinition.h
Expand Up @@ -16,7 +16,6 @@
//
//===----------------------------------------------------------------------===//


#ifndef LLVM_OBJECT_COFF_MODULE_DEFINITION_H
#define LLVM_OBJECT_COFF_MODULE_DEFINITION_H

Expand All @@ -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<COFFModuleDefinition>
parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine);
parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine,
bool MingwDef = false);

} // End namespace object.
} // End namespace llvm.
Expand Down
24 changes: 24 additions & 0 deletions llvm/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 <typename T> class ArrayRef;

int dlltoolDriverMain(ArrayRef<const char *> ArgsArr);
} // namespace llvm

#endif
3 changes: 2 additions & 1 deletion llvm/lib/Object/ArchiveWriter.cpp
Expand Up @@ -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();
Expand Down
114 changes: 101 additions & 13 deletions llvm/lib/Object/COFFImportFile.cpp
Expand Up @@ -162,14 +162,17 @@ class ObjectFactory {
// 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{
Expand All @@ -189,7 +192,7 @@ ObjectFactory::createImportDescriptor(std::vector<uint8_t> &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),
Expand Down Expand Up @@ -219,12 +222,12 @@ ObjectFactory::createImportDescriptor(std::vector<uint8_t> &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)),
Expand Down Expand Up @@ -307,8 +310,8 @@ ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {

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{
Expand All @@ -325,7 +328,7 @@ ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &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),
Expand All @@ -342,7 +345,7 @@ ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &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);
Expand All @@ -367,8 +370,8 @@ ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
}

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
Expand All @@ -388,7 +391,7 @@ NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &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),
Expand Down Expand Up @@ -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<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) {
Expand All @@ -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;
Expand Down
22 changes: 15 additions & 7 deletions llvm/lib/Object/COFFModuleDefinition.cpp
Expand Up @@ -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) {
Expand All @@ -83,6 +85,9 @@ class Lexer {
}
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();
Expand Down Expand Up @@ -120,7 +125,8 @@ class Lexer {

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 {
Expand Down Expand Up @@ -213,9 +219,9 @@ class Parser {
}

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));
}

Expand Down Expand Up @@ -308,11 +314,13 @@ class Parser {
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
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/Object/COFFObjectFile.cpp
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/ToolDrivers/CMakeLists.txt
@@ -1 +1,2 @@
add_subdirectory(llvm-dlltool)
add_subdirectory(llvm-lib)
2 changes: 1 addition & 1 deletion llvm/lib/ToolDrivers/LLVMBuild.txt
Expand Up @@ -16,7 +16,7 @@
;===------------------------------------------------------------------------===;

[common]
subdirectories = llvm-lib
subdirectories = llvm-dlltool llvm-lib

[component_0]
type = Group
Expand Down
9 changes: 9 additions & 0 deletions llvm/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)

0 comments on commit 1079ef8

Please sign in to comment.