Index: lld/trunk/wasm/InputChunks.cpp =================================================================== --- lld/trunk/wasm/InputChunks.cpp +++ lld/trunk/wasm/InputChunks.cpp @@ -61,6 +61,7 @@ for (const WasmRelocation &Rel : Relocations) { uint8_t *Loc = Buf + Rel.Offset + Off; uint32_t Value = File->calcNewValue(Rel); + uint32_t ExistingValue; DEBUG(dbgs() << "apply reloc: type=" << ReloctTypeToString(Rel.Type) << " addend=" << Rel.Addend << " index=" << Rel.Index << " value=" << Value << " offset=" << Rel.Offset << "\n"); @@ -70,19 +71,28 @@ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + ExistingValue = decodeULEB128(Loc); encodeULEB128(Value, Loc, 5); break; case R_WEBASSEMBLY_TABLE_INDEX_SLEB: case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + ExistingValue = static_cast(decodeSLEB128(Loc)); encodeSLEB128(static_cast(Value), Loc, 5); break; case R_WEBASSEMBLY_TABLE_INDEX_I32: case R_WEBASSEMBLY_MEMORY_ADDR_I32: + ExistingValue = static_cast(read32le(Loc)); write32le(Loc, Value); break; default: llvm_unreachable("unknown relocation type"); } + + uint32_t ExpectedValue = File->calcExpectedValue(Rel); + if (ExpectedValue != ExistingValue) + error("unexpected existing value for " + ReloctTypeToString(Rel.Type) + + ": existing=" + Twine(ExistingValue) + + " expected=" + Twine(ExpectedValue)); } } Index: lld/trunk/wasm/InputFiles.h =================================================================== --- lld/trunk/wasm/InputFiles.h +++ lld/trunk/wasm/InputFiles.h @@ -94,12 +94,16 @@ uint32_t calcNewIndex(const WasmRelocation &Reloc) const; uint32_t calcNewValue(const WasmRelocation &Reloc) const; + uint32_t calcExpectedValue(const WasmRelocation &Reloc) const; const WasmSection *CodeSection = nullptr; const WasmSection *DataSection = nullptr; + // Maps input type indices to output type indices std::vector TypeMap; std::vector TypeIsUsed; + // Maps function indices to table indices + std::vector TableEntries; std::vector Segments; std::vector Functions; std::vector Globals; Index: lld/trunk/wasm/InputFiles.cpp =================================================================== --- lld/trunk/wasm/InputFiles.cpp +++ lld/trunk/wasm/InputFiles.cpp @@ -60,6 +60,37 @@ return Symbols[Reloc.Index]->getOutputSymbolIndex(); } +// Calculate the value we expect to find at the relocation location. +// This is used as a sanity check before applying a relocation to a given +// location. It is useful for catching bugs in the compiler and linker. +uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const { + switch (Reloc.Type) { + case R_WEBASSEMBLY_TABLE_INDEX_I32: + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: { + const WasmSymbol& Sym = WasmObj->syms()[Reloc.Index]; + return TableEntries[Sym.Info.ElementIndex]; + } + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: { + const WasmSymbol& Sym = WasmObj->syms()[Reloc.Index]; + if (Sym.isUndefined()) + return 0; + const WasmSegment& Segment = WasmObj->dataSegments()[Sym.Info.DataRef.Segment]; + return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset; + } + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + return Reloc.Index; + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: { + const WasmSymbol& Sym = WasmObj->syms()[Reloc.Index]; + return Sym.Info.ElementIndex; + } + default: + llvm_unreachable("unknown relocation type"); + } +} + // Translate from the relocation's index into the final linked output value. uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const { switch (Reloc.Type) { @@ -97,6 +128,22 @@ Bin.release(); WasmObj.reset(Obj); + // Build up a map of function indices to table indices for use when + // verifying the existing table index relocations + uint32_t TotalFunctions = + WasmObj->getNumImportedFunctions() + WasmObj->functions().size(); + TableEntries.resize(TotalFunctions); + for (const WasmElemSegment &Seg : WasmObj->elements()) { + if (Seg.Offset.Opcode != WASM_OPCODE_I32_CONST) + fatal(toString(this) + ": invalid table elements"); + uint32_t Offset = Seg.Offset.Value.Int32; + for (uint32_t Index = 0; Index < Seg.Functions.size(); Index++) { + + uint32_t FunctionIndex = Seg.Functions[Index]; + TableEntries[FunctionIndex] = Offset + Index; + } + } + // Find the code and data sections. Wasm objects can have at most one code // and one data section. for (const SectionRef &Sec : WasmObj->sections()) {