Skip to content

Commit 894dbbe

Browse files
committed
LLD: Introduce a GNU LD style driver for COFF
When building COFF programs many targets such as mingw prefer to have a gnu ld frontend. Rather then having a fully fledged standalone driver we wrap a shim around the LINK driver. Extra tests were provided by mstorsjo Reviewers: mstorsjo, ruiu Differential Revision: https://reviews.llvm.org/D33880 llvm-svn: 312926
1 parent 7b02020 commit 894dbbe

File tree

13 files changed

+519
-6
lines changed

13 files changed

+519
-6
lines changed

lld/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,5 @@ endif()
221221
add_subdirectory(docs)
222222
add_subdirectory(COFF)
223223
add_subdirectory(ELF)
224+
add_subdirectory(MinGW)
224225

lld/ELF/Driver.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,8 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
113113
.Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
114114
.Default({ELFNoneKind, EM_NONE});
115115

116-
if (Ret.first == ELFNoneKind) {
117-
if (S == "i386pe" || S == "i386pep" || S == "thumb2pe")
118-
error("Windows targets are not supported on the ELF frontend: " + Emul);
119-
else
120-
error("unknown emulation: " + Emul);
121-
}
116+
if (Ret.first == ELFNoneKind)
117+
error("unknown emulation: " + Emul);
122118
return std::make_tuple(Ret.first, Ret.second, OSABI);
123119
}
124120

lld/MinGW/CMakeLists.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
set(LLVM_TARGET_DEFINITIONS Options.td)
2+
tablegen(LLVM Options.inc -gen-opt-parser-defs)
3+
add_public_tablegen_target(ShimOptionsTableGen)
4+
5+
if(NOT LLD_BUILT_STANDALONE)
6+
set(tablegen_deps intrinsics_gen)
7+
endif()
8+
9+
add_lld_library(lldMinGW
10+
Driver.cpp
11+
12+
LINK_LIBS
13+
lldConfig
14+
lldCore
15+
${LLVM_PTHREAD_LIB}
16+
17+
DEPENDS
18+
ShimOptionsTableGen
19+
${tablegen_deps}
20+
)

lld/MinGW/Driver.cpp

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
//===- MinGW/Driver.cpp ---------------------------------------------------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
///
10+
/// GNU ld style linker driver for COFF currently supporting mingw-w64.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "lld/Driver/Driver.h"
15+
#include "llvm/ADT/ArrayRef.h"
16+
#include "llvm/ADT/Optional.h"
17+
#include "llvm/ADT/StringRef.h"
18+
#include "llvm/ADT/StringSwitch.h"
19+
#include "llvm/ADT/Triple.h"
20+
#include "llvm/Option/Arg.h"
21+
#include "llvm/Option/ArgList.h"
22+
#include "llvm/Option/Option.h"
23+
#include "llvm/Support/CommandLine.h"
24+
#include "llvm/Support/FileSystem.h"
25+
#include "llvm/Support/Path.h"
26+
27+
#if !defined(_MSC_VER) && !defined(__MINGW32__)
28+
#include <unistd.h>
29+
#endif
30+
31+
using namespace lld;
32+
using namespace llvm;
33+
34+
namespace lld {
35+
namespace mingw {
36+
namespace {
37+
38+
// Create OptTable
39+
enum {
40+
OPT_INVALID = 0,
41+
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
42+
#include "Options.inc"
43+
#undef OPTION
44+
};
45+
46+
// Create prefix string literals used in Options.td
47+
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
48+
#include "Options.inc"
49+
#undef PREFIX
50+
51+
// Create table mapping all options defined in Options.td
52+
static const opt::OptTable::Info InfoTable[] = {
53+
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
54+
{X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
55+
X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
56+
#include "Options.inc"
57+
#undef OPTION
58+
};
59+
60+
class COFFLdOptTable : public opt::OptTable {
61+
public:
62+
COFFLdOptTable() : OptTable(InfoTable, false) {}
63+
opt::InputArgList parse(ArrayRef<const char *> Argv);
64+
};
65+
66+
} // namespace
67+
68+
static std::vector<std::string> LinkArgs;
69+
static std::vector<StringRef> SearchPaths;
70+
71+
static void error(const Twine &Msg) {
72+
errs() << Msg << "\n";
73+
llvm_shutdown();
74+
exit(1);
75+
}
76+
77+
// Find a file by concatenating given paths.
78+
static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
79+
SmallString<128> S;
80+
sys::path::append(S, Path1, Path2);
81+
if (sys::fs::exists(S))
82+
return S.str().str();
83+
return None;
84+
}
85+
86+
static Optional<std::string> findFromSearchPaths(StringRef Path) {
87+
for (StringRef Dir : SearchPaths)
88+
if (Optional<std::string> S = findFile(Dir, Path))
89+
return S;
90+
return None;
91+
}
92+
93+
// This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths.
94+
static Optional<std::string> searchLibrary(StringRef Name, bool StaticOnly) {
95+
if (Name.startswith(":"))
96+
return findFromSearchPaths(Name.substr(1));
97+
for (StringRef Dir : SearchPaths) {
98+
if (!StaticOnly)
99+
if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".dll.a"))
100+
return S;
101+
if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
102+
return S;
103+
}
104+
return None;
105+
}
106+
107+
// Add a given library by searching it from input search paths.
108+
static void addLibrary(StringRef Name, bool StaticOnly) {
109+
if (Optional<std::string> Path = searchLibrary(Name, StaticOnly))
110+
LinkArgs.push_back(*Path);
111+
else
112+
error("unable to find library -l" + Name);
113+
}
114+
115+
static void createFiles(opt::InputArgList &Args) {
116+
for (auto *Arg : Args) {
117+
switch (Arg->getOption().getUnaliasedOption().getID()) {
118+
case OPT_l:
119+
addLibrary(Arg->getValue(), Args.hasArg(OPT_Bstatic));
120+
break;
121+
case OPT_INPUT:
122+
LinkArgs.push_back(Arg->getValue());
123+
break;
124+
}
125+
}
126+
}
127+
128+
static void forward(opt::InputArgList &Args, unsigned Key,
129+
const std::string &OutArg, std::string Default = "") {
130+
StringRef S = Args.getLastArgValue(Key);
131+
if (!S.empty())
132+
LinkArgs.push_back(std::string("-").append(OutArg).append(":").append(S));
133+
else if (!Default.empty())
134+
LinkArgs.push_back(
135+
std::string("-").append(OutArg).append(":").append(Default));
136+
}
137+
138+
static void forwardValue(opt::InputArgList &Args, unsigned Key,
139+
const std::string &CmpArg, const std::string &OutArg) {
140+
StringRef S = Args.getLastArgValue(Key);
141+
if (S == CmpArg)
142+
LinkArgs.push_back(std::string("-").append(OutArg));
143+
}
144+
145+
static bool convertValue(opt::InputArgList &Args, unsigned Key,
146+
StringRef OutArg) {
147+
if (Args.hasArg(Key)) {
148+
LinkArgs.push_back(std::string("-").append(OutArg));
149+
return true;
150+
}
151+
return false;
152+
}
153+
154+
opt::InputArgList COFFLdOptTable::parse(ArrayRef<const char *> Argv) {
155+
unsigned MissingIndex;
156+
unsigned MissingCount;
157+
SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
158+
opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
159+
if (MissingCount)
160+
error(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
161+
if (!Args.hasArgNoClaim(OPT_INPUT) && !Args.hasArgNoClaim(OPT_l))
162+
error("no input files");
163+
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
164+
error("unknown argument: " + Arg->getSpelling());
165+
return Args;
166+
}
167+
168+
bool link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) {
169+
COFFLdOptTable Parser;
170+
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
171+
LinkArgs.push_back(ArgsArr[0]);
172+
173+
forwardValue(Args, OPT_m, "i386pe", "machine:x86");
174+
forwardValue(Args, OPT_m, "i386pep", "machine:x64");
175+
forwardValue(Args, OPT_m, "thumb2pe", "machine:arm");
176+
forwardValue(Args, OPT_m, "arm64pe", "machine:arm64");
177+
178+
forward(Args, OPT_o, "out",
179+
convertValue(Args, OPT_shared, "dll") ? "a.dll" : "a.exe");
180+
forward(Args, OPT_entry, "entry");
181+
forward(Args, OPT_subs, "subsystem");
182+
forward(Args, OPT_outlib, "implib");
183+
forward(Args, OPT_stack, "stack");
184+
185+
for (auto *Arg : Args.filtered(OPT_L))
186+
SearchPaths.push_back(Arg->getValue());
187+
188+
createFiles(Args);
189+
190+
// handle __image_base__
191+
if (Args.getLastArgValue(OPT_m) == "i386pe")
192+
LinkArgs.push_back("/alternatename:__image_base__=___ImageBase");
193+
else
194+
LinkArgs.push_back("/alternatename:__image_base__=__ImageBase");
195+
196+
// repack vector of strings to vector of const char pointers for coff::link
197+
std::vector<const char *> Vec;
198+
for (const std::string &S : LinkArgs)
199+
Vec.push_back(S.c_str());
200+
return coff::link(Vec);
201+
}
202+
203+
} // namespace mingw
204+
} // namespace lld

lld/MinGW/Options.td

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
include "llvm/Option/OptParser.td"
2+
3+
class F<string name>: Flag<["--", "-"], name>;
4+
class J<string name>: Joined<["--", "-"], name>;
5+
class S<string name>: Separate<["--", "-"], name>;
6+
7+
def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
8+
HelpText<"Add a directory to the library search path">;
9+
def entry: S<"entry">, MetaVarName<"<entry>">,
10+
HelpText<"Name of entry point symbol">;
11+
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
12+
def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
13+
HelpText<"Path to file to write output">;
14+
def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
15+
HelpText<"Root name of library to use">;
16+
def shared: F<"shared">, HelpText<"Build a shared object">;
17+
def subs: Separate<["--"], "subsystem">, HelpText<"Specify subsystem">;
18+
def stack: Separate<["--"], "stack">;
19+
def outlib: Separate<["--"], "out-implib">, HelpText<"Import library name">;
20+
21+
// Currently stubs to avoid errors
22+
def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">;
23+
def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
24+
def major_image_version: Separate<["--"], "major-image-version">;
25+
def minor_image_version: Separate<["--"], "minor-image-version">;
26+
def enable_auto_image_base: Flag<["--"], "enable-auto-image-base">;
27+
def full_shutdown: Flag<["--"], "full-shutdown">;
28+
def O: Joined<["-"], "O">, HelpText<"Optimize output file size">;
29+
def v: Flag<["-"], "v">, HelpText<"Display the version number">;
30+
def verbose: F<"verbose">, HelpText<"Verbose mode">;
31+
def version: F<"version">, HelpText<"Display the version number and exit">;
32+
33+
// Alias
34+
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;

lld/include/lld/Driver/Driver.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ bool link(llvm::ArrayRef<const char *> Args,
1919
llvm::raw_ostream &Diag = llvm::errs());
2020
}
2121

22+
namespace mingw {
23+
bool link(llvm::ArrayRef<const char *> Args,
24+
llvm::raw_ostream &Diag = llvm::errs());
25+
}
26+
2227
namespace elf {
2328
bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
2429
llvm::raw_ostream &Diag = llvm::errs());
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--- !COFF
2+
header:
3+
Machine: IMAGE_FILE_MACHINE_ARM64
4+
Characteristics: [ ]
5+
sections:
6+
- Name: .text
7+
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
8+
Alignment: 16
9+
SectionData: 31C0C3666666662E0F1F84000000000031C0C3666666662E0F1F840000000000488D0500000000C3
10+
symbols:
11+
- Name: .text
12+
Value: 0
13+
SectionNumber: 1
14+
SimpleType: IMAGE_SYM_TYPE_NULL
15+
ComplexType: IMAGE_SYM_DTYPE_NULL
16+
StorageClass: IMAGE_SYM_CLASS_STATIC
17+
SectionDefinition:
18+
Length: 40
19+
NumberOfRelocations: 1
20+
NumberOfLinenumbers: 0
21+
CheckSum: 3930888477
22+
Number: 1
23+
- Name: mainCRTStartup
24+
Value: 0
25+
SectionNumber: 1
26+
SimpleType: IMAGE_SYM_TYPE_NULL
27+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
28+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
29+
- Name: main
30+
Value: 16
31+
SectionNumber: 1
32+
SimpleType: IMAGE_SYM_TYPE_NULL
33+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
34+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
35+
- Name: func
36+
Value: 32
37+
SectionNumber: 1
38+
SimpleType: IMAGE_SYM_TYPE_NULL
39+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
40+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
41+
- Name: __ImageBase
42+
Value: 0
43+
SectionNumber: 0
44+
SimpleType: IMAGE_SYM_TYPE_NULL
45+
ComplexType: IMAGE_SYM_DTYPE_NULL
46+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
47+
...
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--- !COFF
2+
header:
3+
Machine: IMAGE_FILE_MACHINE_ARMNT
4+
Characteristics: [ ]
5+
sections:
6+
- Name: .text
7+
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
8+
Alignment: 16
9+
SectionData: 31C0C3666666662E0F1F84000000000031C0C3666666662E0F1F840000000000B800000000C3
10+
symbols:
11+
- Name: .text
12+
Value: 0
13+
SectionNumber: 1
14+
SimpleType: IMAGE_SYM_TYPE_NULL
15+
ComplexType: IMAGE_SYM_DTYPE_NULL
16+
StorageClass: IMAGE_SYM_CLASS_STATIC
17+
SectionDefinition:
18+
Length: 38
19+
NumberOfRelocations: 1
20+
NumberOfLinenumbers: 0
21+
CheckSum: 3189961473
22+
Number: 1
23+
- Name: mainCRTStartup
24+
Value: 0
25+
SectionNumber: 1
26+
SimpleType: IMAGE_SYM_TYPE_NULL
27+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
28+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
29+
- Name: main
30+
Value: 16
31+
SectionNumber: 1
32+
SimpleType: IMAGE_SYM_TYPE_NULL
33+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
34+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
35+
- Name: func
36+
Value: 32
37+
SectionNumber: 1
38+
SimpleType: IMAGE_SYM_TYPE_NULL
39+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
40+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
41+
- Name: __ImageBase
42+
Value: 0
43+
SectionNumber: 0
44+
SimpleType: IMAGE_SYM_TYPE_NULL
45+
ComplexType: IMAGE_SYM_DTYPE_NULL
46+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
47+
...

0 commit comments

Comments
 (0)