LLVM_DEBUG(dbgs() << "applying relocations: " << toString(this)
<< " count=" << relocations.size() << "\n");
int32_t off = outputOffset - getInputSectionOffset();
+ auto tombstone = getTombstone();
for (const WasmRelocation &rel : relocations) {
uint8_t *loc = buf + rel.Offset + off;
- auto value = file->calcNewValue(rel);
+ auto value = file->calcNewValue(rel, tombstone);
LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(rel.Type));
if (rel.Type != R_WASM_TYPE_INDEX_LEB)
LLVM_DEBUG(dbgs() << " sym=" << file->getSymbols()[rel.Index]->getName());
uint32_t start = getInputSectionOffset();
uint32_t end = start + function->Size;
+ auto tombstone = getTombstone();
+
uint32_t lastRelocEnd = start + functionSizeLength;
for (const WasmRelocation &rel : relocations) {
LLVM_DEBUG(dbgs() << " region: " << (rel.Offset - lastRelocEnd) << "\n");
compressedFuncSize += rel.Offset - lastRelocEnd;
- compressedFuncSize += getRelocWidth(rel, file->calcNewValue(rel));
+ compressedFuncSize += getRelocWidth(rel, file->calcNewValue(rel, tombstone));
lastRelocEnd = rel.Offset + getRelocWidthPadded(rel);
}
LLVM_DEBUG(dbgs() << " final region: " << (end - lastRelocEnd) << "\n");
const uint8_t *secStart = file->codeSection->Content.data();
const uint8_t *funcStart = secStart + getInputSectionOffset();
const uint8_t *end = funcStart + function->Size;
+ auto tombstone = getTombstone();
uint32_t count;
decodeULEB128(funcStart, &count);
funcStart += count;
LLVM_DEBUG(dbgs() << " write chunk: " << chunkSize << "\n");
memcpy(buf, lastRelocEnd, chunkSize);
buf += chunkSize;
- buf += writeCompressedReloc(buf, rel, file->calcNewValue(rel));
+ buf += writeCompressedReloc(buf, rel, file->calcNewValue(rel, tombstone));
lastRelocEnd = secStart + rel.Offset + getRelocWidthPadded(rel);
}
? WASM_OPCODE_I64_ADD
: WASM_OPCODE_I32_ADD;
+ auto tombstone = getTombstone();
// TODO(sbc): Encode the relocations in the data section and write a loop
// here to apply them.
uint64_t segmentVA = outputSeg->startVA + outputSegmentOffset;
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
writeU8(os, opcode_reloc_const, "CONST");
- writeSleb128(os, file->calcNewValue(rel), "offset");
+ writeSleb128(os, file->calcNewValue(rel, tombstone), "offset");
writeU8(os, opcode_reloc_add, "ADD");
}
}
}
+uint64_t InputSection::getTombstoneForSection(StringRef name) {
+ // When a function is not live we need to update relocations referring to it.
+ // If they occur in DWARF debug symbols, we want to change the pc of the
+ // function to -1 to avoid overlapping with a valid range. However for the
+ // debug_ranges and debug_loc sections that would conflict with the existing
+ // meaning of -1 so we use -2.
+ // Returning 0 means there is no tombstone value for this section, and relocation
+ // will just use the addend.
+ if (!name.startswith(".debug_"))
+ return 0;
+ if (name.equals(".debug_ranges") || name.equals(".debug_loc"))
+ return UINT64_C(-2);
+ return UINT64_C(-1);
+}
+
} // namespace wasm
} // namespace lld
: file(f), live(!config->gcSections), discarded(false), sectionKind(k) {}
virtual ~InputChunk() = default;
virtual ArrayRef<uint8_t> data() const = 0;
+ virtual uint64_t getTombstone() const { return 0; }
// Verifies the existing data at relocation targets matches our expectations.
// This is performed only debug builds as an extra sanity check.
class InputSection : public InputChunk {
public:
InputSection(const WasmSection &s, ObjFile *f)
- : InputChunk(f, InputChunk::Section), section(s) {
+ : InputChunk(f, InputChunk::Section), section(s), tombstoneValue(getTombstoneForSection(s.Name)) {
assert(section.Type == llvm::wasm::WASM_SEC_CUSTOM);
}
// Offset within the input section. This is only zero since this chunk
// type represents an entire input section, not part of one.
uint32_t getInputSectionOffset() const override { return 0; }
+ uint64_t getTombstone() const override { return tombstoneValue; }
+ static uint64_t getTombstoneForSection(StringRef name);
const WasmSection §ion;
+ const uint64_t tombstoneValue;
};
} // namespace wasm
}
// Translate from the relocation's index into the final linked output value.
-uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc) const {
+uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone) const {
const Symbol* sym = nullptr;
if (reloc.Type != R_WASM_TYPE_INDEX_LEB) {
sym = symbols[reloc.Index];
// We can end up with relocations against non-live symbols. For example
- // in debug sections. We return reloc.Addend because always returning zero
- // causes the generation of spurious range-list terminators in the
- // .debug_ranges section.
+ // in debug sections. We return a tombstone value in debug symbol sections
+ // so this will not produce a valid range conflicting with ranges of actual
+ // code. In other sections we return reloc.Addend.
+
if ((isa<FunctionSymbol>(sym) || isa<DataSymbol>(sym)) && !sym->isLive())
- return reloc.Addend;
+ return tombstone ? tombstone : reloc.Addend;
}
switch (reloc.Type) {