brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.1 KiB · 7b88576 Raw
447 lines · cpp
1//===-- llvm-ml.cpp - masm-compatible assembler -----------------*- C++ -*-===//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-exception6//7//===----------------------------------------------------------------------===//8//9// A simple driver around MasmParser; based on llvm-mc.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ADT/StringSwitch.h"14#include "llvm/MC/MCAsmBackend.h"15#include "llvm/MC/MCAsmInfo.h"16#include "llvm/MC/MCCodeEmitter.h"17#include "llvm/MC/MCContext.h"18#include "llvm/MC/MCInstPrinter.h"19#include "llvm/MC/MCInstrInfo.h"20#include "llvm/MC/MCObjectFileInfo.h"21#include "llvm/MC/MCObjectWriter.h"22#include "llvm/MC/MCParser/AsmLexer.h"23#include "llvm/MC/MCParser/MCTargetAsmParser.h"24#include "llvm/MC/MCRegisterInfo.h"25#include "llvm/MC/MCStreamer.h"26#include "llvm/MC/MCSubtargetInfo.h"27#include "llvm/MC/MCSymbol.h"28#include "llvm/MC/MCTargetOptionsCommandFlags.h"29#include "llvm/MC/TargetRegistry.h"30#include "llvm/Option/Arg.h"31#include "llvm/Option/ArgList.h"32#include "llvm/Option/Option.h"33#include "llvm/Support/Compression.h"34#include "llvm/Support/FileUtilities.h"35#include "llvm/Support/FormatVariadic.h"36#include "llvm/Support/FormattedStream.h"37#include "llvm/Support/LLVMDriver.h"38#include "llvm/Support/MemoryBuffer.h"39#include "llvm/Support/Path.h"40#include "llvm/Support/Process.h"41#include "llvm/Support/SourceMgr.h"42#include "llvm/Support/TargetSelect.h"43#include "llvm/Support/ToolOutputFile.h"44#include "llvm/Support/VirtualFileSystem.h"45#include "llvm/Support/WithColor.h"46#include "llvm/TargetParser/Host.h"47#include <ctime>48#include <optional>49 50using namespace llvm;51using namespace llvm::opt;52 53namespace {54 55enum ID {56  OPT_INVALID = 0, // This is not an option ID.57#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),58#include "Opts.inc"59#undef OPTION60};61 62#define OPTTABLE_STR_TABLE_CODE63#include "Opts.inc"64#undef OPTTABLE_STR_TABLE_CODE65 66#define OPTTABLE_PREFIXES_TABLE_CODE67#include "Opts.inc"68#undef OPTTABLE_PREFIXES_TABLE_CODE69 70static constexpr opt::OptTable::Info InfoTable[] = {71#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),72#include "Opts.inc"73#undef OPTION74};75 76class MLOptTable : public opt::GenericOptTable {77public:78  MLOptTable()79      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,80                             /*IgnoreCase=*/false) {}81};82} // namespace83 84static Triple GetTriple(StringRef ProgName, opt::InputArgList &Args) {85  // Figure out the target triple.86  StringRef DefaultBitness = "32";87  SmallString<255> Program = ProgName;88  sys::path::replace_extension(Program, "");89  if (Program.ends_with("ml64"))90    DefaultBitness = "64";91 92  StringRef TripleName =93      StringSwitch<StringRef>(Args.getLastArgValue(OPT_bitness, DefaultBitness))94          .Case("32", "i386-pc-windows")95          .Case("64", "x86_64-pc-windows")96          .Default("");97  return Triple(Triple::normalize(TripleName));98}99 100static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path) {101  std::error_code EC;102  auto Out = std::make_unique<ToolOutputFile>(Path, EC, sys::fs::OF_None);103  if (EC) {104    WithColor::error() << EC.message() << '\n';105    return nullptr;106  }107 108  return Out;109}110 111static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) {112  AsmLexer Lexer(MAI);113  Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer());114  Lexer.setLexMasmIntegers(true);115  Lexer.useMasmDefaultRadix(true);116  Lexer.setLexMasmHexFloats(true);117  Lexer.setLexMasmStrings(true);118 119  bool Error = false;120  while (Lexer.Lex().isNot(AsmToken::Eof)) {121    Lexer.getTok().dump(OS);122    OS << "\n";123    if (Lexer.getTok().getKind() == AsmToken::Error)124      Error = true;125  }126 127  return Error;128}129 130static int AssembleInput(StringRef ProgName, const Target *TheTarget,131                         SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,132                         MCAsmInfo &MAI, MCSubtargetInfo &STI,133                         MCInstrInfo &MCII, MCTargetOptions &MCOptions,134                         const opt::ArgList &InputArgs) {135  struct tm TM;136  time_t Timestamp;137  if (InputArgs.hasArg(OPT_timestamp)) {138    StringRef TimestampStr = InputArgs.getLastArgValue(OPT_timestamp);139    int64_t IntTimestamp;140    if (TimestampStr.getAsInteger(10, IntTimestamp)) {141      WithColor::error(errs(), ProgName)142          << "invalid timestamp '" << TimestampStr143          << "'; must be expressed in seconds since the UNIX epoch.\n";144      return 1;145    }146    Timestamp = IntTimestamp;147  } else {148    Timestamp = time(nullptr);149  }150  if (InputArgs.hasArg(OPT_utc)) {151    // Not thread-safe.152    TM = *gmtime(&Timestamp);153  } else {154    // Not thread-safe.155    TM = *localtime(&Timestamp);156  }157 158  std::unique_ptr<MCAsmParser> Parser(159      createMCMasmParser(SrcMgr, Ctx, Str, MAI, TM, 0));160  std::unique_ptr<MCTargetAsmParser> TAP(161      TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));162 163  if (!TAP) {164    WithColor::error(errs(), ProgName)165        << "this target does not support assembly parsing.\n";166    return 1;167  }168 169  Parser->setShowParsedOperands(InputArgs.hasArg(OPT_show_inst_operands));170  Parser->setTargetParser(*TAP);171  Parser->getLexer().setLexMasmIntegers(true);172  Parser->getLexer().useMasmDefaultRadix(true);173  Parser->getLexer().setLexMasmHexFloats(true);174  Parser->getLexer().setLexMasmStrings(true);175 176  auto Defines = InputArgs.getAllArgValues(OPT_define);177  for (StringRef Define : Defines) {178    const auto NameValue = Define.split('=');179    StringRef Name = NameValue.first, Value = NameValue.second;180    if (Parser->defineMacro(Name, Value)) {181      WithColor::error(errs(), ProgName)182          << "can't define macro '" << Name << "' = '" << Value << "'\n";183      return 1;184    }185  }186 187  int Res = Parser->Run(/*NoInitialTextSection=*/true);188 189  return Res;190}191 192int llvm_ml_main(int Argc, char **Argv, const llvm::ToolContext &) {193  StringRef ProgName = sys::path::filename(Argv[0]);194 195  // Initialize targets and assembly printers/parsers.196  llvm::InitializeAllTargetInfos();197  llvm::InitializeAllTargetMCs();198  llvm::InitializeAllAsmParsers();199  llvm::InitializeAllDisassemblers();200 201  MLOptTable T;202  unsigned MissingArgIndex, MissingArgCount;203  ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);204  opt::InputArgList InputArgs =205      T.ParseArgs(ArgsArr, MissingArgIndex, MissingArgCount);206 207  std::string InputFilename;208  for (auto *Arg : InputArgs.filtered(OPT_INPUT)) {209    std::string ArgString = Arg->getAsString(InputArgs);210    bool IsFile = false;211    std::error_code IsFileEC =212        llvm::sys::fs::is_regular_file(ArgString, IsFile);213    if (ArgString == "-" || IsFile) {214      if (!InputFilename.empty()) {215        WithColor::warning(errs(), ProgName)216            << "does not support multiple assembly files in one command; "217            << "ignoring '" << InputFilename << "'\n";218      }219      InputFilename = ArgString;220    } else {221      std::string Diag;222      raw_string_ostream OS(Diag);223      OS << ArgString << ": " << IsFileEC.message();224 225      std::string Nearest;226      if (T.findNearest(ArgString, Nearest) < 2)227        OS << ", did you mean '" << Nearest << "'?";228 229      WithColor::error(errs(), ProgName) << OS.str() << '\n';230      exit(1);231    }232  }233  for (auto *Arg : InputArgs.filtered(OPT_assembly_file)) {234    if (!InputFilename.empty()) {235      WithColor::warning(errs(), ProgName)236          << "does not support multiple assembly files in one command; "237          << "ignoring '" << InputFilename << "'\n";238    }239    InputFilename = Arg->getValue();240  }241 242  for (auto *Arg : InputArgs.filtered(OPT_unsupported_Group)) {243    WithColor::warning(errs(), ProgName)244        << "ignoring unsupported '" << Arg->getOption().getName()245        << "' option\n";246  }247 248  if (InputArgs.hasArg(OPT_debug)) {249    DebugFlag = true;250  }251  for (auto *Arg : InputArgs.filtered(OPT_debug_only)) {252    setCurrentDebugTypes(Arg->getValues().data(), Arg->getNumValues());253  }254 255  if (InputArgs.hasArg(OPT_help)) {256    std::string Usage = llvm::formatv("{0} [ /options ] file", ProgName).str();257    T.printHelp(outs(), Usage.c_str(), "LLVM MASM Assembler",258                /*ShowHidden=*/false);259    return 0;260  } else if (InputFilename.empty()) {261    outs() << "USAGE: " << ProgName << " [ /options ] file\n"262           << "Run \"" << ProgName << " /?\" or \"" << ProgName263           << " /help\" for more info.\n";264    return 0;265  }266 267  MCTargetOptions MCOptions;268  MCOptions.AssemblyLanguage = "masm";269  MCOptions.MCFatalWarnings = InputArgs.hasArg(OPT_fatal_warnings);270  MCOptions.MCSaveTempLabels = InputArgs.hasArg(OPT_save_temp_labels);271  MCOptions.ShowMCInst = InputArgs.hasArg(OPT_show_inst);272  MCOptions.AsmVerbose = true;273 274  Triple TheTriple = GetTriple(ProgName, InputArgs);275  std::string Error;276  const Target *TheTarget = TargetRegistry::lookupTarget("", TheTriple, Error);277  if (!TheTarget) {278    WithColor::error(errs(), ProgName) << Error;279    return 1;280  }281  bool SafeSEH = InputArgs.hasArg(OPT_safeseh);282  if (SafeSEH && !(TheTriple.isArch32Bit() && TheTriple.isX86())) {283    WithColor::warning()284        << "/safeseh applies only to 32-bit X86 platforms; ignoring.\n";285    SafeSEH = false;286  }287 288  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr =289      MemoryBuffer::getFileOrSTDIN(InputFilename);290  if (std::error_code EC = BufferPtr.getError()) {291    WithColor::error(errs(), ProgName)292        << InputFilename << ": " << EC.message() << '\n';293    return 1;294  }295 296  SourceMgr SrcMgr;297 298  // Tell SrcMgr about this buffer, which is what the parser will pick up.299  SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc());300 301  // Record the location of the include directories so that the lexer can find302  // included files later.303  std::vector<std::string> IncludeDirs =304      InputArgs.getAllArgValues(OPT_include_path);305  if (!InputArgs.hasArg(OPT_ignore_include_envvar)) {306    if (std::optional<std::string> IncludeEnvVar =307            llvm::sys::Process::GetEnv("INCLUDE")) {308      SmallVector<StringRef, 8> Dirs;309      StringRef(*IncludeEnvVar)310          .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);311      IncludeDirs.reserve(IncludeDirs.size() + Dirs.size());312      for (StringRef Dir : Dirs)313        IncludeDirs.push_back(Dir.str());314    }315  }316  SrcMgr.setIncludeDirs(IncludeDirs);317  SrcMgr.setVirtualFileSystem(vfs::getRealFileSystem());318 319  std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TheTriple));320  assert(MRI && "Unable to create target register info!");321 322  std::unique_ptr<MCAsmInfo> MAI(323      TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));324  assert(MAI && "Unable to create target asm info!");325 326  MAI->setPreserveAsmComments(InputArgs.hasArg(OPT_preserve_comments));327 328  std::unique_ptr<MCSubtargetInfo> STI(329      TheTarget->createMCSubtargetInfo(TheTriple, /*CPU=*/"", /*Features=*/""));330  if (!STI) {331    WithColor::error(errs(), ProgName) << "unable to create subtarget info\n";332    exit(1);333  }334 335  // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and336  // MCObjectFileInfo needs a MCContext reference in order to initialize itself.337  MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), &SrcMgr);338  std::unique_ptr<MCObjectFileInfo> MOFI(TheTarget->createMCObjectFileInfo(339      Ctx, /*PIC=*/false, /*LargeCodeModel=*/true));340  Ctx.setObjectFileInfo(MOFI.get());341 342  // Set compilation information.343  SmallString<128> CWD;344  if (!sys::fs::current_path(CWD))345    Ctx.setCompilationDir(CWD);346  Ctx.setMainFileName(InputFilename);347 348  StringRef FileType = InputArgs.getLastArgValue(OPT_filetype, "obj");349  SmallString<255> DefaultOutputFilename;350  if (InputArgs.hasArg(OPT_as_lex)) {351    DefaultOutputFilename = "-";352  } else {353    DefaultOutputFilename = InputFilename;354    sys::path::replace_extension(DefaultOutputFilename, FileType);355  }356  const StringRef OutputFilename =357      InputArgs.getLastArgValue(OPT_output_file, DefaultOutputFilename);358  std::unique_ptr<ToolOutputFile> Out = GetOutputStream(OutputFilename);359  if (!Out)360    return 1;361 362  std::unique_ptr<buffer_ostream> BOS;363  raw_pwrite_stream *OS = &Out->os();364  std::unique_ptr<MCStreamer> Str;365 366  std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());367  assert(MCII && "Unable to create instruction info!");368 369  if (FileType == "s") {370    const bool OutputATTAsm = InputArgs.hasArg(OPT_output_att_asm);371    const unsigned OutputAsmVariant = OutputATTAsm ? 0U   // ATT dialect372                                                   : 1U;  // Intel dialect373    std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(374        TheTriple, OutputAsmVariant, *MAI, *MCII, *MRI));375 376    if (!IP) {377      WithColor::error()378          << "unable to create instruction printer for target triple '"379          << TheTriple.normalize() << "' with "380          << (OutputATTAsm ? "ATT" : "Intel") << " assembly variant.\n";381      return 1;382    }383 384    // Set the display preference for hex vs. decimal immediates.385    IP->setPrintImmHex(InputArgs.hasArg(OPT_print_imm_hex));386 387    // Set up the AsmStreamer.388    std::unique_ptr<MCCodeEmitter> CE;389    if (InputArgs.hasArg(OPT_show_encoding))390      CE.reset(TheTarget->createMCCodeEmitter(*MCII, Ctx));391 392    std::unique_ptr<MCAsmBackend> MAB(393        TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));394    auto FOut = std::make_unique<formatted_raw_ostream>(*OS);395    Str.reset(TheTarget->createAsmStreamer(Ctx, std::move(FOut), std::move(IP),396                                           std::move(CE), std::move(MAB)));397 398  } else if (FileType == "null") {399    Str.reset(TheTarget->createNullStreamer(Ctx));400  } else if (FileType == "obj") {401    if (!Out->os().supportsSeeking()) {402      BOS = std::make_unique<buffer_ostream>(Out->os());403      OS = BOS.get();404    }405 406    MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, Ctx);407    MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions);408    Str.reset(TheTarget->createMCObjectStreamer(409        TheTriple, Ctx, std::unique_ptr<MCAsmBackend>(MAB),410        MAB->createObjectWriter(*OS), std::unique_ptr<MCCodeEmitter>(CE),411        *STI));412  } else {413    llvm_unreachable("Invalid file type!");414  }415 416  if (TheTriple.isOSBinFormatCOFF()) {417    // Emit an absolute @feat.00 symbol. This is a features bitfield read by418    // link.exe.419    int64_t Feat00Flags = 0x2;420    if (SafeSEH) {421      // According to the PE-COFF spec, the LSB of this value marks the object422      // for "registered SEH".  This means that all SEH handler entry points423      // must be registered in .sxdata.  Use of any unregistered handlers will424      // cause the process to terminate immediately.425      Feat00Flags |= 0x1;426    }427    MCSymbol *Feat00Sym = Ctx.getOrCreateSymbol("@feat.00");428    Feat00Sym->setRedefinable(true);429    Str->emitSymbolAttribute(Feat00Sym, MCSA_Global);430    Str->emitAssignment(Feat00Sym, MCConstantExpr::create(Feat00Flags, Ctx));431  }432 433  int Res = 1;434  if (InputArgs.hasArg(OPT_as_lex)) {435    // -as-lex; Lex only, and output a stream of tokens436    Res = AsLexInput(SrcMgr, *MAI, Out->os());437  } else {438    Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI,439                        *MCII, MCOptions, InputArgs);440  }441 442  // Keep output if no errors.443  if (Res == 0)444    Out->keep();445  return Res;446}447