diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2018-05-21 19:44:54 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2018-05-21 19:44:54 +0000 |
commit | 63062d9d0f734736e707ede5f828f3690d5ef0e7 (patch) | |
tree | f7a8c4d8f80bd8fc8009c9bdf6f7772e1f29a4ff | |
parent | 16fcc5b6db544b2d552dacdab62c9e1ec243a415 (diff) | |
download | bcm5719-llvm-63062d9d0f734736e707ede5f828f3690d5ef0e7.tar.gz bcm5719-llvm-63062d9d0f734736e707ede5f828f3690d5ef0e7.zip |
MC: Introduce an ELF dwo object writer and teach llvm-mc about it.
Part of PR37466.
Differential Revision: https://reviews.llvm.org/D47051
llvm-svn: 332875
-rw-r--r-- | llvm/include/llvm/MC/MCAsmBackend.h | 6 | ||||
-rw-r--r-- | llvm/include/llvm/MC/MCELFObjectWriter.h | 5 | ||||
-rw-r--r-- | llvm/lib/MC/ELFObjectWriter.cpp | 108 | ||||
-rw-r--r-- | llvm/lib/MC/MCAsmBackend.cpp | 10 | ||||
-rw-r--r-- | llvm/test/MC/ELF/dwo-restrict-relocs.s | 10 | ||||
-rw-r--r-- | llvm/test/MC/ELF/dwo-sections.s | 25 | ||||
-rw-r--r-- | llvm/tools/llvm-mc/llvm-mc.cpp | 43 |
7 files changed, 179 insertions, 28 deletions
diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h index c2b3ca25d11..cca8e53dab4 100644 --- a/llvm/include/llvm/MC/MCAsmBackend.h +++ b/llvm/include/llvm/MC/MCAsmBackend.h @@ -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; diff --git a/llvm/include/llvm/MC/MCELFObjectWriter.h b/llvm/include/llvm/MC/MCELFObjectWriter.h index 0fb9615562a..bff58fef6af 100644 --- a/llvm/include/llvm/MC/MCELFObjectWriter.h +++ b/llvm/include/llvm/MC/MCELFObjectWriter.h @@ -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 diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index a8f88ce49e2..14300642303 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -70,6 +70,10 @@ using SectionIndexMapTy = DenseMap<const MCSectionELF *, uint32_t>; 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(MCAssembler &Asm, const MCAsmLayout &Layout) { 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(MCAssembler &Asm, const MCAsmLayout &Layout) { 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(MCAssembler &Asm, 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_ptr<MCELFObjectTargetWriter> MOTW, 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); +} diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp index 213ea525803..3119bb997d0 100644 --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -49,6 +49,16 @@ MCAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { } } +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; } diff --git a/llvm/test/MC/ELF/dwo-restrict-relocs.s b/llvm/test/MC/ELF/dwo-restrict-relocs.s new file mode 100644 index 00000000000..b624d40aad7 --- /dev/null +++ b/llvm/test/MC/ELF/dwo-restrict-relocs.s @@ -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 diff --git a/llvm/test/MC/ELF/dwo-sections.s b/llvm/test/MC/ELF/dwo-sections.s new file mode 100644 index 00000000000..9b2d2aa58d0 --- /dev/null +++ b/llvm/test/MC/ELF/dwo-sections.s @@ -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 diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp index d6df481afd6..7b83c5e3e05 100644 --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -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 char *ProgName) { 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; } |