1 //===- DlltoolDriver.cpp - dlltool.exe-compatible driver ------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Defines an interface to a dlltool.exe-compatible driver.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
14 #include "llvm/Object/COFF.h"
15 #include "llvm/Object/COFFImportFile.h"
16 #include "llvm/Object/COFFModuleDefinition.h"
17 #include "llvm/Option/Arg.h"
18 #include "llvm/Option/ArgList.h"
19 #include "llvm/Option/Option.h"
20 #include "llvm/Support/Path.h"
25 using namespace llvm::object
;
26 using namespace llvm::COFF
;
32 #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
33 #include "Options.inc"
37 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
38 #include "Options.inc"
41 static const llvm::opt::OptTable::Info InfoTable
[] = {
42 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
43 {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \
44 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
45 #include "Options.inc"
49 class DllOptTable
: public llvm::opt::OptTable
{
51 DllOptTable() : OptTable(InfoTable
, false) {}
56 // Opens a file. Path has to be resolved already.
57 static std::unique_ptr
<MemoryBuffer
> openFile(const Twine
&Path
) {
58 ErrorOr
<std::unique_ptr
<llvm::MemoryBuffer
>> MB
= MemoryBuffer::getFile(Path
);
60 if (std::error_code EC
= MB
.getError()) {
61 llvm::errs() << "cannot open file " << Path
<< ": " << EC
.message() << "\n";
65 return std::move(*MB
);
68 static MachineTypes
getEmulation(StringRef S
) {
69 return StringSwitch
<MachineTypes
>(S
)
70 .Case("i386", IMAGE_FILE_MACHINE_I386
)
71 .Case("i386:x86-64", IMAGE_FILE_MACHINE_AMD64
)
72 .Case("arm", IMAGE_FILE_MACHINE_ARMNT
)
73 .Case("arm64", IMAGE_FILE_MACHINE_ARM64
)
74 .Default(IMAGE_FILE_MACHINE_UNKNOWN
);
77 int llvm::dlltoolDriverMain(llvm::ArrayRef
<const char *> ArgsArr
) {
79 unsigned MissingIndex
;
80 unsigned MissingCount
;
81 llvm::opt::InputArgList Args
=
82 Table
.ParseArgs(ArgsArr
.slice(1), MissingIndex
, MissingCount
);
84 llvm::errs() << Args
.getArgString(MissingIndex
) << ": missing argument\n";
88 // Handle when no input or output is specified
89 if (Args
.hasArgNoClaim(OPT_INPUT
) ||
90 (!Args
.hasArgNoClaim(OPT_d
) && !Args
.hasArgNoClaim(OPT_l
))) {
91 Table
.PrintHelp(outs(), "llvm-dlltool [options] file...", "llvm-dlltool",
93 llvm::outs() << "\nTARGETS: i386, i386:x86-64, arm, arm64\n";
97 if (!Args
.hasArgNoClaim(OPT_m
) && Args
.hasArgNoClaim(OPT_d
)) {
98 llvm::errs() << "error: no target machine specified\n"
99 << "supported targets: i386, i386:x86-64, arm, arm64\n";
103 for (auto *Arg
: Args
.filtered(OPT_UNKNOWN
))
104 llvm::errs() << "ignoring unknown argument: " << Arg
->getAsString(Args
)
107 if (!Args
.hasArg(OPT_d
)) {
108 llvm::errs() << "no definition file specified\n";
112 std::unique_ptr
<MemoryBuffer
> MB
=
113 openFile(Args
.getLastArg(OPT_d
)->getValue());
117 if (!MB
->getBufferSize()) {
118 llvm::errs() << "definition file empty\n";
122 COFF::MachineTypes Machine
= IMAGE_FILE_MACHINE_UNKNOWN
;
123 if (auto *Arg
= Args
.getLastArg(OPT_m
))
124 Machine
= getEmulation(Arg
->getValue());
126 if (Machine
== IMAGE_FILE_MACHINE_UNKNOWN
) {
127 llvm::errs() << "unknown target\n";
131 Expected
<COFFModuleDefinition
> Def
=
132 parseCOFFModuleDefinition(*MB
, Machine
, true);
135 llvm::errs() << "error parsing definition\n"
136 << errorToErrorCode(Def
.takeError()).message();
140 // Do this after the parser because parseCOFFModuleDefinition sets OutputFile.
141 if (auto *Arg
= Args
.getLastArg(OPT_D
))
142 Def
->OutputFile
= Arg
->getValue();
144 if (Def
->OutputFile
.empty()) {
145 llvm::errs() << "no DLL name specified\n";
149 std::string Path
= Args
.getLastArgValue(OPT_l
);
151 // If ExtName is set (if the "ExtName = Name" syntax was used), overwrite
152 // Name with ExtName and clear ExtName. When only creating an import
153 // library and not linking, the internal name is irrelevant. This avoids
154 // cases where writeImportLibrary tries to transplant decoration from
155 // symbol decoration onto ExtName.
156 for (COFFShortExport
& E
: Def
->Exports
) {
157 if (!E
.ExtName
.empty()) {
163 if (Machine
== IMAGE_FILE_MACHINE_I386
&& Args
.getLastArg(OPT_k
)) {
164 for (COFFShortExport
& E
: Def
->Exports
) {
165 if (!E
.AliasTarget
.empty() || (!E
.Name
.empty() && E
.Name
[0] == '?'))
167 E
.SymbolName
= E
.Name
;
168 // Trim off the trailing decoration. Symbols will always have a
169 // starting prefix here (either _ for cdecl/stdcall, @ for fastcall
170 // or ? for C++ functions). Vectorcall functions won't have any
171 // fixed prefix, but the function base name will still be at least
173 E
.Name
= E
.Name
.substr(0, E
.Name
.find('@', 1));
174 // By making sure E.SymbolName != E.Name for decorated symbols,
175 // writeImportLibrary writes these symbols with the type
176 // IMPORT_NAME_UNDECORATE.
181 writeImportLibrary(Def
->OutputFile
, Path
, Def
->Exports
, Machine
, true))