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/Optional.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/Option.h" 21 #include "llvm/Support/Host.h" 22 #include "llvm/Support/Path.h" 23 24 #include <vector> 25 26 using namespace llvm; 27 using namespace llvm::object; 28 using namespace llvm::COFF; 29 30 namespace { 31 32 enum { 33 OPT_INVALID = 0, 34 #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, 35 #include "Options.inc" 36 #undef OPTION 37 }; 38 39 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 40 #include "Options.inc" 41 #undef PREFIX 42 43 static const llvm::opt::OptTable::Info InfoTable[] = { 44 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ 45 {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ 46 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, 47 #include "Options.inc" 48 #undef OPTION 49 }; 50 51 class DllOptTable : public llvm::opt::OptTable { 52 public: 53 DllOptTable() : OptTable(InfoTable, false) {} 54 }; 55 56 // Opens a file. Path has to be resolved already. 57 std::unique_ptr<MemoryBuffer> openFile(const Twine &Path) { 58 ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = MemoryBuffer::getFile(Path); 59 60 if (std::error_code EC = MB.getError()) { 61 llvm::errs() << "cannot open file " << Path << ": " << EC.message() << "\n"; 62 return nullptr; 63 } 64 65 return std::move(*MB); 66 } 67 68 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); 75 } 76 77 MachineTypes getMachine(Triple T) { 78 switch (T.getArch()) { 79 case Triple::x86: 80 return COFF::IMAGE_FILE_MACHINE_I386; 81 case Triple::x86_64: 82 return COFF::IMAGE_FILE_MACHINE_AMD64; 83 case Triple::arm: 84 return COFF::IMAGE_FILE_MACHINE_ARMNT; 85 case Triple::aarch64: 86 return COFF::IMAGE_FILE_MACHINE_ARM64; 87 default: 88 return COFF::IMAGE_FILE_MACHINE_UNKNOWN; 89 } 90 } 91 92 MachineTypes getDefaultMachine() { 93 return getMachine(Triple(sys::getDefaultTargetTriple())); 94 } 95 96 Optional<std::string> getPrefix(StringRef Argv0) { 97 StringRef ProgName = llvm::sys::path::stem(Argv0); 98 // x86_64-w64-mingw32-dlltool -> x86_64-w64-mingw32 99 // llvm-dlltool -> None 100 // aarch64-w64-mingw32-llvm-dlltool-10.exe -> aarch64-w64-mingw32 101 ProgName = ProgName.rtrim("0123456789.-"); 102 if (!ProgName.consume_back_insensitive("dlltool")) 103 return None; 104 ProgName.consume_back_insensitive("llvm-"); 105 ProgName.consume_back_insensitive("-"); 106 return ProgName.str(); 107 } 108 109 } // namespace 110 111 int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) { 112 DllOptTable Table; 113 unsigned MissingIndex; 114 unsigned MissingCount; 115 llvm::opt::InputArgList Args = 116 Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount); 117 if (MissingCount) { 118 llvm::errs() << Args.getArgString(MissingIndex) << ": missing argument\n"; 119 return 1; 120 } 121 122 // Handle when no input or output is specified 123 if (Args.hasArgNoClaim(OPT_INPUT) || 124 (!Args.hasArgNoClaim(OPT_d) && !Args.hasArgNoClaim(OPT_l))) { 125 Table.printHelp(outs(), "llvm-dlltool [options] file...", "llvm-dlltool", 126 false); 127 llvm::outs() << "\nTARGETS: i386, i386:x86-64, arm, arm64\n"; 128 return 1; 129 } 130 131 for (auto *Arg : Args.filtered(OPT_UNKNOWN)) 132 llvm::errs() << "ignoring unknown argument: " << Arg->getAsString(Args) 133 << "\n"; 134 135 if (!Args.hasArg(OPT_d)) { 136 llvm::errs() << "no definition file specified\n"; 137 return 1; 138 } 139 140 std::unique_ptr<MemoryBuffer> MB = 141 openFile(Args.getLastArg(OPT_d)->getValue()); 142 if (!MB) 143 return 1; 144 145 if (!MB->getBufferSize()) { 146 llvm::errs() << "definition file empty\n"; 147 return 1; 148 } 149 150 COFF::MachineTypes Machine = getDefaultMachine(); 151 if (Optional<std::string> Prefix = getPrefix(ArgsArr[0])) { 152 Triple T(*Prefix); 153 if (T.getArch() != Triple::UnknownArch) 154 Machine = getMachine(T); 155 } 156 if (auto *Arg = Args.getLastArg(OPT_m)) 157 Machine = getEmulation(Arg->getValue()); 158 159 if (Machine == IMAGE_FILE_MACHINE_UNKNOWN) { 160 llvm::errs() << "unknown target\n"; 161 return 1; 162 } 163 164 Expected<COFFModuleDefinition> Def = 165 parseCOFFModuleDefinition(*MB, Machine, true); 166 167 if (!Def) { 168 llvm::errs() << "error parsing definition\n" 169 << errorToErrorCode(Def.takeError()).message(); 170 return 1; 171 } 172 173 // Do this after the parser because parseCOFFModuleDefinition sets OutputFile. 174 if (auto *Arg = Args.getLastArg(OPT_D)) 175 Def->OutputFile = Arg->getValue(); 176 177 if (Def->OutputFile.empty()) { 178 llvm::errs() << "no DLL name specified\n"; 179 return 1; 180 } 181 182 std::string Path = std::string(Args.getLastArgValue(OPT_l)); 183 184 // If ExtName is set (if the "ExtName = Name" syntax was used), overwrite 185 // Name with ExtName and clear ExtName. When only creating an import 186 // library and not linking, the internal name is irrelevant. This avoids 187 // cases where writeImportLibrary tries to transplant decoration from 188 // symbol decoration onto ExtName. 189 for (COFFShortExport& E : Def->Exports) { 190 if (!E.ExtName.empty()) { 191 E.Name = E.ExtName; 192 E.ExtName.clear(); 193 } 194 } 195 196 if (Machine == IMAGE_FILE_MACHINE_I386 && Args.getLastArg(OPT_k)) { 197 for (COFFShortExport& E : Def->Exports) { 198 if (!E.AliasTarget.empty() || (!E.Name.empty() && E.Name[0] == '?')) 199 continue; 200 E.SymbolName = E.Name; 201 // Trim off the trailing decoration. Symbols will always have a 202 // starting prefix here (either _ for cdecl/stdcall, @ for fastcall 203 // or ? for C++ functions). Vectorcall functions won't have any 204 // fixed prefix, but the function base name will still be at least 205 // one char. 206 E.Name = E.Name.substr(0, E.Name.find('@', 1)); 207 // By making sure E.SymbolName != E.Name for decorated symbols, 208 // writeImportLibrary writes these symbols with the type 209 // IMPORT_NAME_UNDECORATE. 210 } 211 } 212 213 if (!Path.empty() && 214 writeImportLibrary(Def->OutputFile, Path, Def->Exports, Machine, true)) 215 return 1; 216 return 0; 217 } 218