[WebAssembly] Write DWARF data into wasm object file

- Writes ".debug_XXX" into corresponding custom sections.
- Writes relocation records into "reloc.debug_XXX" sections.

Patch by Yury Delendik!

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@330982 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sam Clegg 2018-04-26 19:27:28 +00:00
parent ee52da49b0
commit db15975983
13 changed files with 545 additions and 37 deletions

View File

@ -250,8 +250,9 @@ enum : unsigned {
// Kind codes used in the custom "linking" section in the WASM_SYMBOL_TABLE
enum WasmSymbolType : unsigned {
WASM_SYMBOL_TYPE_FUNCTION = 0x0,
WASM_SYMBOL_TYPE_DATA = 0x1,
WASM_SYMBOL_TYPE_GLOBAL = 0x2,
WASM_SYMBOL_TYPE_DATA = 0x1,
WASM_SYMBOL_TYPE_GLOBAL = 0x2,
WASM_SYMBOL_TYPE_SECTION = 0x3,
};
const unsigned WASM_SYMBOL_BINDING_MASK = 0x3;

View File

@ -11,3 +11,5 @@ WASM_RELOC(R_WEBASSEMBLY_MEMORY_ADDR_SLEB, 4)
WASM_RELOC(R_WEBASSEMBLY_MEMORY_ADDR_I32, 5)
WASM_RELOC(R_WEBASSEMBLY_TYPE_INDEX_LEB, 6)
WASM_RELOC(R_WEBASSEMBLY_GLOBAL_INDEX_LEB, 7)
WASM_RELOC(R_WEBASSEMBLY_FUNCTION_OFFSET_I32, 8)
WASM_RELOC(R_WEBASSEMBLY_SECTION_OFFSET_I32, 9)

View File

@ -23,6 +23,7 @@
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstdint>
@ -46,6 +47,8 @@ public:
return visitCOFF(Rel, R, Value);
if (isa<MachOObjectFile>(ObjToVisit))
return visitMachO(Rel, R, Value);
if (isa<WasmObjectFile>(ObjToVisit))
return visitWasm(Rel, R, Value);
HasError = true;
return 0;
@ -316,6 +319,27 @@ private:
HasError = true;
return 0;
}
uint64_t visitWasm(uint32_t Rel, RelocationRef R, uint64_t Value) {
if (ObjToVisit.getArch() == Triple::wasm32) {
switch (Rel) {
case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
// For wasm section, its offset at 0 -- ignoring Value
return 0;
}
}
HasError = true;
return 0;
}
};
} // end namespace object

View File

@ -53,6 +53,10 @@ public:
return Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL;
}
bool isTypeSection() const {
return Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION;
}
bool isDefined() const { return !isUndefined(); }
bool isUndefined() const {
@ -206,6 +210,7 @@ private:
bool isValidFunctionSymbol(uint32_t Index) const;
bool isValidGlobalSymbol(uint32_t Index) const;
bool isValidDataSymbol(uint32_t Index) const;
bool isValidSectionSymbol(uint32_t Index) const;
wasm::WasmFunction &getDefinedFunction(uint32_t Index);
wasm::WasmGlobal &getDefinedGlobal(uint32_t Index);

View File

@ -48,7 +48,9 @@ static const uint32_t kInitialTableOffset = 1;
struct SectionBookkeeping {
// Where the size of the section is written.
uint64_t SizeOffset;
// Where the contents of the section starts (after the header).
// Where the section header ends (without custom section name).
uint64_t PayloadOffset;
// Where the contents of the section starts.
uint64_t ContentsOffset;
uint32_t Index;
};
@ -151,6 +153,8 @@ struct WasmRelocationEntry {
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
return true;
default:
return false;
@ -169,11 +173,17 @@ struct WasmRelocationEntry {
};
struct WasmCustomSection {
StringRef Name;
const SmallVectorImpl<char> &Contents;
const uint32_t INVALID_INDEX = -1;
WasmCustomSection(StringRef Name, const SmallVectorImpl<char> &Contents)
: Name(Name), Contents(Contents) {}
StringRef Name;
MCSectionWasm *Section;
uint32_t OutputContentsOffset;
uint32_t OutputIndex;
WasmCustomSection(StringRef Name, MCSectionWasm *Section)
: Name(Name), Section(Section), OutputContentsOffset(0),
OutputIndex(INVALID_INDEX) {}
};
#if !defined(NDEBUG)
@ -207,13 +217,21 @@ class WasmObjectWriter : public MCObjectWriter {
DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices;
// Maps data symbols to the Wasm segment and offset/size with the segment.
DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations;
// Maps section symbols to the section.
DenseMap<const MCSymbolWasm *, const MCSectionWasm *> CustomSectionSymbols;
// Stores output data (index, relocations, content offset) for custom
// section.
std::vector<WasmCustomSection> CustomSections;
// Relocations for fixing up references in the custom sections.
DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>>
CustomSectionsRelocations;
DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo>
FunctionTypeIndices;
SmallVector<WasmFunctionType, 4> FunctionTypes;
SmallVector<WasmGlobal, 4> Globals;
SmallVector<WasmDataSegment, 4> DataSegments;
std::vector<WasmCustomSection> CustomSections;
unsigned NumFunctionImports = 0;
unsigned NumGlobalImports = 0;
uint32_t SectionCount = 0;
@ -245,10 +263,12 @@ private:
WasmIndices.clear();
TableIndices.clear();
DataLocations.clear();
CustomSectionsRelocations.clear();
FunctionTypeIndices.clear();
FunctionTypes.clear();
Globals.clear();
DataSegments.clear();
CustomSectionSymbols.clear();
MCObjectWriter::reset();
NumFunctionImports = 0;
NumGlobalImports = 0;
@ -290,7 +310,11 @@ private:
ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats);
void writeUserCustomSections(ArrayRef<WasmCustomSection> CustomSections);
void writeCustomSections(const MCAssembler &Asm, const MCAsmLayout &Layout);
void writeCustomRelocSections();
void
updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions,
const MCAsmLayout &Layout);
uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
@ -319,6 +343,7 @@ void WasmObjectWriter::startSection(SectionBookkeeping &Section,
// The position where the section starts, for measuring its size.
Section.ContentsOffset = getStream().tell();
Section.PayloadOffset = getStream().tell();
Section.Index = SectionCount++;
}
@ -326,14 +351,21 @@ void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section,
StringRef Name) {
DEBUG(dbgs() << "startCustomSection " << Name << "\n");
startSection(Section, wasm::WASM_SEC_CUSTOM);
// The position where the section header ends, for measuring its size.
Section.PayloadOffset = getStream().tell();
// Custom sections in wasm also have a string identifier.
writeString(Name);
// The position where the custom section starts.
Section.ContentsOffset = getStream().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 = getStream().tell() - Section.ContentsOffset;
uint64_t Size = getStream().tell() - Section.PayloadOffset;
if (uint32_t(Size) != Size)
report_fatal_error("section size does not fit in a uint32_t");
@ -374,8 +406,9 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
if (FixupSection.getSectionName().startswith(".init_array"))
return;
// TODO(sbc): Add support for debug sections.
if (FixupSection.getKind().isMetadata())
// TODO: Add support for non-debug metadata sections?
if (FixupSection.getKind().isMetadata() &&
!FixupSection.getSectionName().startswith(".debug_"))
return;
if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
@ -446,21 +479,29 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
DEBUG(dbgs() << "WasmReloc: " << Rec << "\n");
// Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are currently required
// to be against a named symbol.
// Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB,
// R_WEBASSEMBLY_SECTION_OFFSET_I32 or R_WEBASSEMBLY_FUNCTION_OFFSET_I32
// are currently required to be against a named symbol.
// TODO(sbc): Add support for relocations against unnamed temporaries such
// as those generated by llvm's `blockaddress`.
// See: test/MC/WebAssembly/blockaddress.ll
if (SymA->getName().empty() && Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB)
if (SymA->getName().empty() &&
!(Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB ||
Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32 ||
Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32))
report_fatal_error("relocations against un-named temporaries are not yet "
"supported by wasm");
if (FixupSection.isWasmData())
if (FixupSection.isWasmData()) {
DataRelocations.push_back(Rec);
else if (FixupSection.getKind().isText())
} else if (FixupSection.getKind().isText()) {
CodeRelocations.push_back(Rec);
else
} else if (FixupSection.getKind().isMetadata()) {
assert(FixupSection.getSectionName().startswith(".debug_"));
CustomSectionsRelocations[&FixupSection].push_back(Rec);
} else {
llvm_unreachable("unexpected section type");
}
}
// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
@ -523,6 +564,15 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
report_fatal_error("symbol not found in wasm index space: " +
RelEntry.Symbol->getName());
return WasmIndices[RelEntry.Symbol];
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: {
const auto &Section =
static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection());
return Section.getSectionOffset() + RelEntry.Addend;
}
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: {
const auto &Section = *CustomSectionSymbols.find(RelEntry.Symbol)->second;
return Section.getSectionOffset() + RelEntry.Addend;
}
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: {
@ -614,6 +664,8 @@ void WasmObjectWriter::applyRelocations(
break;
case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
WriteI32(Stream, Value, Offset);
break;
case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
@ -851,6 +903,13 @@ void WasmObjectWriter::writeRelocSection(
endSection(Section);
}
void WasmObjectWriter::writeCustomRelocSections() {
for (const auto &Sec : CustomSections) {
auto &Relocations = CustomSectionsRelocations[Sec.Section];
writeRelocSection(Sec.OutputIndex, Sec.Name, Relocations);
}
}
void WasmObjectWriter::writeLinkingMetaDataSection(
ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
@ -881,6 +940,12 @@ void WasmObjectWriter::writeLinkingMetaDataSection(
encodeULEB128(Sym.DataRef.Size, getStream());
}
break;
case wasm::WASM_SYMBOL_TYPE_SECTION: {
const uint32_t SectionIndex =
CustomSections[Sym.ElementIndex].OutputIndex;
encodeULEB128(SectionIndex, getStream());
break;
}
default:
llvm_unreachable("unexpected kind");
}
@ -927,16 +992,66 @@ void WasmObjectWriter::writeLinkingMetaDataSection(
endSection(Section);
}
void WasmObjectWriter::writeUserCustomSections(
ArrayRef<WasmCustomSection> CustomSections) {
for (const auto &CustomSection : CustomSections) {
void WasmObjectWriter::writeCustomSections(const MCAssembler &Asm,
const MCAsmLayout &Layout) {
for (auto &CustomSection : CustomSections) {
SectionBookkeeping Section;
auto *Sec = CustomSection.Section;
startCustomSection(Section, CustomSection.Name);
writeBytes(CustomSection.Contents);
Sec->setSectionOffset(getStream().tell() - Section.ContentsOffset);
Asm.writeSectionData(Sec, Layout);
CustomSection.OutputContentsOffset = Section.ContentsOffset;
CustomSection.OutputIndex = Section.Index;
endSection(Section);
}
}
void WasmObjectWriter::updateCustomSectionRelocations(
const SmallVector<WasmFunction, 4> &Functions, const MCAsmLayout &Layout) {
std::map<const MCSection *, const MCSymbolWasm *> SectionSymbols;
for (const auto &P : CustomSectionSymbols)
SectionSymbols[P.second] = P.first;
std::map<const MCSection *, const MCSymbolWasm *> FuncSymbols;
for (const auto &FuncInfo : Functions)
FuncSymbols[&FuncInfo.Sym->getSection()] = FuncInfo.Sym;
// Patch relocation records for R_WEBASSEMBLY_FUNCTION_OFFSET_I32 and
// R_WEBASSEMBLY_SECTION_OFFSET_I32. The Addend is stuffed the offset from
// the beginning of the function or custom section -- all such relocations
// target the function or custom section starts.
for (auto &Section : CustomSections) {
auto &Relocations = CustomSectionsRelocations[Section.Section];
for (WasmRelocationEntry &RelEntry : Relocations) {
switch (RelEntry.Type) {
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: {
assert(RelEntry.hasAddend());
auto &Section =
static_cast<MCSectionWasm &>(RelEntry.Symbol->getSection());
RelEntry.Addend += Layout.getSymbolOffset(*RelEntry.Symbol);
RelEntry.Symbol = FuncSymbols[&Section];
break;
}
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: {
assert(RelEntry.hasAddend());
auto &Section =
static_cast<MCSectionWasm &>(RelEntry.Symbol->getSection());
RelEntry.Addend += Layout.getSymbolOffset(*RelEntry.Symbol);
RelEntry.Symbol = SectionSymbols[&Section];
break;
}
default:
break;
}
}
// Apply fixups.
applyRelocations(Relocations, Section.OutputContentsOffset);
}
}
uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) {
assert(Symbol.isFunction());
assert(TypeIndices.count(&Symbol));
@ -1043,8 +1158,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
for (MCSection &Sec : Asm) {
auto &Section = static_cast<MCSectionWasm &>(Sec);
if (cast<MCSectionWasm>(Sec).getSectionName().startswith(
".custom_section.")) {
if (Section.getSectionName().startswith(".custom_section.")) {
if (Section.getFragmentList().empty())
continue;
if (Section.getFragmentList().size() != 1)
@ -1057,8 +1171,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
if (!DataFrag.getFixups().empty())
report_fatal_error("fixups not supported in .custom_section section");
StringRef UserName = Section.getSectionName().substr(16);
const SmallVectorImpl<char> &Contents = DataFrag.getContents();
CustomSections.push_back(WasmCustomSection(UserName, Contents));
CustomSections.emplace_back(UserName, &Section);
continue;
}
@ -1088,6 +1201,31 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
}
}
// Create symbols for debug/custom sections.
for (MCSection &Sec : Asm) {
auto &DebugSection = static_cast<MCSectionWasm &>(Sec);
StringRef SectionName = DebugSection.getSectionName();
// TODO: Add support for non-debug metadata sections?
if (!Sec.getKind().isMetadata() || !SectionName.startswith(".debug_"))
continue;
uint32_t ElementIndex = CustomSections.size();
CustomSections.emplace_back(SectionName, &DebugSection);
MCSymbolWasm *SectionSym =
cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SectionName));
CustomSectionSymbols[SectionSym] = &DebugSection;
wasm::WasmSymbolInfo Info;
Info.Name = SectionSym->getName();
Info.Kind = wasm::WASM_SYMBOL_TYPE_SECTION;
Info.Flags = 0;
Info.ElementIndex = ElementIndex;
SymbolIndices[SectionSym] = SymbolInfos.size();
SymbolInfos.emplace_back(Info);
}
// Populate WasmIndices and DataLocations for defined symbols.
for (const MCSymbol &S : Asm.symbols()) {
// Ignore unnamed temporary symbols, which aren't ever exported, imported,
@ -1331,13 +1469,14 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
writeElemSection(TableElems);
writeCodeSection(Asm, Layout, Functions);
writeDataSection();
writeUserCustomSections(CustomSections);
writeCustomSections(Asm, Layout);
updateCustomSectionRelocations(Functions, Layout);
writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
writeCustomRelocSections();
// TODO: Translate the .comment section to the output.
// TODO: Translate debug sections to the output.
}
std::unique_ptr<MCObjectWriter>

View File

@ -465,6 +465,14 @@ Error WasmObjectFile::parseLinkingSectionSymtab(const uint8_t *&Ptr,
}
break;
case wasm::WASM_SYMBOL_TYPE_SECTION: {
Info.ElementIndex = readVaruint32(Ptr);
// Use somewhat unique section name as symbol name.
StringRef SectionName = Sections[Info.ElementIndex].Name;
Info.Name = SectionName;
break;
}
default:
return make_error<GenericBinaryError>("Invalid symbol type",
object_error::parse_failed);
@ -573,6 +581,18 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr,
object_error::parse_failed);
Reloc.Addend = readVarint32(Ptr);
break;
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
if (!isValidFunctionSymbol(Reloc.Index))
return make_error<GenericBinaryError>("Bad relocation function index",
object_error::parse_failed);
Reloc.Addend = readVarint32(Ptr);
break;
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
if (!isValidSectionSymbol(Reloc.Index))
return make_error<GenericBinaryError>("Bad relocation section index",
object_error::parse_failed);
Reloc.Addend = readVarint32(Ptr);
break;
default:
return make_error<GenericBinaryError>("Bad relocation type: " +
Twine(Reloc.Type),
@ -584,7 +604,9 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr,
// to check that.
uint64_t Size = 5;
if (Reloc.Type == wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 ||
Reloc.Type == wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32)
Reloc.Type == wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32 ||
Reloc.Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32 ||
Reloc.Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32)
Size = 4;
if (Reloc.Offset + Size > EndOffset)
return make_error<GenericBinaryError>("Bad relocation offset",
@ -811,6 +833,10 @@ bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeData();
}
bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeSection();
}
wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
assert(isDefinedFunctionIndex(Index));
return Functions[Index - NumImportedFunctions];
@ -991,6 +1017,8 @@ uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol& Sym) const {
assert(Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST);
return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
}
case wasm::WASM_SYMBOL_TYPE_SECTION:
return 0;
}
llvm_unreachable("invalid symbol type");
}
@ -1020,6 +1048,8 @@ WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
return SymbolRef::ST_Other;
case wasm::WASM_SYMBOL_TYPE_DATA:
return SymbolRef::ST_Data;
case wasm::WASM_SYMBOL_TYPE_SECTION:
return SymbolRef::ST_Debug;
}
llvm_unreachable("Unknown WasmSymbol::SymbolType");
@ -1043,6 +1073,10 @@ WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
case wasm::WASM_SYMBOL_TYPE_DATA:
Ref.d.a = DataSection;
break;
case wasm::WASM_SYMBOL_TYPE_SECTION: {
Ref.d.a = Sym.Info.ElementIndex;
break;
}
default:
llvm_unreachable("Unknown WasmSymbol::SymbolType");
}

View File

@ -405,6 +405,8 @@ void MappingTraits<WasmYAML::SymbolInfo>::mapping(IO &IO,
IO.mapOptional("Offset", Info.DataRef.Offset, 0u);
IO.mapRequired("Size", Info.DataRef.Size);
}
} else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION) {
IO.mapRequired("Section", Info.ElementIndex);
} else {
llvm_unreachable("unsupported symbol kind");
}
@ -439,6 +441,7 @@ void ScalarEnumerationTraits<WasmYAML::SymbolKind>::enumeration(
ECase(FUNCTION);
ECase(DATA);
ECase(GLOBAL);
ECase(SECTION);
#undef ECase
}

View File

@ -20,9 +20,10 @@
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSectionWasm.h"
#include "llvm/MC/MCSymbolWasm.h"
#include "llvm/MC/MCWasmObjectWriter.h"
#include "llvm/MC/MCValue.h"
#include "llvm/MC/MCWasmObjectWriter.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@ -61,6 +62,25 @@ static bool IsFunctionType(const MCValue &Target) {
return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX;
}
static const MCSection *GetFixupSection(const MCExpr *Expr) {
if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) {
if (SyExp->getSymbol().isInSection())
return &SyExp->getSymbol().getSection();
return nullptr;
}
if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr)) {
auto SectionLHS = GetFixupSection(BinOp->getLHS());
auto SectionRHS = GetFixupSection(BinOp->getRHS());
return SectionLHS == SectionRHS ? nullptr : SectionLHS;
}
if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))
return GetFixupSection(UnOp->getSubExpr());
return nullptr;
}
unsigned
WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
const MCFixup &Fixup) const {
@ -86,6 +106,13 @@ WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
case FK_Data_4:
if (IsFunction)
return wasm::R_WEBASSEMBLY_TABLE_INDEX_I32;
if (auto Section = static_cast<const MCSectionWasm *>(
GetFixupSection(Fixup.getValue()))) {
if (Section->getKind().isText())
return wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32;
else if (!Section->isWasmData())
return wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32;
}
return wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32;
case FK_Data_8:
llvm_unreachable("FK_Data_8 not implemented yet");

View File

@ -1,9 +1,169 @@
; RUN: llc -filetype=obj %s -o - | llvm-readobj -r -s -expand-relocs
; RUN: llc -filetype=obj %s -o - | llvm-readobj -r -s | FileCheck %s
; CHECK: Format: WASM
; CHECK-NEXT:Arch: wasm32
; CHECK-NEXT:AddressSize: 32bit
; CHECK-NEXT:Sections [
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: TYPE (0x1)
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Offset: 8
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: IMPORT (0x2)
; CHECK-NEXT: Size: 58
; CHECK-NEXT: Offset: 18
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: FUNCTION (0x3)
; CHECK-NEXT: Size: 2
; CHECK-NEXT: Offset: 82
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: ELEM (0x9)
; CHECK-NEXT: Size: 7
; CHECK-NEXT: Offset: 90
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CODE (0xA)
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Offset: 103
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: DATA (0xB)
; CHECK-NEXT: Size: 19
; CHECK-NEXT: Offset: 113
; CHECK-NEXT: Segments [
; CHECK-NEXT: Segment {
; CHECK-NEXT: Name: .data.foo
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Offset: 0
; CHECK-NEXT: }
; CHECK-NEXT: Segment {
; CHECK-NEXT: Name: .data.ptr2
; CHECK-NEXT: Size: 4
; CHECK-NEXT: Offset: 4
; CHECK-NEXT: }
; CHECK-NEXT: ]
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 121
; CHECK-NEXT: Offset: 138
; CHECK-NEXT: Name: .debug_str
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 84
; CHECK-NEXT: Offset: 276
; CHECK-NEXT: Name: .debug_abbrev
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 106
; CHECK-NEXT: Offset: 380
; CHECK-NEXT: Name: .debug_info
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 0
; CHECK-NEXT: Offset: 504
; CHECK-NEXT: Name: .debug_ranges
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 1
; CHECK-NEXT: Offset: 524
; CHECK-NEXT: Name: .debug_macinfo
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 42
; CHECK-NEXT: Offset: 546
; CHECK-NEXT: Name: .debug_pubnames
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 26
; CHECK-NEXT: Offset: 610
; CHECK-NEXT: Name: .debug_pubtypes
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 57
; CHECK-NEXT: Offset: 658
; CHECK-NEXT: Name: .debug_line
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 100
; CHECK-NEXT: Offset: 733
; CHECK-NEXT: Name: linking
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 9
; CHECK-NEXT: Offset: 847
; CHECK-NEXT: Name: reloc.DATA
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 58
; CHECK-NEXT: Offset: 873
; CHECK-NEXT: Name: reloc..debug_info
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 6
; CHECK-NEXT: Offset: 955
; CHECK-NEXT: Name: reloc..debug_pubnames
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 6
; CHECK-NEXT: Offset: 989
; CHECK-NEXT: Name: reloc..debug_pubtypes
; CHECK-NEXT: }
; CHECK-NEXT: Section {
; CHECK-NEXT: Type: CUSTOM (0x0)
; CHECK-NEXT: Size: 6
; CHECK-NEXT: Offset: 1023
; CHECK-NEXT: Name: reloc..debug_line
; CHECK-NEXT: }
; CHECK-NEXT:]
; CHECK-NEXT:Relocations [
; CHECK-NEXT: Section (6) DATA {
; CHECK-NEXT: 0x6 R_WEBASSEMBLY_MEMORY_ADDR_I32[10] 0
; CHECK-NEXT: 0xF R_WEBASSEMBLY_TABLE_INDEX_I32[8]
; CHECK-NEXT: }
; CHECK-NEXT: Section (9) .debug_info {
; CHECK-NEXT: 0x6 R_WEBASSEMBLY_SECTION_OFFSET_I32[1] 0
; CHECK-NEXT: 0xC R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 0
; CHECK-NEXT: 0x12 R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 55
; CHECK-NEXT: 0x16 R_WEBASSEMBLY_SECTION_OFFSET_I32[7] 0
; CHECK-NEXT: 0x1A R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 62
; CHECK-NEXT: 0x1E R_WEBASSEMBLY_FUNCTION_OFFSET_I32[8] 0
; CHECK-NEXT: 0x27 R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 105
; CHECK-NEXT: 0x33 R_WEBASSEMBLY_MEMORY_ADDR_I32[9] 0
; CHECK-NEXT: 0x3D R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 109
; CHECK-NEXT: 0x44 R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 113
; CHECK-NEXT: 0x50 R_WEBASSEMBLY_MEMORY_ADDR_I32[11] 0
; CHECK-NEXT: 0x5B R_WEBASSEMBLY_FUNCTION_OFFSET_I32[8] 0
; CHECK-NEXT: 0x63 R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 118
; CHECK-NEXT: }
; CHECK-NEXT: Section (12) .debug_pubnames {
; CHECK-NEXT: 0x6 R_WEBASSEMBLY_SECTION_OFFSET_I32[2] 0
; CHECK-NEXT: }
; CHECK-NEXT: Section (13) .debug_pubtypes {
; CHECK-NEXT: 0x6 R_WEBASSEMBLY_SECTION_OFFSET_I32[2] 0
; CHECK-NEXT: }
; CHECK-NEXT: Section (14) .debug_line {
; CHECK-NEXT: 0x2B R_WEBASSEMBLY_FUNCTION_OFFSET_I32[8] 0
; CHECK-NEXT: }
; CHECK-NEXT:]
target triple = "wasm32-unknown-unknown-wasm"
; Debug information is currently not supported. This test simply verifies that
; a valid object generated.
source_filename = "test.c"
@myextern = external global i32, align 4

View File

@ -0,0 +1,95 @@
; RUN: llc -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s
; CHECK: .debug_info contents:
; CHECK-NEXT: 0x00000000: Compile Unit: length = 0x00000066 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000006a)
; CHECK: 0x0000000b: DW_TAG_compile_unit
; CHECK-NEXT: DW_AT_producer ("clang version 6.0.0 (trunk 315924) (llvm/trunk 315960)")
; CHECK-NEXT: DW_AT_language (DW_LANG_C99)
; CHECK-NEXT: DW_AT_name ("test.c")
; CHECK-NEXT: DW_AT_stmt_list (0x00000000)
; CHECK-NEXT: DW_AT_comp_dir ("/usr/local/google/home/sbc/dev/wasm/simple")
; CHECK-NEXT: DW_AT_GNU_pubnames (true)
; CHECK-NEXT: DW_AT_low_pc (0x0000000000000002)
; CHECK-NEXT: DW_AT_high_pc (0x0000000000000004)
; CHECK: 0x00000026: DW_TAG_variable
; CHECK-NEXT: DW_AT_name ("foo")
; CHECK-NEXT: DW_AT_type (0x00000037 "int*")
; CHECK-NEXT: DW_AT_external (true)
; CHECK-NEXT: DW_AT_decl_file ("/usr/local/google/home/sbc/dev/wasm/simple/test.c")
; CHECK-NEXT: DW_AT_decl_line (4)
; CHECK-NEXT: DW_AT_location (DW_OP_addr 0x0)
; CHECK: 0x00000037: DW_TAG_pointer_type
; CHECK-NEXT: DW_AT_type (0x0000003c "int")
; CHECK: 0x0000003c: DW_TAG_base_type
; CHECK-NEXT: DW_AT_name ("int")
; CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
; CHECK-NEXT: DW_AT_byte_size (0x04)
; CHECK: 0x00000043: DW_TAG_variable
; CHECK-NEXT: DW_AT_name ("ptr2")
; CHECK-NEXT: DW_AT_type (0x00000054 "subroutine *")
; CHECK-NEXT: DW_AT_external (true)
; CHECK-NEXT: DW_AT_decl_file ("/usr/local/google/home/sbc/dev/wasm/simple/test.c")
; CHECK-NEXT: DW_AT_decl_line (5)
; CHECK-NEXT: DW_AT_location (DW_OP_addr 0x4)
; CHECK: 0x00000054: DW_TAG_pointer_type
; CHECK-NEXT: DW_AT_type (0x00000059 "subroutine ")
; CHECK: 0x00000059: DW_TAG_subroutine_type
; CHECK-NEXT: DW_AT_prototyped (true)
; CHECK: 0x0000005a: DW_TAG_subprogram
; CHECK-NEXT: DW_AT_low_pc (0x0000000000000002)
; CHECK-NEXT: DW_AT_high_pc (0x0000000000000004)
; CHECK-NEXT: DW_AT_name ("f2")
; CHECK-NEXT: DW_AT_decl_file ("/usr/local/google/home/sbc/dev/wasm/simple/test.c")
; CHECK-NEXT: DW_AT_decl_line (2)
; CHECK-NEXT: DW_AT_prototyped (true)
; CHECK-NEXT: DW_AT_external (true)
; CHECK: 0x00000069: NULL
target triple = "wasm32-unknown-unknown-wasm"
source_filename = "test.c"
@myextern = external global i32, align 4
@foo = hidden global i32* @myextern, align 4, !dbg !0
@ptr2 = hidden global void ()* @f2, align 4, !dbg !6
; Function Attrs: noinline nounwind optnone
define hidden void @f2() #0 !dbg !17 {
entry:
ret void, !dbg !18
}
attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!13, !14, !15}
!llvm.ident = !{!16}
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "foo", scope: !2, file: !3, line: 4, type: !11, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 6.0.0 (trunk 315924) (llvm/trunk 315960)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
!3 = !DIFile(filename: "test.c", directory: "/usr/local/google/home/sbc/dev/wasm/simple")
!4 = !{}
!5 = !{!0, !6}
!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
!7 = distinct !DIGlobalVariable(name: "ptr2", scope: !2, file: !3, line: 5, type: !8, isLocal: false, isDefinition: true)
!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 32)
!9 = !DISubroutineType(types: !10)
!10 = !{null}
!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 32)
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!13 = !{i32 2, !"Dwarf Version", i32 4}
!14 = !{i32 2, !"Debug Info Version", i32 3}
!15 = !{i32 1, !"wchar_size", i32 4}
!16 = !{!"clang version 6.0.0 (trunk 315924) (llvm/trunk 315960)"}
!17 = distinct !DISubprogram(name: "f2", scope: !3, file: !3, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !2, variables: !4)
!18 = !DILocation(line: 2, column: 16, scope: !17)

View File

@ -84,6 +84,8 @@ void WasmDumper::printRelocation(const SectionRef &Section,
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
HasAddend = true;
break;
default:

View File

@ -106,6 +106,9 @@ std::unique_ptr<WasmYAML::CustomSection> WasmDumper::dumpCustomSection(const Was
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
Info.ElementIndex = Symbol.ElementIndex;
break;
case wasm::WASM_SYMBOL_TYPE_SECTION:
Info.ElementIndex = Symbol.ElementIndex;
break;
}
LinkingSec->SymbolTable.emplace_back(Info);
}

View File

@ -165,6 +165,9 @@ int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &S
encodeULEB128(Info.DataRef.Size, SubSection.GetStream());
}
break;
case wasm::WASM_SYMBOL_TYPE_SECTION:
encodeULEB128(Info.ElementIndex, SubSection.GetStream());
break;
default:
llvm_unreachable("unexpected kind");
}
@ -424,20 +427,28 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
int WasmWriter::writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec,
uint32_t SectionIndex) {
StringRef Name;
switch (Sec.Type) {
case wasm::WASM_SEC_CODE:
Name = "reloc.CODE";
writeStringRef("reloc.CODE", OS);
break;
case wasm::WASM_SEC_DATA:
Name = "reloc.DATA";
writeStringRef("reloc.DATA", OS);
break;
case wasm::WASM_SEC_CUSTOM: {
auto CustomSection = dyn_cast<WasmYAML::CustomSection>(&Sec);
if (!CustomSection->Name.startswith(".debug_")) {
llvm_unreachable("not yet implemented (only for debug sections)");
return 1;
}
writeStringRef(("reloc." + CustomSection->Name).str(), OS);
break;
}
default:
llvm_unreachable("not yet implemented");
return 1;
}
writeStringRef(Name, OS);
encodeULEB128(SectionIndex, OS);
encodeULEB128(Sec.Relocations.size(), OS);
@ -449,6 +460,8 @@ int WasmWriter::writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec,
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
encodeULEB128(Reloc.Addend, OS);
}
}