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/MC/TargetRegistry.h"
40 #include "llvm/Option/Arg.h"
41 #include "llvm/Option/ArgList.h"
42 #include "llvm/Option/OptTable.h"
43 #include "llvm/Support/CommandLine.h"
44 #include "llvm/Support/ErrorHandling.h"
45 #include "llvm/Support/FileSystem.h"
46 #include "llvm/Support/FormattedStream.h"
47 #include "llvm/Support/Host.h"
48 #include "llvm/Support/MemoryBuffer.h"
49 #include "llvm/Support/Path.h"
50 #include "llvm/Support/Process.h"
51 #include "llvm/Support/Signals.h"
52 #include "llvm/Support/SourceMgr.h"
53 #include "llvm/Support/TargetSelect.h"
54 #include "llvm/Support/Timer.h"
55 #include "llvm/Support/raw_ostream.h"
58 #include <system_error>
59 using namespace clang;
60 using namespace clang::driver;
61 using namespace clang::driver::options;
63 using namespace llvm::opt;
68 struct AssemblerInvocation {
81 std::vector<std::string> Features;
84 std::vector<std::string> SymbolDefs;
90 std::vector<std::string> IncludePaths;
91 unsigned NoInitialTextSection : 1;
92 unsigned SaveTemporaryLabels : 1;
93 unsigned GenDwarfForAssembly : 1;
94 unsigned RelaxELFRelocations : 1;
96 unsigned DwarfVersion;
97 std::string DwarfDebugFlags;
98 std::string DwarfDebugProducer;
99 std::string DebugCompilationDir;
100 std::map<const std::string, const std::string> DebugPrefixMap;
101 llvm::DebugCompressionType CompressDebugSections = llvm::DebugCompressionType::None;
102 std::string MainFileName;
103 std::string SplitDwarfOutput;
109 std::string InputFile;
110 std::vector<std::string> LLVMArgs;
111 std::string OutputPath;
118 unsigned ShowHelp : 1;
119 unsigned ShowVersion : 1;
125 unsigned OutputAsmVariant;
126 unsigned ShowEncoding : 1;
127 unsigned ShowInst : 1;
133 unsigned RelaxAll : 1;
134 unsigned NoExecStack : 1;
135 unsigned FatalWarnings : 1;
137 unsigned NoTypeCheck : 1;
138 unsigned IncrementalLinkerCompatible : 1;
139 unsigned EmbedBitcode : 1;
142 EmitDwarfUnwindType EmitDwarfUnwind;
145 std::string RelocationModel;
149 std::string TargetABI;
153 std::optional<llvm::Triple> DarwinTargetVariantTriple;
157 llvm::VersionTuple DarwinTargetVariantSDKVersion;
160 std::string AsSecureLogFile;
164 AssemblerInvocation() {
166 NoInitialTextSection = 0;
170 OutputAsmVariant = 0;
178 IncrementalLinkerCompatible = 0;
182 EmitDwarfUnwind = EmitDwarfUnwindType::Default;
185 static bool CreateFromArgs(AssemblerInvocation &Res, ArrayRef<const char *> Argv, DiagnosticsEngine &Diags);
190 bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
191 ArrayRef<const char *> Argv,
192 DiagnosticsEngine &Diags) {
196 const OptTable &OptTbl = getDriverOptTable();
198 const unsigned IncludedFlagsBitmask = options::CC1AsOption;
199 unsigned MissingArgIndex, MissingArgCount;
200 InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount, IncludedFlagsBitmask);
203 if (MissingArgCount) {
204 Diags.Report(diag::err_drv_missing_argument) << Args.getArgString(MissingArgIndex) << MissingArgCount;
209 for (
const Arg *A : Args.filtered(OPT_UNKNOWN)) {
210 auto ArgString = A->getAsString(Args);
212 if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
213 Diags.Report(diag::err_drv_unknown_argument) << ArgString;
215 Diags.Report(diag::err_drv_unknown_argument_with_suggestion) << ArgString << Nearest;
222 Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
223 if (Arg *A = Args.getLastArg(options::OPT_darwin_target_variant_triple))
224 Opts.DarwinTargetVariantTriple = llvm::Triple(A->getValue());
225 if (Arg *A = Args.getLastArg(OPT_darwin_target_variant_sdk_version_EQ)) {
226 VersionTuple Version;
227 if (Version.tryParse(A->getValue()))
228 Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue();
230 Opts.DarwinTargetVariantSDKVersion = Version;
233 Opts.CPU = std::string(Args.getLastArgValue(OPT_target_cpu));
234 Opts.Features = Args.getAllArgValues(OPT_target_feature);
237 if (Opts.Triple.empty())
238 Opts.Triple = llvm::sys::getDefaultTargetTriple();
241 Opts.IncludePaths = Args.getAllArgValues(OPT_I);
242 Opts.NoInitialTextSection = Args.hasArg(OPT_n);
243 Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
245 Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
247 if (
const Arg *A = Args.getLastArg(OPT_compress_debug_sections_EQ)) {
248 Opts.CompressDebugSections = llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
249 .Case(
"none", llvm::DebugCompressionType::None)
250 .Case(
"zlib", llvm::DebugCompressionType::Zlib)
251 .Case(
"zstd", llvm::DebugCompressionType::Zstd)
252 .Default(llvm::DebugCompressionType::None);
255 Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
256 if (
auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
257 Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
258 Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
259 Opts.DwarfDebugFlags = std::string(Args.getLastArgValue(OPT_dwarf_debug_flags));
260 Opts.DwarfDebugProducer = std::string(Args.getLastArgValue(OPT_dwarf_debug_producer));
261 if (
const Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, options::OPT_fdebug_compilation_dir_EQ))
262 Opts.DebugCompilationDir = A->getValue();
263 Opts.MainFileName = std::string(Args.getLastArgValue(OPT_main_file_name));
265 for (
const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
266 auto Split = StringRef(Arg).split(
'=');
267 Opts.DebugPrefixMap.insert({std::string(Split.first), std::string(Split.second)});
271 if (Args.hasArg(OPT_INPUT)) {
273 for (
const Arg *A : Args.filtered(OPT_INPUT)) {
275 Opts.InputFile = A->getValue();
278 Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
283 Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
284 Opts.OutputPath = std::string(Args.getLastArgValue(OPT_o));
285 Opts.SplitDwarfOutput = std::string(Args.getLastArgValue(OPT_split_dwarf_output));
286 if (Arg *A = Args.getLastArg(OPT_filetype)) {
287 StringRef Name = A->getValue();
288 unsigned OutputType =
289 StringSwitch<unsigned>(Name).Case(
"asm", FT_Asm).Case(
"null", FT_Null).Case(
"obj", FT_Obj).Default(~0U);
290 if (OutputType == ~0U) {
291 Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
294 Opts.OutputType = FileType(OutputType);
296 Opts.ShowHelp = Args.hasArg(OPT_help);
297 Opts.ShowVersion = Args.hasArg(OPT_version);
300 Opts.OutputAsmVariant = getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags);
301 Opts.ShowEncoding = Args.hasArg(OPT_show_encoding);
302 Opts.ShowInst = Args.hasArg(OPT_show_inst);
305 Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
306 Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
307 Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
308 Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
309 Opts.NoTypeCheck = Args.hasArg(OPT_mno_type_check);
310 Opts.RelocationModel = std::string(Args.getLastArgValue(OPT_mrelocation_model,
"pic"));
311 Opts.TargetABI = std::string(Args.getLastArgValue(OPT_target_abi));
312 Opts.IncrementalLinkerCompatible = Args.hasArg(OPT_mincremental_linker_compatible);
313 Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym);
317 if (
auto *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) {
319 llvm::StringSwitch<unsigned>(A->getValue()).Case(
"all", 1).Case(
"bitcode", 1).Case(
"marker", 1).Default(0);
322 if (
auto *A = Args.getLastArg(OPT_femit_dwarf_unwind_EQ)) {
323 Opts.EmitDwarfUnwind = llvm::StringSwitch<EmitDwarfUnwindType>(A->getValue())
324 .Case(
"always", EmitDwarfUnwindType::Always)
325 .Case(
"no-compact-unwind", EmitDwarfUnwindType::NoCompactUnwind)
326 .Case(
"default", EmitDwarfUnwindType::Default);
329 Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
334 static std::unique_ptr<raw_fd_ostream> getOutputStream(StringRef Path, DiagnosticsEngine &Diags,
bool Binary) {
338 sys::RemoveFileOnSignal(Path);
341 auto Out = std::make_unique<raw_fd_ostream>(Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_TextWithCRLF));
343 Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
350 static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
353 const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
355 return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
357 ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = MemoryBuffer::getFileOrSTDIN(Opts.InputFile,
true);
359 if (std::error_code EC = Buffer.getError()) {
360 Error = EC.message();
361 return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
367 unsigned BufferIndex = SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc());
371 SrcMgr.setIncludeDirs(Opts.IncludePaths);
373 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
374 assert(MRI &&
"Unable to create target register info!");
376 MCTargetOptions MCOptions;
377 MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
378 MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
380 std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
381 assert(MAI &&
"Unable to create target asm info!");
385 MAI->setCompressDebugSections(Opts.CompressDebugSections);
387 MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
389 bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
390 if (Opts.OutputPath.empty())
391 Opts.OutputPath =
"-";
392 std::unique_ptr<raw_fd_ostream> FDOS = getOutputStream(Opts.OutputPath, Diags, IsBinary);
395 std::unique_ptr<raw_fd_ostream> DwoOS;
396 if (!Opts.SplitDwarfOutput.empty())
397 DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
400 std::string FS = llvm::join(Opts.Features,
",");
402 std::unique_ptr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
403 assert(STI &&
"Unable to create subtarget info!");
405 MCContext Ctx(Triple(Opts.Triple), MAI.get(), MRI.get(), STI.get(), &SrcMgr, &MCOptions);
408 if (Opts.RelocationModel ==
"static") {
410 }
else if (Opts.RelocationModel ==
"pic") {
413 assert(Opts.RelocationModel ==
"dynamic-no-pic" &&
"Invalid PIC model!");
419 std::unique_ptr<MCObjectFileInfo> MOFI(TheTarget->createMCObjectFileInfo(Ctx, PIC));
420 if (Opts.DarwinTargetVariantTriple)
421 MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
422 if (!Opts.DarwinTargetVariantSDKVersion.empty())
423 MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion);
424 Ctx.setObjectFileInfo(MOFI.get());
426 if (Opts.SaveTemporaryLabels)
427 Ctx.setAllowTemporaryLabels(
false);
428 if (Opts.GenDwarfForAssembly)
429 Ctx.setGenDwarfForAssembly(
true);
430 if (!Opts.DwarfDebugFlags.empty())
431 Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
432 if (!Opts.DwarfDebugProducer.empty())
433 Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
434 if (!Opts.DebugCompilationDir.empty())
435 Ctx.setCompilationDir(Opts.DebugCompilationDir);
438 SmallString<128> CWD;
439 if (!sys::fs::current_path(CWD))
440 Ctx.setCompilationDir(CWD);
442 if (!Opts.DebugPrefixMap.empty())
443 for (
const auto &KV : Opts.DebugPrefixMap)
444 Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
445 if (!Opts.MainFileName.empty())
446 Ctx.setMainFileName(StringRef(Opts.MainFileName));
447 Ctx.setDwarfFormat(Opts.Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32);
448 Ctx.setDwarfVersion(Opts.DwarfVersion);
449 if (Opts.GenDwarfForAssembly)
450 Ctx.setGenDwarfRootFile(Opts.InputFile, SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
452 std::unique_ptr<MCStreamer> Str;
454 std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
455 assert(MCII &&
"Unable to create instruction info!");
457 raw_pwrite_stream *Out = FDOS.get();
458 std::unique_ptr<buffer_ostream> BOS;
460 MCOptions.MCNoWarn = Opts.NoWarn;
461 MCOptions.MCFatalWarnings = Opts.FatalWarnings;
462 MCOptions.MCNoTypeCheck = Opts.NoTypeCheck;
463 MCOptions.ABIName = Opts.TargetABI;
466 if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
468 TheTarget->createMCInstPrinter(llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
470 std::unique_ptr<MCCodeEmitter> CE;
471 if (Opts.ShowEncoding)
472 CE.reset(TheTarget->createMCCodeEmitter(*MCII, Ctx));
473 std::unique_ptr<MCAsmBackend> MAB(TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
475 auto FOut = std::make_unique<formatted_raw_ostream>(*Out);
476 Str.reset(TheTarget->createAsmStreamer(Ctx,
484 }
else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
485 Str.reset(createNullStreamer(Ctx));
487 assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
"Invalid file type!");
488 if (!FDOS->supportsSeeking()) {
489 BOS = std::make_unique<buffer_ostream>(*FDOS);
493 std::unique_ptr<MCCodeEmitter> CE(TheTarget->createMCCodeEmitter(*MCII, Ctx));
494 std::unique_ptr<MCAsmBackend> MAB(TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
495 assert(MAB &&
"Unable to create asm backend!");
497 std::unique_ptr<MCObjectWriter> OW =
498 DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS) : MAB->createObjectWriter(*Out);
500 Triple T(Opts.Triple);
501 Str.reset(TheTarget->createMCObjectStreamer(T,
508 Opts.IncrementalLinkerCompatible,
510 Str.get()->initSections(Opts.NoExecStack, *STI);
515 if (Opts.EmbedBitcode && Ctx.getObjectFileType() == MCContext::IsMachO) {
516 MCSection *AsmLabel = Ctx.getMachOSection(
"__LLVM",
"__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
517 Str.get()->switchSection(AsmLabel);
518 Str.get()->emitZeros(1);
522 Str->setUseAssemblerInfoForParsing(
true);
526 std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
529 std::unique_ptr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser, *MCII, MCOptions));
531 Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
534 for (
auto &S : Opts.SymbolDefs) {
535 auto Pair = StringRef(S).split(
'=');
536 auto Sym = Pair.first;
537 auto Val = Pair.second;
540 Val.getAsInteger(0, Value);
541 Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value);
545 Parser->setTargetParser(*TAP.get());
546 Failed = Parser->Run(Opts.NoInitialTextSection);
552 static bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
553 bool Failed = ExecuteAssemblerImpl(Opts, Diags);
557 if (Opts.OutputPath !=
"-")
558 sys::fs::remove(Opts.OutputPath);
559 if (!Opts.SplitDwarfOutput.empty() && Opts.SplitDwarfOutput !=
"-")
560 sys::fs::remove(Opts.SplitDwarfOutput);
566 static void LLVMErrorHandler(
void *UserData,
const char *Message,
bool GenCrashDiag) {
567 DiagnosticsEngine &Diags = *
static_cast<DiagnosticsEngine *
>(UserData);
569 Diags.Report(diag::err_fe_error_backend) << Message;
572 sys::Process::Exit(1);
575 int cc1as_main(ArrayRef<const char *> Argv,
const char *Argv0,
void *MainAddr) {
577 InitializeAllTargetInfos();
578 InitializeAllTargetMCs();
579 InitializeAllAsmParsers();
582 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
new DiagnosticOptions();
583 TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(errs(), &*DiagOpts);
584 DiagClient->setPrefix(
"clang -cc1as");
585 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(
new DiagnosticIDs());
586 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
590 ScopedFatalErrorHandler FatalErrorHandler(LLVMErrorHandler,
static_cast<void *
>(&Diags));
593 AssemblerInvocation Asm;
594 if (!AssemblerInvocation::CreateFromArgs(Asm, Argv, Diags))
598 getDriverOptTable().printHelp(llvm::outs(),
599 "clang -cc1as [options] file...",
600 "Clang Integrated Assembler",
601 driver::options::CC1AsOption,
610 if (Asm.ShowVersion) {
611 llvm::cl::PrintVersionMessage();
618 if (!Asm.LLVMArgs.empty()) {
619 unsigned NumArgs = Asm.LLVMArgs.size();
620 auto Args = std::make_unique<const char *[]>(NumArgs + 2);
621 Args[0] =
"clang (LLVM option parsing)";
622 for (
unsigned i = 0; i != NumArgs; ++i)
623 Args[i + 1] = Asm.LLVMArgs[i].c_str();
624 Args[NumArgs + 1] =
nullptr;
625 llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
629 bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags);
633 TimerGroup::printAll(errs());
634 TimerGroup::clearAll();