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