DlltoolDriver.cpp 7.0 KB

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