10b57cec5SDimitry Andric //===- DlltoolDriver.cpp - dlltool.exe-compatible driver ------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Defines an interface to a dlltool.exe-compatible driver. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" 14*fe6060f1SDimitry Andric #include "llvm/ADT/Optional.h" 150b57cec5SDimitry Andric #include "llvm/Object/COFF.h" 160b57cec5SDimitry Andric #include "llvm/Object/COFFImportFile.h" 170b57cec5SDimitry Andric #include "llvm/Object/COFFModuleDefinition.h" 180b57cec5SDimitry Andric #include "llvm/Option/Arg.h" 190b57cec5SDimitry Andric #include "llvm/Option/ArgList.h" 200b57cec5SDimitry Andric #include "llvm/Option/Option.h" 21*fe6060f1SDimitry Andric #include "llvm/Support/Host.h" 220b57cec5SDimitry Andric #include "llvm/Support/Path.h" 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric #include <vector> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric using namespace llvm::object; 280b57cec5SDimitry Andric using namespace llvm::COFF; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric namespace { 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric enum { 330b57cec5SDimitry Andric OPT_INVALID = 0, 340b57cec5SDimitry Andric #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, 350b57cec5SDimitry Andric #include "Options.inc" 360b57cec5SDimitry Andric #undef OPTION 370b57cec5SDimitry Andric }; 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 400b57cec5SDimitry Andric #include "Options.inc" 410b57cec5SDimitry Andric #undef PREFIX 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric static const llvm::opt::OptTable::Info InfoTable[] = { 440b57cec5SDimitry Andric #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ 450b57cec5SDimitry Andric {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ 460b57cec5SDimitry Andric X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, 470b57cec5SDimitry Andric #include "Options.inc" 480b57cec5SDimitry Andric #undef OPTION 490b57cec5SDimitry Andric }; 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric class DllOptTable : public llvm::opt::OptTable { 520b57cec5SDimitry Andric public: 530b57cec5SDimitry Andric DllOptTable() : OptTable(InfoTable, false) {} 540b57cec5SDimitry Andric }; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric // Opens a file. Path has to be resolved already. 57*fe6060f1SDimitry Andric std::unique_ptr<MemoryBuffer> openFile(const Twine &Path) { 580b57cec5SDimitry Andric ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = MemoryBuffer::getFile(Path); 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric if (std::error_code EC = MB.getError()) { 610b57cec5SDimitry Andric llvm::errs() << "cannot open file " << Path << ": " << EC.message() << "\n"; 620b57cec5SDimitry Andric return nullptr; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric return std::move(*MB); 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 68*fe6060f1SDimitry Andric MachineTypes getEmulation(StringRef S) { 690b57cec5SDimitry Andric return StringSwitch<MachineTypes>(S) 700b57cec5SDimitry Andric .Case("i386", IMAGE_FILE_MACHINE_I386) 710b57cec5SDimitry Andric .Case("i386:x86-64", IMAGE_FILE_MACHINE_AMD64) 720b57cec5SDimitry Andric .Case("arm", IMAGE_FILE_MACHINE_ARMNT) 730b57cec5SDimitry Andric .Case("arm64", IMAGE_FILE_MACHINE_ARM64) 740b57cec5SDimitry Andric .Default(IMAGE_FILE_MACHINE_UNKNOWN); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 77*fe6060f1SDimitry Andric MachineTypes getMachine(Triple T) { 78*fe6060f1SDimitry Andric switch (T.getArch()) { 79*fe6060f1SDimitry Andric case Triple::x86: 80*fe6060f1SDimitry Andric return COFF::IMAGE_FILE_MACHINE_I386; 81*fe6060f1SDimitry Andric case Triple::x86_64: 82*fe6060f1SDimitry Andric return COFF::IMAGE_FILE_MACHINE_AMD64; 83*fe6060f1SDimitry Andric case Triple::arm: 84*fe6060f1SDimitry Andric return COFF::IMAGE_FILE_MACHINE_ARMNT; 85*fe6060f1SDimitry Andric case Triple::aarch64: 86*fe6060f1SDimitry Andric return COFF::IMAGE_FILE_MACHINE_ARM64; 87*fe6060f1SDimitry Andric default: 88*fe6060f1SDimitry Andric return COFF::IMAGE_FILE_MACHINE_UNKNOWN; 89*fe6060f1SDimitry Andric } 90*fe6060f1SDimitry Andric } 91*fe6060f1SDimitry Andric 92*fe6060f1SDimitry Andric MachineTypes getDefaultMachine() { 93*fe6060f1SDimitry Andric return getMachine(Triple(sys::getDefaultTargetTriple())); 94*fe6060f1SDimitry Andric } 95*fe6060f1SDimitry Andric 96*fe6060f1SDimitry Andric Optional<std::string> getPrefix(StringRef Argv0) { 97*fe6060f1SDimitry Andric StringRef ProgName = llvm::sys::path::stem(Argv0); 98*fe6060f1SDimitry Andric // x86_64-w64-mingw32-dlltool -> x86_64-w64-mingw32 99*fe6060f1SDimitry Andric // llvm-dlltool -> None 100*fe6060f1SDimitry Andric // aarch64-w64-mingw32-llvm-dlltool-10.exe -> aarch64-w64-mingw32 101*fe6060f1SDimitry Andric ProgName = ProgName.rtrim("0123456789.-"); 102*fe6060f1SDimitry Andric if (!ProgName.consume_back_insensitive("dlltool")) 103*fe6060f1SDimitry Andric return None; 104*fe6060f1SDimitry Andric ProgName.consume_back_insensitive("llvm-"); 105*fe6060f1SDimitry Andric ProgName.consume_back_insensitive("-"); 106*fe6060f1SDimitry Andric return ProgName.str(); 107*fe6060f1SDimitry Andric } 108*fe6060f1SDimitry Andric 109*fe6060f1SDimitry Andric } // namespace 110*fe6060f1SDimitry Andric 1110b57cec5SDimitry Andric int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) { 1120b57cec5SDimitry Andric DllOptTable Table; 1130b57cec5SDimitry Andric unsigned MissingIndex; 1140b57cec5SDimitry Andric unsigned MissingCount; 1150b57cec5SDimitry Andric llvm::opt::InputArgList Args = 1160b57cec5SDimitry Andric Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount); 1170b57cec5SDimitry Andric if (MissingCount) { 1180b57cec5SDimitry Andric llvm::errs() << Args.getArgString(MissingIndex) << ": missing argument\n"; 1190b57cec5SDimitry Andric return 1; 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric // Handle when no input or output is specified 1230b57cec5SDimitry Andric if (Args.hasArgNoClaim(OPT_INPUT) || 1240b57cec5SDimitry Andric (!Args.hasArgNoClaim(OPT_d) && !Args.hasArgNoClaim(OPT_l))) { 125*fe6060f1SDimitry Andric Table.printHelp(outs(), "llvm-dlltool [options] file...", "llvm-dlltool", 1260b57cec5SDimitry Andric false); 1270b57cec5SDimitry Andric llvm::outs() << "\nTARGETS: i386, i386:x86-64, arm, arm64\n"; 1280b57cec5SDimitry Andric return 1; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric for (auto *Arg : Args.filtered(OPT_UNKNOWN)) 1320b57cec5SDimitry Andric llvm::errs() << "ignoring unknown argument: " << Arg->getAsString(Args) 1330b57cec5SDimitry Andric << "\n"; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric if (!Args.hasArg(OPT_d)) { 1360b57cec5SDimitry Andric llvm::errs() << "no definition file specified\n"; 1370b57cec5SDimitry Andric return 1; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> MB = 1410b57cec5SDimitry Andric openFile(Args.getLastArg(OPT_d)->getValue()); 1420b57cec5SDimitry Andric if (!MB) 1430b57cec5SDimitry Andric return 1; 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric if (!MB->getBufferSize()) { 1460b57cec5SDimitry Andric llvm::errs() << "definition file empty\n"; 1470b57cec5SDimitry Andric return 1; 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric 150*fe6060f1SDimitry Andric COFF::MachineTypes Machine = getDefaultMachine(); 151*fe6060f1SDimitry Andric if (Optional<std::string> Prefix = getPrefix(ArgsArr[0])) { 152*fe6060f1SDimitry Andric Triple T(*Prefix); 153*fe6060f1SDimitry Andric if (T.getArch() != Triple::UnknownArch) 154*fe6060f1SDimitry Andric Machine = getMachine(T); 155*fe6060f1SDimitry Andric } 1560b57cec5SDimitry Andric if (auto *Arg = Args.getLastArg(OPT_m)) 1570b57cec5SDimitry Andric Machine = getEmulation(Arg->getValue()); 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric if (Machine == IMAGE_FILE_MACHINE_UNKNOWN) { 1600b57cec5SDimitry Andric llvm::errs() << "unknown target\n"; 1610b57cec5SDimitry Andric return 1; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric Expected<COFFModuleDefinition> Def = 1650b57cec5SDimitry Andric parseCOFFModuleDefinition(*MB, Machine, true); 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric if (!Def) { 1680b57cec5SDimitry Andric llvm::errs() << "error parsing definition\n" 1690b57cec5SDimitry Andric << errorToErrorCode(Def.takeError()).message(); 1700b57cec5SDimitry Andric return 1; 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric // Do this after the parser because parseCOFFModuleDefinition sets OutputFile. 1740b57cec5SDimitry Andric if (auto *Arg = Args.getLastArg(OPT_D)) 1750b57cec5SDimitry Andric Def->OutputFile = Arg->getValue(); 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric if (Def->OutputFile.empty()) { 1788bcb0991SDimitry Andric llvm::errs() << "no DLL name specified\n"; 1790b57cec5SDimitry Andric return 1; 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1825ffd83dbSDimitry Andric std::string Path = std::string(Args.getLastArgValue(OPT_l)); 1838bcb0991SDimitry Andric 1848bcb0991SDimitry Andric // If ExtName is set (if the "ExtName = Name" syntax was used), overwrite 1858bcb0991SDimitry Andric // Name with ExtName and clear ExtName. When only creating an import 1868bcb0991SDimitry Andric // library and not linking, the internal name is irrelevant. This avoids 1878bcb0991SDimitry Andric // cases where writeImportLibrary tries to transplant decoration from 1888bcb0991SDimitry Andric // symbol decoration onto ExtName. 1898bcb0991SDimitry Andric for (COFFShortExport& E : Def->Exports) { 1908bcb0991SDimitry Andric if (!E.ExtName.empty()) { 1918bcb0991SDimitry Andric E.Name = E.ExtName; 1928bcb0991SDimitry Andric E.ExtName.clear(); 1938bcb0991SDimitry Andric } 1948bcb0991SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric if (Machine == IMAGE_FILE_MACHINE_I386 && Args.getLastArg(OPT_k)) { 1970b57cec5SDimitry Andric for (COFFShortExport& E : Def->Exports) { 1980b57cec5SDimitry Andric if (!E.AliasTarget.empty() || (!E.Name.empty() && E.Name[0] == '?')) 1990b57cec5SDimitry Andric continue; 2000b57cec5SDimitry Andric E.SymbolName = E.Name; 2010b57cec5SDimitry Andric // Trim off the trailing decoration. Symbols will always have a 2020b57cec5SDimitry Andric // starting prefix here (either _ for cdecl/stdcall, @ for fastcall 2030b57cec5SDimitry Andric // or ? for C++ functions). Vectorcall functions won't have any 2040b57cec5SDimitry Andric // fixed prefix, but the function base name will still be at least 2050b57cec5SDimitry Andric // one char. 2060b57cec5SDimitry Andric E.Name = E.Name.substr(0, E.Name.find('@', 1)); 2070b57cec5SDimitry Andric // By making sure E.SymbolName != E.Name for decorated symbols, 2080b57cec5SDimitry Andric // writeImportLibrary writes these symbols with the type 2090b57cec5SDimitry Andric // IMPORT_NAME_UNDECORATE. 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2138bcb0991SDimitry Andric if (!Path.empty() && 2148bcb0991SDimitry Andric writeImportLibrary(Def->OutputFile, Path, Def->Exports, Machine, true)) 2150b57cec5SDimitry Andric return 1; 2160b57cec5SDimitry Andric return 0; 2170b57cec5SDimitry Andric } 218