Path: blob/main/contrib/llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp
35231 views
//===-- llvm-mc.cpp - Machine Code Hacking Driver ---------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This utility is a simple driver that allows command line hacking on machine9// code.10//11//===----------------------------------------------------------------------===//1213#include "Disassembler.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/MCTargetOptionsCommandFlags.h"28#include "llvm/MC/TargetRegistry.h"29#include "llvm/Support/CommandLine.h"30#include "llvm/Support/Compression.h"31#include "llvm/Support/FileUtilities.h"32#include "llvm/Support/FormattedStream.h"33#include "llvm/Support/InitLLVM.h"34#include "llvm/Support/MemoryBuffer.h"35#include "llvm/Support/SourceMgr.h"36#include "llvm/Support/TargetSelect.h"37#include "llvm/Support/ToolOutputFile.h"38#include "llvm/Support/WithColor.h"39#include "llvm/TargetParser/Host.h"4041using namespace llvm;4243static mc::RegisterMCTargetOptionsFlags MOF;4445static cl::OptionCategory MCCategory("MC Options");4647static cl::opt<std::string> InputFilename(cl::Positional,48cl::desc("<input file>"),49cl::init("-"), cl::cat(MCCategory));5051static cl::list<std::string>52DisassemblerOptions("M", cl::desc("Disassembler options"),53cl::cat(MCCategory));5455static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),56cl::value_desc("filename"),57cl::init("-"), cl::cat(MCCategory));5859static cl::opt<std::string> SplitDwarfFile("split-dwarf-file",60cl::desc("DWO output filename"),61cl::value_desc("filename"),62cl::cat(MCCategory));6364static cl::opt<bool> ShowEncoding("show-encoding",65cl::desc("Show instruction encodings"),66cl::cat(MCCategory));6768static cl::opt<DebugCompressionType> CompressDebugSections(69"compress-debug-sections", cl::ValueOptional,70cl::init(DebugCompressionType::None),71cl::desc("Choose DWARF debug sections compression:"),72cl::values(clEnumValN(DebugCompressionType::None, "none", "No compression"),73clEnumValN(DebugCompressionType::Zlib, "zlib", "Use zlib"),74clEnumValN(DebugCompressionType::Zstd, "zstd", "Use zstd")),75cl::cat(MCCategory));7677static cl::opt<bool>78ShowInst("show-inst", cl::desc("Show internal instruction representation"),79cl::cat(MCCategory));8081static cl::opt<bool>82ShowInstOperands("show-inst-operands",83cl::desc("Show instructions operands as parsed"),84cl::cat(MCCategory));8586static cl::opt<unsigned>87OutputAsmVariant("output-asm-variant",88cl::desc("Syntax variant to use for output printing"),89cl::cat(MCCategory));9091static cl::opt<bool>92PrintImmHex("print-imm-hex", cl::init(false),93cl::desc("Prefer hex format for immediate values"),94cl::cat(MCCategory));9596static cl::list<std::string>97DefineSymbol("defsym",98cl::desc("Defines a symbol to be an integer constant"),99cl::cat(MCCategory));100101static cl::opt<bool>102PreserveComments("preserve-comments",103cl::desc("Preserve Comments in outputted assembly"),104cl::cat(MCCategory));105106enum OutputFileType {107OFT_Null,108OFT_AssemblyFile,109OFT_ObjectFile110};111static cl::opt<OutputFileType>112FileType("filetype", cl::init(OFT_AssemblyFile),113cl::desc("Choose an output file type:"),114cl::values(clEnumValN(OFT_AssemblyFile, "asm",115"Emit an assembly ('.s') file"),116clEnumValN(OFT_Null, "null",117"Don't emit anything (for timing purposes)"),118clEnumValN(OFT_ObjectFile, "obj",119"Emit a native object ('.o') file")),120cl::cat(MCCategory));121122static cl::list<std::string> IncludeDirs("I",123cl::desc("Directory of include files"),124cl::value_desc("directory"),125cl::Prefix, cl::cat(MCCategory));126127static cl::opt<std::string>128ArchName("arch",129cl::desc("Target arch to assemble for, "130"see -version for available targets"),131cl::cat(MCCategory));132133static cl::opt<std::string>134TripleName("triple",135cl::desc("Target triple to assemble for, "136"see -version for available targets"),137cl::cat(MCCategory));138139static cl::opt<std::string>140MCPU("mcpu",141cl::desc("Target a specific cpu type (-mcpu=help for details)"),142cl::value_desc("cpu-name"), cl::init(""), cl::cat(MCCategory));143144static cl::list<std::string>145MAttrs("mattr", cl::CommaSeparated,146cl::desc("Target specific attributes (-mattr=help for details)"),147cl::value_desc("a1,+a2,-a3,..."), cl::cat(MCCategory));148149static cl::opt<bool> PIC("position-independent",150cl::desc("Position independent"), cl::init(false),151cl::cat(MCCategory));152153static cl::opt<bool>154LargeCodeModel("large-code-model",155cl::desc("Create cfi directives that assume the code might "156"be more than 2gb away"),157cl::cat(MCCategory));158159static cl::opt<bool>160NoInitialTextSection("n",161cl::desc("Don't assume assembly file starts "162"in the text section"),163cl::cat(MCCategory));164165static cl::opt<bool>166GenDwarfForAssembly("g",167cl::desc("Generate dwarf debugging info for assembly "168"source files"),169cl::cat(MCCategory));170171static cl::opt<std::string>172DebugCompilationDir("fdebug-compilation-dir",173cl::desc("Specifies the debug info's compilation dir"),174cl::cat(MCCategory));175176static cl::list<std::string> DebugPrefixMap(177"fdebug-prefix-map", cl::desc("Map file source paths in debug info"),178cl::value_desc("= separated key-value pairs"), cl::cat(MCCategory));179180static cl::opt<std::string> MainFileName(181"main-file-name",182cl::desc("Specifies the name we should consider the input file"),183cl::cat(MCCategory));184185static cl::opt<bool> LexMasmIntegers(186"masm-integers",187cl::desc("Enable binary and hex masm integers (0b110 and 0ABCh)"),188cl::cat(MCCategory));189190static cl::opt<bool> LexMasmHexFloats(191"masm-hexfloats",192cl::desc("Enable MASM-style hex float initializers (3F800000r)"),193cl::cat(MCCategory));194195static cl::opt<bool> LexMotorolaIntegers(196"motorola-integers",197cl::desc("Enable binary and hex Motorola integers (%110 and $ABC)"),198cl::cat(MCCategory));199200static cl::opt<bool> NoExecStack("no-exec-stack",201cl::desc("File doesn't need an exec stack"),202cl::cat(MCCategory));203204enum ActionType {205AC_AsLex,206AC_Assemble,207AC_Disassemble,208AC_MDisassemble,209AC_CDisassemble,210};211212static cl::opt<ActionType> Action(213cl::desc("Action to perform:"), cl::init(AC_Assemble),214cl::values(clEnumValN(AC_AsLex, "as-lex", "Lex tokens from a .s file"),215clEnumValN(AC_Assemble, "assemble",216"Assemble a .s file (default)"),217clEnumValN(AC_Disassemble, "disassemble",218"Disassemble strings of hex bytes"),219clEnumValN(AC_MDisassemble, "mdis",220"Marked up disassembly of strings of hex bytes"),221clEnumValN(AC_CDisassemble, "cdis",222"Colored disassembly of strings of hex bytes")),223cl::cat(MCCategory));224225static const Target *GetTarget(const char *ProgName) {226// Figure out the target triple.227if (TripleName.empty())228TripleName = sys::getDefaultTargetTriple();229Triple TheTriple(Triple::normalize(TripleName));230231// Get the target specific parser.232std::string Error;233const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,234Error);235if (!TheTarget) {236WithColor::error(errs(), ProgName) << Error;237return nullptr;238}239240// Update the triple name and return the found target.241TripleName = TheTriple.getTriple();242return TheTarget;243}244245static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path,246sys::fs::OpenFlags Flags) {247std::error_code EC;248auto Out = std::make_unique<ToolOutputFile>(Path, EC, Flags);249if (EC) {250WithColor::error() << EC.message() << '\n';251return nullptr;252}253254return Out;255}256257static std::string DwarfDebugFlags;258static void setDwarfDebugFlags(int argc, char **argv) {259if (!getenv("RC_DEBUG_OPTIONS"))260return;261for (int i = 0; i < argc; i++) {262DwarfDebugFlags += argv[i];263if (i + 1 < argc)264DwarfDebugFlags += " ";265}266}267268static std::string DwarfDebugProducer;269static void setDwarfDebugProducer() {270if(!getenv("DEBUG_PRODUCER"))271return;272DwarfDebugProducer += getenv("DEBUG_PRODUCER");273}274275static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI,276raw_ostream &OS) {277278AsmLexer Lexer(MAI);279Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer());280281bool Error = false;282while (Lexer.Lex().isNot(AsmToken::Eof)) {283Lexer.getTok().dump(OS);284OS << "\n";285if (Lexer.getTok().getKind() == AsmToken::Error)286Error = true;287}288289return Error;290}291292static int fillCommandLineSymbols(MCAsmParser &Parser) {293for (auto &I: DefineSymbol) {294auto Pair = StringRef(I).split('=');295auto Sym = Pair.first;296auto Val = Pair.second;297298if (Sym.empty() || Val.empty()) {299WithColor::error() << "defsym must be of the form: sym=value: " << I300<< "\n";301return 1;302}303int64_t Value;304if (Val.getAsInteger(0, Value)) {305WithColor::error() << "value is not an integer: " << Val << "\n";306return 1;307}308Parser.getContext().setSymbolValue(Parser.getStreamer(), Sym, Value);309}310return 0;311}312313static int AssembleInput(const char *ProgName, const Target *TheTarget,314SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,315MCAsmInfo &MAI, MCSubtargetInfo &STI,316MCInstrInfo &MCII, MCTargetOptions const &MCOptions) {317std::unique_ptr<MCAsmParser> Parser(318createMCAsmParser(SrcMgr, Ctx, Str, MAI));319std::unique_ptr<MCTargetAsmParser> TAP(320TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));321322if (!TAP) {323WithColor::error(errs(), ProgName)324<< "this target does not support assembly parsing.\n";325return 1;326}327328int SymbolResult = fillCommandLineSymbols(*Parser);329if(SymbolResult)330return SymbolResult;331Parser->setShowParsedOperands(ShowInstOperands);332Parser->setTargetParser(*TAP);333Parser->getLexer().setLexMasmIntegers(LexMasmIntegers);334Parser->getLexer().setLexMasmHexFloats(LexMasmHexFloats);335Parser->getLexer().setLexMotorolaIntegers(LexMotorolaIntegers);336337int Res = Parser->Run(NoInitialTextSection);338339return Res;340}341342int main(int argc, char **argv) {343InitLLVM X(argc, argv);344345// Initialize targets and assembly printers/parsers.346llvm::InitializeAllTargetInfos();347llvm::InitializeAllTargetMCs();348llvm::InitializeAllAsmParsers();349llvm::InitializeAllDisassemblers();350351// Register the target printer for --version.352cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);353354cl::HideUnrelatedOptions({&MCCategory, &getColorCategory()});355cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");356MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();357MCOptions.CompressDebugSections = CompressDebugSections.getValue();358MCOptions.ShowMCInst = ShowInst;359MCOptions.AsmVerbose = true;360MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory;361362setDwarfDebugFlags(argc, argv);363setDwarfDebugProducer();364365const char *ProgName = argv[0];366const Target *TheTarget = GetTarget(ProgName);367if (!TheTarget)368return 1;369// Now that GetTarget() has (potentially) replaced TripleName, it's safe to370// construct the Triple object.371Triple TheTriple(TripleName);372373ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr =374MemoryBuffer::getFileOrSTDIN(InputFilename, /*IsText=*/true);375if (std::error_code EC = BufferPtr.getError()) {376WithColor::error(errs(), ProgName)377<< InputFilename << ": " << EC.message() << '\n';378return 1;379}380MemoryBuffer *Buffer = BufferPtr->get();381382SourceMgr SrcMgr;383384// Tell SrcMgr about this buffer, which is what the parser will pick up.385SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc());386387// Record the location of the include directories so that the lexer can find388// it later.389SrcMgr.setIncludeDirs(IncludeDirs);390391std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));392assert(MRI && "Unable to create target register info!");393394std::unique_ptr<MCAsmInfo> MAI(395TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));396assert(MAI && "Unable to create target asm info!");397398if (CompressDebugSections != DebugCompressionType::None) {399if (const char *Reason = compression::getReasonIfUnsupported(400compression::formatFor(CompressDebugSections))) {401WithColor::error(errs(), ProgName)402<< "--compress-debug-sections: " << Reason;403return 1;404}405}406MAI->setPreserveAsmComments(PreserveComments);407408// Package up features to be passed to target/subtarget409std::string FeaturesStr;410if (MAttrs.size()) {411SubtargetFeatures Features;412for (unsigned i = 0; i != MAttrs.size(); ++i)413Features.AddFeature(MAttrs[i]);414FeaturesStr = Features.getString();415}416417std::unique_ptr<MCSubtargetInfo> STI(418TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));419assert(STI && "Unable to create subtarget info!");420421// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and422// MCObjectFileInfo needs a MCContext reference in order to initialize itself.423MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), &SrcMgr,424&MCOptions);425std::unique_ptr<MCObjectFileInfo> MOFI(426TheTarget->createMCObjectFileInfo(Ctx, PIC, LargeCodeModel));427Ctx.setObjectFileInfo(MOFI.get());428429Ctx.setGenDwarfForAssembly(GenDwarfForAssembly);430// Default to 4 for dwarf version.431unsigned DwarfVersion = MCOptions.DwarfVersion ? MCOptions.DwarfVersion : 4;432if (DwarfVersion < 2 || DwarfVersion > 5) {433errs() << ProgName << ": Dwarf version " << DwarfVersion434<< " is not supported." << '\n';435return 1;436}437Ctx.setDwarfVersion(DwarfVersion);438if (MCOptions.Dwarf64) {439// The 64-bit DWARF format was introduced in DWARFv3.440if (DwarfVersion < 3) {441errs() << ProgName442<< ": the 64-bit DWARF format is not supported for DWARF versions "443"prior to 3\n";444return 1;445}446// 32-bit targets don't support DWARF64, which requires 64-bit relocations.447if (MAI->getCodePointerSize() < 8) {448errs() << ProgName449<< ": the 64-bit DWARF format is only supported for 64-bit "450"targets\n";451return 1;452}453// If needsDwarfSectionOffsetDirective is true, we would eventually call454// MCStreamer::emitSymbolValue() with IsSectionRelative = true, but that455// is supported only for 4-byte long references.456if (MAI->needsDwarfSectionOffsetDirective()) {457errs() << ProgName << ": the 64-bit DWARF format is not supported for "458<< TheTriple.normalize() << "\n";459return 1;460}461Ctx.setDwarfFormat(dwarf::DWARF64);462}463if (!DwarfDebugFlags.empty())464Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags));465if (!DwarfDebugProducer.empty())466Ctx.setDwarfDebugProducer(StringRef(DwarfDebugProducer));467if (!DebugCompilationDir.empty())468Ctx.setCompilationDir(DebugCompilationDir);469else {470// If no compilation dir is set, try to use the current directory.471SmallString<128> CWD;472if (!sys::fs::current_path(CWD))473Ctx.setCompilationDir(CWD);474}475for (const auto &Arg : DebugPrefixMap) {476const auto &KV = StringRef(Arg).split('=');477Ctx.addDebugPrefixMapEntry(std::string(KV.first), std::string(KV.second));478}479if (!MainFileName.empty())480Ctx.setMainFileName(MainFileName);481if (GenDwarfForAssembly)482Ctx.setGenDwarfRootFile(InputFilename, Buffer->getBuffer());483484sys::fs::OpenFlags Flags = (FileType == OFT_AssemblyFile)485? sys::fs::OF_TextWithCRLF486: sys::fs::OF_None;487std::unique_ptr<ToolOutputFile> Out = GetOutputStream(OutputFilename, Flags);488if (!Out)489return 1;490491std::unique_ptr<ToolOutputFile> DwoOut;492if (!SplitDwarfFile.empty()) {493if (FileType != OFT_ObjectFile) {494WithColor::error() << "dwo output only supported with object files\n";495return 1;496}497DwoOut = GetOutputStream(SplitDwarfFile, sys::fs::OF_None);498if (!DwoOut)499return 1;500}501502std::unique_ptr<buffer_ostream> BOS;503raw_pwrite_stream *OS = &Out->os();504std::unique_ptr<MCStreamer> Str;505506std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());507assert(MCII && "Unable to create instruction info!");508509MCInstPrinter *IP = nullptr;510if (FileType == OFT_AssemblyFile) {511IP = TheTarget->createMCInstPrinter(Triple(TripleName), OutputAsmVariant,512*MAI, *MCII, *MRI);513514if (!IP) {515WithColor::error()516<< "unable to create instruction printer for target triple '"517<< TheTriple.normalize() << "' with assembly variant "518<< OutputAsmVariant << ".\n";519return 1;520}521522for (StringRef Opt : DisassemblerOptions)523if (!IP->applyTargetSpecificCLOption(Opt)) {524WithColor::error() << "invalid disassembler option '" << Opt << "'\n";525return 1;526}527528// Set the display preference for hex vs. decimal immediates.529IP->setPrintImmHex(PrintImmHex);530531// Set up the AsmStreamer.532std::unique_ptr<MCCodeEmitter> CE;533if (ShowEncoding)534CE.reset(TheTarget->createMCCodeEmitter(*MCII, Ctx));535536std::unique_ptr<MCAsmBackend> MAB(537TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));538auto FOut = std::make_unique<formatted_raw_ostream>(*OS);539Str.reset(TheTarget->createAsmStreamer(Ctx, std::move(FOut), IP,540std::move(CE), std::move(MAB)));541542} else if (FileType == OFT_Null) {543Str.reset(TheTarget->createNullStreamer(Ctx));544} else {545assert(FileType == OFT_ObjectFile && "Invalid file type!");546547if (!Out->os().supportsSeeking()) {548BOS = std::make_unique<buffer_ostream>(Out->os());549OS = BOS.get();550}551552MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, Ctx);553MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions);554Str.reset(TheTarget->createMCObjectStreamer(555TheTriple, Ctx, std::unique_ptr<MCAsmBackend>(MAB),556DwoOut ? MAB->createDwoObjectWriter(*OS, DwoOut->os())557: MAB->createObjectWriter(*OS),558std::unique_ptr<MCCodeEmitter>(CE), *STI));559if (NoExecStack)560Str->initSections(true, *STI);561}562563int Res = 1;564bool disassemble = false;565switch (Action) {566case AC_AsLex:567Res = AsLexInput(SrcMgr, *MAI, Out->os());568break;569case AC_Assemble:570Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI,571*MCII, MCOptions);572break;573case AC_MDisassemble:574IP->setUseMarkup(true);575disassemble = true;576break;577case AC_CDisassemble:578IP->setUseColor(true);579disassemble = true;580break;581case AC_Disassemble:582disassemble = true;583break;584}585if (disassemble)586Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, *Buffer,587SrcMgr, Ctx, MCOptions);588589// Keep output if no errors.590if (Res == 0) {591Out->keep();592if (DwoOut)593DwoOut->keep();594}595return Res;596}597598599