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");
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<uint32_t>(decodeSLEB128(Loc));
encodeSLEB128(static_cast<int32_t>(Value), Loc, 5);
break;
case R_WEBASSEMBLY_TABLE_INDEX_I32:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+ ExistingValue = static_cast<uint32_t>(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));
}
}
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) {
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()) {
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<uint32_t> TypeMap;
std::vector<bool> TypeIsUsed;
+ // Maps function indices to table indices
+ std::vector<uint32_t> TableEntries;
std::vector<InputSegment *> Segments;
std::vector<InputFunction *> Functions;
std::vector<InputGlobal *> Globals;