llvm-mc.cpp revision 4445215622598c5c95cccf38ee2f89ec5f203cb8
1//===-- llvm-mc.cpp - Machine Code Hacking Driver -------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This utility is a simple driver that allows command line hacking on machine
11// code.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/MC/MCParser/AsmLexer.h"
16#include "llvm/MC/MCParser/MCAsmLexer.h"
17#include "llvm/MC/MCAsmBackend.h"
18#include "llvm/MC/MCContext.h"
19#include "llvm/MC/MCCodeEmitter.h"
20#include "llvm/MC/MCInstPrinter.h"
21#include "llvm/MC/MCInstrInfo.h"
22#include "llvm/MC/MCObjectFileInfo.h"
23#include "llvm/MC/MCRegisterInfo.h"
24#include "llvm/MC/MCSectionMachO.h"
25#include "llvm/MC/MCStreamer.h"
26#include "llvm/MC/MCSubtargetInfo.h"
27#include "llvm/MC/MCTargetAsmParser.h"
28#include "llvm/MC/SubtargetFeature.h"
29#include "llvm/ADT/OwningPtr.h"
30#include "llvm/Support/CommandLine.h"
31#include "llvm/Support/FileUtilities.h"
32#include "llvm/Support/FormattedStream.h"
33#include "llvm/Support/ManagedStatic.h"
34#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/PrettyStackTrace.h"
36#include "llvm/Support/SourceMgr.h"
37#include "llvm/Support/ToolOutputFile.h"
38#include "llvm/Support/Host.h"
39#include "llvm/Support/Signals.h"
40#include "llvm/Support/TargetRegistry.h"
41#include "llvm/Support/TargetSelect.h"
42#include "llvm/Support/system_error.h"
43#include "Disassembler.h"
44using namespace llvm;
45
46static cl::opt<std::string>
47InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
48
49static cl::opt<std::string>
50OutputFilename("o", cl::desc("Output filename"),
51               cl::value_desc("filename"));
52
53static cl::opt<bool>
54ShowEncoding("show-encoding", cl::desc("Show instruction encodings"));
55
56static cl::opt<bool>
57ShowInst("show-inst", cl::desc("Show internal instruction representation"));
58
59static cl::opt<bool>
60ShowInstOperands("show-inst-operands",
61                 cl::desc("Show instructions operands as parsed"));
62
63static cl::opt<unsigned>
64OutputAsmVariant("output-asm-variant",
65                 cl::desc("Syntax variant to use for output printing"));
66
67static cl::opt<bool>
68RelaxAll("mc-relax-all", cl::desc("Relax all fixups"));
69
70static cl::opt<bool>
71NoExecStack("mc-no-exec-stack", cl::desc("File doesn't need an exec stack"));
72
73enum OutputFileType {
74  OFT_Null,
75  OFT_AssemblyFile,
76  OFT_ObjectFile
77};
78static cl::opt<OutputFileType>
79FileType("filetype", cl::init(OFT_AssemblyFile),
80  cl::desc("Choose an output file type:"),
81  cl::values(
82       clEnumValN(OFT_AssemblyFile, "asm",
83                  "Emit an assembly ('.s') file"),
84       clEnumValN(OFT_Null, "null",
85                  "Don't emit anything (for timing purposes)"),
86       clEnumValN(OFT_ObjectFile, "obj",
87                  "Emit a native object ('.o') file"),
88       clEnumValEnd));
89
90static cl::list<std::string>
91IncludeDirs("I", cl::desc("Directory of include files"),
92            cl::value_desc("directory"), cl::Prefix);
93
94static cl::opt<std::string>
95ArchName("arch", cl::desc("Target arch to assemble for, "
96                          "see -version for available targets"));
97
98static cl::opt<std::string>
99TripleName("triple", cl::desc("Target triple to assemble for, "
100                              "see -version for available targets"));
101
102static cl::opt<std::string>
103MCPU("mcpu",
104     cl::desc("Target a specific cpu type (-mcpu=help for details)"),
105     cl::value_desc("cpu-name"),
106     cl::init(""));
107
108static cl::list<std::string>
109MAttrs("mattr",
110  cl::CommaSeparated,
111  cl::desc("Target specific attributes (-mattr=help for details)"),
112  cl::value_desc("a1,+a2,-a3,..."));
113
114static cl::opt<Reloc::Model>
115RelocModel("relocation-model",
116             cl::desc("Choose relocation model"),
117             cl::init(Reloc::Default),
118             cl::values(
119            clEnumValN(Reloc::Default, "default",
120                       "Target default relocation model"),
121            clEnumValN(Reloc::Static, "static",
122                       "Non-relocatable code"),
123            clEnumValN(Reloc::PIC_, "pic",
124                       "Fully relocatable, position independent code"),
125            clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
126                       "Relocatable external references, non-relocatable code"),
127            clEnumValEnd));
128
129static cl::opt<llvm::CodeModel::Model>
130CMModel("code-model",
131        cl::desc("Choose code model"),
132        cl::init(CodeModel::Default),
133        cl::values(clEnumValN(CodeModel::Default, "default",
134                              "Target default code model"),
135                   clEnumValN(CodeModel::Small, "small",
136                              "Small code model"),
137                   clEnumValN(CodeModel::Kernel, "kernel",
138                              "Kernel code model"),
139                   clEnumValN(CodeModel::Medium, "medium",
140                              "Medium code model"),
141                   clEnumValN(CodeModel::Large, "large",
142                              "Large code model"),
143                   clEnumValEnd));
144
145static cl::opt<bool>
146NoInitialTextSection("n", cl::desc("Don't assume assembly file starts "
147                                   "in the text section"));
148
149static cl::opt<bool>
150SaveTempLabels("L", cl::desc("Don't discard temporary labels"));
151
152static cl::opt<bool>
153GenDwarfForAssembly("g", cl::desc("Generate dwarf debugging info for assembly "
154                                  "source files"));
155
156enum ActionType {
157  AC_AsLex,
158  AC_Assemble,
159  AC_Disassemble,
160  AC_EDisassemble
161};
162
163static cl::opt<ActionType>
164Action(cl::desc("Action to perform:"),
165       cl::init(AC_Assemble),
166       cl::values(clEnumValN(AC_AsLex, "as-lex",
167                             "Lex tokens from a .s file"),
168                  clEnumValN(AC_Assemble, "assemble",
169                             "Assemble a .s file (default)"),
170                  clEnumValN(AC_Disassemble, "disassemble",
171                             "Disassemble strings of hex bytes"),
172                  clEnumValN(AC_EDisassemble, "edis",
173                             "Enhanced disassembly of strings of hex bytes"),
174                  clEnumValEnd));
175
176static const Target *GetTarget(const char *ProgName) {
177  // Figure out the target triple.
178  if (TripleName.empty())
179    TripleName = sys::getDefaultTargetTriple();
180  Triple TheTriple(Triple::normalize(TripleName));
181
182  const Target *TheTarget = 0;
183  if (!ArchName.empty()) {
184    for (TargetRegistry::iterator it = TargetRegistry::begin(),
185           ie = TargetRegistry::end(); it != ie; ++it) {
186      if (ArchName == it->getName()) {
187        TheTarget = &*it;
188        break;
189      }
190    }
191
192    if (!TheTarget) {
193      errs() << ProgName << ": error: invalid target '" << ArchName << "'.\n";
194      return 0;
195    }
196
197    // Adjust the triple to match (if known), otherwise stick with the
198    // module/host triple.
199    Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName);
200    if (Type != Triple::UnknownArch)
201      TheTriple.setArch(Type);
202  } else {
203    // Get the target specific parser.
204    std::string Error;
205    TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
206    if (TheTarget == 0) {
207      errs() << ProgName << ": error: unable to get target for '"
208             << TheTriple.getTriple()
209             << "', see --version and --triple.\n";
210      return 0;
211    }
212  }
213
214  TripleName = TheTriple.getTriple();
215  return TheTarget;
216}
217
218static tool_output_file *GetOutputStream() {
219  if (OutputFilename == "")
220    OutputFilename = "-";
221
222  std::string Err;
223  tool_output_file *Out = new tool_output_file(OutputFilename.c_str(), Err,
224                                               raw_fd_ostream::F_Binary);
225  if (!Err.empty()) {
226    errs() << Err << '\n';
227    delete Out;
228    return 0;
229  }
230
231  return Out;
232}
233
234static std::string DwarfDebugFlags;
235static void setDwarfDebugFlags(int argc, char **argv) {
236  if (!getenv("RC_DEBUG_OPTIONS"))
237    return;
238  for (int i = 0; i < argc; i++) {
239    DwarfDebugFlags += argv[i];
240    if (i + 1 < argc)
241      DwarfDebugFlags += " ";
242  }
243}
244
245static int AsLexInput(const char *ProgName) {
246  OwningPtr<MemoryBuffer> BufferPtr;
247  if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) {
248    errs() << ProgName << ": " << ec.message() << '\n';
249    return 1;
250  }
251  MemoryBuffer *Buffer = BufferPtr.take();
252
253  SourceMgr SrcMgr;
254
255  // Tell SrcMgr about this buffer, which is what TGParser will pick up.
256  SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
257
258  // Record the location of the include directories so that the lexer can find
259  // it later.
260  SrcMgr.setIncludeDirs(IncludeDirs);
261
262  const Target *TheTarget = GetTarget(ProgName);
263  if (!TheTarget)
264    return 1;
265
266  llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName));
267  assert(MAI && "Unable to create target asm info!");
268
269  AsmLexer Lexer(*MAI);
270  Lexer.setBuffer(SrcMgr.getMemoryBuffer(0));
271
272  OwningPtr<tool_output_file> Out(GetOutputStream());
273  if (!Out)
274    return 1;
275
276  bool Error = false;
277  while (Lexer.Lex().isNot(AsmToken::Eof)) {
278    AsmToken Tok = Lexer.getTok();
279
280    switch (Tok.getKind()) {
281    default:
282      SrcMgr.PrintMessage(Lexer.getLoc(), SourceMgr::DK_Warning,
283                          "unknown token");
284      Error = true;
285      break;
286    case AsmToken::Error:
287      Error = true; // error already printed.
288      break;
289    case AsmToken::Identifier:
290      Out->os() << "identifier: " << Lexer.getTok().getString();
291      break;
292    case AsmToken::Integer:
293      Out->os() << "int: " << Lexer.getTok().getString();
294      break;
295    case AsmToken::Real:
296      Out->os() << "real: " << Lexer.getTok().getString();
297      break;
298    case AsmToken::Register:
299      Out->os() << "register: " << Lexer.getTok().getRegVal();
300      break;
301    case AsmToken::String:
302      Out->os() << "string: " << Lexer.getTok().getString();
303      break;
304
305    case AsmToken::Amp:            Out->os() << "Amp"; break;
306    case AsmToken::AmpAmp:         Out->os() << "AmpAmp"; break;
307    case AsmToken::At:             Out->os() << "At"; break;
308    case AsmToken::Caret:          Out->os() << "Caret"; break;
309    case AsmToken::Colon:          Out->os() << "Colon"; break;
310    case AsmToken::Comma:          Out->os() << "Comma"; break;
311    case AsmToken::Dollar:         Out->os() << "Dollar"; break;
312    case AsmToken::Dot:            Out->os() << "Dot"; break;
313    case AsmToken::EndOfStatement: Out->os() << "EndOfStatement"; break;
314    case AsmToken::Eof:            Out->os() << "Eof"; break;
315    case AsmToken::Equal:          Out->os() << "Equal"; break;
316    case AsmToken::EqualEqual:     Out->os() << "EqualEqual"; break;
317    case AsmToken::Exclaim:        Out->os() << "Exclaim"; break;
318    case AsmToken::ExclaimEqual:   Out->os() << "ExclaimEqual"; break;
319    case AsmToken::Greater:        Out->os() << "Greater"; break;
320    case AsmToken::GreaterEqual:   Out->os() << "GreaterEqual"; break;
321    case AsmToken::GreaterGreater: Out->os() << "GreaterGreater"; break;
322    case AsmToken::Hash:           Out->os() << "Hash"; break;
323    case AsmToken::LBrac:          Out->os() << "LBrac"; break;
324    case AsmToken::LCurly:         Out->os() << "LCurly"; break;
325    case AsmToken::LParen:         Out->os() << "LParen"; break;
326    case AsmToken::Less:           Out->os() << "Less"; break;
327    case AsmToken::LessEqual:      Out->os() << "LessEqual"; break;
328    case AsmToken::LessGreater:    Out->os() << "LessGreater"; break;
329    case AsmToken::LessLess:       Out->os() << "LessLess"; break;
330    case AsmToken::Minus:          Out->os() << "Minus"; break;
331    case AsmToken::Percent:        Out->os() << "Percent"; break;
332    case AsmToken::Pipe:           Out->os() << "Pipe"; break;
333    case AsmToken::PipePipe:       Out->os() << "PipePipe"; break;
334    case AsmToken::Plus:           Out->os() << "Plus"; break;
335    case AsmToken::RBrac:          Out->os() << "RBrac"; break;
336    case AsmToken::RCurly:         Out->os() << "RCurly"; break;
337    case AsmToken::RParen:         Out->os() << "RParen"; break;
338    case AsmToken::Slash:          Out->os() << "Slash"; break;
339    case AsmToken::Star:           Out->os() << "Star"; break;
340    case AsmToken::Tilde:          Out->os() << "Tilde"; break;
341    }
342
343    // Print the token string.
344    Out->os() << " (\"";
345    Out->os().write_escaped(Tok.getString());
346    Out->os() << "\")\n";
347  }
348
349  // Keep output if no errors.
350  if (Error == 0) Out->keep();
351
352  return Error;
353}
354
355static int AssembleInput(const char *ProgName) {
356  const Target *TheTarget = GetTarget(ProgName);
357  if (!TheTarget)
358    return 1;
359
360  OwningPtr<MemoryBuffer> BufferPtr;
361  if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) {
362    errs() << ProgName << ": " << ec.message() << '\n';
363    return 1;
364  }
365  MemoryBuffer *Buffer = BufferPtr.take();
366
367  SourceMgr SrcMgr;
368
369  // Tell SrcMgr about this buffer, which is what the parser will pick up.
370  SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
371
372  // Record the location of the include directories so that the lexer can find
373  // it later.
374  SrcMgr.setIncludeDirs(IncludeDirs);
375
376
377  llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName));
378  assert(MAI && "Unable to create target asm info!");
379
380  llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
381  assert(MRI && "Unable to create target register info!");
382
383  // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
384  // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
385  OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
386  MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
387  MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx);
388
389  if (SaveTempLabels)
390    Ctx.setAllowTemporaryLabels(false);
391
392  Ctx.setGenDwarfForAssembly(GenDwarfForAssembly);
393  if (!DwarfDebugFlags.empty())
394    Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags));
395
396  // Package up features to be passed to target/subtarget
397  std::string FeaturesStr;
398  if (MAttrs.size()) {
399    SubtargetFeatures Features;
400    for (unsigned i = 0; i != MAttrs.size(); ++i)
401      Features.AddFeature(MAttrs[i]);
402    FeaturesStr = Features.getString();
403  }
404
405  OwningPtr<tool_output_file> Out(GetOutputStream());
406  if (!Out)
407    return 1;
408
409  formatted_raw_ostream FOS(Out->os());
410  OwningPtr<MCStreamer> Str;
411
412  OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
413  OwningPtr<MCSubtargetInfo>
414    STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));
415
416  // FIXME: There is a bit of code duplication with addPassesToEmitFile.
417  if (FileType == OFT_AssemblyFile) {
418    MCInstPrinter *IP =
419      TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *MRI, *STI);
420    MCCodeEmitter *CE = 0;
421    MCAsmBackend *MAB = 0;
422    if (ShowEncoding) {
423      CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
424      MAB = TheTarget->createMCAsmBackend(TripleName);
425    }
426    Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true,
427                                           /*useLoc*/ true,
428                                           /*useCFI*/ true,
429                                           /*useDwarfDirectory*/ true,
430                                           IP, CE, MAB, ShowInst));
431
432  } else if (FileType == OFT_Null) {
433    Str.reset(createNullStreamer(Ctx));
434  } else {
435    assert(FileType == OFT_ObjectFile && "Invalid file type!");
436    MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
437    MCAsmBackend *MAB = TheTarget->createMCAsmBackend(TripleName);
438    Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB,
439                                                FOS, CE, RelaxAll,
440                                                NoExecStack));
441  }
442
443  OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx,
444                                                  *Str.get(), *MAI));
445  OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser));
446  if (!TAP) {
447    errs() << ProgName
448           << ": error: this target does not support assembly parsing.\n";
449    return 1;
450  }
451
452  Parser->setShowParsedOperands(ShowInstOperands);
453  Parser->setTargetParser(*TAP.get());
454
455  int Res = Parser->Run(NoInitialTextSection);
456
457  // Keep output if no errors.
458  if (Res == 0) Out->keep();
459
460  return Res;
461}
462
463static int DisassembleInput(const char *ProgName, bool Enhanced) {
464  const Target *TheTarget = GetTarget(ProgName);
465  if (!TheTarget)
466    return 0;
467
468  OwningPtr<MemoryBuffer> Buffer;
469  if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, Buffer)) {
470    errs() << ProgName << ": " << ec.message() << '\n';
471    return 1;
472  }
473
474  OwningPtr<tool_output_file> Out(GetOutputStream());
475  if (!Out)
476    return 1;
477
478  int Res;
479  if (Enhanced) {
480    Res =
481      Disassembler::disassembleEnhanced(TripleName, *Buffer.take(), Out->os());
482  } else {
483    // Package up features to be passed to target/subtarget
484    std::string FeaturesStr;
485    if (MAttrs.size()) {
486      SubtargetFeatures Features;
487      for (unsigned i = 0; i != MAttrs.size(); ++i)
488        Features.AddFeature(MAttrs[i]);
489      FeaturesStr = Features.getString();
490    }
491
492    Res = Disassembler::disassemble(*TheTarget, TripleName, MCPU, FeaturesStr,
493                                    *Buffer.take(), Out->os());
494  }
495
496  // Keep output if no errors.
497  if (Res == 0) Out->keep();
498
499  return Res;
500}
501
502
503int main(int argc, char **argv) {
504  // Print a stack trace if we signal out.
505  sys::PrintStackTraceOnErrorSignal();
506  PrettyStackTraceProgram X(argc, argv);
507  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
508
509  // Initialize targets and assembly printers/parsers.
510  llvm::InitializeAllTargetInfos();
511  llvm::InitializeAllTargetMCs();
512  llvm::InitializeAllAsmParsers();
513  llvm::InitializeAllDisassemblers();
514
515  // Register the target printer for --version.
516  cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
517
518  cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
519  TripleName = Triple::normalize(TripleName);
520  setDwarfDebugFlags(argc, argv);
521
522  switch (Action) {
523  case AC_AsLex:
524    return AsLexInput(argv[0]);
525  case AC_Assemble:
526    return AssembleInput(argv[0]);
527  case AC_Disassemble:
528    return DisassembleInput(argv[0], false);
529  case AC_EDisassemble:
530    return DisassembleInput(argv[0], true);
531  }
532}
533