1 //===- 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 
27 using namespace llvm;
28 using namespace llvm::object;
29 using namespace llvm::COFF;
30 
31 namespace {
32 
33 enum {
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 
44 static 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 
52 class DllOptTable : public llvm::opt::OptTable {
53 public:
54   DllOptTable() : OptTable(InfoTable, false) {}
55 };
56 
57 } // namespace
58 
59 // Opens a file. Path has to be resolved already.
60 static std::unique_ptr<MemoryBuffer> openFile(const Twine &Path) {
61   ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = MemoryBuffer::getFile(Path);
62 
63   if (std::error_code EC = MB.getError()) {
64     llvm::errs() << "cannot open file " << Path << ": " << EC.message() << "\n";
65     return nullptr;
66   }
67 
68   return std::move(*MB);
69 }
70 
71 static MachineTypes getEmulation(StringRef S) {
72   return StringSwitch<MachineTypes>(S)
73       .Case("i386", IMAGE_FILE_MACHINE_I386)
74       .Case("i386:x86-64", IMAGE_FILE_MACHINE_AMD64)
75       .Case("arm", IMAGE_FILE_MACHINE_ARMNT)
76       .Case("arm64", IMAGE_FILE_MACHINE_ARM64)
77       .Default(IMAGE_FILE_MACHINE_UNKNOWN);
78 }
79 
80 static std::string getImplibPath(StringRef Path) {
81   SmallString<128> Out = StringRef("lib");
82   Out.append(Path);
83   sys::path::replace_extension(Out, ".a");
84   return Out.str();
85 }
86 
87 int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
88   DllOptTable Table;
89   unsigned MissingIndex;
90   unsigned MissingCount;
91   llvm::opt::InputArgList Args =
92       Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
93   if (MissingCount) {
94     llvm::errs() << Args.getArgString(MissingIndex) << ": missing argument\n";
95     return 1;
96   }
97 
98   // Handle when no input or output is specified
99   if (Args.hasArgNoClaim(OPT_INPUT) ||
100       (!Args.hasArgNoClaim(OPT_d) && !Args.hasArgNoClaim(OPT_l))) {
101     Table.PrintHelp(outs(), ArgsArr[0], "dlltool", false);
102     llvm::outs() << "\nTARGETS: i386, i386:x86-64, arm, arm64\n";
103     return 1;
104   }
105 
106   if (!Args.hasArgNoClaim(OPT_m) && Args.hasArgNoClaim(OPT_d)) {
107     llvm::errs() << "error: no target machine specified\n"
108                  << "supported targets: i386, i386:x86-64, arm, arm64\n";
109     return 1;
110   }
111 
112   for (auto *Arg : Args.filtered(OPT_UNKNOWN))
113     llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
114 
115   if (!Args.hasArg(OPT_d)) {
116     llvm::errs() << "no definition file specified\n";
117     return 1;
118   }
119 
120   std::unique_ptr<MemoryBuffer> MB =
121       openFile(Args.getLastArg(OPT_d)->getValue());
122   if (!MB)
123     return 1;
124 
125   if (!MB->getBufferSize()) {
126     llvm::errs() << "definition file empty\n";
127     return 1;
128   }
129 
130   COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
131   if (auto *Arg = Args.getLastArg(OPT_m))
132     Machine = getEmulation(Arg->getValue());
133 
134   if (Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
135     llvm::errs() << "unknown target\n";
136     return 1;
137   }
138 
139   Expected<COFFModuleDefinition> Def =
140       parseCOFFModuleDefinition(*MB, Machine, true);
141 
142   if (!Def) {
143     llvm::errs() << "error parsing definition\n"
144                  << errorToErrorCode(Def.takeError()).message();
145     return 1;
146   }
147 
148   // Do this after the parser because parseCOFFModuleDefinition sets OutputFile.
149   if (auto *Arg = Args.getLastArg(OPT_D))
150     Def->OutputFile = Arg->getValue();
151 
152   if (Def->OutputFile.empty()) {
153     llvm::errs() << "no output file specified\n";
154     return 1;
155   }
156 
157   std::string Path = Args.getLastArgValue(OPT_l);
158   if (Path.empty())
159     Path = getImplibPath(Def->OutputFile);
160 
161   if (Machine == IMAGE_FILE_MACHINE_I386 && Args.getLastArg(OPT_k)) {
162     for (COFFShortExport& E : Def->Exports) {
163       if (E.isWeak() || (!E.Name.empty() && E.Name[0] == '?'))
164         continue;
165       E.SymbolName = E.Name;
166       // Trim off the trailing decoration. Symbols will always have a
167       // starting prefix here (either _ for cdecl/stdcall, @ for fastcall
168       // or ? for C++ functions). Vectorcall functions won't have any
169       // fixed prefix, but the function base name will still be at least
170       // one char.
171       E.Name = E.Name.substr(0, E.Name.find('@', 1));
172       // By making sure E.SymbolName != E.Name for decorated symbols,
173       // writeImportLibrary writes these symbols with the type
174       // IMPORT_NAME_UNDECORATE.
175     }
176   }
177 
178   if (writeImportLibrary(Def->OutputFile, Path, Def->Exports, Machine, true))
179     return 1;
180   return 0;
181 }
182