aboutsummaryrefslogtreecommitdiff
path: root/wasm/OutputSections.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wasm/OutputSections.cpp')
-rw-r--r--wasm/OutputSections.cpp287
1 files changed, 89 insertions, 198 deletions
diff --git a/wasm/OutputSections.cpp b/wasm/OutputSections.cpp
index a55538269065..256a9884f947 100644
--- a/wasm/OutputSections.cpp
+++ b/wasm/OutputSections.cpp
@@ -8,13 +8,11 @@
//===----------------------------------------------------------------------===//
#include "OutputSections.h"
-
-#include "Config.h"
+#include "InputChunks.h"
#include "InputFiles.h"
#include "OutputSegment.h"
-#include "SymbolTable.h"
+#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
-#include "lld/Common/Memory.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/LEB128.h"
@@ -26,12 +24,6 @@ using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
-enum class RelocEncoding {
- Uleb128,
- Sleb128,
- I32,
-};
-
static StringRef sectionTypeToString(uint32_t SectionType) {
switch (SectionType) {
case WASM_SEC_CUSTOM:
@@ -63,159 +55,40 @@ static StringRef sectionTypeToString(uint32_t SectionType) {
}
}
-std::string lld::toString(const OutputSection &Section) {
- std::string rtn = Section.getSectionName();
- if (!Section.Name.empty())
- rtn += "(" + Section.Name + ")";
- return rtn;
-}
-
-static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) {
- DEBUG(dbgs() << "write reloc: type=" << Reloc.Reloc.Type
- << " index=" << Reloc.Reloc.Index << " value=" << Reloc.Value
- << " offset=" << Reloc.Reloc.Offset << "\n");
- Buf += Reloc.Reloc.Offset;
- int64_t ExistingValue;
- switch (Reloc.Reloc.Type) {
- case R_WEBASSEMBLY_TYPE_INDEX_LEB:
- case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
- ExistingValue = decodeULEB128(Buf);
- if (ExistingValue != Reloc.Reloc.Index) {
- DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n");
- assert(decodeULEB128(Buf) == Reloc.Reloc.Index);
- }
- LLVM_FALLTHROUGH;
- case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
- encodeULEB128(Reloc.Value, Buf, 5);
- break;
- case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
- ExistingValue = decodeSLEB128(Buf);
- if (ExistingValue != Reloc.Reloc.Index) {
- DEBUG(dbgs() << "existing value: " << decodeSLEB128(Buf) << "\n");
- assert(decodeSLEB128(Buf) == Reloc.Reloc.Index);
- }
- LLVM_FALLTHROUGH;
- case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- encodeSLEB128(static_cast<int32_t>(Reloc.Value), Buf, 5);
- break;
- case R_WEBASSEMBLY_TABLE_INDEX_I32:
- case R_WEBASSEMBLY_MEMORY_ADDR_I32:
- support::endian::write32<support::little>(Buf, Reloc.Value);
- break;
- default:
- llvm_unreachable("unknown relocation type");
- }
-}
-
-static void applyRelocations(uint8_t *Buf, ArrayRef<OutputRelocation> Relocs) {
- if (!Relocs.size())
- return;
- log("applyRelocations: count=" + Twine(Relocs.size()));
- for (const OutputRelocation &Reloc : Relocs)
- applyRelocation(Buf, Reloc);
-}
-
-// Relocations contain an index into the function, global or table index
-// space of the input file. This function takes a relocation and returns the
-// relocated index (i.e. translates from the input index space to the output
-// index space).
-static uint32_t calcNewIndex(const ObjFile &File, const WasmRelocation &Reloc) {
- switch (Reloc.Type) {
- case R_WEBASSEMBLY_TYPE_INDEX_LEB:
- return File.relocateTypeIndex(Reloc.Index);
- case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
- return File.relocateFunctionIndex(Reloc.Index);
- case R_WEBASSEMBLY_TABLE_INDEX_I32:
- case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
- return File.relocateTableIndex(Reloc.Index);
- case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_I32:
- return File.relocateGlobalIndex(Reloc.Index);
- default:
- llvm_unreachable("unknown relocation type");
- }
-}
-
-// Take a vector of relocations from an input file and create output
-// relocations based on them. Calculates the updated index and offset for
-// each relocation as well as the value to write out in the final binary.
-static void calcRelocations(const ObjFile &File,
- ArrayRef<WasmRelocation> Relocs,
- std::vector<OutputRelocation> &OutputRelocs,
- int32_t OutputOffset) {
- log("calcRelocations: " + File.getName() + " offset=" + Twine(OutputOffset));
- for (const WasmRelocation &Reloc : Relocs) {
- OutputRelocation NewReloc;
- NewReloc.Reloc = Reloc;
- NewReloc.Reloc.Offset += OutputOffset;
- DEBUG(dbgs() << "reloc: type=" << Reloc.Type << " index=" << Reloc.Index
- << " offset=" << Reloc.Offset
- << " newOffset=" << NewReloc.Reloc.Offset << "\n");
-
- if (Config->EmitRelocs)
- NewReloc.NewIndex = calcNewIndex(File, Reloc);
- else
- NewReloc.NewIndex = UINT32_MAX;
-
- switch (Reloc.Type) {
- case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- case R_WEBASSEMBLY_MEMORY_ADDR_I32:
- case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- NewReloc.Value = File.getRelocatedAddress(Reloc.Index);
- if (NewReloc.Value != UINT32_MAX)
- NewReloc.Value += Reloc.Addend;
- break;
- default:
- NewReloc.Value = calcNewIndex(File, Reloc);
- break;
- }
-
- OutputRelocs.emplace_back(NewReloc);
- }
+// Returns a string, e.g. "FUNCTION(.text)".
+std::string lld::toString(const OutputSection &Sec) {
+ if (!Sec.Name.empty())
+ return (Sec.getSectionName() + "(" + Sec.Name + ")").str();
+ return Sec.getSectionName();
}
-std::string OutputSection::getSectionName() const {
+StringRef OutputSection::getSectionName() const {
return sectionTypeToString(Type);
}
-std::string SubSection::getSectionName() const {
- return std::string("subsection <type=") + std::to_string(Type) + ">";
-}
-
void OutputSection::createHeader(size_t BodySize) {
raw_string_ostream OS(Header);
- debugWrite(OS.tell(), "section type [" + Twine(getSectionName()) + "]");
- writeUleb128(OS, Type, nullptr);
+ debugWrite(OS.tell(), "section type [" + getSectionName() + "]");
+ encodeULEB128(Type, OS);
writeUleb128(OS, BodySize, "section size");
OS.flush();
log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) +
" total=" + Twine(getSize()));
}
-CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs)
- : OutputSection(WASM_SEC_CODE), InputObjects(Objs) {
+CodeSection::CodeSection(ArrayRef<InputFunction *> Functions)
+ : OutputSection(WASM_SEC_CODE), Functions(Functions) {
+ assert(Functions.size() > 0);
+
raw_string_ostream OS(CodeSectionHeader);
- writeUleb128(OS, NumFunctions, "function count");
+ writeUleb128(OS, Functions.size(), "function count");
OS.flush();
BodySize = CodeSectionHeader.size();
- for (ObjFile *File : InputObjects) {
- if (!File->CodeSection)
- continue;
-
- File->CodeOffset = BodySize;
- ArrayRef<uint8_t> Content = File->CodeSection->Content;
- unsigned HeaderSize = 0;
- decodeULEB128(Content.data(), &HeaderSize);
-
- calcRelocations(*File, File->CodeSection->Relocations,
- File->CodeRelocations, BodySize - HeaderSize);
-
- size_t PayloadSize = Content.size() - HeaderSize;
- BodySize += PayloadSize;
+ for (InputFunction *Func : Functions) {
+ Func->OutputOffset = BodySize;
+ Func->calculateSize();
+ BodySize += Func->getSize();
}
createHeader(BodySize);
@@ -224,49 +97,32 @@ CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs)
void CodeSection::writeTo(uint8_t *Buf) {
log("writing " + toString(*this));
log(" size=" + Twine(getSize()));
+ log(" headersize=" + Twine(Header.size()));
+ log(" codeheadersize=" + Twine(CodeSectionHeader.size()));
Buf += Offset;
// Write section header
memcpy(Buf, Header.data(), Header.size());
Buf += Header.size();
- uint8_t *ContentsStart = Buf;
-
// Write code section headers
memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
- Buf += CodeSectionHeader.size();
// Write code section bodies
- parallelForEach(InputObjects, [ContentsStart](ObjFile *File) {
- if (!File->CodeSection)
- return;
-
- ArrayRef<uint8_t> Content(File->CodeSection->Content);
-
- // Payload doesn't include the initial header (function count)
- unsigned HeaderSize = 0;
- decodeULEB128(Content.data(), &HeaderSize);
-
- size_t PayloadSize = Content.size() - HeaderSize;
- memcpy(ContentsStart + File->CodeOffset, Content.data() + HeaderSize,
- PayloadSize);
-
- log("applying relocations for: " + File->getName());
- applyRelocations(ContentsStart, File->CodeRelocations);
- });
+ parallelForEach(Functions,
+ [&](const InputChunk *Chunk) { Chunk->writeTo(Buf); });
}
uint32_t CodeSection::numRelocations() const {
uint32_t Count = 0;
- for (ObjFile *File : InputObjects)
- Count += File->CodeRelocations.size();
+ for (const InputChunk *Func : Functions)
+ Count += Func->NumRelocations();
return Count;
}
void CodeSection::writeRelocations(raw_ostream &OS) const {
- for (ObjFile *File : InputObjects)
- for (const OutputRelocation &Reloc : File->CodeRelocations)
- writeReloc(OS, Reloc);
+ for (const InputChunk *C : Functions)
+ C->writeRelocations(OS);
}
DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
@@ -285,18 +141,14 @@ DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
writeUleb128(OS, Segment->Size, "segment size");
OS.flush();
- Segment->setSectionOffset(BodySize);
- BodySize += Segment->Header.size();
+
+ Segment->SectionOffset = BodySize;
+ BodySize += Segment->Header.size() + Segment->Size;
log("Data segment: size=" + Twine(Segment->Size));
- for (InputSegment *InputSeg : Segment->InputSegments) {
- uint32_t InputOffset = InputSeg->getInputSectionOffset();
- uint32_t OutputOffset = Segment->getSectionOffset() +
- Segment->Header.size() +
- InputSeg->getOutputSegmentOffset();
- calcRelocations(*InputSeg->File, InputSeg->Relocations,
- InputSeg->OutRelocations, OutputOffset - InputOffset);
- }
- BodySize += Segment->Size;
+
+ for (InputSegment *InputSeg : Segment->InputSegments)
+ InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() +
+ InputSeg->OutputSegmentOffset;
}
createHeader(BodySize);
@@ -311,38 +163,77 @@ void DataSection::writeTo(uint8_t *Buf) {
memcpy(Buf, Header.data(), Header.size());
Buf += Header.size();
- uint8_t *ContentsStart = Buf;
-
// Write data section headers
memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
- parallelForEach(Segments, [ContentsStart](const OutputSegment *Segment) {
+ parallelForEach(Segments, [&](const OutputSegment *Segment) {
// Write data segment header
- uint8_t *SegStart = ContentsStart + Segment->getSectionOffset();
+ uint8_t *SegStart = Buf + Segment->SectionOffset;
memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
// Write segment data payload
- for (const InputSegment *Input : Segment->InputSegments) {
- ArrayRef<uint8_t> Content(Input->Segment->Data.Content);
- memcpy(SegStart + Segment->Header.size() +
- Input->getOutputSegmentOffset(),
- Content.data(), Content.size());
- applyRelocations(ContentsStart, Input->OutRelocations);
- }
+ for (const InputChunk *Chunk : Segment->InputSegments)
+ Chunk->writeTo(Buf);
});
}
uint32_t DataSection::numRelocations() const {
uint32_t Count = 0;
for (const OutputSegment *Seg : Segments)
- for (const InputSegment *InputSeg : Seg->InputSegments)
- Count += InputSeg->OutRelocations.size();
+ for (const InputChunk *InputSeg : Seg->InputSegments)
+ Count += InputSeg->NumRelocations();
return Count;
}
void DataSection::writeRelocations(raw_ostream &OS) const {
for (const OutputSegment *Seg : Segments)
- for (const InputSegment *InputSeg : Seg->InputSegments)
- for (const OutputRelocation &Reloc : InputSeg->OutRelocations)
- writeReloc(OS, Reloc);
+ for (const InputChunk *C : Seg->InputSegments)
+ C->writeRelocations(OS);
+}
+
+CustomSection::CustomSection(std::string Name,
+ ArrayRef<InputSection *> InputSections)
+ : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0),
+ InputSections(InputSections) {
+ raw_string_ostream OS(NameData);
+ encodeULEB128(Name.size(), OS);
+ OS << Name;
+ OS.flush();
+
+ for (InputSection *Section : InputSections) {
+ Section->OutputOffset = PayloadSize;
+ PayloadSize += Section->getSize();
+ }
+
+ createHeader(PayloadSize + NameData.size());
+}
+
+void CustomSection::writeTo(uint8_t *Buf) {
+ log("writing " + toString(*this) + " size=" + Twine(getSize()) +
+ " chunks=" + Twine(InputSections.size()));
+
+ assert(Offset);
+ Buf += Offset;
+
+ // Write section header
+ memcpy(Buf, Header.data(), Header.size());
+ Buf += Header.size();
+ memcpy(Buf, NameData.data(), NameData.size());
+ Buf += NameData.size();
+
+ // Write custom sections payload
+ parallelForEach(InputSections,
+ [&](const InputSection *Section) { Section->writeTo(Buf); });
+}
+
+uint32_t CustomSection::numRelocations() const {
+ uint32_t Count = 0;
+ for (const InputSection *InputSect : InputSections)
+ Count += InputSect->NumRelocations();
+ return Count;
+}
+
+void CustomSection::writeRelocations(raw_ostream &OS) const {
+ for (const InputSection *S : InputSections)
+ S->writeRelocations(OS);
}