1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

Support dwarf fission for wasm object files

Initial support for dwarf fission sections (-gsplit-dwarf) on wasm.
The most interesting change is support for writing 2 files (.o and .dwo) in the
wasm object writer. My approach moves object-writing logic into its own function
and calls it twice, swapping out the endian::Writer (W) in between calls.
It also splits the import-preparation step into its own function (and skips it when writing a dwo).

Differential Revision: https://reviews.llvm.org/D85685
This commit is contained in:
Derek Schuff 2020-08-07 21:23:11 -07:00
parent 57f2631c85
commit 28f861215e
7 changed files with 429 additions and 144 deletions

View File

@ -52,6 +52,10 @@ std::unique_ptr<MCObjectWriter>
createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
raw_pwrite_stream &OS);
std::unique_ptr<MCObjectWriter>
createWasmDwoObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS);
} // namespace llvm
#endif

View File

@ -422,7 +422,10 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) {
// FIXME: duplicated from Target/WebAssembly/WebAssembly.h
// don't want to depend on target specific headers in this code?
const unsigned TI_GLOBAL_RELOC = 3;
if (FrameBase.Location.WasmLoc.Kind == TI_GLOBAL_RELOC) {
// FIXME: when writing dwo, we need to avoid relocations. Probably
// the "right" solution is to treat globals the way func and data symbols
// are (with entries in .debug_addr).
if (FrameBase.Location.WasmLoc.Kind == TI_GLOBAL_RELOC && !isDwoUnit()) {
// These need to be relocatable.
assert(FrameBase.Location.WasmLoc.Index == 0); // Only SP so far.
auto SPSym = cast<MCSymbolWasm>(

View File

@ -54,10 +54,17 @@ 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);
switch (TW->getFormat()) {
case Triple::ELF:
return createELFDwoObjectWriter(
cast<MCELFObjectTargetWriter>(std::move(TW)), OS, DwoOS,
Endian == support::little);
case Triple::Wasm:
return createWasmDwoObjectWriter(
cast<MCWasmObjectTargetWriter>(std::move(TW)), OS, DwoOS);
default:
report_fatal_error("dwo only supported with ELF and Wasm");
}
}
Optional<MCFixupKind> MCAsmBackend::getFixupKind(StringRef Name) const {

View File

@ -796,6 +796,10 @@ void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) {
DwarfFrameSection = Ctx->getWasmSection(".debug_frame", SectionKind::getMetadata());
DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", SectionKind::getMetadata());
DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", SectionKind::getMetadata());
DwarfGnuPubNamesSection =
Ctx->getWasmSection(".debug_gnu_pubnames", SectionKind::getMetadata());
DwarfGnuPubTypesSection =
Ctx->getWasmSection(".debug_gnu_pubtypes", SectionKind::getMetadata());
DwarfDebugNamesSection =
Ctx->getWasmSection(".debug_names", SectionKind::getMetadata());
@ -808,6 +812,37 @@ void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) {
DwarfLoclistsSection =
Ctx->getWasmSection(".debug_loclists", SectionKind::getMetadata());
// Fission Sections
DwarfInfoDWOSection =
Ctx->getWasmSection(".debug_info.dwo", SectionKind::getMetadata());
DwarfTypesDWOSection =
Ctx->getWasmSection(".debug_types.dwo", SectionKind::getMetadata());
DwarfAbbrevDWOSection =
Ctx->getWasmSection(".debug_abbrev.dwo", SectionKind::getMetadata());
DwarfStrDWOSection =
Ctx->getWasmSection(".debug_str.dwo", SectionKind::getMetadata());
DwarfLineDWOSection =
Ctx->getWasmSection(".debug_line.dwo", SectionKind::getMetadata());
DwarfLocDWOSection =
Ctx->getWasmSection(".debug_loc.dwo", SectionKind::getMetadata());
DwarfStrOffDWOSection =
Ctx->getWasmSection(".debug_str_offsets.dwo", SectionKind::getMetadata());
DwarfRnglistsDWOSection =
Ctx->getWasmSection(".debug_rnglists.dwo", SectionKind::getMetadata());
DwarfMacinfoDWOSection =
Ctx->getWasmSection(".debug_macinfo.dwo", SectionKind::getMetadata());
DwarfMacroDWOSection =
Ctx->getWasmSection(".debug_macro.dwo", SectionKind::getMetadata());
DwarfLoclistsDWOSection =
Ctx->getWasmSection(".debug_loclists.dwo", SectionKind::getMetadata());
// DWP Sections
DwarfCUIndexSection =
Ctx->getWasmSection(".debug_cu_index", SectionKind::getMetadata(), 0);
DwarfTUIndexSection =
Ctx->getWasmSection(".debug_tu_index", SectionKind::getMetadata(), 0);
// Wasm use data section for LSDA.
// TODO Consider putting each function's exception table in a separate
// section, as in -function-sections, to facilitate lld's --gc-section.

View File

@ -216,8 +216,12 @@ static void patchI64(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) {
Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
}
bool isDwoSection(const MCSection &Sec) {
return Sec.getName().endswith(".dwo");
}
class WasmObjectWriter : public MCObjectWriter {
support::endian::Writer W;
support::endian::Writer *W;
/// The target specific Wasm writer instance.
std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
@ -260,7 +264,16 @@ class WasmObjectWriter : public MCObjectWriter {
unsigned NumEventImports = 0;
uint32_t SectionCount = 0;
// TargetObjectWriter wrappers.
enum class DwoMode {
AllSections,
NonDwoOnly,
DwoOnly,
};
bool IsSplitDwarf = false;
raw_pwrite_stream *OS = nullptr;
raw_pwrite_stream *DwoOS = nullptr;
// TargetObjectWriter wranppers.
bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
bool isEmscripten() const { return TargetObjectWriter->isEmscripten(); }
@ -270,8 +283,13 @@ class WasmObjectWriter : public MCObjectWriter {
public:
WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
raw_pwrite_stream &OS)
: W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {}
raw_pwrite_stream &OS_)
: TargetObjectWriter(std::move(MOTW)), OS(&OS_) {}
WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
raw_pwrite_stream &OS_, raw_pwrite_stream &DwoOS_)
: TargetObjectWriter(std::move(MOTW)), IsSplitDwarf(true), OS(&OS_),
DwoOS(&DwoOS_) {}
private:
void reset() override {
@ -303,27 +321,31 @@ private:
void executePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) override;
void prepareImports(SmallVectorImpl<wasm::WasmImport> &Imports,
MCAssembler &Asm, const MCAsmLayout &Layout);
uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
uint64_t writeOneObject(MCAssembler &Asm, const MCAsmLayout &Layout,
DwoMode Mode);
void writeString(const StringRef Str) {
encodeULEB128(Str.size(), W.OS);
W.OS << Str;
encodeULEB128(Str.size(), W->OS);
W->OS << Str;
}
void writeI32(int32_t val) {
char Buffer[4];
support::endian::write32le(Buffer, val);
W.OS.write(Buffer, sizeof(Buffer));
W->OS.write(Buffer, sizeof(Buffer));
}
void writeI64(int64_t val) {
char Buffer[8];
support::endian::write64le(Buffer, val);
W.OS.write(Buffer, sizeof(Buffer));
W->OS.write(Buffer, sizeof(Buffer));
}
void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); }
void writeValueType(wasm::ValType Ty) { W->OS << static_cast<char>(Ty); }
void writeTypeSection(ArrayRef<WasmSignature> Signatures);
void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint64_t DataSize,
@ -368,17 +390,17 @@ private:
void WasmObjectWriter::startSection(SectionBookkeeping &Section,
unsigned SectionId) {
LLVM_DEBUG(dbgs() << "startSection " << SectionId << "\n");
W.OS << char(SectionId);
W->OS << char(SectionId);
Section.SizeOffset = W.OS.tell();
Section.SizeOffset = W->OS.tell();
// The section size. We don't know the size yet, so reserve enough space
// for any 32-bit value; we'll patch it later.
encodeULEB128(0, W.OS, 5);
encodeULEB128(0, W->OS, 5);
// The position where the section starts, for measuring its size.
Section.ContentsOffset = W.OS.tell();
Section.PayloadOffset = W.OS.tell();
Section.ContentsOffset = W->OS.tell();
Section.PayloadOffset = W->OS.tell();
Section.Index = SectionCount++;
}
@ -388,19 +410,19 @@ void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section,
startSection(Section, wasm::WASM_SEC_CUSTOM);
// The position where the section header ends, for measuring its size.
Section.PayloadOffset = W.OS.tell();
Section.PayloadOffset = W->OS.tell();
// Custom sections in wasm also have a string identifier.
writeString(Name);
// The position where the custom section starts.
Section.ContentsOffset = W.OS.tell();
Section.ContentsOffset = W->OS.tell();
}
// Now that the section is complete and we know how big it is, patch up the
// section size field at the start of the section.
void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
uint64_t Size = W.OS.tell();
uint64_t Size = W->OS.tell();
// /dev/null doesn't support seek/tell and can report offset of 0.
// Simply skip this patching in that case.
if (!Size)
@ -414,14 +436,14 @@ void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
// Write the final section size to the payload_len field, which follows
// the section id byte.
writePatchableLEB<5>(static_cast<raw_pwrite_stream &>(W.OS), Size,
writePatchableLEB<5>(static_cast<raw_pwrite_stream &>(W->OS), Size,
Section.SizeOffset);
}
// Emit the Wasm header.
void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
W.OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
W.write<uint32_t>(wasm::WasmVersion);
W->OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
W->write<uint32_t>(wasm::WasmVersion);
}
void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
@ -663,7 +685,7 @@ WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) {
void WasmObjectWriter::applyRelocations(
ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset,
const MCAsmLayout &Layout) {
auto &Stream = static_cast<raw_pwrite_stream &>(W.OS);
auto &Stream = static_cast<raw_pwrite_stream &>(W->OS);
for (const WasmRelocationEntry &RelEntry : Relocations) {
uint64_t Offset = ContentsOffset +
RelEntry.FixupSection->getSectionOffset() +
@ -718,14 +740,14 @@ void WasmObjectWriter::writeTypeSection(ArrayRef<WasmSignature> Signatures) {
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_TYPE);
encodeULEB128(Signatures.size(), W.OS);
encodeULEB128(Signatures.size(), W->OS);
for (const WasmSignature &Sig : Signatures) {
W.OS << char(wasm::WASM_TYPE_FUNC);
encodeULEB128(Sig.Params.size(), W.OS);
W->OS << char(wasm::WASM_TYPE_FUNC);
encodeULEB128(Sig.Params.size(), W->OS);
for (wasm::ValType Ty : Sig.Params)
writeValueType(Ty);
encodeULEB128(Sig.Returns.size(), W.OS);
encodeULEB128(Sig.Returns.size(), W->OS);
for (wasm::ValType Ty : Sig.Returns)
writeValueType(Ty);
}
@ -744,32 +766,32 @@ void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_IMPORT);
encodeULEB128(Imports.size(), W.OS);
encodeULEB128(Imports.size(), W->OS);
for (const wasm::WasmImport &Import : Imports) {
writeString(Import.Module);
writeString(Import.Field);
W.OS << char(Import.Kind);
W->OS << char(Import.Kind);
switch (Import.Kind) {
case wasm::WASM_EXTERNAL_FUNCTION:
encodeULEB128(Import.SigIndex, W.OS);
encodeULEB128(Import.SigIndex, W->OS);
break;
case wasm::WASM_EXTERNAL_GLOBAL:
W.OS << char(Import.Global.Type);
W.OS << char(Import.Global.Mutable ? 1 : 0);
W->OS << char(Import.Global.Type);
W->OS << char(Import.Global.Mutable ? 1 : 0);
break;
case wasm::WASM_EXTERNAL_MEMORY:
encodeULEB128(Import.Memory.Flags, W.OS);
encodeULEB128(NumPages, W.OS); // initial
encodeULEB128(Import.Memory.Flags, W->OS);
encodeULEB128(NumPages, W->OS); // initial
break;
case wasm::WASM_EXTERNAL_TABLE:
W.OS << char(Import.Table.ElemType);
encodeULEB128(0, W.OS); // flags
encodeULEB128(NumElements, W.OS); // initial
W->OS << char(Import.Table.ElemType);
encodeULEB128(0, W->OS); // flags
encodeULEB128(NumElements, W->OS); // initial
break;
case wasm::WASM_EXTERNAL_EVENT:
encodeULEB128(Import.Event.Attribute, W.OS);
encodeULEB128(Import.Event.SigIndex, W.OS);
encodeULEB128(Import.Event.Attribute, W->OS);
encodeULEB128(Import.Event.SigIndex, W->OS);
break;
default:
llvm_unreachable("unsupported import kind");
@ -786,9 +808,9 @@ void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) {
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_FUNCTION);
encodeULEB128(Functions.size(), W.OS);
encodeULEB128(Functions.size(), W->OS);
for (const WasmFunction &Func : Functions)
encodeULEB128(Func.SigIndex, W.OS);
encodeULEB128(Func.SigIndex, W->OS);
endSection(Section);
}
@ -800,10 +822,10 @@ void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) {
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_EVENT);
encodeULEB128(Events.size(), W.OS);
encodeULEB128(Events.size(), W->OS);
for (const wasm::WasmEventType &Event : Events) {
encodeULEB128(Event.Attribute, W.OS);
encodeULEB128(Event.SigIndex, W.OS);
encodeULEB128(Event.Attribute, W->OS);
encodeULEB128(Event.SigIndex, W->OS);
}
endSection(Section);
@ -816,17 +838,17 @@ void WasmObjectWriter::writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals) {
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_GLOBAL);
encodeULEB128(Globals.size(), W.OS);
encodeULEB128(Globals.size(), W->OS);
for (const wasm::WasmGlobal &Global : Globals) {
encodeULEB128(Global.Type.Type, W.OS);
W.OS << char(Global.Type.Mutable);
W.OS << char(Global.InitExpr.Opcode);
encodeULEB128(Global.Type.Type, W->OS);
W->OS << char(Global.Type.Mutable);
W->OS << char(Global.InitExpr.Opcode);
switch (Global.Type.Type) {
case wasm::WASM_TYPE_I32:
encodeSLEB128(0, W.OS);
encodeSLEB128(0, W->OS);
break;
case wasm::WASM_TYPE_I64:
encodeSLEB128(0, W.OS);
encodeSLEB128(0, W->OS);
break;
case wasm::WASM_TYPE_F32:
writeI32(0);
@ -840,7 +862,7 @@ void WasmObjectWriter::writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals) {
default:
llvm_unreachable("unexpected type");
}
W.OS << char(wasm::WASM_OPCODE_END);
W->OS << char(wasm::WASM_OPCODE_END);
}
endSection(Section);
@ -853,11 +875,11 @@ void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_EXPORT);
encodeULEB128(Exports.size(), W.OS);
encodeULEB128(Exports.size(), W->OS);
for (const wasm::WasmExport &Export : Exports) {
writeString(Export.Name);
W.OS << char(Export.Kind);
encodeULEB128(Export.Index, W.OS);
W->OS << char(Export.Kind);
encodeULEB128(Export.Index, W->OS);
}
endSection(Section);
@ -870,17 +892,17 @@ void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) {
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_ELEM);
encodeULEB128(1, W.OS); // number of "segments"
encodeULEB128(0, W.OS); // the table index
encodeULEB128(1, W->OS); // number of "segments"
encodeULEB128(0, W->OS); // the table index
// init expr for starting offset
W.OS << char(wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(InitialTableOffset, W.OS);
W.OS << char(wasm::WASM_OPCODE_END);
W->OS << char(wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(InitialTableOffset, W->OS);
W->OS << char(wasm::WASM_OPCODE_END);
encodeULEB128(TableElems.size(), W.OS);
encodeULEB128(TableElems.size(), W->OS);
for (uint32_t Elem : TableElems)
encodeULEB128(Elem, W.OS);
encodeULEB128(Elem, W->OS);
endSection(Section);
}
@ -891,7 +913,7 @@ void WasmObjectWriter::writeDataCountSection() {
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_DATACOUNT);
encodeULEB128(DataSegments.size(), W.OS);
encodeULEB128(DataSegments.size(), W->OS);
endSection(Section);
}
@ -904,7 +926,7 @@ uint32_t WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_CODE);
encodeULEB128(Functions.size(), W.OS);
encodeULEB128(Functions.size(), W->OS);
for (const WasmFunction &Func : Functions) {
auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection());
@ -913,9 +935,9 @@ uint32_t WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
report_fatal_error(".size expression must be evaluatable");
encodeULEB128(Size, W.OS);
FuncSection.setSectionOffset(W.OS.tell() - Section.ContentsOffset);
Asm.writeSectionData(W.OS, &FuncSection, Layout);
encodeULEB128(Size, W->OS);
FuncSection.setSectionOffset(W->OS.tell() - Section.ContentsOffset);
Asm.writeSectionData(W->OS, &FuncSection, Layout);
}
// Apply fixups.
@ -932,21 +954,21 @@ uint32_t WasmObjectWriter::writeDataSection(const MCAsmLayout &Layout) {
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_DATA);
encodeULEB128(DataSegments.size(), W.OS); // count
encodeULEB128(DataSegments.size(), W->OS); // count
for (const WasmDataSegment &Segment : DataSegments) {
encodeULEB128(Segment.InitFlags, W.OS); // flags
encodeULEB128(Segment.InitFlags, W->OS); // flags
if (Segment.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX)
encodeULEB128(0, W.OS); // memory index
encodeULEB128(0, W->OS); // memory index
if ((Segment.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0) {
W.OS << char(Segment.Offset > INT32_MAX ? wasm::WASM_OPCODE_I64_CONST
: wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(Segment.Offset, W.OS); // offset
W.OS << char(wasm::WASM_OPCODE_END);
W->OS << char(Segment.Offset > INT32_MAX ? wasm::WASM_OPCODE_I64_CONST
: wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(Segment.Offset, W->OS); // offset
W->OS << char(wasm::WASM_OPCODE_END);
}
encodeULEB128(Segment.Data.size(), W.OS); // size
Segment.Section->setSectionOffset(W.OS.tell() - Section.ContentsOffset);
W.OS << Segment.Data; // data
encodeULEB128(Segment.Data.size(), W->OS); // size
Segment.Section->setSectionOffset(W->OS.tell() - Section.ContentsOffset);
W->OS << Segment.Data; // data
}
// Apply fixups.
@ -979,18 +1001,18 @@ void WasmObjectWriter::writeRelocSection(
SectionBookkeeping Section;
startCustomSection(Section, std::string("reloc.") + Name.str());
encodeULEB128(SectionIndex, W.OS);
encodeULEB128(Relocs.size(), W.OS);
encodeULEB128(SectionIndex, W->OS);
encodeULEB128(Relocs.size(), W->OS);
for (const WasmRelocationEntry &RelEntry : Relocs) {
uint64_t Offset =
RelEntry.Offset + RelEntry.FixupSection->getSectionOffset();
uint32_t Index = getRelocationIndexValue(RelEntry);
W.OS << char(RelEntry.Type);
encodeULEB128(Offset, W.OS);
encodeULEB128(Index, W.OS);
W->OS << char(RelEntry.Type);
encodeULEB128(Offset, W->OS);
encodeULEB128(Index, W->OS);
if (RelEntry.hasAddend())
encodeSLEB128(RelEntry.Addend, W.OS);
encodeSLEB128(RelEntry.Addend, W->OS);
}
endSection(Section);
@ -1009,20 +1031,20 @@ void WasmObjectWriter::writeLinkingMetaDataSection(
const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) {
SectionBookkeeping Section;
startCustomSection(Section, "linking");
encodeULEB128(wasm::WasmMetadataVersion, W.OS);
encodeULEB128(wasm::WasmMetadataVersion, W->OS);
SectionBookkeeping SubSection;
if (SymbolInfos.size() != 0) {
startSection(SubSection, wasm::WASM_SYMBOL_TABLE);
encodeULEB128(SymbolInfos.size(), W.OS);
encodeULEB128(SymbolInfos.size(), W->OS);
for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) {
encodeULEB128(Sym.Kind, W.OS);
encodeULEB128(Sym.Flags, W.OS);
encodeULEB128(Sym.Kind, W->OS);
encodeULEB128(Sym.Flags, W->OS);
switch (Sym.Kind) {
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
encodeULEB128(Sym.ElementIndex, W.OS);
encodeULEB128(Sym.ElementIndex, W->OS);
if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 ||
(Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeString(Sym.Name);
@ -1030,15 +1052,15 @@ void WasmObjectWriter::writeLinkingMetaDataSection(
case wasm::WASM_SYMBOL_TYPE_DATA:
writeString(Sym.Name);
if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
encodeULEB128(Sym.DataRef.Segment, W.OS);
encodeULEB128(Sym.DataRef.Offset, W.OS);
encodeULEB128(Sym.DataRef.Size, W.OS);
encodeULEB128(Sym.DataRef.Segment, W->OS);
encodeULEB128(Sym.DataRef.Offset, W->OS);
encodeULEB128(Sym.DataRef.Size, W->OS);
}
break;
case wasm::WASM_SYMBOL_TYPE_SECTION: {
const uint32_t SectionIndex =
CustomSections[Sym.ElementIndex].OutputIndex;
encodeULEB128(SectionIndex, W.OS);
encodeULEB128(SectionIndex, W->OS);
break;
}
default:
@ -1050,35 +1072,35 @@ void WasmObjectWriter::writeLinkingMetaDataSection(
if (DataSegments.size()) {
startSection(SubSection, wasm::WASM_SEGMENT_INFO);
encodeULEB128(DataSegments.size(), W.OS);
encodeULEB128(DataSegments.size(), W->OS);
for (const WasmDataSegment &Segment : DataSegments) {
writeString(Segment.Name);
encodeULEB128(Segment.Alignment, W.OS);
encodeULEB128(Segment.LinkerFlags, W.OS);
encodeULEB128(Segment.Alignment, W->OS);
encodeULEB128(Segment.LinkerFlags, W->OS);
}
endSection(SubSection);
}
if (!InitFuncs.empty()) {
startSection(SubSection, wasm::WASM_INIT_FUNCS);
encodeULEB128(InitFuncs.size(), W.OS);
encodeULEB128(InitFuncs.size(), W->OS);
for (auto &StartFunc : InitFuncs) {
encodeULEB128(StartFunc.first, W.OS); // priority
encodeULEB128(StartFunc.second, W.OS); // function index
encodeULEB128(StartFunc.first, W->OS); // priority
encodeULEB128(StartFunc.second, W->OS); // function index
}
endSection(SubSection);
}
if (Comdats.size()) {
startSection(SubSection, wasm::WASM_COMDAT_INFO);
encodeULEB128(Comdats.size(), W.OS);
encodeULEB128(Comdats.size(), W->OS);
for (const auto &C : Comdats) {
writeString(C.first);
encodeULEB128(0, W.OS); // flags for future use
encodeULEB128(C.second.size(), W.OS);
encodeULEB128(0, W->OS); // flags for future use
encodeULEB128(C.second.size(), W->OS);
for (const WasmComdatEntry &Entry : C.second) {
encodeULEB128(Entry.Kind, W.OS);
encodeULEB128(Entry.Index, W.OS);
encodeULEB128(Entry.Kind, W->OS);
encodeULEB128(Entry.Index, W->OS);
}
}
endSection(SubSection);
@ -1094,8 +1116,8 @@ void WasmObjectWriter::writeCustomSection(WasmCustomSection &CustomSection,
auto *Sec = CustomSection.Section;
startCustomSection(Section, CustomSection.Name);
Sec->setSectionOffset(W.OS.tell() - Section.ContentsOffset);
Asm.writeSectionData(W.OS, Sec, Layout);
Sec->setSectionOffset(W->OS.tell() - Section.ContentsOffset);
Asm.writeSectionData(W->OS, Sec, Layout);
CustomSection.OutputContentsOffset = Section.ContentsOffset;
CustomSection.OutputIndex = Section.Index;
@ -1175,25 +1197,9 @@ static bool isInSymtab(const MCSymbolWasm &Sym) {
return true;
}
uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
const MCAsmLayout &Layout) {
uint64_t StartOffset = W.OS.tell();
LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
// Collect information from the available symbols.
SmallVector<WasmFunction, 4> Functions;
SmallVector<uint32_t, 4> TableElems;
SmallVector<wasm::WasmImport, 4> Imports;
SmallVector<wasm::WasmExport, 4> Exports;
SmallVector<wasm::WasmEventType, 1> Events;
SmallVector<wasm::WasmGlobal, 1> Globals;
SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
uint64_t DataSize = 0;
void WasmObjectWriter::prepareImports(
SmallVectorImpl<wasm::WasmImport> &Imports, MCAssembler &Asm,
const MCAsmLayout &Layout) {
// For now, always emit the memory import, since loads and stores are not
// valid without it. In the future, we could perhaps be more clever and omit
// it if there are no loads or stores.
@ -1291,13 +1297,57 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
GOTIndices[&WS] = NumGlobalImports++;
}
}
}
uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
const MCAsmLayout &Layout) {
support::endian::Writer MainWriter(*OS, support::little);
W = &MainWriter;
if (IsSplitDwarf) {
uint64_t TotalSize = writeOneObject(Asm, Layout, DwoMode::NonDwoOnly);
assert(DwoOS);
support::endian::Writer DwoWriter(*DwoOS, support::little);
W = &DwoWriter;
return TotalSize + writeOneObject(Asm, Layout, DwoMode::DwoOnly);
} else {
return writeOneObject(Asm, Layout, DwoMode::AllSections);
}
}
uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
const MCAsmLayout &Layout,
DwoMode Mode) {
uint64_t StartOffset = W->OS.tell();
SectionCount = 0;
CustomSections.clear();
LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
// Collect information from the available symbols.
SmallVector<WasmFunction, 4> Functions;
SmallVector<uint32_t, 4> TableElems;
SmallVector<wasm::WasmImport, 4> Imports;
SmallVector<wasm::WasmExport, 4> Exports;
SmallVector<wasm::WasmEventType, 1> Events;
SmallVector<wasm::WasmGlobal, 1> Globals;
SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
uint64_t DataSize = 0;
if (Mode != DwoMode::DwoOnly) {
prepareImports(Imports, Asm, Layout);
}
// Populate DataSegments and CustomSections, which must be done before
// populating DataLocations.
for (MCSection &Sec : Asm) {
auto &Section = static_cast<MCSectionWasm &>(Sec);
StringRef SectionName = Section.getName();
if (Mode == DwoMode::NonDwoOnly && isDwoSection(Sec))
continue;
if (Mode == DwoMode::DwoOnly && !isDwoSection(Sec))
continue;
// .init_array sections are handled specially elsewhere.
if (SectionName.startswith(".init_array"))
continue;
@ -1694,23 +1744,33 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// Write out the Wasm header.
writeHeader(Asm);
writeTypeSection(Signatures);
writeImportSection(Imports, DataSize, TableElems.size());
writeFunctionSection(Functions);
// Skip the "table" section; we import the table instead.
// Skip the "memory" section; we import the memory instead.
writeEventSection(Events);
writeGlobalSection(Globals);
writeExportSection(Exports);
writeElemSection(TableElems);
writeDataCountSection();
uint32_t CodeSectionIndex = writeCodeSection(Asm, Layout, Functions);
uint32_t DataSectionIndex = writeDataSection(Layout);
for (auto &CustomSection : CustomSections)
uint32_t CodeSectionIndex, DataSectionIndex;
if (Mode != DwoMode::DwoOnly) {
writeTypeSection(Signatures);
writeImportSection(Imports, DataSize, TableElems.size());
writeFunctionSection(Functions);
// Skip the "table" section; we import the table instead.
// Skip the "memory" section; we import the memory instead.
writeEventSection(Events);
writeGlobalSection(Globals);
writeExportSection(Exports);
writeElemSection(TableElems);
writeDataCountSection();
CodeSectionIndex = writeCodeSection(Asm, Layout, Functions);
DataSectionIndex = writeDataSection(Layout);
}
for (auto &CustomSection : CustomSections) {
writeCustomSection(CustomSection, Asm, Layout);
writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
}
if (Mode != DwoMode::DwoOnly) {
writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
}
writeCustomRelocSections();
if (ProducersSection)
writeCustomSection(*ProducersSection, Asm, Layout);
@ -1718,7 +1778,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
writeCustomSection(*TargetFeaturesSection, Asm, Layout);
// TODO: Translate the .comment section to the output.
return W.OS.tell() - StartOffset;
return W->OS.tell() - StartOffset;
}
std::unique_ptr<MCObjectWriter>
@ -1726,3 +1786,10 @@ llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
raw_pwrite_stream &OS) {
return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS);
}
std::unique_ptr<MCObjectWriter>
llvm::createWasmDwoObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
raw_pwrite_stream &OS,
raw_pwrite_stream &DwoOS) {
return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS, DwoOS);
}

View File

@ -0,0 +1,121 @@
; RUN: llc -split-dwarf-file=baz.dwo -O0 %s -mtriple=wasm32-unknown-unknown -filetype=obj -o %t
; RUN: llvm-dwarfdump -v -all %t | FileCheck %s
; RUN: llvm-readobj --relocations %t | FileCheck --check-prefix=OBJ %s
; RUN: llvm-objdump -h %t | FileCheck --check-prefix=HDR %s
; This test is derived from test/DebugInfo/X86/fission-cu.ll
source_filename = "test/DebugInfo/WebAssembly/fission-cu.ll"
@a = global i32 0, align 4, !dbg !0
!llvm.dbg.cu = !{!4}
!llvm.module.flags = !{!7}
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = !DIGlobalVariable(name: "a", scope: null, file: !2, line: 1, type: !3, isLocal: false, isDefinition: true)
!2 = !DIFile(filename: "baz.c", directory: "/usr/local/google/home/echristo/tmp")
!3 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 3.3 (trunk 169021) (llvm/trunk 169020)", isOptimized: false, runtimeVersion: 0, splitDebugFilename: "baz.dwo", emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !5)
!5 = !{}
; Check that the skeleton compile unit contains the proper attributes:
; This DIE has the following attributes: DW_AT_comp_dir, DW_AT_stmt_list,
; DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_dwo_name, DW_AT_dwo_id,
; DW_AT_ranges_base, DW_AT_addr_base.
; CHECK: .debug_abbrev contents:
; CHECK: Abbrev table for offset: 0x00000000
; CHECK: [1] DW_TAG_compile_unit DW_CHILDREN_no
; CHECK: DW_AT_stmt_list DW_FORM_sec_offset
; CHECK: DW_AT_comp_dir DW_FORM_strp
; CHECK: DW_AT_GNU_dwo_name DW_FORM_strp
; CHECK: DW_AT_GNU_dwo_id DW_FORM_data8
; Check that we're using the right forms.
; CHECK: .debug_abbrev.dwo contents:
; CHECK: Abbrev table for offset: 0x00000000
; CHECK: [1] DW_TAG_compile_unit DW_CHILDREN_yes
; CHECK: DW_AT_producer DW_FORM_GNU_str_index
; CHECK: DW_AT_language DW_FORM_data2
; CHECK: DW_AT_name DW_FORM_GNU_str_index
; CHECK: DW_AT_GNU_dwo_name DW_FORM_GNU_str_index
; CHECK-NOT: DW_AT_low_pc
; CHECK-NOT: DW_AT_stmt_list
; CHECK-NOT: DW_AT_comp_dir
; CHECK: DW_AT_GNU_dwo_id DW_FORM_data8
; CHECK: [2] DW_TAG_variable DW_CHILDREN_no
; CHECK: DW_AT_name DW_FORM_GNU_str_index
; CHECK: DW_AT_type DW_FORM_ref4
; CHECK: DW_AT_external DW_FORM_flag_present
; CHECK: DW_AT_decl_file DW_FORM_data1
; CHECK: DW_AT_decl_line DW_FORM_data1
; CHECK: DW_AT_location DW_FORM_exprloc
; CHECK: [3] DW_TAG_base_type DW_CHILDREN_no
; CHECK: DW_AT_name DW_FORM_GNU_str_index
; CHECK: DW_AT_encoding DW_FORM_data1
; CHECK: DW_AT_byte_size DW_FORM_data1
; CHECK: .debug_info contents:
; CHECK: DW_TAG_compile_unit
; CHECK-NEXT: DW_AT_stmt_list [DW_FORM_sec_offset] (0x00000000)
; CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000000] = "/usr/local/google/home/echristo/tmp")
; CHECK-NEXT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x00000024] = "baz.dwo")
; CHECK-NEXT: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x1f1f859683d49324)
; Check that the rest of the compile units have information.
; CHECK: .debug_info.dwo contents:
; CHECK: DW_TAG_compile_unit
; CHECK: DW_AT_producer [DW_FORM_GNU_str_index] (indexed (00000002) string = "clang version 3.3 (trunk 169021) (llvm/trunk 169020)")
; CHECK: DW_AT_language [DW_FORM_data2] (DW_LANG_C99)
; CHECK: DW_AT_name [DW_FORM_GNU_str_index] (indexed (00000003) string = "baz.c")
; CHECK: DW_AT_GNU_dwo_name [DW_FORM_GNU_str_index] (indexed (00000004) string = "baz.dwo")
; CHECK-NOT: DW_AT_low_pc
; CHECK-NOT: DW_AT_stmt_list
; CHECK-NOT: DW_AT_comp_dir
; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x1f1f859683d49324)
; CHECK: DW_TAG_variable
; CHECK: DW_AT_name [DW_FORM_GNU_str_index] (indexed (00000000) string = "a")
; CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x{{[0-9a-f]*}} => {[[TYPE:0x[0-9a-f]*]]}
; CHECK: DW_AT_external [DW_FORM_flag_present] (true)
; CHECK: DW_AT_decl_file [DW_FORM_data1] (0x01)
; CHECK: DW_AT_decl_line [DW_FORM_data1] (1)
; CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_GNU_addr_index 0x0)
; CHECK: [[TYPE]]: DW_TAG_base_type
; CHECK: DW_AT_name [DW_FORM_GNU_str_index] (indexed (00000001) string = "int")
; CHECK: .debug_str contents:
; CHECK: 0x00000000: "/usr/local/google/home/echristo/tmp"
; CHECK: 0x00000024: "baz.dwo"
; CHECK: .debug_str.dwo contents:
; CHECK: 0x00000000: "a"
; CHECK: 0x00000002: "int"
; CHECK: 0x00000006: "clang version 3.3 (trunk 169021) (llvm/trunk 169020)"
; CHECK: 0x0000003b: "baz.c"
; CHECK: 0x00000041: "baz.dwo"
; CHECK: .debug_str_offsets.dwo contents:
; CHECK: 0x00000000: 00000000
; CHECK: 0x00000004: 00000002
; CHECK: 0x00000008: 00000006
; CHECK: 0x0000000c: 0000003b
; CHECK: 0x00000010: 00000041
; Object file checks
; For wasm we should have this set of relocations for the debug info section
;
; OBJ: .debug_info
; OBJ-NEXT: R_WASM_SECTION_OFFSET_I32 .debug_abbrev 0
; OBJ-NEXT: R_WASM_SECTION_OFFSET_I32 .debug_line 0
; OBJ-NEXT: R_WASM_SECTION_OFFSET_I32 .debug_str 0
; OBJ-NEXT: R_WASM_SECTION_OFFSET_I32 .debug_str 36
; OBJ-NEXT: R_WASM_SECTION_OFFSET_I32 .debug_addr 0
; OBJ-NEXT: }
; HDR-NOT: .debug_aranges
; HDR-NOT: .rela.{{.*}}.dwo
!6 = !{!0}
!7 = !{i32 1, !"Debug Info Version", i32 3}

View File

@ -0,0 +1,48 @@
; RUN: llc -split-dwarf-file=baz.dwo -split-dwarf-output=%t.dwo -O0 %s -mtriple=wasm32-unknown-unknown -filetype=obj -o %t
; RUN: llvm-objdump -h %t | FileCheck --check-prefix=OBJ %s
; RUN: llvm-objdump -h %t.dwo | FileCheck --check-prefix=DWO %s
; This test is derived from test/DebugInfo/X86/fission-cu.ll
; But it checks that the output objects have the expected sections
source_filename = "test/DebugInfo/WebAssembly/fission-cu.ll"
@a = global i32 0, align 4, !dbg !0
!llvm.dbg.cu = !{!4}
!llvm.module.flags = !{!7}
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = !DIGlobalVariable(name: "a", scope: null, file: !2, line: 1, type: !3, isLocal: false, isDefinition: true)
!2 = !DIFile(filename: "baz.c", directory: "/usr/local/google/home/echristo/tmp")
!3 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 3.3 (trunk 169021) (llvm/trunk 169020)", isOptimized: false, runtimeVersion: 0, splitDebugFilename: "baz.dwo", emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !5)
!5 = !{}
!6 = !{!0}
!7 = !{i32 1, !"Debug Info Version", i32 3}
; CHECK-LABEL: Sections:
; OBJ: Idx Name
; OBJ-NEXT: 0 IMPORT
; OBJ-NEXT: DATACOUNT
; OBJ-NEXT: DATA
; OBJ-NEXT: .debug_abbrev
; OBJ-NEXT: .debug_info
; OBJ-NEXT: .debug_str
; OBJ-NEXT: .debug_addr
; OBJ-NEXT: .debug_pubnames
; OBJ-NEXT: .debug_pubtypes
; OBJ-NEXT: .debug_line
; OBJ-NEXT: linking
; DWO: Idx Name
; DWO-NOT: IMPORT
; DWO-NOT: DATA
; DWO: 0 .debug_str.dwo
; DWO-NEXT: .debug_str_offsets.dwo
; DWO-NEXT: .debug_info.dwo
; DWO-NEXT: .debug_abbrev.dwo
; DWO-NEXT: producers