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