1 //===- yaml2wasm - Convert YAML to a Wasm object file --------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief The Wasm component of yaml2obj.
13 //===----------------------------------------------------------------------===//
16 #include "llvm/Object/Wasm.h"
17 #include "llvm/ObjectYAML/ObjectYAML.h"
18 #include "llvm/Support/Endian.h"
19 #include "llvm/Support/LEB128.h"
23 /// This parses a yaml stream that represents a Wasm object file.
24 /// See docs/yaml2obj for the yaml scheema.
27 WasmWriter(WasmYAML::Object
&Obj
) : Obj(Obj
) {}
28 int writeWasm(raw_ostream
&OS
);
31 int writeRelocSection(raw_ostream
&OS
, WasmYAML::Section
&Sec
);
33 int writeSectionContent(raw_ostream
&OS
, WasmYAML::CustomSection
&Section
);
34 int writeSectionContent(raw_ostream
&OS
, WasmYAML::TypeSection
&Section
);
35 int writeSectionContent(raw_ostream
&OS
, WasmYAML::ImportSection
&Section
);
36 int writeSectionContent(raw_ostream
&OS
, WasmYAML::FunctionSection
&Section
);
37 int writeSectionContent(raw_ostream
&OS
, WasmYAML::TableSection
&Section
);
38 int writeSectionContent(raw_ostream
&OS
, WasmYAML::MemorySection
&Section
);
39 int writeSectionContent(raw_ostream
&OS
, WasmYAML::GlobalSection
&Section
);
40 int writeSectionContent(raw_ostream
&OS
, WasmYAML::ExportSection
&Section
);
41 int writeSectionContent(raw_ostream
&OS
, WasmYAML::StartSection
&Section
);
42 int writeSectionContent(raw_ostream
&OS
, WasmYAML::ElemSection
&Section
);
43 int writeSectionContent(raw_ostream
&OS
, WasmYAML::CodeSection
&Section
);
44 int writeSectionContent(raw_ostream
&OS
, WasmYAML::DataSection
&Section
);
46 // Custom section types
47 int writeSectionContent(raw_ostream
&OS
, WasmYAML::NameSection
&Section
);
48 int writeSectionContent(raw_ostream
&OS
, WasmYAML::LinkingSection
&Section
);
49 WasmYAML::Object
&Obj
;
52 static int writeUint64(raw_ostream
&OS
, uint64_t Value
) {
53 char Data
[sizeof(Value
)];
54 support::endian::write64le(Data
, Value
);
55 OS
.write(Data
, sizeof(Data
));
59 static int writeUint32(raw_ostream
&OS
, uint32_t Value
) {
60 char Data
[sizeof(Value
)];
61 support::endian::write32le(Data
, Value
);
62 OS
.write(Data
, sizeof(Data
));
66 static int writeUint8(raw_ostream
&OS
, uint8_t Value
) {
67 char Data
[sizeof(Value
)];
68 memcpy(Data
, &Value
, sizeof(Data
));
69 OS
.write(Data
, sizeof(Data
));
73 static int writeStringRef(const StringRef
&Str
, raw_ostream
&OS
) {
74 encodeULEB128(Str
.size(), OS
);
79 static int writeLimits(const WasmYAML::Limits
&Lim
, raw_ostream
&OS
) {
80 encodeULEB128(Lim
.Flags
, OS
);
81 encodeULEB128(Lim
.Initial
, OS
);
82 if (Lim
.Flags
& wasm::WASM_LIMITS_FLAG_HAS_MAX
)
83 encodeULEB128(Lim
.Maximum
, OS
);
87 static int writeInitExpr(const wasm::WasmInitExpr
&InitExpr
, raw_ostream
&OS
) {
88 writeUint8(OS
, InitExpr
.Opcode
);
89 switch (InitExpr
.Opcode
) {
90 case wasm::WASM_OPCODE_I32_CONST
:
91 encodeSLEB128(InitExpr
.Value
.Int32
, OS
);
93 case wasm::WASM_OPCODE_I64_CONST
:
94 encodeSLEB128(InitExpr
.Value
.Int64
, OS
);
96 case wasm::WASM_OPCODE_F32_CONST
:
97 writeUint32(OS
, InitExpr
.Value
.Float32
);
99 case wasm::WASM_OPCODE_F64_CONST
:
100 writeUint64(OS
, InitExpr
.Value
.Float64
);
102 case wasm::WASM_OPCODE_GET_GLOBAL
:
103 encodeULEB128(InitExpr
.Value
.Global
, OS
);
106 errs() << "Unknown opcode in init_expr: " << InitExpr
.Opcode
;
109 writeUint8(OS
, wasm::WASM_OPCODE_END
);
113 class SubSectionWriter
{
115 std::string OutString
;
116 raw_string_ostream StringStream
;
119 SubSectionWriter(raw_ostream
&OS
) : OS(OS
), StringStream(OutString
) {}
122 StringStream
.flush();
123 encodeULEB128(OutString
.size(), OS
);
128 raw_ostream
& GetStream() {
133 int WasmWriter::writeSectionContent(raw_ostream
&OS
, WasmYAML::LinkingSection
&Section
) {
134 writeStringRef(Section
.Name
, OS
);
136 SubSectionWriter
SubSection(OS
);
138 // DATA_SIZE subsection
139 encodeULEB128(wasm::WASM_DATA_SIZE
, OS
);
140 encodeULEB128(Section
.DataSize
, SubSection
.GetStream());
143 // SYMBOL_INFO subsection
144 if (Section
.SymbolInfos
.size()) {
145 encodeULEB128(wasm::WASM_SYMBOL_INFO
, OS
);
147 encodeULEB128(Section
.SymbolInfos
.size(), SubSection
.GetStream());
148 for (const WasmYAML::SymbolInfo
&Info
: Section
.SymbolInfos
) {
149 writeStringRef(Info
.Name
, SubSection
.GetStream());
150 encodeULEB128(Info
.Flags
, SubSection
.GetStream());
156 // SEGMENT_NAMES subsection
157 if (Section
.SegmentInfos
.size()) {
158 encodeULEB128(wasm::WASM_SEGMENT_INFO
, OS
);
159 encodeULEB128(Section
.SegmentInfos
.size(), SubSection
.GetStream());
160 for (const WasmYAML::SegmentInfo
&SegmentInfo
: Section
.SegmentInfos
) {
161 encodeULEB128(SegmentInfo
.Index
, SubSection
.GetStream());
162 writeStringRef(SegmentInfo
.Name
, SubSection
.GetStream());
163 encodeULEB128(SegmentInfo
.Alignment
, SubSection
.GetStream());
164 encodeULEB128(SegmentInfo
.Flags
, SubSection
.GetStream());
171 int WasmWriter::writeSectionContent(raw_ostream
&OS
, WasmYAML::NameSection
&Section
) {
172 writeStringRef(Section
.Name
, OS
);
173 if (Section
.FunctionNames
.size()) {
174 encodeULEB128(wasm::WASM_NAMES_FUNCTION
, OS
);
176 SubSectionWriter
SubSection(OS
);
178 encodeULEB128(Section
.FunctionNames
.size(), SubSection
.GetStream());
179 for (const WasmYAML::NameEntry
&NameEntry
: Section
.FunctionNames
) {
180 encodeULEB128(NameEntry
.Index
, SubSection
.GetStream());
181 writeStringRef(NameEntry
.Name
, SubSection
.GetStream());
189 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
190 WasmYAML::CustomSection
&Section
) {
191 if (auto S
= dyn_cast
<WasmYAML::NameSection
>(&Section
)) {
192 if (auto Err
= writeSectionContent(OS
, *S
))
194 } else if (auto S
= dyn_cast
<WasmYAML::LinkingSection
>(&Section
)) {
195 if (auto Err
= writeSectionContent(OS
, *S
))
198 Section
.Payload
.writeAsBinary(OS
);
203 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
204 WasmYAML::TypeSection
&Section
) {
205 encodeULEB128(Section
.Signatures
.size(), OS
);
206 for (const WasmYAML::Signature
&Sig
: Section
.Signatures
) {
207 encodeSLEB128(Sig
.Form
, OS
);
208 encodeULEB128(Sig
.ParamTypes
.size(), OS
);
209 for (auto ParamType
: Sig
.ParamTypes
)
210 encodeSLEB128(ParamType
, OS
);
211 if (Sig
.ReturnType
== wasm::WASM_TYPE_NORESULT
) {
212 encodeSLEB128(0, OS
);
214 encodeULEB128(1, OS
);
215 encodeSLEB128(Sig
.ReturnType
, OS
);
221 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
222 WasmYAML::ImportSection
&Section
) {
223 encodeULEB128(Section
.Imports
.size(), OS
);
224 for (const WasmYAML::Import
&Import
: Section
.Imports
) {
225 writeStringRef(Import
.Module
, OS
);
226 writeStringRef(Import
.Field
, OS
);
227 encodeULEB128(Import
.Kind
, OS
);
228 switch (Import
.Kind
) {
229 case wasm::WASM_EXTERNAL_FUNCTION
:
230 encodeULEB128(Import
.SigIndex
, OS
);
232 case wasm::WASM_EXTERNAL_GLOBAL
:
233 encodeSLEB128(Import
.GlobalImport
.Type
, OS
);
234 writeUint8(OS
, Import
.GlobalImport
.Mutable
);
236 case wasm::WASM_EXTERNAL_MEMORY
:
237 writeLimits(Import
.Memory
, OS
);
239 case wasm::WASM_EXTERNAL_TABLE
:
240 encodeSLEB128(Import
.TableImport
.ElemType
, OS
);
241 writeLimits(Import
.TableImport
.TableLimits
, OS
);
244 errs() << "Unknown import type: " << Import
.Kind
;
251 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
252 WasmYAML::FunctionSection
&Section
) {
253 encodeULEB128(Section
.FunctionTypes
.size(), OS
);
254 for (uint32_t FuncType
: Section
.FunctionTypes
) {
255 encodeULEB128(FuncType
, OS
);
260 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
261 WasmYAML::ExportSection
&Section
) {
262 encodeULEB128(Section
.Exports
.size(), OS
);
263 for (const WasmYAML::Export
&Export
: Section
.Exports
) {
264 writeStringRef(Export
.Name
, OS
);
265 encodeULEB128(Export
.Kind
, OS
);
266 encodeULEB128(Export
.Index
, OS
);
271 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
272 WasmYAML::StartSection
&Section
) {
273 encodeULEB128(Section
.StartFunction
, OS
);
277 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
278 WasmYAML::TableSection
&Section
) {
279 encodeULEB128(Section
.Tables
.size(), OS
);
280 for (auto &Table
: Section
.Tables
) {
281 encodeSLEB128(Table
.ElemType
, OS
);
282 writeLimits(Table
.TableLimits
, OS
);
287 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
288 WasmYAML::MemorySection
&Section
) {
289 encodeULEB128(Section
.Memories
.size(), OS
);
290 for (const WasmYAML::Limits
&Mem
: Section
.Memories
) {
291 writeLimits(Mem
, OS
);
296 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
297 WasmYAML::GlobalSection
&Section
) {
298 encodeULEB128(Section
.Globals
.size(), OS
);
299 for (auto &Global
: Section
.Globals
) {
300 encodeSLEB128(Global
.Type
, OS
);
301 writeUint8(OS
, Global
.Mutable
);
302 writeInitExpr(Global
.InitExpr
, OS
);
307 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
308 WasmYAML::ElemSection
&Section
) {
309 encodeULEB128(Section
.Segments
.size(), OS
);
310 for (auto &Segment
: Section
.Segments
) {
311 encodeULEB128(Segment
.TableIndex
, OS
);
312 writeInitExpr(Segment
.Offset
, OS
);
314 encodeULEB128(Segment
.Functions
.size(), OS
);
315 for (auto &Function
: Segment
.Functions
) {
316 encodeULEB128(Function
, OS
);
322 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
323 WasmYAML::CodeSection
&Section
) {
324 encodeULEB128(Section
.Functions
.size(), OS
);
325 for (auto &Func
: Section
.Functions
) {
326 std::string OutString
;
327 raw_string_ostream
StringStream(OutString
);
329 encodeULEB128(Func
.Locals
.size(), StringStream
);
330 for (auto &LocalDecl
: Func
.Locals
) {
331 encodeULEB128(LocalDecl
.Count
, StringStream
);
332 encodeSLEB128(LocalDecl
.Type
, StringStream
);
335 Func
.Body
.writeAsBinary(StringStream
);
337 // Write the section size followed by the content
338 StringStream
.flush();
339 encodeULEB128(OutString
.size(), OS
);
345 int WasmWriter::writeSectionContent(raw_ostream
&OS
,
346 WasmYAML::DataSection
&Section
) {
347 encodeULEB128(Section
.Segments
.size(), OS
);
348 for (auto &Segment
: Section
.Segments
) {
349 encodeULEB128(Segment
.MemoryIndex
, OS
);
350 writeInitExpr(Segment
.Offset
, OS
);
351 encodeULEB128(Segment
.Content
.binary_size(), OS
);
352 Segment
.Content
.writeAsBinary(OS
);
357 int WasmWriter::writeRelocSection(raw_ostream
&OS
,
358 WasmYAML::Section
&Sec
) {
361 case wasm::WASM_SEC_CODE
:
364 case wasm::WASM_SEC_DATA
:
368 llvm_unreachable("not yet implemented");
372 writeStringRef(Name
, OS
);
373 encodeULEB128(Sec
.Type
, OS
);
374 encodeULEB128(Sec
.Relocations
.size(), OS
);
376 for (auto Reloc
: Sec
.Relocations
) {
377 encodeULEB128(Reloc
.Type
, OS
);
378 encodeULEB128(Reloc
.Offset
, OS
);
379 encodeULEB128(Reloc
.Index
, OS
);
380 switch (Reloc
.Type
) {
381 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB
:
382 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB
:
383 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32
:
384 encodeULEB128(Reloc
.Addend
, OS
);
391 int WasmWriter::writeWasm(raw_ostream
&OS
) {
393 OS
.write(wasm::WasmMagic
, sizeof(wasm::WasmMagic
));
394 writeUint32(OS
, Obj
.Header
.Version
);
396 // Write each section
397 for (const std::unique_ptr
<WasmYAML::Section
> &Sec
: Obj
.Sections
) {
398 encodeULEB128(Sec
->Type
, OS
);
400 std::string OutString
;
401 raw_string_ostream
StringStream(OutString
);
402 if (auto S
= dyn_cast
<WasmYAML::CustomSection
>(Sec
.get())) {
403 if (auto Err
= writeSectionContent(StringStream
, *S
))
405 } else if (auto S
= dyn_cast
<WasmYAML::TypeSection
>(Sec
.get())) {
406 if (auto Err
= writeSectionContent(StringStream
, *S
))
408 } else if (auto S
= dyn_cast
<WasmYAML::ImportSection
>(Sec
.get())) {
409 if (auto Err
= writeSectionContent(StringStream
, *S
))
411 } else if (auto S
= dyn_cast
<WasmYAML::FunctionSection
>(Sec
.get())) {
412 if (auto Err
= writeSectionContent(StringStream
, *S
))
414 } else if (auto S
= dyn_cast
<WasmYAML::TableSection
>(Sec
.get())) {
415 if (auto Err
= writeSectionContent(StringStream
, *S
))
417 } else if (auto S
= dyn_cast
<WasmYAML::MemorySection
>(Sec
.get())) {
418 if (auto Err
= writeSectionContent(StringStream
, *S
))
420 } else if (auto S
= dyn_cast
<WasmYAML::GlobalSection
>(Sec
.get())) {
421 if (auto Err
= writeSectionContent(StringStream
, *S
))
423 } else if (auto S
= dyn_cast
<WasmYAML::ExportSection
>(Sec
.get())) {
424 if (auto Err
= writeSectionContent(StringStream
, *S
))
426 } else if (auto S
= dyn_cast
<WasmYAML::StartSection
>(Sec
.get())) {
427 if (auto Err
= writeSectionContent(StringStream
, *S
))
429 } else if (auto S
= dyn_cast
<WasmYAML::ElemSection
>(Sec
.get())) {
430 if (auto Err
= writeSectionContent(StringStream
, *S
))
432 } else if (auto S
= dyn_cast
<WasmYAML::CodeSection
>(Sec
.get())) {
433 if (auto Err
= writeSectionContent(StringStream
, *S
))
435 } else if (auto S
= dyn_cast
<WasmYAML::DataSection
>(Sec
.get())) {
436 if (auto Err
= writeSectionContent(StringStream
, *S
))
439 errs() << "Unknown section type: " << Sec
->Type
<< "\n";
442 StringStream
.flush();
444 // Write the section size followed by the content
445 encodeULEB128(OutString
.size(), OS
);
449 // write reloc sections for any section that have relocations
450 for (const std::unique_ptr
<WasmYAML::Section
> &Sec
: Obj
.Sections
) {
451 if (Sec
->Relocations
.empty())
454 encodeULEB128(wasm::WASM_SEC_CUSTOM
, OS
);
455 std::string OutString
;
456 raw_string_ostream
StringStream(OutString
);
457 writeRelocSection(StringStream
, *Sec
);
458 StringStream
.flush();
460 encodeULEB128(OutString
.size(), OS
);
467 int yaml2wasm(llvm::WasmYAML::Object
&Doc
, raw_ostream
&Out
) {
468 WasmWriter
Writer(Doc
);
470 return Writer
.writeWasm(Out
);