mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-24 06:10:12 +00:00
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
This commit is contained in:
parent
16fcc5b6db
commit
63062d9d0f
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
10
llvm/test/MC/ELF/dwo-restrict-relocs.s
Normal file
10
llvm/test/MC/ELF/dwo-restrict-relocs.s
Normal file
@ -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
|
25
llvm/test/MC/ELF/dwo-sections.s
Normal file
25
llvm/test/MC/ELF/dwo-sections.s
Normal file
@ -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
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user