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