cc1as.cpp raw

   1  //go:build byollvm
   2  
   3  // Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
   4  // This file needs to be updated each LLVM release.
   5  // There are a few small modifications to make, like:
   6  //   * ExecuteAssembler is made non-static.
   7  //   * The struct AssemblerImplementation is moved to cc1as.h so it can be
   8  //     included elsewhere.
   9  
  10  //===-- cc1as.cpp - Clang Assembler  --------------------------------------===//
  11  //
  12  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  13  // See https://llvm.org/LICENSE.txt for license information.
  14  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  15  //
  16  //===----------------------------------------------------------------------===//
  17  //
  18  // This is the entry point to the clang -cc1as functionality, which implements
  19  // the direct interface to the LLVM MC based assembler.
  20  //
  21  //===----------------------------------------------------------------------===//
  22  
  23  #include "clang/Basic/Diagnostic.h"
  24  #include "clang/Basic/DiagnosticOptions.h"
  25  #include "clang/Driver/DriverDiagnostic.h"
  26  #include "clang/Driver/Options.h"
  27  #include "clang/Frontend/FrontendDiagnostic.h"
  28  #include "clang/Frontend/TextDiagnosticPrinter.h"
  29  #include "clang/Frontend/Utils.h"
  30  #include "llvm/ADT/STLExtras.h"
  31  #include "llvm/ADT/StringExtras.h"
  32  #include "llvm/ADT/StringSwitch.h"
  33  #include "llvm/IR/DataLayout.h"
  34  #include "llvm/MC/MCAsmBackend.h"
  35  #include "llvm/MC/MCAsmInfo.h"
  36  #include "llvm/MC/MCCodeEmitter.h"
  37  #include "llvm/MC/MCContext.h"
  38  #include "llvm/MC/MCInstrInfo.h"
  39  #include "llvm/MC/MCObjectFileInfo.h"
  40  #include "llvm/MC/MCObjectWriter.h"
  41  #include "llvm/MC/MCParser/MCAsmParser.h"
  42  #include "llvm/MC/MCParser/MCTargetAsmParser.h"
  43  #include "llvm/MC/MCRegisterInfo.h"
  44  #include "llvm/MC/MCSectionMachO.h"
  45  #include "llvm/MC/MCStreamer.h"
  46  #include "llvm/MC/MCSubtargetInfo.h"
  47  #include "llvm/MC/MCTargetOptions.h"
  48  #include "llvm/MC/TargetRegistry.h"
  49  #include "llvm/Option/Arg.h"
  50  #include "llvm/Option/ArgList.h"
  51  #include "llvm/Option/OptTable.h"
  52  #include "llvm/Support/CommandLine.h"
  53  #include "llvm/Support/ErrorHandling.h"
  54  #include "llvm/Support/FileSystem.h"
  55  #include "llvm/Support/FormattedStream.h"
  56  #include "llvm/Support/MemoryBuffer.h"
  57  #include "llvm/Support/Path.h"
  58  #include "llvm/Support/Process.h"
  59  #include "llvm/Support/Signals.h"
  60  #include "llvm/Support/SourceMgr.h"
  61  #include "llvm/Support/TargetSelect.h"
  62  #include "llvm/Support/Timer.h"
  63  #include "llvm/Support/raw_ostream.h"
  64  #include "llvm/TargetParser/Host.h"
  65  #include "llvm/TargetParser/Triple.h"
  66  #include <memory>
  67  #include <optional>
  68  #include <system_error>
  69  using namespace clang;
  70  using namespace clang::driver;
  71  using namespace clang::driver::options;
  72  using namespace llvm;
  73  using namespace llvm::opt;
  74  
  75  #include "cc1as.h"
  76  
  77  bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
  78                                           ArrayRef<const char *> Argv,
  79                                           DiagnosticsEngine &Diags) {
  80    bool Success = true;
  81  
  82    // Parse the arguments.
  83    const OptTable &OptTbl = getDriverOptTable();
  84  
  85    llvm::opt::Visibility VisibilityMask(options::CC1AsOption);
  86    unsigned MissingArgIndex, MissingArgCount;
  87    InputArgList Args =
  88        OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount, VisibilityMask);
  89  
  90    // Check for missing argument error.
  91    if (MissingArgCount) {
  92      Diags.Report(diag::err_drv_missing_argument)
  93          << Args.getArgString(MissingArgIndex) << MissingArgCount;
  94      Success = false;
  95    }
  96  
  97    // Issue errors on unknown arguments.
  98    for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
  99      auto ArgString = A->getAsString(Args);
 100      std::string Nearest;
 101      if (OptTbl.findNearest(ArgString, Nearest, VisibilityMask) > 1)
 102        Diags.Report(diag::err_drv_unknown_argument) << ArgString;
 103      else
 104        Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
 105            << ArgString << Nearest;
 106      Success = false;
 107    }
 108  
 109    // Construct the invocation.
 110  
 111    // Target Options
 112    Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
 113    if (Arg *A = Args.getLastArg(options::OPT_darwin_target_variant_triple))
 114      Opts.DarwinTargetVariantTriple = llvm::Triple(A->getValue());
 115    if (Arg *A = Args.getLastArg(OPT_darwin_target_variant_sdk_version_EQ)) {
 116      VersionTuple Version;
 117      if (Version.tryParse(A->getValue()))
 118        Diags.Report(diag::err_drv_invalid_value)
 119            << A->getAsString(Args) << A->getValue();
 120      else
 121        Opts.DarwinTargetVariantSDKVersion = Version;
 122    }
 123  
 124    Opts.CPU = std::string(Args.getLastArgValue(OPT_target_cpu));
 125    Opts.Features = Args.getAllArgValues(OPT_target_feature);
 126  
 127    // Use the default target triple if unspecified.
 128    if (Opts.Triple.empty())
 129      Opts.Triple = llvm::sys::getDefaultTargetTriple();
 130  
 131    // Language Options
 132    Opts.IncludePaths = Args.getAllArgValues(OPT_I);
 133    Opts.NoInitialTextSection = Args.hasArg(OPT_n);
 134    Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
 135    // Any DebugInfoKind implies GenDwarfForAssembly.
 136    Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
 137  
 138    if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections_EQ)) {
 139      Opts.CompressDebugSections =
 140          llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
 141              .Case("none", llvm::DebugCompressionType::None)
 142              .Case("zlib", llvm::DebugCompressionType::Zlib)
 143              .Case("zstd", llvm::DebugCompressionType::Zstd)
 144              .Default(llvm::DebugCompressionType::None);
 145    }
 146  
 147    if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
 148      Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
 149    Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
 150    Opts.DwarfDebugFlags =
 151        std::string(Args.getLastArgValue(OPT_dwarf_debug_flags));
 152    Opts.DwarfDebugProducer =
 153        std::string(Args.getLastArgValue(OPT_dwarf_debug_producer));
 154    if (const Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ,
 155                                       options::OPT_fdebug_compilation_dir_EQ))
 156      Opts.DebugCompilationDir = A->getValue();
 157    Opts.MainFileName = std::string(Args.getLastArgValue(OPT_main_file_name));
 158  
 159    for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
 160      auto Split = StringRef(Arg).split('=');
 161      Opts.DebugPrefixMap.emplace_back(Split.first, Split.second);
 162    }
 163  
 164    // Frontend Options
 165    if (Args.hasArg(OPT_INPUT)) {
 166      bool First = true;
 167      for (const Arg *A : Args.filtered(OPT_INPUT)) {
 168        if (First) {
 169          Opts.InputFile = A->getValue();
 170          First = false;
 171        } else {
 172          Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
 173          Success = false;
 174        }
 175      }
 176    }
 177    Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
 178    Opts.OutputPath = std::string(Args.getLastArgValue(OPT_o));
 179    Opts.SplitDwarfOutput =
 180        std::string(Args.getLastArgValue(OPT_split_dwarf_output));
 181    if (Arg *A = Args.getLastArg(OPT_filetype)) {
 182      StringRef Name = A->getValue();
 183      unsigned OutputType = StringSwitch<unsigned>(Name)
 184        .Case("asm", FT_Asm)
 185        .Case("null", FT_Null)
 186        .Case("obj", FT_Obj)
 187        .Default(~0U);
 188      if (OutputType == ~0U) {
 189        Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
 190        Success = false;
 191      } else
 192        Opts.OutputType = FileType(OutputType);
 193    }
 194    Opts.ShowHelp = Args.hasArg(OPT_help);
 195    Opts.ShowVersion = Args.hasArg(OPT_version);
 196  
 197    // Transliterate Options
 198    Opts.OutputAsmVariant =
 199        getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags);
 200    Opts.ShowEncoding = Args.hasArg(OPT_show_encoding);
 201    Opts.ShowInst = Args.hasArg(OPT_show_inst);
 202  
 203    // Assemble Options
 204    Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
 205    Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
 206    Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
 207    Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
 208    Opts.NoTypeCheck = Args.hasArg(OPT_mno_type_check);
 209    Opts.RelocationModel =
 210        std::string(Args.getLastArgValue(OPT_mrelocation_model, "pic"));
 211    Opts.TargetABI = std::string(Args.getLastArgValue(OPT_target_abi));
 212    Opts.IncrementalLinkerCompatible =
 213        Args.hasArg(OPT_mincremental_linker_compatible);
 214    Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym);
 215  
 216    // EmbedBitcode Option. If -fembed-bitcode is enabled, set the flag.
 217    // EmbedBitcode behaves the same for all embed options for assembly files.
 218    if (auto *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) {
 219      Opts.EmbedBitcode = llvm::StringSwitch<unsigned>(A->getValue())
 220                              .Case("all", 1)
 221                              .Case("bitcode", 1)
 222                              .Case("marker", 1)
 223                              .Default(0);
 224    }
 225  
 226    if (auto *A = Args.getLastArg(OPT_femit_dwarf_unwind_EQ)) {
 227      Opts.EmitDwarfUnwind =
 228          llvm::StringSwitch<EmitDwarfUnwindType>(A->getValue())
 229              .Case("always", EmitDwarfUnwindType::Always)
 230              .Case("no-compact-unwind", EmitDwarfUnwindType::NoCompactUnwind)
 231              .Case("default", EmitDwarfUnwindType::Default);
 232    }
 233  
 234    Opts.EmitCompactUnwindNonCanonical =
 235        Args.hasArg(OPT_femit_compact_unwind_non_canonical);
 236    Opts.Crel = Args.hasArg(OPT_crel);
 237  #if LLVM_VERSION_MAJOR >= 20
 238    Opts.ImplicitMapsyms = Args.hasArg(OPT_mmapsyms_implicit);
 239  #endif
 240    Opts.X86RelaxRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
 241    Opts.X86Sse2Avx = Args.hasArg(OPT_msse2avx);
 242  
 243    Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
 244  
 245    return Success;
 246  }
 247  
 248  static std::unique_ptr<raw_fd_ostream>
 249  getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
 250    // Make sure that the Out file gets unlinked from the disk if we get a
 251    // SIGINT.
 252    if (Path != "-")
 253      sys::RemoveFileOnSignal(Path);
 254  
 255    std::error_code EC;
 256    auto Out = std::make_unique<raw_fd_ostream>(
 257        Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_TextWithCRLF));
 258    if (EC) {
 259      Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
 260      return nullptr;
 261    }
 262  
 263    return Out;
 264  }
 265  
 266  static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
 267                                   DiagnosticsEngine &Diags) {
 268    // Get the target specific parser.
 269    std::string Error;
 270    const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
 271    if (!TheTarget)
 272      return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
 273  
 274    ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
 275        MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
 276  
 277    if (std::error_code EC = Buffer.getError()) {
 278      return Diags.Report(diag::err_fe_error_reading)
 279             << Opts.InputFile << EC.message();
 280    }
 281  
 282    SourceMgr SrcMgr;
 283  
 284    // Tell SrcMgr about this buffer, which is what the parser will pick up.
 285    unsigned BufferIndex = SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc());
 286  
 287    // Record the location of the include directories so that the lexer can find
 288    // it later.
 289    SrcMgr.setIncludeDirs(Opts.IncludePaths);
 290  
 291    std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
 292    assert(MRI && "Unable to create target register info!");
 293  
 294    MCTargetOptions MCOptions;
 295    MCOptions.MCRelaxAll = Opts.RelaxAll;
 296    MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
 297    MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
 298    MCOptions.MCSaveTempLabels = Opts.SaveTemporaryLabels;
 299    MCOptions.Crel = Opts.Crel;
 300  #if LLVM_VERSION_MAJOR >= 20
 301    MCOptions.ImplicitMapSyms = Opts.ImplicitMapsyms;
 302  #endif
 303    MCOptions.X86RelaxRelocations = Opts.X86RelaxRelocations;
 304    MCOptions.X86Sse2Avx = Opts.X86Sse2Avx;
 305    MCOptions.CompressDebugSections = Opts.CompressDebugSections;
 306    MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
 307  
 308    std::unique_ptr<MCAsmInfo> MAI(
 309        TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
 310    assert(MAI && "Unable to create target asm info!");
 311  
 312    // Ensure MCAsmInfo initialization occurs before any use, otherwise sections
 313    // may be created with a combination of default and explicit settings.
 314  
 315  
 316    bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
 317    if (Opts.OutputPath.empty())
 318      Opts.OutputPath = "-";
 319    std::unique_ptr<raw_fd_ostream> FDOS =
 320        getOutputStream(Opts.OutputPath, Diags, IsBinary);
 321    if (!FDOS)
 322      return true;
 323    std::unique_ptr<raw_fd_ostream> DwoOS;
 324    if (!Opts.SplitDwarfOutput.empty())
 325      DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
 326  
 327    // Build up the feature string from the target feature list.
 328    std::string FS = llvm::join(Opts.Features, ",");
 329  
 330    std::unique_ptr<MCSubtargetInfo> STI(
 331        TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
 332    assert(STI && "Unable to create subtarget info!");
 333  
 334    MCContext Ctx(Triple(Opts.Triple), MAI.get(), MRI.get(), STI.get(), &SrcMgr,
 335                  &MCOptions);
 336  
 337    bool PIC = false;
 338    if (Opts.RelocationModel == "static") {
 339      PIC = false;
 340    } else if (Opts.RelocationModel == "pic") {
 341      PIC = true;
 342    } else {
 343      assert(Opts.RelocationModel == "dynamic-no-pic" &&
 344             "Invalid PIC model!");
 345      PIC = false;
 346    }
 347  
 348    // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
 349    // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
 350    std::unique_ptr<MCObjectFileInfo> MOFI(
 351        TheTarget->createMCObjectFileInfo(Ctx, PIC));
 352    Ctx.setObjectFileInfo(MOFI.get());
 353  
 354    if (Opts.GenDwarfForAssembly)
 355      Ctx.setGenDwarfForAssembly(true);
 356    if (!Opts.DwarfDebugFlags.empty())
 357      Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
 358    if (!Opts.DwarfDebugProducer.empty())
 359      Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
 360    if (!Opts.DebugCompilationDir.empty())
 361      Ctx.setCompilationDir(Opts.DebugCompilationDir);
 362    else {
 363      // If no compilation dir is set, try to use the current directory.
 364      SmallString<128> CWD;
 365      if (!sys::fs::current_path(CWD))
 366        Ctx.setCompilationDir(CWD);
 367    }
 368    if (!Opts.DebugPrefixMap.empty())
 369      for (const auto &KV : Opts.DebugPrefixMap)
 370        Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
 371    if (!Opts.MainFileName.empty())
 372      Ctx.setMainFileName(StringRef(Opts.MainFileName));
 373    Ctx.setDwarfFormat(Opts.Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32);
 374    Ctx.setDwarfVersion(Opts.DwarfVersion);
 375    if (Opts.GenDwarfForAssembly)
 376      Ctx.setGenDwarfRootFile(Opts.InputFile,
 377                              SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
 378  
 379    std::unique_ptr<MCStreamer> Str;
 380  
 381    std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
 382    assert(MCII && "Unable to create instruction info!");
 383  
 384    raw_pwrite_stream *Out = FDOS.get();
 385    std::unique_ptr<buffer_ostream> BOS;
 386  
 387    MCOptions.MCNoWarn = Opts.NoWarn;
 388    MCOptions.MCFatalWarnings = Opts.FatalWarnings;
 389    MCOptions.MCNoTypeCheck = Opts.NoTypeCheck;
 390    MCOptions.ShowMCInst = Opts.ShowInst;
 391    MCOptions.AsmVerbose = true;
 392    MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory;
 393    MCOptions.ABIName = Opts.TargetABI;
 394  
 395    // FIXME: There is a bit of code duplication with addPassesToEmitFile.
 396    if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
 397      MCInstPrinter *IP = TheTarget->createMCInstPrinter(
 398          llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
 399  
 400      std::unique_ptr<MCCodeEmitter> CE;
 401      if (Opts.ShowEncoding)
 402        CE.reset(TheTarget->createMCCodeEmitter(*MCII, Ctx));
 403      std::unique_ptr<MCAsmBackend> MAB(
 404          TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
 405  
 406      auto FOut = std::make_unique<formatted_raw_ostream>(*Out);
 407      Str.reset(TheTarget->createAsmStreamer(Ctx, std::move(FOut), IP,
 408                                             std::move(CE), std::move(MAB)));
 409    } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
 410      Str.reset(createNullStreamer(Ctx));
 411    } else {
 412      assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
 413             "Invalid file type!");
 414      if (!FDOS->supportsSeeking()) {
 415        BOS = std::make_unique<buffer_ostream>(*FDOS);
 416        Out = BOS.get();
 417      }
 418  
 419      std::unique_ptr<MCCodeEmitter> CE(
 420          TheTarget->createMCCodeEmitter(*MCII, Ctx));
 421      std::unique_ptr<MCAsmBackend> MAB(
 422          TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
 423      assert(MAB && "Unable to create asm backend!");
 424  
 425      std::unique_ptr<MCObjectWriter> OW =
 426          DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
 427                : MAB->createObjectWriter(*Out);
 428  
 429      Triple T(Opts.Triple);
 430      Str.reset(TheTarget->createMCObjectStreamer(
 431          T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI));
 432      Str.get()->initSections(Opts.NoExecStack, *STI);
 433      if (T.isOSBinFormatMachO() && T.isOSDarwin()) {
 434        Triple *TVT = Opts.DarwinTargetVariantTriple
 435                          ? &*Opts.DarwinTargetVariantTriple
 436                          : nullptr;
 437        Str->emitVersionForTarget(T, VersionTuple(), TVT,
 438                                  Opts.DarwinTargetVariantSDKVersion);
 439      }
 440    }
 441  
 442    // When -fembed-bitcode is passed to clang_as, a 1-byte marker
 443    // is emitted in __LLVM,__asm section if the object file is MachO format.
 444    if (Opts.EmbedBitcode && Ctx.getObjectFileType() == MCContext::IsMachO) {
 445      MCSection *AsmLabel = Ctx.getMachOSection(
 446          "__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
 447      Str.get()->switchSection(AsmLabel);
 448      Str.get()->emitZeros(1);
 449    }
 450  
 451    bool Failed = false;
 452  
 453    std::unique_ptr<MCAsmParser> Parser(
 454        createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
 455  
 456    // FIXME: init MCTargetOptions from sanitizer flags here.
 457    std::unique_ptr<MCTargetAsmParser> TAP(
 458        TheTarget->createMCAsmParser(*STI, *Parser, *MCII, MCOptions));
 459    if (!TAP)
 460      Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
 461  
 462    // Set values for symbols, if any.
 463    for (auto &S : Opts.SymbolDefs) {
 464      auto Pair = StringRef(S).split('=');
 465      auto Sym = Pair.first;
 466      auto Val = Pair.second;
 467      int64_t Value;
 468      // We have already error checked this in the driver.
 469      Val.getAsInteger(0, Value);
 470      Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value);
 471    }
 472  
 473    if (!Failed) {
 474      Parser->setTargetParser(*TAP.get());
 475      Failed = Parser->Run(Opts.NoInitialTextSection);
 476    }
 477  
 478    return Failed;
 479  }
 480  
 481  bool ExecuteAssembler(AssemblerInvocation &Opts,
 482                               DiagnosticsEngine &Diags) {
 483    bool Failed = ExecuteAssemblerImpl(Opts, Diags);
 484  
 485    // Delete output file if there were errors.
 486    if (Failed) {
 487      if (Opts.OutputPath != "-")
 488        sys::fs::remove(Opts.OutputPath);
 489      if (!Opts.SplitDwarfOutput.empty() && Opts.SplitDwarfOutput != "-")
 490        sys::fs::remove(Opts.SplitDwarfOutput);
 491    }
 492  
 493    return Failed;
 494  }
 495  
 496  static void LLVMErrorHandler(void *UserData, const char *Message,
 497                               bool GenCrashDiag) {
 498    DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
 499  
 500    Diags.Report(diag::err_fe_error_backend) << Message;
 501  
 502    // We cannot recover from llvm errors.
 503    sys::Process::Exit(1);
 504  }
 505  
 506  int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
 507    // Initialize targets and assembly printers/parsers.
 508    InitializeAllTargetInfos();
 509    InitializeAllTargetMCs();
 510    InitializeAllAsmParsers();
 511  
 512    // Construct our diagnostic client.
 513    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
 514    TextDiagnosticPrinter *DiagClient
 515      = new TextDiagnosticPrinter(errs(), &*DiagOpts);
 516    DiagClient->setPrefix("clang -cc1as");
 517    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 518    DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
 519  
 520    // Set an error handler, so that any LLVM backend diagnostics go through our
 521    // error handler.
 522    ScopedFatalErrorHandler FatalErrorHandler
 523      (LLVMErrorHandler, static_cast<void*>(&Diags));
 524  
 525    // Parse the arguments.
 526    AssemblerInvocation Asm;
 527    if (!AssemblerInvocation::CreateFromArgs(Asm, Argv, Diags))
 528      return 1;
 529  
 530    if (Asm.ShowHelp) {
 531      getDriverOptTable().printHelp(
 532          llvm::outs(), "clang -cc1as [options] file...",
 533          "Clang Integrated Assembler", /*ShowHidden=*/false,
 534          /*ShowAllAliases=*/false,
 535          llvm::opt::Visibility(driver::options::CC1AsOption));
 536  
 537      return 0;
 538    }
 539  
 540    // Honor -version.
 541    //
 542    // FIXME: Use a better -version message?
 543    if (Asm.ShowVersion) {
 544      llvm::cl::PrintVersionMessage();
 545      return 0;
 546    }
 547  
 548    // Honor -mllvm.
 549    //
 550    // FIXME: Remove this, one day.
 551    if (!Asm.LLVMArgs.empty()) {
 552      unsigned NumArgs = Asm.LLVMArgs.size();
 553      auto Args = std::make_unique<const char*[]>(NumArgs + 2);
 554      Args[0] = "clang (LLVM option parsing)";
 555      for (unsigned i = 0; i != NumArgs; ++i)
 556        Args[i + 1] = Asm.LLVMArgs[i].c_str();
 557      Args[NumArgs + 1] = nullptr;
 558      llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
 559    }
 560  
 561    // Execute the invocation, unless there were parsing errors.
 562    bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags);
 563  
 564    // If any timers were active but haven't been destroyed yet, print their
 565    // results now.
 566    TimerGroup::printAll(errs());
 567    TimerGroup::clearAll();
 568  
 569    return !!Failed;
 570  }
 571