[llvm] r332875 - MC: Introduce an ELF dwo object writer and teach llvm-mc about it.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Mon May 21 12:44:54 PDT 2018


Author: pcc
Date: Mon May 21 12:44:54 2018
New Revision: 332875

URL: http://llvm.org/viewvc/llvm-project?rev=332875&view=rev
Log:
MC: Introduce an ELF dwo object writer and teach llvm-mc about it.

Part of PR37466.

Differential Revision: https://reviews.llvm.org/D47051

Added:
    llvm/trunk/test/MC/ELF/dwo-restrict-relocs.s
    llvm/trunk/test/MC/ELF/dwo-sections.s
Modified:
    llvm/trunk/include/llvm/MC/MCAsmBackend.h
    llvm/trunk/include/llvm/MC/MCELFObjectWriter.h
    llvm/trunk/lib/MC/ELFObjectWriter.cpp
    llvm/trunk/lib/MC/MCAsmBackend.cpp
    llvm/trunk/tools/llvm-mc/llvm-mc.cpp

Modified: llvm/trunk/include/llvm/MC/MCAsmBackend.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCAsmBackend.h?rev=332875&r1=332874&r2=332875&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCAsmBackend.h (original)
+++ llvm/trunk/include/llvm/MC/MCAsmBackend.h Mon May 21 12:44:54 2018
@@ -60,6 +60,12 @@ public:
   std::unique_ptr<MCObjectWriter>
   createObjectWriter(raw_pwrite_stream &OS) const;
 
+  /// Create an MCObjectWriter that writes two object files: a .o file which is
+  /// linked into the final program and a .dwo file which is used by debuggers.
+  /// This function is only supported with ELF targets.
+  std::unique_ptr<MCObjectWriter>
+  createDwoObjectWriter(raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS) const;
+
   virtual std::unique_ptr<MCObjectTargetWriter>
   createObjectTargetWriter() const = 0;
 

Modified: llvm/trunk/include/llvm/MC/MCELFObjectWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCELFObjectWriter.h?rev=332875&r1=332874&r2=332875&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCELFObjectWriter.h (original)
+++ llvm/trunk/include/llvm/MC/MCELFObjectWriter.h Mon May 21 12:44:54 2018
@@ -147,6 +147,11 @@ std::unique_ptr<MCObjectWriter>
 createELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
                       raw_pwrite_stream &OS, bool IsLittleEndian);
 
+std::unique_ptr<MCObjectWriter>
+createELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
+                         raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
+                         bool IsLittleEndian);
+
 } // end namespace llvm
 
 #endif // LLVM_MC_MCELFOBJECTWRITER_H

Modified: llvm/trunk/lib/MC/ELFObjectWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/ELFObjectWriter.cpp?rev=332875&r1=332874&r2=332875&view=diff
==============================================================================
--- llvm/trunk/lib/MC/ELFObjectWriter.cpp (original)
+++ llvm/trunk/lib/MC/ELFObjectWriter.cpp Mon May 21 12:44:54 2018
@@ -70,6 +70,10 @@ using SectionIndexMapTy = DenseMap<const
 class ELFObjectWriter;
 struct ELFWriter;
 
+bool isDwoSection(const MCSectionELF &Sec) {
+  return Sec.getSectionName().endswith(".dwo");
+}
+
 class SymbolTableWriter {
   ELFWriter &EWriter;
   bool Is64Bit;
@@ -97,6 +101,12 @@ struct ELFWriter {
   ELFObjectWriter &OWriter;
   support::endian::Writer W;
 
+  enum DwoMode {
+    AllSections,
+    NonDwoOnly,
+    DwoOnly,
+  } Mode;
+
   static uint64_t SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout);
   static bool isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol,
                          bool Used, bool Renamed);
@@ -152,9 +162,9 @@ struct ELFWriter {
 
 public:
   ELFWriter(ELFObjectWriter &OWriter, raw_pwrite_stream &OS,
-            bool IsLittleEndian)
+            bool IsLittleEndian, DwoMode Mode)
       : OWriter(OWriter),
-        W(OS, IsLittleEndian ? support::little : support::big) {}
+        W(OS, IsLittleEndian ? support::little : support::big), Mode(Mode) {}
 
   void WriteWord(uint64_t Word) {
     if (is64Bit())
@@ -244,6 +254,12 @@ public:
                                               const MCFragment &FB, bool InSet,
                                               bool IsPCRel) const override;
 
+  virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc,
+                               const MCSectionELF *From,
+                               const MCSectionELF *To) {
+    return true;
+  }
+
   void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
                         const MCFragment *Fragment, const MCFixup &Fixup,
                         MCValue Target, uint64_t &FixedValue) override;
@@ -265,7 +281,44 @@ public:
         IsLittleEndian(IsLittleEndian) {}
 
   uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override {
-    return ELFWriter(*this, OS, IsLittleEndian).writeObject(Asm, Layout);
+    return ELFWriter(*this, OS, IsLittleEndian, ELFWriter::AllSections)
+        .writeObject(Asm, Layout);
+  }
+
+  friend struct ELFWriter;
+};
+
+class ELFDwoObjectWriter : public ELFObjectWriter {
+  raw_pwrite_stream &OS, &DwoOS;
+  bool IsLittleEndian;
+
+public:
+  ELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
+                     raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
+                     bool IsLittleEndian)
+      : ELFObjectWriter(std::move(MOTW)), OS(OS), DwoOS(DwoOS),
+        IsLittleEndian(IsLittleEndian) {}
+
+  virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc,
+                               const MCSectionELF *From,
+                               const MCSectionELF *To) override {
+    if (isDwoSection(*From)) {
+      Ctx.reportError(Loc, "A dwo section may not contain relocations");
+      return false;
+    }
+    if (To && isDwoSection(*To)) {
+      Ctx.reportError(Loc, "A relocation may not refer to a dwo section");
+      return false;
+    }
+    return true;
+  }
+
+  uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override {
+    uint64_t Size = ELFWriter(*this, OS, IsLittleEndian, ELFWriter::NonDwoOnly)
+                        .writeObject(Asm, Layout);
+    Size += ELFWriter(*this, DwoOS, IsLittleEndian, ELFWriter::DwoOnly)
+                .writeObject(Asm, Layout);
+    return Size;
   }
 };
 
@@ -604,6 +657,8 @@ void ELFWriter::computeSymbolTable(
     } else {
       const MCSectionELF &Section =
           static_cast<const MCSectionELF &>(Symbol.getSection());
+      if (Mode == NonDwoOnly && isDwoSection(Section))
+        continue;
       MSD.SectionIndex = SectionIndexMap.lookup(&Section);
       assert(MSD.SectionIndex && "Invalid section index!");
       if (MSD.SectionIndex >= ELF::SHN_LORESERVE)
@@ -995,6 +1050,10 @@ uint64_t ELFWriter::writeObject(MCAssemb
   std::vector<MCSectionELF *> Relocations;
   for (MCSection &Sec : Asm) {
     MCSectionELF &Section = static_cast<MCSectionELF &>(Sec);
+    if (Mode == NonDwoOnly && isDwoSection(Section))
+      continue;
+    if (Mode == DwoOnly && !isDwoSection(Section))
+      continue;
 
     align(Section.getAlignment());
 
@@ -1050,20 +1109,27 @@ uint64_t ELFWriter::writeObject(MCAssemb
     SectionOffsets[Group] = std::make_pair(SecStart, SecEnd);
   }
 
-  // Compute symbol table information.
-  computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap, SectionOffsets);
+  if (Mode == DwoOnly) {
+    // dwo files don't have symbol tables or relocations, but they do have
+    // string tables.
+    StrTabBuilder.finalize();
+  } else {
+    // Compute symbol table information.
+    computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap,
+                       SectionOffsets);
 
-  for (MCSectionELF *RelSection : Relocations) {
-    align(RelSection->getAlignment());
+    for (MCSectionELF *RelSection : Relocations) {
+      align(RelSection->getAlignment());
 
-    // Remember the offset into the file for this section.
-    uint64_t SecStart = W.OS.tell();
+      // Remember the offset into the file for this section.
+      uint64_t SecStart = W.OS.tell();
 
-    writeRelocations(Asm,
-                     cast<MCSectionELF>(*RelSection->getAssociatedSection()));
+      writeRelocations(Asm,
+                       cast<MCSectionELF>(*RelSection->getAssociatedSection()));
 
-    uint64_t SecEnd = W.OS.tell();
-    SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd);
+      uint64_t SecEnd = W.OS.tell();
+      SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd);
+    }
   }
 
   {
@@ -1336,9 +1402,13 @@ void ELFObjectWriter::recordRelocation(M
 
   FixedValue = C;
 
+  const MCSectionELF *SecA = (SymA && SymA->isInSection())
+                                 ? cast<MCSectionELF>(&SymA->getSection())
+                                 : nullptr;
+  if (!checkRelocation(Ctx, Fixup.getLoc(), &FixupSection, SecA))
+    return;
+
   if (!RelocateWithSymbol) {
-    const MCSection *SecA =
-        (SymA && !SymA->isUndefined()) ? &SymA->getSection() : nullptr;
     const auto *SectionSymbol =
         SecA ? cast<MCSymbolELF>(SecA->getBeginSymbol()) : nullptr;
     if (SectionSymbol)
@@ -1383,3 +1453,11 @@ llvm::createELFObjectWriter(std::unique_
   return llvm::make_unique<ELFSingleObjectWriter>(std::move(MOTW), OS,
                                                   IsLittleEndian);
 }
+
+std::unique_ptr<MCObjectWriter>
+llvm::createELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
+                               raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
+                               bool IsLittleEndian) {
+  return llvm::make_unique<ELFDwoObjectWriter>(std::move(MOTW), OS, DwoOS,
+                                               IsLittleEndian);
+}

Modified: llvm/trunk/lib/MC/MCAsmBackend.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAsmBackend.cpp?rev=332875&r1=332874&r2=332875&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCAsmBackend.cpp (original)
+++ llvm/trunk/lib/MC/MCAsmBackend.cpp Mon May 21 12:44:54 2018
@@ -49,6 +49,16 @@ MCAsmBackend::createObjectWriter(raw_pwr
   }
 }
 
+std::unique_ptr<MCObjectWriter>
+MCAsmBackend::createDwoObjectWriter(raw_pwrite_stream &OS,
+                                    raw_pwrite_stream &DwoOS) const {
+  auto TW = createObjectTargetWriter();
+  if (TW->getFormat() != Triple::ELF)
+    report_fatal_error("dwo only supported with ELF");
+  return createELFDwoObjectWriter(cast<MCELFObjectTargetWriter>(std::move(TW)),
+                                  OS, DwoOS, Endian == support::little);
+}
+
 Optional<MCFixupKind> MCAsmBackend::getFixupKind(StringRef Name) const {
   return None;
 }

Added: llvm/trunk/test/MC/ELF/dwo-restrict-relocs.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ELF/dwo-restrict-relocs.s?rev=332875&view=auto
==============================================================================
--- llvm/trunk/test/MC/ELF/dwo-restrict-relocs.s (added)
+++ llvm/trunk/test/MC/ELF/dwo-restrict-relocs.s Mon May 21 12:44:54 2018
@@ -0,0 +1,10 @@
+// RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t1 -split-dwarf-file %t2 2>&1 | FileCheck %s
+
+// CHECK: error: A relocation may not refer to a dwo section
+.quad .foo.dwo
+
+.section .foo.dwo
+// CHECK: error: A dwo section may not contain relocations
+.quad .text
+// CHECK: error: A dwo section may not contain relocations
+.quad .foo.dwo

Added: llvm/trunk/test/MC/ELF/dwo-sections.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ELF/dwo-sections.s?rev=332875&view=auto
==============================================================================
--- llvm/trunk/test/MC/ELF/dwo-sections.s (added)
+++ llvm/trunk/test/MC/ELF/dwo-sections.s Mon May 21 12:44:54 2018
@@ -0,0 +1,25 @@
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t1 -split-dwarf-file %t2
+// RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=O %s
+// RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=DWO %s
+
+// O-NOT: Contents of section
+// O: Contents of section .strtab:
+// O-NOT: Contents of section
+// O: Contents of section .text:
+// O-NEXT: 0000 c3
+// O-NEXT: Contents of section .symtab:
+// O-NOT: Contents of section
+.globl main
+main:
+.Ltmp1:
+ret
+.Ltmp2:
+
+// DWO-NOT: Contents of section
+// DWO: Contents of section .strtab:
+// DWO-NOT: Contents of section
+// DWO: Contents of section .foo.dwo:
+// DWO-NEXT: 0000 01000000
+// DWO-NOT: Contents of section
+.section .foo.dwo
+.long .Ltmp2-.Ltmp1

Modified: llvm/trunk/tools/llvm-mc/llvm-mc.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mc/llvm-mc.cpp?rev=332875&r1=332874&r2=332875&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mc/llvm-mc.cpp (original)
+++ llvm/trunk/tools/llvm-mc/llvm-mc.cpp Mon May 21 12:44:54 2018
@@ -45,9 +45,13 @@ using namespace llvm;
 static cl::opt<std::string>
 InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
 
-static cl::opt<std::string>
-OutputFilename("o", cl::desc("Output filename"),
-               cl::value_desc("filename"));
+static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
+                                           cl::value_desc("filename"),
+                                           cl::init("-"));
+
+static cl::opt<std::string> SplitDwarfFile("split-dwarf-file",
+                                           cl::desc("DWO output filename"),
+                                           cl::value_desc("filename"));
 
 static cl::opt<bool>
 ShowEncoding("show-encoding", cl::desc("Show instruction encodings"));
@@ -197,13 +201,9 @@ static const Target *GetTarget(const cha
   return TheTarget;
 }
 
-static std::unique_ptr<ToolOutputFile> GetOutputStream() {
-  if (OutputFilename == "")
-    OutputFilename = "-";
-
+static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path) {
   std::error_code EC;
-  auto Out =
-      llvm::make_unique<ToolOutputFile>(OutputFilename, EC, sys::fs::F_None);
+  auto Out = llvm::make_unique<ToolOutputFile>(Path, EC, sys::fs::F_None);
   if (EC) {
     WithColor::error() << EC.message() << '\n';
     return nullptr;
@@ -411,10 +411,21 @@ int main(int argc, char **argv) {
     FeaturesStr = Features.getString();
   }
 
-  std::unique_ptr<ToolOutputFile> Out = GetOutputStream();
+  std::unique_ptr<ToolOutputFile> Out = GetOutputStream(OutputFilename);
   if (!Out)
     return 1;
 
+  std::unique_ptr<ToolOutputFile> DwoOut;
+  if (!SplitDwarfFile.empty()) {
+    if (FileType != OFT_ObjectFile) {
+      WithColor::error() << "dwo output only supported with object files\n";
+      return 1;
+    }
+    DwoOut = GetOutputStream(SplitDwarfFile);
+    if (!DwoOut)
+      return 1;
+  }
+
   std::unique_ptr<buffer_ostream> BOS;
   raw_pwrite_stream *OS = &Out->os();
   std::unique_ptr<MCStreamer> Str;
@@ -469,8 +480,10 @@ int main(int argc, char **argv) {
     MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions);
     Str.reset(TheTarget->createMCObjectStreamer(
         TheTriple, Ctx, std::unique_ptr<MCAsmBackend>(MAB),
-        MAB->createObjectWriter(*OS), std::unique_ptr<MCCodeEmitter>(CE), *STI,
-        MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible,
+        DwoOut ? MAB->createDwoObjectWriter(*OS, DwoOut->os())
+               : MAB->createObjectWriter(*OS),
+        std::unique_ptr<MCCodeEmitter>(CE), *STI, MCOptions.MCRelaxAll,
+        MCOptions.MCIncrementalLinkerCompatible,
         /*DWARFMustBeAtTheEnd*/ false));
     if (NoExecStack)
       Str->InitSections(true);
@@ -503,6 +516,10 @@ int main(int argc, char **argv) {
                                     *Buffer, SrcMgr, Out->os());
 
   // Keep output if no errors.
-  if (Res == 0) Out->keep();
+  if (Res == 0) {
+    Out->keep();
+    if (DwoOut)
+      DwoOut->keep();
+  }
   return Res;
 }




More information about the llvm-commits mailing list