1 //===-- cc1as_main.cpp - Clang Assembler ---------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This is the entry point to the clang -cc1as functionality, which implements
11 // the direct interface to the LLVM MC based assembler.
13 //===----------------------------------------------------------------------===//
15 #include "clang/Basic/Diagnostic.h"
16 #include "clang/Basic/DiagnosticOptions.h"
17 #include "clang/Driver/DriverDiagnostic.h"
18 #include "clang/Driver/Options.h"
19 #include "clang/Frontend/FrontendDiagnostic.h"
20 #include "clang/Frontend/TextDiagnosticPrinter.h"
21 #include "clang/Frontend/Utils.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/MCParser/MCAsmParser.h"
32 #include "llvm/MC/MCRegisterInfo.h"
33 #include "llvm/MC/MCStreamer.h"
34 #include "llvm/MC/MCSubtargetInfo.h"
35 #include "llvm/MC/MCTargetAsmParser.h"
36 #include "llvm/MC/MCTargetOptions.h"
37 #include "llvm/Option/Arg.h"
38 #include "llvm/Option/ArgList.h"
39 #include "llvm/Option/OptTable.h"
40 #include "llvm/Support/CommandLine.h"
41 #include "llvm/Support/ErrorHandling.h"
42 #include "llvm/Support/FileSystem.h"
43 #include "llvm/Support/FormattedStream.h"
44 #include "llvm/Support/Host.h"
45 #include "llvm/Support/ManagedStatic.h"
46 #include "llvm/Support/MemoryBuffer.h"
47 #include "llvm/Support/Path.h"
48 #include "llvm/Support/PrettyStackTrace.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"
56 #include <system_error>
57 using namespace clang
;
58 using namespace clang::driver
;
59 using namespace clang::driver::options
;
61 using namespace llvm::opt
;
65 /// \brief Helper class for representing a single invocation of the assembler.
66 struct AssemblerInvocation
{
67 /// @name Target Options
70 /// The name of the target triple to assemble for.
73 /// If given, the name of the target CPU to determine which instructions
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::string
> Features
;
82 /// @name Language Options
85 std::vector
<std::string
> IncludePaths
;
86 unsigned NoInitialTextSection
: 1;
87 unsigned SaveTemporaryLabels
: 1;
88 unsigned GenDwarfForAssembly
: 1;
89 unsigned CompressDebugSections
: 1;
90 unsigned DwarfVersion
;
91 std::string DwarfDebugFlags
;
92 std::string DwarfDebugProducer
;
93 std::string DebugCompilationDir
;
94 std::string MainFileName
;
97 /// @name Frontend Options
100 std::string InputFile
;
101 std::vector
<std::string
> LLVMArgs
;
102 std::string OutputPath
;
104 FT_Asm
, ///< Assembly (.s) output, transliterate mode.
105 FT_Null
, ///< No output, for timing purposes.
106 FT_Obj
///< Object file output.
109 unsigned ShowHelp
: 1;
110 unsigned ShowVersion
: 1;
113 /// @name Transliterate Options
116 unsigned OutputAsmVariant
;
117 unsigned ShowEncoding
: 1;
118 unsigned ShowInst
: 1;
121 /// @name Assembler Options
124 unsigned RelaxAll
: 1;
125 unsigned NoExecStack
: 1;
126 unsigned FatalWarnings
: 1;
131 AssemblerInvocation() {
133 NoInitialTextSection
= 0;
137 OutputAsmVariant
= 0;
146 static bool CreateFromArgs(AssemblerInvocation
&Res
,
147 ArrayRef
<const char *> Argv
,
148 DiagnosticsEngine
&Diags
);
153 bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation
&Opts
,
154 ArrayRef
<const char *> Argv
,
155 DiagnosticsEngine
&Diags
) {
158 // Parse the arguments.
159 std::unique_ptr
<OptTable
> OptTbl(createDriverOptTable());
161 const unsigned IncludedFlagsBitmask
= options::CC1AsOption
;
162 unsigned MissingArgIndex
, MissingArgCount
;
163 std::unique_ptr
<InputArgList
> Args(
164 OptTbl
->ParseArgs(Argv
.begin(), Argv
.end(), MissingArgIndex
, MissingArgCount
,
165 IncludedFlagsBitmask
));
167 // Check for missing argument error.
168 if (MissingArgCount
) {
169 Diags
.Report(diag::err_drv_missing_argument
)
170 << Args
->getArgString(MissingArgIndex
) << MissingArgCount
;
174 // Issue errors on unknown arguments.
175 for (arg_iterator it
= Args
->filtered_begin(OPT_UNKNOWN
),
176 ie
= Args
->filtered_end();
178 Diags
.Report(diag::err_drv_unknown_argument
) << (*it
)->getAsString(*Args
);
182 // Construct the invocation.
185 Opts
.Triple
= llvm::Triple::normalize(Args
->getLastArgValue(OPT_triple
));
186 Opts
.CPU
= Args
->getLastArgValue(OPT_target_cpu
);
187 Opts
.Features
= Args
->getAllArgValues(OPT_target_feature
);
189 // Use the default target triple if unspecified.
190 if (Opts
.Triple
.empty())
191 Opts
.Triple
= llvm::sys::getDefaultTargetTriple();
194 Opts
.IncludePaths
= Args
->getAllArgValues(OPT_I
);
195 Opts
.NoInitialTextSection
= Args
->hasArg(OPT_n
);
196 Opts
.SaveTemporaryLabels
= Args
->hasArg(OPT_msave_temp_labels
);
197 Opts
.GenDwarfForAssembly
= Args
->hasArg(OPT_g_Flag
);
198 Opts
.CompressDebugSections
= Args
->hasArg(OPT_compress_debug_sections
);
199 if (Args
->hasArg(OPT_gdwarf_2
))
200 Opts
.DwarfVersion
= 2;
201 if (Args
->hasArg(OPT_gdwarf_3
))
202 Opts
.DwarfVersion
= 3;
203 if (Args
->hasArg(OPT_gdwarf_4
))
204 Opts
.DwarfVersion
= 4;
205 Opts
.DwarfDebugFlags
= Args
->getLastArgValue(OPT_dwarf_debug_flags
);
206 Opts
.DwarfDebugProducer
= Args
->getLastArgValue(OPT_dwarf_debug_producer
);
207 Opts
.DebugCompilationDir
= Args
->getLastArgValue(OPT_fdebug_compilation_dir
);
208 Opts
.MainFileName
= Args
->getLastArgValue(OPT_main_file_name
);
211 if (Args
->hasArg(OPT_INPUT
)) {
213 for (arg_iterator it
= Args
->filtered_begin(OPT_INPUT
),
214 ie
= Args
->filtered_end(); it
!= ie
; ++it
, First
=false) {
217 Opts
.InputFile
= A
->getValue();
219 Diags
.Report(diag::err_drv_unknown_argument
) << A
->getAsString(*Args
);
224 Opts
.LLVMArgs
= Args
->getAllArgValues(OPT_mllvm
);
225 Opts
.OutputPath
= Args
->getLastArgValue(OPT_o
);
226 if (Arg
*A
= Args
->getLastArg(OPT_filetype
)) {
227 StringRef Name
= A
->getValue();
228 unsigned OutputType
= StringSwitch
<unsigned>(Name
)
230 .Case("null", FT_Null
)
233 if (OutputType
== ~0U) {
234 Diags
.Report(diag::err_drv_invalid_value
)
235 << A
->getAsString(*Args
) << Name
;
238 Opts
.OutputType
= FileType(OutputType
);
240 Opts
.ShowHelp
= Args
->hasArg(OPT_help
);
241 Opts
.ShowVersion
= Args
->hasArg(OPT_version
);
243 // Transliterate Options
244 Opts
.OutputAsmVariant
=
245 getLastArgIntValue(*Args
.get(), OPT_output_asm_variant
, 0, Diags
);
246 Opts
.ShowEncoding
= Args
->hasArg(OPT_show_encoding
);
247 Opts
.ShowInst
= Args
->hasArg(OPT_show_inst
);
250 Opts
.RelaxAll
= Args
->hasArg(OPT_mrelax_all
);
251 Opts
.NoExecStack
= Args
->hasArg(OPT_mno_exec_stack
);
252 Opts
.FatalWarnings
= Args
->hasArg(OPT_massembler_fatal_warnings
);
257 static formatted_raw_ostream
*GetOutputStream(AssemblerInvocation
&Opts
,
258 DiagnosticsEngine
&Diags
,
260 if (Opts
.OutputPath
.empty())
261 Opts
.OutputPath
= "-";
263 // Make sure that the Out file gets unlinked from the disk if we get a
265 if (Opts
.OutputPath
!= "-")
266 sys::RemoveFileOnSignal(Opts
.OutputPath
);
269 raw_fd_ostream
*Out
= new raw_fd_ostream(
270 Opts
.OutputPath
, EC
, (Binary
? sys::fs::F_None
: sys::fs::F_Text
));
272 Diags
.Report(diag::err_fe_unable_to_open_output
) << Opts
.OutputPath
278 return new formatted_raw_ostream(*Out
, formatted_raw_ostream::DELETE_STREAM
);
281 static bool ExecuteAssembler(AssemblerInvocation
&Opts
,
282 DiagnosticsEngine
&Diags
) {
283 // Get the target specific parser.
285 const Target
*TheTarget
= TargetRegistry::lookupTarget(Opts
.Triple
, Error
);
287 return Diags
.Report(diag::err_target_unknown_triple
) << Opts
.Triple
;
289 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> Buffer
=
290 MemoryBuffer::getFileOrSTDIN(Opts
.InputFile
);
292 if (std::error_code EC
= Buffer
.getError()) {
293 Error
= EC
.message();
294 return Diags
.Report(diag::err_fe_error_reading
) << Opts
.InputFile
;
299 // Tell SrcMgr about this buffer, which is what the parser will pick up.
300 SrcMgr
.AddNewSourceBuffer(std::move(*Buffer
), SMLoc());
302 // Record the location of the include directories so that the lexer can find
304 SrcMgr
.setIncludeDirs(Opts
.IncludePaths
);
306 std::unique_ptr
<MCRegisterInfo
> MRI(TheTarget
->createMCRegInfo(Opts
.Triple
));
307 assert(MRI
&& "Unable to create target register info!");
309 std::unique_ptr
<MCAsmInfo
> MAI(TheTarget
->createMCAsmInfo(*MRI
, Opts
.Triple
));
310 assert(MAI
&& "Unable to create target asm info!");
312 // Ensure MCAsmInfo initialization occurs before any use, otherwise sections
313 // may be created with a combination of default and explicit settings.
314 if (Opts
.CompressDebugSections
)
315 MAI
->setCompressDebugSections(true);
317 bool IsBinary
= Opts
.OutputType
== AssemblerInvocation::FT_Obj
;
318 std::unique_ptr
<formatted_raw_ostream
> Out(
319 GetOutputStream(Opts
, Diags
, IsBinary
));
323 // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
324 // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
325 std::unique_ptr
<MCObjectFileInfo
> MOFI(new MCObjectFileInfo());
327 MCContext
Ctx(MAI
.get(), MRI
.get(), MOFI
.get(), &SrcMgr
);
328 // FIXME: Assembler behavior can change with -static.
329 MOFI
->InitMCObjectFileInfo(Opts
.Triple
,
330 Reloc::Default
, CodeModel::Default
, Ctx
);
331 if (Opts
.SaveTemporaryLabels
)
332 Ctx
.setAllowTemporaryLabels(false);
333 if (Opts
.GenDwarfForAssembly
)
334 Ctx
.setGenDwarfForAssembly(true);
335 if (!Opts
.DwarfDebugFlags
.empty())
336 Ctx
.setDwarfDebugFlags(StringRef(Opts
.DwarfDebugFlags
));
337 if (!Opts
.DwarfDebugProducer
.empty())
338 Ctx
.setDwarfDebugProducer(StringRef(Opts
.DwarfDebugProducer
));
339 if (!Opts
.DebugCompilationDir
.empty())
340 Ctx
.setCompilationDir(Opts
.DebugCompilationDir
);
341 if (!Opts
.MainFileName
.empty())
342 Ctx
.setMainFileName(StringRef(Opts
.MainFileName
));
343 Ctx
.setDwarfVersion(Opts
.DwarfVersion
);
345 // Build up the feature string from the target feature list.
347 if (!Opts
.Features
.empty()) {
348 FS
= Opts
.Features
[0];
349 for (unsigned i
= 1, e
= Opts
.Features
.size(); i
!= e
; ++i
)
350 FS
+= "," + Opts
.Features
[i
];
353 std::unique_ptr
<MCStreamer
> Str
;
355 std::unique_ptr
<MCInstrInfo
> MCII(TheTarget
->createMCInstrInfo());
356 std::unique_ptr
<MCSubtargetInfo
> STI(
357 TheTarget
->createMCSubtargetInfo(Opts
.Triple
, Opts
.CPU
, FS
));
359 // FIXME: There is a bit of code duplication with addPassesToEmitFile.
360 if (Opts
.OutputType
== AssemblerInvocation::FT_Asm
) {
362 TheTarget
->createMCInstPrinter(Opts
.OutputAsmVariant
, *MAI
, *MCII
, *MRI
,
364 MCCodeEmitter
*CE
= nullptr;
365 MCAsmBackend
*MAB
= nullptr;
366 if (Opts
.ShowEncoding
) {
367 CE
= TheTarget
->createMCCodeEmitter(*MCII
, *MRI
, *STI
, Ctx
);
368 MAB
= TheTarget
->createMCAsmBackend(*MRI
, Opts
.Triple
, Opts
.CPU
);
370 Str
.reset(TheTarget
->createAsmStreamer(Ctx
, *Out
, /*asmverbose*/true,
371 /*useDwarfDirectory*/ true,
374 } else if (Opts
.OutputType
== AssemblerInvocation::FT_Null
) {
375 Str
.reset(createNullStreamer(Ctx
));
377 assert(Opts
.OutputType
== AssemblerInvocation::FT_Obj
&&
378 "Invalid file type!");
379 MCCodeEmitter
*CE
= TheTarget
->createMCCodeEmitter(*MCII
, *MRI
, *STI
, Ctx
);
380 MCAsmBackend
*MAB
= TheTarget
->createMCAsmBackend(*MRI
, Opts
.Triple
,
382 Str
.reset(TheTarget
->createMCObjectStreamer(Opts
.Triple
, Ctx
, *MAB
, *Out
,
383 CE
, *STI
, Opts
.RelaxAll
));
384 Str
.get()->InitSections(Opts
.NoExecStack
);
389 std::unique_ptr
<MCAsmParser
> Parser(
390 createMCAsmParser(SrcMgr
, Ctx
, *Str
.get(), *MAI
));
392 // FIXME: init MCTargetOptions from sanitizer flags here.
393 MCTargetOptions Options
;
394 std::unique_ptr
<MCTargetAsmParser
> TAP(
395 TheTarget
->createMCAsmParser(*STI
, *Parser
, *MCII
, Options
));
397 Failed
= Diags
.Report(diag::err_target_unknown_triple
) << Opts
.Triple
;
400 Parser
->setTargetParser(*TAP
.get());
401 Failed
= Parser
->Run(Opts
.NoInitialTextSection
);
404 // Close the output stream early.
407 // Delete output file if there were errors.
408 if (Failed
&& Opts
.OutputPath
!= "-")
409 sys::fs::remove(Opts
.OutputPath
);
414 static void LLVMErrorHandler(void *UserData
, const std::string
&Message
,
416 DiagnosticsEngine
&Diags
= *static_cast<DiagnosticsEngine
*>(UserData
);
418 Diags
.Report(diag::err_fe_error_backend
) << Message
;
420 // We cannot recover from llvm errors.
424 int cc1as_main(ArrayRef
<const char *> Argv
, const char *Argv0
, void *MainAddr
) {
425 // Print a stack trace if we signal out.
426 sys::PrintStackTraceOnErrorSignal();
427 PrettyStackTraceProgram
X(Argv
.size(), Argv
.data());
428 llvm_shutdown_obj Y
; // Call llvm_shutdown() on exit.
430 // Initialize targets and assembly printers/parsers.
431 InitializeAllTargetInfos();
432 InitializeAllTargetMCs();
433 InitializeAllAsmParsers();
435 // Construct our diagnostic client.
436 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
437 TextDiagnosticPrinter
*DiagClient
438 = new TextDiagnosticPrinter(errs(), &*DiagOpts
);
439 DiagClient
->setPrefix("clang -cc1as");
440 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
441 DiagnosticsEngine
Diags(DiagID
, &*DiagOpts
, DiagClient
);
443 // Set an error handler, so that any LLVM backend diagnostics go through our
445 ScopedFatalErrorHandler FatalErrorHandler
446 (LLVMErrorHandler
, static_cast<void*>(&Diags
));
448 // Parse the arguments.
449 AssemblerInvocation Asm
;
450 if (!AssemblerInvocation::CreateFromArgs(Asm
, Argv
, Diags
))
454 std::unique_ptr
<OptTable
> Opts(driver::createDriverOptTable());
455 Opts
->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler",
456 /*Include=*/driver::options::CC1AsOption
, /*Exclude=*/0);
462 // FIXME: Use a better -version message?
463 if (Asm
.ShowVersion
) {
464 llvm::cl::PrintVersionMessage();
470 // FIXME: Remove this, one day.
471 if (!Asm
.LLVMArgs
.empty()) {
472 unsigned NumArgs
= Asm
.LLVMArgs
.size();
473 const char **Args
= new const char*[NumArgs
+ 2];
474 Args
[0] = "clang (LLVM option parsing)";
475 for (unsigned i
= 0; i
!= NumArgs
; ++i
)
476 Args
[i
+ 1] = Asm
.LLVMArgs
[i
].c_str();
477 Args
[NumArgs
+ 1] = nullptr;
478 llvm::cl::ParseCommandLineOptions(NumArgs
+ 1, Args
);
481 // Execute the invocation, unless there were parsing errors.
482 bool Failed
= Diags
.hasErrorOccurred() || ExecuteAssembler(Asm
, Diags
);
484 // If any timers were active but haven't been destroyed yet, print their
486 TimerGroup::printAll(errs());