summaryrefslogtreecommitdiff
path: root/llvm/lib/MC/WasmObjectWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC/WasmObjectWriter.cpp')
-rw-r--r--llvm/lib/MC/WasmObjectWriter.cpp360
1 files changed, 237 insertions, 123 deletions
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index 321f93d76092b..f51d908c53e13 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -27,6 +27,7 @@
#include "llvm/MC/MCWasmObjectWriter.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/StringSaver.h"
@@ -107,7 +108,7 @@ struct WasmDataSegment {
MCSectionWasm *Section;
StringRef Name;
uint32_t InitFlags;
- uint32_t Offset;
+ uint64_t Offset;
uint32_t Alignment;
uint32_t LinkerFlags;
SmallVector<char, 4> Data;
@@ -152,7 +153,7 @@ struct WasmRelocationEntry {
void print(raw_ostream &Out) const {
Out << wasm::relocTypetoString(Type) << " Off=" << Offset
<< ", Sym=" << *Symbol << ", Addend=" << Addend
- << ", FixupSection=" << FixupSection->getSectionName();
+ << ", FixupSection=" << FixupSection->getName();
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@@ -184,31 +185,37 @@ raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) {
// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
// to allow patching.
-static void writePatchableLEB(raw_pwrite_stream &Stream, uint32_t X,
- uint64_t Offset) {
- uint8_t Buffer[5];
- unsigned SizeLen = encodeULEB128(X, Buffer, 5);
- assert(SizeLen == 5);
+template <int W>
+void writePatchableLEB(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) {
+ uint8_t Buffer[W];
+ unsigned SizeLen = encodeULEB128(X, Buffer, W);
+ assert(SizeLen == W);
Stream.pwrite((char *)Buffer, SizeLen, Offset);
}
// Write X as an signed LEB value at offset Offset in Stream, padded
// to allow patching.
-static void writePatchableSLEB(raw_pwrite_stream &Stream, int32_t X,
- uint64_t Offset) {
- uint8_t Buffer[5];
- unsigned SizeLen = encodeSLEB128(X, Buffer, 5);
- assert(SizeLen == 5);
+template <int W>
+void writePatchableSLEB(raw_pwrite_stream &Stream, int64_t X, uint64_t Offset) {
+ uint8_t Buffer[W];
+ unsigned SizeLen = encodeSLEB128(X, Buffer, W);
+ assert(SizeLen == W);
Stream.pwrite((char *)Buffer, SizeLen, Offset);
}
// Write X as a plain integer value at offset Offset in Stream.
-static void writeI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
+static void patchI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
uint8_t Buffer[4];
support::endian::write32le(Buffer, X);
Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
}
+static void patchI64(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) {
+ uint8_t Buffer[8];
+ support::endian::write64le(Buffer, X);
+ Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
+}
+
class WasmObjectWriter : public MCObjectWriter {
support::endian::Writer W;
@@ -217,11 +224,8 @@ class WasmObjectWriter : public MCObjectWriter {
// Relocations for fixing up references in the code section.
std::vector<WasmRelocationEntry> CodeRelocations;
- uint32_t CodeSectionIndex;
-
// Relocations for fixing up references in the data section.
std::vector<WasmRelocationEntry> DataRelocations;
- uint32_t DataSectionIndex;
// Index values to use for fixing up call_indirect type indices.
// Maps function symbols to the index of the type of the function
@@ -307,19 +311,32 @@ private:
W.OS << Str;
}
+ void writeI32(int32_t val) {
+ char Buffer[4];
+ support::endian::write32le(Buffer, val);
+ 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));
+ }
+
void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); }
void writeTypeSection(ArrayRef<WasmSignature> Signatures);
- void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize,
+ void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint64_t DataSize,
uint32_t NumElements);
void writeFunctionSection(ArrayRef<WasmFunction> Functions);
void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
void writeElemSection(ArrayRef<uint32_t> TableElems);
void writeDataCountSection();
- void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
- ArrayRef<WasmFunction> Functions);
- void writeDataSection();
+ uint32_t writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ ArrayRef<WasmFunction> Functions);
+ uint32_t writeDataSection(const MCAsmLayout &Layout);
void writeEventSection(ArrayRef<wasm::WasmEventType> Events);
+ void writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals);
void writeRelocSection(uint32_t SectionIndex, StringRef Name,
std::vector<WasmRelocationEntry> &Relocations);
void writeLinkingMetaDataSection(
@@ -333,9 +350,10 @@ private:
updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions,
const MCAsmLayout &Layout);
- uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
+ uint64_t getProvisionalValue(const WasmRelocationEntry &RelEntry,
+ const MCAsmLayout &Layout);
void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
- uint64_t ContentsOffset);
+ uint64_t ContentsOffset, const MCAsmLayout &Layout);
uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
uint32_t getFunctionType(const MCSymbolWasm &Symbol);
@@ -396,8 +414,8 @@ void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
// Write the final section size to the payload_len field, which follows
// the section id byte.
- writePatchableLEB(static_cast<raw_pwrite_stream &>(W.OS), Size,
- Section.SizeOffset);
+ writePatchableLEB<5>(static_cast<raw_pwrite_stream &>(W.OS), Size,
+ Section.SizeOffset);
}
// Emit the Wasm header.
@@ -417,7 +435,7 @@ void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
auto Pair = SectionFunctions.insert(std::make_pair(&Sec, &S));
if (!Pair.second)
report_fatal_error("section already has a defining function: " +
- Sec.getSectionName());
+ Sec.getName());
}
}
}
@@ -436,10 +454,6 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
MCContext &Ctx = Asm.getContext();
- // The .init_array isn't translated as data, so don't do relocations in it.
- if (FixupSection.getSectionName().startswith(".init_array"))
- return;
-
if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
// To get here the A - B expression must have failed evaluateAsRelocatable.
// This means either A or B must be undefined and in WebAssembly we can't
@@ -456,11 +470,17 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
const MCSymbolRefExpr *RefA = Target.getSymA();
const auto *SymA = cast<MCSymbolWasm>(&RefA->getSymbol());
+ // The .init_array isn't translated as data, so don't do relocations in it.
+ if (FixupSection.getName().startswith(".init_array")) {
+ SymA->setUsedInInitArray();
+ return;
+ }
+
if (SymA->isVariable()) {
const MCExpr *Expr = SymA->getVariableValue();
- const auto *Inner = cast<MCSymbolRefExpr>(Expr);
- if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
- llvm_unreachable("weakref used in reloc not yet implemented");
+ if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr))
+ if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
+ llvm_unreachable("weakref used in reloc not yet implemented");
}
// Put any constant offset in an addend. Offsets can be negative, and
@@ -519,23 +539,16 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
}
}
-static const MCSymbolWasm *resolveSymbol(const MCSymbolWasm &Symbol) {
- const MCSymbolWasm* Ret = &Symbol;
- while (Ret->isVariable()) {
- const MCExpr *Expr = Ret->getVariableValue();
- auto *Inner = cast<MCSymbolRefExpr>(Expr);
- Ret = cast<MCSymbolWasm>(&Inner->getSymbol());
- }
- return Ret;
-}
-
// Compute a value to write into the code at the location covered
// by RelEntry. This value isn't used by the static linker; it just serves
// to make the object format more readable and more likely to be directly
// useable.
-uint32_t
-WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
- if (RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB && !RelEntry.Symbol->isGlobal()) {
+uint64_t
+WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry,
+ const MCAsmLayout &Layout) {
+ if ((RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB ||
+ RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_I32) &&
+ !RelEntry.Symbol->isGlobal()) {
assert(GOTIndices.count(RelEntry.Symbol) > 0 && "symbol not found in GOT index space");
return GOTIndices[RelEntry.Symbol];
}
@@ -545,15 +558,20 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
case wasm::R_WASM_TABLE_INDEX_SLEB:
case wasm::R_WASM_TABLE_INDEX_I32: {
// Provisional value is table address of the resolved symbol itself
- const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol);
- assert(Sym->isFunction());
- return TableIndices[Sym];
+ const MCSymbolWasm *Base =
+ cast<MCSymbolWasm>(Layout.getBaseSymbol(*RelEntry.Symbol));
+ assert(Base->isFunction());
+ if (RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB)
+ return TableIndices[Base] - InitialTableOffset;
+ else
+ return TableIndices[Base];
}
case wasm::R_WASM_TYPE_INDEX_LEB:
// Provisional value is same as the index
return getRelocationIndexValue(RelEntry);
case wasm::R_WASM_FUNCTION_INDEX_LEB:
case wasm::R_WASM_GLOBAL_INDEX_LEB:
+ case wasm::R_WASM_GLOBAL_INDEX_I32:
case wasm::R_WASM_EVENT_INDEX_LEB:
// Provisional value is function/global/event Wasm index
assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space");
@@ -565,15 +583,20 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
return Section.getSectionOffset() + RelEntry.Addend;
}
case wasm::R_WASM_MEMORY_ADDR_LEB:
- case wasm::R_WASM_MEMORY_ADDR_I32:
+ case wasm::R_WASM_MEMORY_ADDR_LEB64:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB64:
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
- case wasm::R_WASM_MEMORY_ADDR_SLEB: {
+ case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
+ case wasm::R_WASM_MEMORY_ADDR_I32:
+ case wasm::R_WASM_MEMORY_ADDR_I64: {
// Provisional value is address of the global
- const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol);
+ const MCSymbolWasm *Base =
+ cast<MCSymbolWasm>(Layout.getBaseSymbol(*RelEntry.Symbol));
// For undefined symbols, use zero
- if (!Sym->isDefined())
+ if (!Base->isDefined())
return 0;
- const wasm::WasmDataReference &Ref = DataLocations[Sym];
+ const wasm::WasmDataReference &Ref = DataLocations[Base];
const WasmDataSegment &Segment = DataSegments[Ref.Segment];
// Ignore overflow. LLVM allows address arithmetic to silently wrap.
return Segment.Offset + Ref.Offset + RelEntry.Addend;
@@ -585,7 +608,7 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
static void addData(SmallVectorImpl<char> &DataBytes,
MCSectionWasm &DataSection) {
- LLVM_DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n");
+ LLVM_DEBUG(errs() << "addData: " << DataSection.getName() << "\n");
DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
@@ -636,7 +659,8 @@ WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) {
// Apply the portions of the relocation records that we can handle ourselves
// directly.
void WasmObjectWriter::applyRelocations(
- ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) {
+ ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset,
+ const MCAsmLayout &Layout) {
auto &Stream = static_cast<raw_pwrite_stream &>(W.OS);
for (const WasmRelocationEntry &RelEntry : Relocations) {
uint64_t Offset = ContentsOffset +
@@ -644,7 +668,7 @@ void WasmObjectWriter::applyRelocations(
RelEntry.Offset;
LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n");
- uint32_t Value = getProvisionalValue(RelEntry);
+ auto Value = getProvisionalValue(RelEntry, Layout);
switch (RelEntry.Type) {
case wasm::R_WASM_FUNCTION_INDEX_LEB:
@@ -652,19 +676,30 @@ void WasmObjectWriter::applyRelocations(
case wasm::R_WASM_GLOBAL_INDEX_LEB:
case wasm::R_WASM_MEMORY_ADDR_LEB:
case wasm::R_WASM_EVENT_INDEX_LEB:
- writePatchableLEB(Stream, Value, Offset);
+ writePatchableLEB<5>(Stream, Value, Offset);
+ break;
+ case wasm::R_WASM_MEMORY_ADDR_LEB64:
+ writePatchableLEB<10>(Stream, Value, Offset);
break;
case wasm::R_WASM_TABLE_INDEX_I32:
case wasm::R_WASM_MEMORY_ADDR_I32:
case wasm::R_WASM_FUNCTION_OFFSET_I32:
case wasm::R_WASM_SECTION_OFFSET_I32:
- writeI32(Stream, Value, Offset);
+ case wasm::R_WASM_GLOBAL_INDEX_I32:
+ patchI32(Stream, Value, Offset);
+ break;
+ case wasm::R_WASM_MEMORY_ADDR_I64:
+ patchI64(Stream, Value, Offset);
break;
case wasm::R_WASM_TABLE_INDEX_SLEB:
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
case wasm::R_WASM_MEMORY_ADDR_SLEB:
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
- writePatchableSLEB(Stream, Value, Offset);
+ writePatchableSLEB<5>(Stream, Value, Offset);
+ break;
+ case wasm::R_WASM_MEMORY_ADDR_SLEB64:
+ case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
+ writePatchableSLEB<10>(Stream, Value, Offset);
break;
default:
llvm_unreachable("invalid relocation type");
@@ -695,12 +730,12 @@ void WasmObjectWriter::writeTypeSection(ArrayRef<WasmSignature> Signatures) {
}
void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
- uint32_t DataSize,
+ uint64_t DataSize,
uint32_t NumElements) {
if (Imports.empty())
return;
- uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
+ uint64_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_IMPORT);
@@ -720,8 +755,8 @@ void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
W.OS << char(Import.Global.Mutable ? 1 : 0);
break;
case wasm::WASM_EXTERNAL_MEMORY:
- encodeULEB128(0, W.OS); // flags
- 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);
@@ -770,6 +805,43 @@ void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) {
endSection(Section);
}
+void WasmObjectWriter::writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals) {
+ if (Globals.empty())
+ return;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_GLOBAL);
+
+ 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);
+ switch (Global.Type.Type) {
+ case wasm::WASM_TYPE_I32:
+ encodeSLEB128(0, W.OS);
+ break;
+ case wasm::WASM_TYPE_I64:
+ encodeSLEB128(0, W.OS);
+ break;
+ case wasm::WASM_TYPE_F32:
+ writeI32(0);
+ break;
+ case wasm::WASM_TYPE_F64:
+ writeI64(0);
+ break;
+ case wasm::WASM_TYPE_EXTERNREF:
+ writeValueType(wasm::ValType::EXTERNREF);
+ break;
+ default:
+ llvm_unreachable("unexpected type");
+ }
+ W.OS << char(wasm::WASM_OPCODE_END);
+ }
+
+ endSection(Section);
+}
+
void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
if (Exports.empty())
return;
@@ -819,15 +891,14 @@ void WasmObjectWriter::writeDataCountSection() {
endSection(Section);
}
-void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
- const MCAsmLayout &Layout,
- ArrayRef<WasmFunction> Functions) {
+uint32_t WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ ArrayRef<WasmFunction> Functions) {
if (Functions.empty())
- return;
+ return 0;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_CODE);
- CodeSectionIndex = Section.Index;
encodeULEB128(Functions.size(), W.OS);
@@ -844,18 +915,18 @@ void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
}
// Apply fixups.
- applyRelocations(CodeRelocations, Section.ContentsOffset);
+ applyRelocations(CodeRelocations, Section.ContentsOffset, Layout);
endSection(Section);
+ return Section.Index;
}
-void WasmObjectWriter::writeDataSection() {
+uint32_t WasmObjectWriter::writeDataSection(const MCAsmLayout &Layout) {
if (DataSegments.empty())
- return;
+ return 0;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_DATA);
- DataSectionIndex = Section.Index;
encodeULEB128(DataSegments.size(), W.OS); // count
@@ -864,7 +935,9 @@ void WasmObjectWriter::writeDataSection() {
if (Segment.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX)
encodeULEB128(0, W.OS); // memory index
if ((Segment.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0) {
- W.OS << char(wasm::WASM_OPCODE_I32_CONST);
+ W.OS << char(Segment.Offset > std::numeric_limits<int32_t>().max()
+ ? wasm::WASM_OPCODE_I64_CONST
+ : wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(Segment.Offset, W.OS); // offset
W.OS << char(wasm::WASM_OPCODE_END);
}
@@ -874,9 +947,10 @@ void WasmObjectWriter::writeDataSection() {
}
// Apply fixups.
- applyRelocations(DataRelocations, Section.ContentsOffset);
+ applyRelocations(DataRelocations, Section.ContentsOffset, Layout);
endSection(Section);
+ return Section.Index;
}
void WasmObjectWriter::writeRelocSection(
@@ -1027,7 +1101,7 @@ void WasmObjectWriter::writeCustomSection(WasmCustomSection &CustomSection,
// Apply fixups.
auto &Relocations = CustomSectionsRelocations[CustomSection.Section];
- applyRelocations(Relocations, CustomSection.OutputContentsOffset);
+ applyRelocations(Relocations, CustomSection.OutputContentsOffset, Layout);
}
uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) {
@@ -1046,8 +1120,8 @@ void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) {
assert(Symbol.isFunction());
WasmSignature S;
- const MCSymbolWasm *ResolvedSym = resolveSymbol(Symbol);
- if (auto *Sig = ResolvedSym->getSignature()) {
+
+ if (auto *Sig = Symbol.getSignature()) {
S.Returns = Sig->Returns;
S.Params = Sig->Params;
}
@@ -1084,16 +1158,13 @@ void WasmObjectWriter::registerEventType(const MCSymbolWasm &Symbol) {
}
static bool isInSymtab(const MCSymbolWasm &Sym) {
- if (Sym.isUsedInReloc())
+ if (Sym.isUsedInReloc() || Sym.isUsedInInitArray())
return true;
if (Sym.isComdat() && !Sym.isDefined())
return false;
- if (Sym.isTemporary() && Sym.getName().empty())
- return false;
-
- if (Sym.isTemporary() && Sym.isData() && !Sym.getSize())
+ if (Sym.isTemporary())
return false;
if (Sym.isSection())
@@ -1114,10 +1185,11 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
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;
- uint32_t DataSize = 0;
+ uint64_t DataSize = 0;
// 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
@@ -1126,6 +1198,8 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
MemImport.Module = "env";
MemImport.Field = "__linear_memory";
MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY;
+ MemImport.Memory.Flags = is64Bit() ? wasm::WASM_LIMITS_FLAG_IS_64
+ : wasm::WASM_LIMITS_FLAG_NONE;
Imports.push_back(MemImport);
// For now, always emit the table section, since indirect calls are not
@@ -1146,8 +1220,10 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// Register types for all functions, including those with private linkage
// (because wasm always needs a type signature).
- if (WS.isFunction())
- registerFunctionType(WS);
+ if (WS.isFunction()) {
+ const MCSymbolWasm *Base = cast<MCSymbolWasm>(Layout.getBaseSymbol(S));
+ registerFunctionType(*Base);
+ }
if (WS.isEvent())
registerEventType(WS);
@@ -1217,7 +1293,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// populating DataLocations.
for (MCSection &Sec : Asm) {
auto &Section = static_cast<MCSectionWasm &>(Sec);
- StringRef SectionName = Section.getSectionName();
+ StringRef SectionName = Section.getName();
// .init_array sections are handled specially elsewhere.
if (SectionName.startswith(".init_array"))
@@ -1365,30 +1441,53 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// For each data symbol, export it in the symtab as a reference to the
// corresponding Wasm data segment.
wasm::WasmDataReference Ref = wasm::WasmDataReference{
- DataSection.getSegmentIndex(),
- static_cast<uint32_t>(Layout.getSymbolOffset(WS)),
- static_cast<uint32_t>(Size)};
+ DataSection.getSegmentIndex(), Layout.getSymbolOffset(WS),
+ static_cast<uint64_t>(Size)};
DataLocations[&WS] = Ref;
LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n");
} else if (WS.isGlobal()) {
// A "true" Wasm global (currently just __stack_pointer)
- if (WS.isDefined())
- report_fatal_error("don't yet support defined globals");
-
- // An import; the index was assigned above
- LLVM_DEBUG(dbgs() << " -> global index: "
- << WasmIndices.find(&WS)->second << "\n");
-
+ if (WS.isDefined()) {
+ assert(WasmIndices.count(&WS) == 0);
+ wasm::WasmGlobal Global;
+ Global.Type = WS.getGlobalType();
+ Global.Index = NumGlobalImports + Globals.size();
+ switch (Global.Type.Type) {
+ case wasm::WASM_TYPE_I32:
+ Global.InitExpr.Opcode = wasm::WASM_OPCODE_I32_CONST;
+ break;
+ case wasm::WASM_TYPE_I64:
+ Global.InitExpr.Opcode = wasm::WASM_OPCODE_I64_CONST;
+ break;
+ case wasm::WASM_TYPE_F32:
+ Global.InitExpr.Opcode = wasm::WASM_OPCODE_F32_CONST;
+ break;
+ case wasm::WASM_TYPE_F64:
+ Global.InitExpr.Opcode = wasm::WASM_OPCODE_F64_CONST;
+ break;
+ case wasm::WASM_TYPE_EXTERNREF:
+ Global.InitExpr.Opcode = wasm::WASM_OPCODE_REF_NULL;
+ break;
+ default:
+ llvm_unreachable("unexpected type");
+ }
+ WasmIndices[&WS] = Global.Index;
+ Globals.push_back(Global);
+ } else {
+ // An import; the index was assigned above
+ LLVM_DEBUG(dbgs() << " -> global index: "
+ << WasmIndices.find(&WS)->second << "\n");
+ }
} else if (WS.isEvent()) {
// C++ exception symbol (__cpp_exception)
unsigned Index;
if (WS.isDefined()) {
+ assert(WasmIndices.count(&WS) == 0);
Index = NumEventImports + Events.size();
wasm::WasmEventType Event;
Event.SigIndex = getEventType(WS);
Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
- assert(WasmIndices.count(&WS) == 0);
WasmIndices[&WS] = Index;
Events.push_back(Event);
} else {
@@ -1413,22 +1512,36 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
assert(S.isDefined());
+ const MCSymbolWasm *Base = cast<MCSymbolWasm>(Layout.getBaseSymbol(S));
+
// Find the target symbol of this weak alias and export that index
const auto &WS = static_cast<const MCSymbolWasm &>(S);
- const MCSymbolWasm *ResolvedSym = resolveSymbol(WS);
- LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym
- << "'\n");
+ LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *Base << "'\n");
- if (ResolvedSym->isFunction()) {
- assert(WasmIndices.count(ResolvedSym) > 0);
- uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second;
+ if (Base->isFunction()) {
+ assert(WasmIndices.count(Base) > 0);
+ uint32_t WasmIndex = WasmIndices.find(Base)->second;
assert(WasmIndices.count(&WS) == 0);
WasmIndices[&WS] = WasmIndex;
LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n");
- } else if (ResolvedSym->isData()) {
- assert(DataLocations.count(ResolvedSym) > 0);
- const wasm::WasmDataReference &Ref =
- DataLocations.find(ResolvedSym)->second;
+ } else if (Base->isData()) {
+ auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
+ uint64_t Offset = Layout.getSymbolOffset(S);
+ int64_t Size = 0;
+ // For data symbol alias we use the size of the base symbol as the
+ // size of the alias. When an offset from the base is involved this
+ // can result in a offset + size goes past the end of the data section
+ // which out object format doesn't support. So we must clamp it.
+ if (!Base->getSize()->evaluateAsAbsolute(Size, Layout))
+ report_fatal_error(".size expression must be evaluatable");
+ const WasmDataSegment &Segment =
+ DataSegments[DataSection.getSegmentIndex()];
+ Size =
+ std::min(static_cast<uint64_t>(Size), Segment.Data.size() - Offset);
+ wasm::WasmDataReference Ref = wasm::WasmDataReference{
+ DataSection.getSegmentIndex(),
+ static_cast<uint32_t>(Layout.getSymbolOffset(S)),
+ static_cast<uint32_t>(Size)};
DataLocations[&WS] = Ref;
LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n");
} else {
@@ -1486,17 +1599,19 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// purely to make the object file's provisional values readable, and is
// ignored by the linker, which re-calculates the relocations itself.
if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 &&
- Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB)
+ Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB &&
+ Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB)
return;
assert(Rel.Symbol->isFunction());
- const MCSymbolWasm &WS = *resolveSymbol(*Rel.Symbol);
- uint32_t FunctionIndex = WasmIndices.find(&WS)->second;
+ const MCSymbolWasm *Base =
+ cast<MCSymbolWasm>(Layout.getBaseSymbol(*Rel.Symbol));
+ uint32_t FunctionIndex = WasmIndices.find(Base)->second;
uint32_t TableIndex = TableElems.size() + InitialTableOffset;
- if (TableIndices.try_emplace(&WS, TableIndex).second) {
- LLVM_DEBUG(dbgs() << " -> adding " << WS.getName()
+ if (TableIndices.try_emplace(Base, TableIndex).second) {
+ LLVM_DEBUG(dbgs() << " -> adding " << Base->getName()
<< " to table: " << TableIndex << "\n");
TableElems.push_back(FunctionIndex);
- registerFunctionType(WS);
+ registerFunctionType(*Base);
}
};
@@ -1509,9 +1624,9 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// Translate .init_array section contents into start functions.
for (const MCSection &S : Asm) {
const auto &WS = static_cast<const MCSectionWasm &>(S);
- if (WS.getSectionName().startswith(".fini_array"))
+ if (WS.getName().startswith(".fini_array"))
report_fatal_error(".fini_array sections are unsupported");
- if (!WS.getSectionName().startswith(".init_array"))
+ if (!WS.getName().startswith(".init_array"))
continue;
if (WS.getFragmentList().empty())
continue;
@@ -1538,13 +1653,11 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
uint16_t Priority = UINT16_MAX;
unsigned PrefixLength = strlen(".init_array");
- if (WS.getSectionName().size() > PrefixLength) {
- if (WS.getSectionName()[PrefixLength] != '.')
+ if (WS.getName().size() > PrefixLength) {
+ if (WS.getName()[PrefixLength] != '.')
report_fatal_error(
".init_array section priority should start with '.'");
- if (WS.getSectionName()
- .substr(PrefixLength + 1)
- .getAsInteger(10, Priority))
+ if (WS.getName().substr(PrefixLength + 1).getAsInteger(10, Priority))
report_fatal_error("invalid .init_array section priority");
}
const auto &DataFrag = cast<MCDataFragment>(Frag);
@@ -1565,7 +1678,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
report_fatal_error("fixups in .init_array should be symbol references");
const auto &TargetSym = cast<const MCSymbolWasm>(SymRef->getSymbol());
if (TargetSym.getIndex() == InvalidIndex)
- report_fatal_error("symbols in .init_array should exist in symbtab");
+ report_fatal_error("symbols in .init_array should exist in symtab");
if (!TargetSym.isFunction())
report_fatal_error("symbols in .init_array should be for functions");
InitFuncs.push_back(
@@ -1582,11 +1695,12 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// 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();
- writeCodeSection(Asm, Layout, Functions);
- writeDataSection();
+ uint32_t CodeSectionIndex = writeCodeSection(Asm, Layout, Functions);
+ uint32_t DataSectionIndex = writeDataSection(Layout);
for (auto &CustomSection : CustomSections)
writeCustomSection(CustomSection, Asm, Layout);
writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);