blob: 94533270c30b83ec9c7ebf671bd1593dcbeb72eb [file] [log] [blame]
Martell Malone1079ef82017-07-18 21:26:38 +00001//===- DlltoolDriver.cpp - dlltool.exe-compatible driver ------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Defines an interface to a dlltool.exe-compatible driver.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
15#include "llvm/Object/ArchiveWriter.h"
16#include "llvm/Object/COFF.h"
17#include "llvm/Object/COFFImportFile.h"
18#include "llvm/Object/COFFModuleDefinition.h"
19#include "llvm/Option/Arg.h"
20#include "llvm/Option/ArgList.h"
21#include "llvm/Option/Option.h"
22#include "llvm/Support/Path.h"
23
24#include <string>
25#include <vector>
26
27using namespace llvm;
28using namespace llvm::object;
29using namespace llvm::COFF;
30
31namespace {
32
33enum {
34 OPT_INVALID = 0,
35#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
36#include "Options.inc"
37#undef OPTION
38};
39
40#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
41#include "Options.inc"
42#undef PREFIX
43
44static const llvm::opt::OptTable::Info infoTable[] = {
45#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
46 {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \
47 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
48#include "Options.inc"
49#undef OPTION
50};
51
52class DllOptTable : public llvm::opt::OptTable {
53public:
54 DllOptTable() : OptTable(infoTable, false) {}
55};
56
57} // namespace
58
59std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
60
61// Opens a file. Path has to be resolved already.
62// Newly created memory buffers are owned by this driver.
Martin Storsjo9d8ecb42017-08-17 05:58:27 +000063Optional<MemoryBufferRef> openFile(StringRef Path) {
Martell Malone1079ef82017-07-18 21:26:38 +000064 ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = MemoryBuffer::getFile(Path);
65
Martin Storsjo9d8ecb42017-08-17 05:58:27 +000066 if (std::error_code EC = MB.getError()) {
Martin Storsjocaff3262017-08-17 06:26:42 +000067 llvm::errs() << "cannot open file " << Path << ": " << EC.message() << "\n";
Martin Storsjo9d8ecb42017-08-17 05:58:27 +000068 return None;
69 }
Martell Malone1079ef82017-07-18 21:26:38 +000070
71 MemoryBufferRef MBRef = MB.get()->getMemBufferRef();
72 OwningMBs.push_back(std::move(MB.get())); // take ownership
73 return MBRef;
74}
75
76static MachineTypes getEmulation(StringRef S) {
77 return StringSwitch<MachineTypes>(S)
78 .Case("i386", IMAGE_FILE_MACHINE_I386)
79 .Case("i386:x86-64", IMAGE_FILE_MACHINE_AMD64)
80 .Case("arm", IMAGE_FILE_MACHINE_ARMNT)
Martin Storsjoc9263f42017-08-06 19:58:13 +000081 .Case("arm64", IMAGE_FILE_MACHINE_ARM64)
Martell Malone1079ef82017-07-18 21:26:38 +000082 .Default(IMAGE_FILE_MACHINE_UNKNOWN);
83}
84
85static std::string getImplibPath(std::string Path) {
86 SmallString<128> Out = StringRef("lib");
87 Out.append(Path);
88 sys::path::replace_extension(Out, ".a");
89 return Out.str();
90}
91
92int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
93 DllOptTable Table;
94 unsigned MissingIndex;
95 unsigned MissingCount;
96 llvm::opt::InputArgList Args =
97 Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
98 if (MissingCount) {
99 llvm::errs() << Args.getArgString(MissingIndex) << ": missing argument\n";
100 return 1;
101 }
102
103 // Handle when no input or output is specified
104 if (Args.hasArgNoClaim(OPT_INPUT) ||
105 (!Args.hasArgNoClaim(OPT_d) && !Args.hasArgNoClaim(OPT_l))) {
106 Table.PrintHelp(outs(), ArgsArr[0], "dlltool", false);
107 llvm::outs() << "\nTARGETS: i386, i386:x86-64, arm\n";
108 return 1;
109 }
110
111 if (!Args.hasArgNoClaim(OPT_m) && Args.hasArgNoClaim(OPT_d)) {
112 llvm::errs() << "error: no target machine specified\n"
113 << "supported targets: i386, i386:x86-64, arm\n";
114 return 1;
115 }
116
117 for (auto *Arg : Args.filtered(OPT_UNKNOWN))
118 llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
119
Martin Storsjo9d8ecb42017-08-17 05:58:27 +0000120 if (!Args.hasArg(OPT_d)) {
121 llvm::errs() << "no definition file specified\n";
122 return 1;
123 }
Martell Malone1079ef82017-07-18 21:26:38 +0000124
Martin Storsjo9d8ecb42017-08-17 05:58:27 +0000125 Optional<MemoryBufferRef> MB = openFile(Args.getLastArg(OPT_d)->getValue());
126 if (!MB)
127 return 1;
128
129 if (!MB->getBufferSize()) {
Martell Malone1079ef82017-07-18 21:26:38 +0000130 llvm::errs() << "definition file empty\n";
131 return 1;
132 }
133
134 COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
135 if (auto *Arg = Args.getLastArg(OPT_m))
136 Machine = getEmulation(Arg->getValue());
137
138 if (Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
139 llvm::errs() << "unknown target\n";
140 return 1;
141 }
142
143 Expected<COFFModuleDefinition> Def =
Martin Storsjo9d8ecb42017-08-17 05:58:27 +0000144 parseCOFFModuleDefinition(*MB, Machine, true);
Martell Malone1079ef82017-07-18 21:26:38 +0000145
146 if (!Def) {
147 llvm::errs() << "error parsing definition\n"
148 << errorToErrorCode(Def.takeError()).message();
149 return 1;
150 }
151
152 // Do this after the parser because parseCOFFModuleDefinition sets OutputFile.
153 if (auto *Arg = Args.getLastArg(OPT_D))
154 Def->OutputFile = Arg->getValue();
155
156 if (Def->OutputFile.empty()) {
157 llvm::errs() << "no output file specified\n";
158 return 1;
159 }
160
161 std::string Path = Args.getLastArgValue(OPT_l);
162 if (Path.empty())
163 Path = getImplibPath(Def->OutputFile);
164
Martin Storsjo58c95272017-08-16 05:18:36 +0000165 if (Machine == IMAGE_FILE_MACHINE_I386 && Args.getLastArg(OPT_k)) {
166 for (COFFShortExport& E : Def->Exports) {
167 if (E.isWeak() || (!E.Name.empty() && E.Name[0] == '?'))
168 continue;
169 E.SymbolName = E.Name;
170 // Trim off the trailing decoration. Symbols will always have a
171 // starting prefix here (either _ for cdecl/stdcall, @ for fastcall
172 // or ? for C++ functions). (Vectorcall functions also will end up having
173 // a prefix here, even if they shouldn't.)
174 E.Name = E.Name.substr(0, E.Name.find('@', 1));
175 // By making sure E.SymbolName != E.Name for decorated symbols,
176 // writeImportLibrary writes these symbols with the type
177 // IMPORT_NAME_UNDECORATE.
178 }
179 }
180
Martin Storsjoe1f120b2017-08-16 05:22:49 +0000181 if (writeImportLibrary(Def->OutputFile, Path, Def->Exports, Machine, true))
Martell Malone1079ef82017-07-18 21:26:38 +0000182 return 1;
183 return 0;
184}