Clang Project

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