Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
35271 views
1
//===- DlltoolDriver.cpp - dlltool.exe-compatible driver ------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// Defines an interface to a dlltool.exe-compatible driver.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
14
#include "llvm/ADT/StringSwitch.h"
15
#include "llvm/Object/COFF.h"
16
#include "llvm/Object/COFFImportFile.h"
17
#include "llvm/Object/COFFModuleDefinition.h"
18
#include "llvm/Option/Arg.h"
19
#include "llvm/Option/ArgList.h"
20
#include "llvm/Option/OptTable.h"
21
#include "llvm/Option/Option.h"
22
#include "llvm/Support/Path.h"
23
#include "llvm/TargetParser/Host.h"
24
25
#include <optional>
26
#include <vector>
27
28
using namespace llvm;
29
using namespace llvm::object;
30
using namespace llvm::COFF;
31
32
namespace {
33
34
enum {
35
OPT_INVALID = 0,
36
#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
37
#include "Options.inc"
38
#undef OPTION
39
};
40
41
#define PREFIX(NAME, VALUE) \
42
static constexpr StringLiteral NAME##_init[] = VALUE; \
43
static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
44
std::size(NAME##_init) - 1);
45
#include "Options.inc"
46
#undef PREFIX
47
48
using namespace llvm::opt;
49
static constexpr opt::OptTable::Info InfoTable[] = {
50
#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
51
#include "Options.inc"
52
#undef OPTION
53
};
54
55
class DllOptTable : public opt::GenericOptTable {
56
public:
57
DllOptTable() : opt::GenericOptTable(InfoTable, false) {}
58
};
59
60
// Opens a file. Path has to be resolved already.
61
std::unique_ptr<MemoryBuffer> openFile(const Twine &Path) {
62
ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = MemoryBuffer::getFile(Path);
63
64
if (std::error_code EC = MB.getError()) {
65
llvm::errs() << "cannot open file " << Path << ": " << EC.message() << "\n";
66
return nullptr;
67
}
68
69
return std::move(*MB);
70
}
71
72
MachineTypes getEmulation(StringRef S) {
73
return StringSwitch<MachineTypes>(S)
74
.Case("i386", IMAGE_FILE_MACHINE_I386)
75
.Case("i386:x86-64", IMAGE_FILE_MACHINE_AMD64)
76
.Case("arm", IMAGE_FILE_MACHINE_ARMNT)
77
.Case("arm64", IMAGE_FILE_MACHINE_ARM64)
78
.Case("arm64ec", IMAGE_FILE_MACHINE_ARM64EC)
79
.Default(IMAGE_FILE_MACHINE_UNKNOWN);
80
}
81
82
MachineTypes getMachine(Triple T) {
83
switch (T.getArch()) {
84
case Triple::x86:
85
return COFF::IMAGE_FILE_MACHINE_I386;
86
case Triple::x86_64:
87
return COFF::IMAGE_FILE_MACHINE_AMD64;
88
case Triple::arm:
89
return COFF::IMAGE_FILE_MACHINE_ARMNT;
90
case Triple::aarch64:
91
return T.isWindowsArm64EC() ? COFF::IMAGE_FILE_MACHINE_ARM64EC
92
: COFF::IMAGE_FILE_MACHINE_ARM64;
93
default:
94
return COFF::IMAGE_FILE_MACHINE_UNKNOWN;
95
}
96
}
97
98
MachineTypes getDefaultMachine() {
99
return getMachine(Triple(sys::getDefaultTargetTriple()));
100
}
101
102
std::optional<std::string> getPrefix(StringRef Argv0) {
103
StringRef ProgName = llvm::sys::path::stem(Argv0);
104
// x86_64-w64-mingw32-dlltool -> x86_64-w64-mingw32
105
// llvm-dlltool -> None
106
// aarch64-w64-mingw32-llvm-dlltool-10.exe -> aarch64-w64-mingw32
107
ProgName = ProgName.rtrim("0123456789.-");
108
if (!ProgName.consume_back_insensitive("dlltool"))
109
return std::nullopt;
110
ProgName.consume_back_insensitive("llvm-");
111
ProgName.consume_back_insensitive("-");
112
return ProgName.str();
113
}
114
115
bool parseModuleDefinition(StringRef DefFileName, MachineTypes Machine,
116
bool AddUnderscores,
117
std::vector<COFFShortExport> &Exports,
118
std::string &OutputFile) {
119
std::unique_ptr<MemoryBuffer> MB = openFile(DefFileName);
120
if (!MB)
121
return false;
122
123
if (!MB->getBufferSize()) {
124
llvm::errs() << "definition file empty\n";
125
return false;
126
}
127
128
Expected<COFFModuleDefinition> Def = parseCOFFModuleDefinition(
129
*MB, Machine, /*MingwDef=*/true, AddUnderscores);
130
if (!Def) {
131
llvm::errs() << "error parsing definition\n"
132
<< errorToErrorCode(Def.takeError()).message() << "\n";
133
return false;
134
}
135
136
if (OutputFile.empty())
137
OutputFile = std::move(Def->OutputFile);
138
139
// If ExtName is set (if the "ExtName = Name" syntax was used), overwrite
140
// Name with ExtName and clear ExtName. When only creating an import
141
// library and not linking, the internal name is irrelevant. This avoids
142
// cases where writeImportLibrary tries to transplant decoration from
143
// symbol decoration onto ExtName.
144
for (COFFShortExport &E : Def->Exports) {
145
if (!E.ExtName.empty()) {
146
E.Name = E.ExtName;
147
E.ExtName.clear();
148
}
149
}
150
151
Exports = std::move(Def->Exports);
152
return true;
153
}
154
155
} // namespace
156
157
int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
158
DllOptTable Table;
159
unsigned MissingIndex;
160
unsigned MissingCount;
161
llvm::opt::InputArgList Args =
162
Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
163
if (MissingCount) {
164
llvm::errs() << Args.getArgString(MissingIndex) << ": missing argument\n";
165
return 1;
166
}
167
168
// Handle when no input or output is specified
169
if (Args.hasArgNoClaim(OPT_INPUT) ||
170
(!Args.hasArgNoClaim(OPT_d) && !Args.hasArgNoClaim(OPT_l))) {
171
Table.printHelp(outs(), "llvm-dlltool [options] file...", "llvm-dlltool",
172
false);
173
llvm::outs() << "\nTARGETS: i386, i386:x86-64, arm, arm64, arm64ec\n";
174
return 1;
175
}
176
177
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
178
llvm::errs() << "ignoring unknown argument: " << Arg->getAsString(Args)
179
<< "\n";
180
181
if (!Args.hasArg(OPT_d)) {
182
llvm::errs() << "no definition file specified\n";
183
return 1;
184
}
185
186
COFF::MachineTypes Machine = getDefaultMachine();
187
if (std::optional<std::string> Prefix = getPrefix(ArgsArr[0])) {
188
Triple T(*Prefix);
189
if (T.getArch() != Triple::UnknownArch)
190
Machine = getMachine(T);
191
}
192
if (auto *Arg = Args.getLastArg(OPT_m))
193
Machine = getEmulation(Arg->getValue());
194
195
if (Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
196
llvm::errs() << "unknown target\n";
197
return 1;
198
}
199
200
bool AddUnderscores = !Args.hasArg(OPT_no_leading_underscore);
201
202
std::string OutputFile;
203
if (auto *Arg = Args.getLastArg(OPT_D))
204
OutputFile = Arg->getValue();
205
206
std::vector<COFFShortExport> Exports, NativeExports;
207
208
if (Args.hasArg(OPT_N)) {
209
if (!isArm64EC(Machine)) {
210
llvm::errs() << "native .def file is supported only on arm64ec target\n";
211
return 1;
212
}
213
if (!parseModuleDefinition(Args.getLastArg(OPT_N)->getValue(),
214
IMAGE_FILE_MACHINE_ARM64, AddUnderscores,
215
NativeExports, OutputFile))
216
return 1;
217
}
218
219
if (!parseModuleDefinition(Args.getLastArg(OPT_d)->getValue(), Machine,
220
AddUnderscores, Exports, OutputFile))
221
return 1;
222
223
if (OutputFile.empty()) {
224
llvm::errs() << "no DLL name specified\n";
225
return 1;
226
}
227
228
if (Machine == IMAGE_FILE_MACHINE_I386 && Args.hasArg(OPT_k)) {
229
for (COFFShortExport &E : Exports) {
230
if (!E.ImportName.empty() || (!E.Name.empty() && E.Name[0] == '?'))
231
continue;
232
E.SymbolName = E.Name;
233
// Trim off the trailing decoration. Symbols will always have a
234
// starting prefix here (either _ for cdecl/stdcall, @ for fastcall
235
// or ? for C++ functions). Vectorcall functions won't have any
236
// fixed prefix, but the function base name will still be at least
237
// one char.
238
E.Name = E.Name.substr(0, E.Name.find('@', 1));
239
// By making sure E.SymbolName != E.Name for decorated symbols,
240
// writeImportLibrary writes these symbols with the type
241
// IMPORT_NAME_UNDECORATE.
242
}
243
}
244
245
std::string Path = std::string(Args.getLastArgValue(OPT_l));
246
if (!Path.empty() && writeImportLibrary(OutputFile, Path, Exports, Machine,
247
/*MinGW=*/true, NativeExports))
248
return 1;
249
return 0;
250
}
251
252