DlltoolDriver.cpp 6.7 KB

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