mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-28 08:02:08 +00:00
[WebAssembly] Add support for custom sections
Copy user-defined custom sections into the output, concatenating sections with the same name. Differential Revision: https://reviews.llvm.org/D45340 llvm-svn: 329717
This commit is contained in:
parent
e4b90d82a0
commit
80ba43872e
6
lld/test/wasm/Inputs/custom.ll
Normal file
6
lld/test/wasm/Inputs/custom.ll
Normal file
@ -0,0 +1,6 @@
|
||||
target triple = "wasm32-unknown-unknown-wasm"
|
||||
|
||||
!0 = !{ !"red", !"foo" }
|
||||
!1 = !{ !"green", !"bar" }
|
||||
!2 = !{ !"green", !"qux" }
|
||||
!wasm.custom_sections = !{ !0, !1, !2 }
|
22
lld/test/wasm/custom-sections.ll
Normal file
22
lld/test/wasm/custom-sections.ll
Normal file
@ -0,0 +1,22 @@
|
||||
; RUN: llc -filetype=obj %s -o %t1.o
|
||||
; RUN: llc -filetype=obj %S/Inputs/custom.ll -o %t2.o
|
||||
; RUN: wasm-ld --check-signatures --relocatable -o %t.wasm %t1.o %t2.o
|
||||
; RUN: obj2yaml %t.wasm | FileCheck %s
|
||||
|
||||
target triple = "wasm32-unknown-unknown-wasm"
|
||||
|
||||
define i32 @_start() local_unnamed_addr {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
!0 = !{ !"red", !"extra" }
|
||||
!wasm.custom_sections = !{ !0 }
|
||||
|
||||
; CHECK: - Type: CUSTOM
|
||||
; CHECK-NEXT: Name: green
|
||||
; CHECK-NEXT: Payload: '05677265656E626172717578'
|
||||
; CHECK-NEXT: - Type: CUSTOM
|
||||
; CHECK-NEXT: Name: red
|
||||
; CHECK-NEXT: Payload: 037265646578747261666F6F
|
@ -143,3 +143,13 @@ void InputFunction::setTableIndex(uint32_t Index) {
|
||||
assert(!hasTableIndex());
|
||||
TableIndex = Index;
|
||||
}
|
||||
|
||||
InputSection::InputSection(const WasmSection &S, ObjFile *F)
|
||||
: InputChunk(F, InputChunk::Section), Section(S) {
|
||||
assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM);
|
||||
// TODO check LEB errors
|
||||
unsigned Count;
|
||||
uint64_t NameSize = llvm::decodeULEB128(Section.Content.data(), &Count);
|
||||
uint32_t PayloadOffset = Count + NameSize;
|
||||
Payload = Section.Content.slice(PayloadOffset);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class OutputSegment;
|
||||
|
||||
class InputChunk {
|
||||
public:
|
||||
enum Kind { DataSegment, Function, SyntheticFunction };
|
||||
enum Kind { DataSegment, Function, SyntheticFunction, Section };
|
||||
|
||||
Kind kind() const { return SectionKind; }
|
||||
|
||||
@ -173,6 +173,25 @@ protected:
|
||||
ArrayRef<uint8_t> Body;
|
||||
};
|
||||
|
||||
// Represents a single Wasm Section within an input file.
|
||||
class InputSection : public InputChunk {
|
||||
public:
|
||||
InputSection(const WasmSection &S, ObjFile *F);
|
||||
|
||||
StringRef getName() const override { return Section.Name; }
|
||||
uint32_t getComdat() const override { return UINT32_MAX; }
|
||||
|
||||
protected:
|
||||
ArrayRef<uint8_t> data() const override { return Payload; }
|
||||
|
||||
// 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; }
|
||||
|
||||
const WasmSection &Section;
|
||||
ArrayRef<uint8_t> Payload;
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
|
||||
std::string toString(const wasm::InputChunk *);
|
||||
|
@ -153,6 +153,8 @@ void ObjFile::parse() {
|
||||
CodeSection = &Section;
|
||||
else if (Section.Type == WASM_SEC_DATA)
|
||||
DataSection = &Section;
|
||||
else if (Section.Type == WASM_SEC_CUSTOM)
|
||||
CustomSections.emplace_back(make<InputSection>(Section, this));
|
||||
}
|
||||
|
||||
TypeMap.resize(getWasmObj()->types().size());
|
||||
|
@ -35,6 +35,7 @@ class InputChunk;
|
||||
class InputFunction;
|
||||
class InputSegment;
|
||||
class InputGlobal;
|
||||
class InputSection;
|
||||
|
||||
class InputFile {
|
||||
public:
|
||||
@ -108,6 +109,7 @@ public:
|
||||
std::vector<InputSegment *> Segments;
|
||||
std::vector<InputFunction *> Functions;
|
||||
std::vector<InputGlobal *> Globals;
|
||||
std::vector<InputSection *> CustomSections;
|
||||
|
||||
ArrayRef<Symbol *> getSymbols() const { return Symbols; }
|
||||
Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; }
|
||||
|
@ -189,3 +189,38 @@ void DataSection::writeRelocations(raw_ostream &OS) const {
|
||||
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); });
|
||||
}
|
||||
|
@ -113,6 +113,27 @@ protected:
|
||||
size_t BodySize = 0;
|
||||
};
|
||||
|
||||
// Represents a custom section in the output file. Wasm custom sections are
|
||||
// used for storing user-defined metadata. Unlike the core sections types
|
||||
// they are identified by their string name.
|
||||
// The linker combines custom sections that have the same name by simply
|
||||
// concatenating them.
|
||||
// Note that some custom sections such as "name" and "linking" are handled
|
||||
// separately and are instead synthesized by the linker.
|
||||
class CustomSection : public OutputSection {
|
||||
public:
|
||||
CustomSection(std::string Name, ArrayRef<InputSection *> InputSections);
|
||||
size_t getSize() const override {
|
||||
return Header.size() + NameData.size() + PayloadSize;
|
||||
}
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
|
||||
protected:
|
||||
size_t PayloadSize;
|
||||
ArrayRef<InputSection *> InputSections;
|
||||
std::string NameData;
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace lld
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "lld/Common/Strings.h"
|
||||
#include "lld/Common/Threads.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/BinaryFormat/Wasm.h"
|
||||
#include "llvm/Object/WasmTraits.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
@ -85,6 +86,7 @@ private:
|
||||
void createElemSection();
|
||||
void createCodeSection();
|
||||
void createDataSection();
|
||||
void createCustomSections();
|
||||
|
||||
// Custom sections
|
||||
void createRelocSections();
|
||||
@ -111,6 +113,8 @@ private:
|
||||
std::vector<const Symbol *> SymtabEntries;
|
||||
std::vector<WasmInitEntry> InitFunctions;
|
||||
|
||||
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
|
||||
|
||||
// Elements that are used to construct the final output
|
||||
std::string Header;
|
||||
std::vector<OutputSection *> OutputSections;
|
||||
@ -295,6 +299,23 @@ void Writer::createExportSection() {
|
||||
}
|
||||
}
|
||||
|
||||
void Writer::createCustomSections() {
|
||||
log("createCustomSections");
|
||||
for (ObjFile *File : Symtab->ObjectFiles)
|
||||
for (InputSection *Section : File->CustomSections)
|
||||
CustomSectionMapping[Section->getName()].push_back(Section);
|
||||
|
||||
for (auto &Pair : CustomSectionMapping) {
|
||||
StringRef Name = Pair.first();
|
||||
// These custom sections are known the linker and synthesized rather than
|
||||
// blindly copied
|
||||
if (Name == "linking" || Name == "name" || Name.startswith("reloc."))
|
||||
continue;
|
||||
DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
|
||||
OutputSections.push_back(make<CustomSection>(Name, Pair.second));
|
||||
}
|
||||
}
|
||||
|
||||
void Writer::createElemSection() {
|
||||
if (IndirectFunctions.empty())
|
||||
return;
|
||||
@ -647,6 +668,7 @@ void Writer::createSections() {
|
||||
createElemSection();
|
||||
createCodeSection();
|
||||
createDataSection();
|
||||
createCustomSections();
|
||||
|
||||
// Custom sections
|
||||
if (Config->Relocatable) {
|
||||
|
Loading…
Reference in New Issue
Block a user