Skip to content

Commit 80ba438

Browse files
committedApr 10, 2018
[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
1 parent e4b90d8 commit 80ba438

9 files changed

+140
-1
lines changed
 

‎lld/test/wasm/Inputs/custom.ll

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
target triple = "wasm32-unknown-unknown-wasm"
2+
3+
!0 = !{ !"red", !"foo" }
4+
!1 = !{ !"green", !"bar" }
5+
!2 = !{ !"green", !"qux" }
6+
!wasm.custom_sections = !{ !0, !1, !2 }

‎lld/test/wasm/custom-sections.ll

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; RUN: llc -filetype=obj %s -o %t1.o
2+
; RUN: llc -filetype=obj %S/Inputs/custom.ll -o %t2.o
3+
; RUN: wasm-ld --check-signatures --relocatable -o %t.wasm %t1.o %t2.o
4+
; RUN: obj2yaml %t.wasm | FileCheck %s
5+
6+
target triple = "wasm32-unknown-unknown-wasm"
7+
8+
define i32 @_start() local_unnamed_addr {
9+
entry:
10+
%retval = alloca i32, align 4
11+
ret i32 0
12+
}
13+
14+
!0 = !{ !"red", !"extra" }
15+
!wasm.custom_sections = !{ !0 }
16+
17+
; CHECK: - Type: CUSTOM
18+
; CHECK-NEXT: Name: green
19+
; CHECK-NEXT: Payload: '05677265656E626172717578'
20+
; CHECK-NEXT: - Type: CUSTOM
21+
; CHECK-NEXT: Name: red
22+
; CHECK-NEXT: Payload: 037265646578747261666F6F

‎lld/wasm/InputChunks.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,13 @@ void InputFunction::setTableIndex(uint32_t Index) {
143143
assert(!hasTableIndex());
144144
TableIndex = Index;
145145
}
146+
147+
InputSection::InputSection(const WasmSection &S, ObjFile *F)
148+
: InputChunk(F, InputChunk::Section), Section(S) {
149+
assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM);
150+
// TODO check LEB errors
151+
unsigned Count;
152+
uint64_t NameSize = llvm::decodeULEB128(Section.Content.data(), &Count);
153+
uint32_t PayloadOffset = Count + NameSize;
154+
Payload = Section.Content.slice(PayloadOffset);
155+
}

‎lld/wasm/InputChunks.h

+20-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class OutputSegment;
4444

4545
class InputChunk {
4646
public:
47-
enum Kind { DataSegment, Function, SyntheticFunction };
47+
enum Kind { DataSegment, Function, SyntheticFunction, Section };
4848

4949
Kind kind() const { return SectionKind; }
5050

@@ -173,6 +173,25 @@ class SyntheticFunction : public InputFunction {
173173
ArrayRef<uint8_t> Body;
174174
};
175175

176+
// Represents a single Wasm Section within an input file.
177+
class InputSection : public InputChunk {
178+
public:
179+
InputSection(const WasmSection &S, ObjFile *F);
180+
181+
StringRef getName() const override { return Section.Name; }
182+
uint32_t getComdat() const override { return UINT32_MAX; }
183+
184+
protected:
185+
ArrayRef<uint8_t> data() const override { return Payload; }
186+
187+
// Offset within the input section. This is only zero since this chunk
188+
// type represents an entire input section, not part of one.
189+
uint32_t getInputSectionOffset() const override { return 0; }
190+
191+
const WasmSection &Section;
192+
ArrayRef<uint8_t> Payload;
193+
};
194+
176195
} // namespace wasm
177196

178197
std::string toString(const wasm::InputChunk *);

‎lld/wasm/InputFiles.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ void ObjFile::parse() {
153153
CodeSection = &Section;
154154
else if (Section.Type == WASM_SEC_DATA)
155155
DataSection = &Section;
156+
else if (Section.Type == WASM_SEC_CUSTOM)
157+
CustomSections.emplace_back(make<InputSection>(Section, this));
156158
}
157159

158160
TypeMap.resize(getWasmObj()->types().size());

‎lld/wasm/InputFiles.h

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class InputChunk;
3535
class InputFunction;
3636
class InputSegment;
3737
class InputGlobal;
38+
class InputSection;
3839

3940
class InputFile {
4041
public:
@@ -108,6 +109,7 @@ class ObjFile : public InputFile {
108109
std::vector<InputSegment *> Segments;
109110
std::vector<InputFunction *> Functions;
110111
std::vector<InputGlobal *> Globals;
112+
std::vector<InputSection *> CustomSections;
111113

112114
ArrayRef<Symbol *> getSymbols() const { return Symbols; }
113115
Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; }

‎lld/wasm/OutputSections.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,38 @@ void DataSection::writeRelocations(raw_ostream &OS) const {
189189
for (const InputChunk *C : Seg->InputSegments)
190190
C->writeRelocations(OS);
191191
}
192+
193+
CustomSection::CustomSection(std::string Name,
194+
ArrayRef<InputSection *> InputSections)
195+
: OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0),
196+
InputSections(InputSections) {
197+
raw_string_ostream OS(NameData);
198+
encodeULEB128(Name.size(), OS);
199+
OS << Name;
200+
OS.flush();
201+
202+
for (InputSection *Section : InputSections) {
203+
Section->OutputOffset = PayloadSize;
204+
PayloadSize += Section->getSize();
205+
}
206+
207+
createHeader(PayloadSize + NameData.size());
208+
}
209+
210+
void CustomSection::writeTo(uint8_t *Buf) {
211+
log("writing " + toString(*this) + " size=" + Twine(getSize()) +
212+
" chunks=" + Twine(InputSections.size()));
213+
214+
assert(Offset);
215+
Buf += Offset;
216+
217+
// Write section header
218+
memcpy(Buf, Header.data(), Header.size());
219+
Buf += Header.size();
220+
memcpy(Buf, NameData.data(), NameData.size());
221+
Buf += NameData.size();
222+
223+
// Write custom sections payload
224+
parallelForEach(InputSections,
225+
[&](const InputSection *Section) { Section->writeTo(Buf); });
226+
}

‎lld/wasm/OutputSections.h

+21
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,27 @@ class DataSection : public OutputSection {
113113
size_t BodySize = 0;
114114
};
115115

116+
// Represents a custom section in the output file. Wasm custom sections are
117+
// used for storing user-defined metadata. Unlike the core sections types
118+
// they are identified by their string name.
119+
// The linker combines custom sections that have the same name by simply
120+
// concatenating them.
121+
// Note that some custom sections such as "name" and "linking" are handled
122+
// separately and are instead synthesized by the linker.
123+
class CustomSection : public OutputSection {
124+
public:
125+
CustomSection(std::string Name, ArrayRef<InputSection *> InputSections);
126+
size_t getSize() const override {
127+
return Header.size() + NameData.size() + PayloadSize;
128+
}
129+
void writeTo(uint8_t *Buf) override;
130+
131+
protected:
132+
size_t PayloadSize;
133+
ArrayRef<InputSection *> InputSections;
134+
std::string NameData;
135+
};
136+
116137
} // namespace wasm
117138
} // namespace lld
118139

‎lld/wasm/Writer.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "lld/Common/Strings.h"
2121
#include "lld/Common/Threads.h"
2222
#include "llvm/ADT/DenseSet.h"
23+
#include "llvm/ADT/StringMap.h"
2324
#include "llvm/BinaryFormat/Wasm.h"
2425
#include "llvm/Object/WasmTraits.h"
2526
#include "llvm/Support/FileOutputBuffer.h"
@@ -85,6 +86,7 @@ class Writer {
8586
void createElemSection();
8687
void createCodeSection();
8788
void createDataSection();
89+
void createCustomSections();
8890

8991
// Custom sections
9092
void createRelocSections();
@@ -111,6 +113,8 @@ class Writer {
111113
std::vector<const Symbol *> SymtabEntries;
112114
std::vector<WasmInitEntry> InitFunctions;
113115

116+
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
117+
114118
// Elements that are used to construct the final output
115119
std::string Header;
116120
std::vector<OutputSection *> OutputSections;
@@ -295,6 +299,23 @@ void Writer::createExportSection() {
295299
}
296300
}
297301

302+
void Writer::createCustomSections() {
303+
log("createCustomSections");
304+
for (ObjFile *File : Symtab->ObjectFiles)
305+
for (InputSection *Section : File->CustomSections)
306+
CustomSectionMapping[Section->getName()].push_back(Section);
307+
308+
for (auto &Pair : CustomSectionMapping) {
309+
StringRef Name = Pair.first();
310+
// These custom sections are known the linker and synthesized rather than
311+
// blindly copied
312+
if (Name == "linking" || Name == "name" || Name.startswith("reloc."))
313+
continue;
314+
DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
315+
OutputSections.push_back(make<CustomSection>(Name, Pair.second));
316+
}
317+
}
318+
298319
void Writer::createElemSection() {
299320
if (IndirectFunctions.empty())
300321
return;
@@ -647,6 +668,7 @@ void Writer::createSections() {
647668
createElemSection();
648669
createCodeSection();
649670
createDataSection();
671+
createCustomSections();
650672

651673
// Custom sections
652674
if (Config->Relocatable) {

0 commit comments

Comments
 (0)
Please sign in to comment.