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