1 //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements Wasm object file writer information.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/SmallPtrSet.h"
15 #include "llvm/BinaryFormat/Wasm.h"
16 #include "llvm/Config/llvm-config.h"
17 #include "llvm/MC/MCAsmBackend.h"
18 #include "llvm/MC/MCAsmLayout.h"
19 #include "llvm/MC/MCAssembler.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCExpr.h"
22 #include "llvm/MC/MCFixupKindInfo.h"
23 #include "llvm/MC/MCObjectWriter.h"
24 #include "llvm/MC/MCSectionWasm.h"
25 #include "llvm/MC/MCSymbolWasm.h"
26 #include "llvm/MC/MCValue.h"
27 #include "llvm/MC/MCWasmObjectWriter.h"
28 #include "llvm/Support/Casting.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/LEB128.h"
32 #include "llvm/Support/StringSaver.h"
37 #define DEBUG_TYPE "mc"
41 // Went we ceate the indirect function table we start at 1, so that there is
42 // and emtpy slot at 0 and therefore calling a null function pointer will trap.
43 static const uint32_t InitialTableOffset
= 1;
45 // For patching purposes, we need to remember where each section starts, both
46 // for patching up the section size field, and for patching up references to
47 // locations within the section.
48 struct SectionBookkeeping
{
49 // Where the size of the section is written.
51 // Where the section header ends (without custom section name).
52 uint64_t PayloadOffset
;
53 // Where the contents of the section starts.
54 uint64_t ContentsOffset
;
58 // The signature of a wasm function or event, in a struct capable of being used
60 // TODO: Consider using wasm::WasmSignature directly instead.
61 struct WasmSignature
{
62 // Support empty and tombstone instances, needed by DenseMap.
63 enum { Plain
, Empty
, Tombstone
} State
= Plain
;
65 // The return types of the function.
66 SmallVector
<wasm::ValType
, 1> Returns
;
68 // The parameter types of the function.
69 SmallVector
<wasm::ValType
, 4> Params
;
71 bool operator==(const WasmSignature
&Other
) const {
72 return State
== Other
.State
&& Returns
== Other
.Returns
&&
73 Params
== Other
.Params
;
77 // Traits for using WasmSignature in a DenseMap.
78 struct WasmSignatureDenseMapInfo
{
79 static WasmSignature
getEmptyKey() {
81 Sig
.State
= WasmSignature::Empty
;
84 static WasmSignature
getTombstoneKey() {
86 Sig
.State
= WasmSignature::Tombstone
;
89 static unsigned getHashValue(const WasmSignature
&Sig
) {
90 uintptr_t Value
= Sig
.State
;
91 for (wasm::ValType Ret
: Sig
.Returns
)
92 Value
+= DenseMapInfo
<uint32_t>::getHashValue(uint32_t(Ret
));
93 for (wasm::ValType Param
: Sig
.Params
)
94 Value
+= DenseMapInfo
<uint32_t>::getHashValue(uint32_t(Param
));
97 static bool isEqual(const WasmSignature
&LHS
, const WasmSignature
&RHS
) {
102 // A wasm data segment. A wasm binary contains only a single data section
103 // but that can contain many segments, each with their own virtual location
104 // in memory. Each MCSection data created by llvm is modeled as its own
105 // wasm data segment.
106 struct WasmDataSegment
{
107 MCSectionWasm
*Section
;
112 uint32_t LinkerFlags
;
113 SmallVector
<char, 4> Data
;
116 // A wasm function to be written into the function section.
117 struct WasmFunction
{
119 const MCSymbolWasm
*Sym
;
122 // A wasm global to be written into the global section.
124 wasm::WasmGlobalType Type
;
125 uint64_t InitialValue
;
128 // Information about a single item which is part of a COMDAT. For each data
129 // segment or function which is in the COMDAT, there is a corresponding
131 struct WasmComdatEntry
{
136 // Information about a single relocation.
137 struct WasmRelocationEntry
{
138 uint64_t Offset
; // Where is the relocation.
139 const MCSymbolWasm
*Symbol
; // The symbol to relocate with.
140 int64_t Addend
; // A value to add to the symbol.
141 unsigned Type
; // The type of the relocation.
142 const MCSectionWasm
*FixupSection
; // The section the relocation is targeting.
144 WasmRelocationEntry(uint64_t Offset
, const MCSymbolWasm
*Symbol
,
145 int64_t Addend
, unsigned Type
,
146 const MCSectionWasm
*FixupSection
)
147 : Offset(Offset
), Symbol(Symbol
), Addend(Addend
), Type(Type
),
148 FixupSection(FixupSection
) {}
150 bool hasAddend() const { return wasm::relocTypeHasAddend(Type
); }
152 void print(raw_ostream
&Out
) const {
153 Out
<< wasm::relocTypetoString(Type
) << " Off=" << Offset
154 << ", Sym=" << *Symbol
<< ", Addend=" << Addend
155 << ", FixupSection=" << FixupSection
->getSectionName();
158 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
159 LLVM_DUMP_METHOD
void dump() const { print(dbgs()); }
163 static const uint32_t InvalidIndex
= -1;
165 struct WasmCustomSection
{
168 MCSectionWasm
*Section
;
170 uint32_t OutputContentsOffset
;
171 uint32_t OutputIndex
;
173 WasmCustomSection(StringRef Name
, MCSectionWasm
*Section
)
174 : Name(Name
), Section(Section
), OutputContentsOffset(0),
175 OutputIndex(InvalidIndex
) {}
179 raw_ostream
&operator<<(raw_ostream
&OS
, const WasmRelocationEntry
&Rel
) {
185 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded
186 // to allow patching.
187 static void writePatchableLEB(raw_pwrite_stream
&Stream
, uint32_t X
,
190 unsigned SizeLen
= encodeULEB128(X
, Buffer
, 5);
191 assert(SizeLen
== 5);
192 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
195 // Write X as an signed LEB value at offset Offset in Stream, padded
196 // to allow patching.
197 static void writePatchableSLEB(raw_pwrite_stream
&Stream
, int32_t X
,
200 unsigned SizeLen
= encodeSLEB128(X
, Buffer
, 5);
201 assert(SizeLen
== 5);
202 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
205 // Write X as a plain integer value at offset Offset in Stream.
206 static void writeI32(raw_pwrite_stream
&Stream
, uint32_t X
, uint64_t Offset
) {
208 support::endian::write32le(Buffer
, X
);
209 Stream
.pwrite((char *)Buffer
, sizeof(Buffer
), Offset
);
212 class WasmObjectWriter
: public MCObjectWriter
{
213 support::endian::Writer W
;
215 /// The target specific Wasm writer instance.
216 std::unique_ptr
<MCWasmObjectTargetWriter
> TargetObjectWriter
;
218 // Relocations for fixing up references in the code section.
219 std::vector
<WasmRelocationEntry
> CodeRelocations
;
220 uint32_t CodeSectionIndex
;
222 // Relocations for fixing up references in the data section.
223 std::vector
<WasmRelocationEntry
> DataRelocations
;
224 uint32_t DataSectionIndex
;
226 // Index values to use for fixing up call_indirect type indices.
227 // Maps function symbols to the index of the type of the function
228 DenseMap
<const MCSymbolWasm
*, uint32_t> TypeIndices
;
229 // Maps function symbols to the table element index space. Used
230 // for TABLE_INDEX relocation types (i.e. address taken functions).
231 DenseMap
<const MCSymbolWasm
*, uint32_t> TableIndices
;
232 // Maps function/global symbols to the function/global/event/section index
234 DenseMap
<const MCSymbolWasm
*, uint32_t> WasmIndices
;
235 DenseMap
<const MCSymbolWasm
*, uint32_t> GOTIndices
;
236 // Maps data symbols to the Wasm segment and offset/size with the segment.
237 DenseMap
<const MCSymbolWasm
*, wasm::WasmDataReference
> DataLocations
;
239 // Stores output data (index, relocations, content offset) for custom
241 std::vector
<WasmCustomSection
> CustomSections
;
242 std::unique_ptr
<WasmCustomSection
> ProducersSection
;
243 std::unique_ptr
<WasmCustomSection
> TargetFeaturesSection
;
244 // Relocations for fixing up references in the custom sections.
245 DenseMap
<const MCSectionWasm
*, std::vector
<WasmRelocationEntry
>>
246 CustomSectionsRelocations
;
248 // Map from section to defining function symbol.
249 DenseMap
<const MCSection
*, const MCSymbol
*> SectionFunctions
;
251 DenseMap
<WasmSignature
, uint32_t, WasmSignatureDenseMapInfo
> SignatureIndices
;
252 SmallVector
<WasmSignature
, 4> Signatures
;
253 SmallVector
<WasmDataSegment
, 4> DataSegments
;
254 unsigned NumFunctionImports
= 0;
255 unsigned NumGlobalImports
= 0;
256 unsigned NumEventImports
= 0;
257 uint32_t SectionCount
= 0;
259 // TargetObjectWriter wrappers.
260 bool is64Bit() const { return TargetObjectWriter
->is64Bit(); }
261 bool isEmscripten() const { return TargetObjectWriter
->isEmscripten(); }
263 void startSection(SectionBookkeeping
&Section
, unsigned SectionId
);
264 void startCustomSection(SectionBookkeeping
&Section
, StringRef Name
);
265 void endSection(SectionBookkeeping
&Section
);
268 WasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
269 raw_pwrite_stream
&OS
)
270 : W(OS
, support::little
), TargetObjectWriter(std::move(MOTW
)) {}
273 void reset() override
{
274 CodeRelocations
.clear();
275 DataRelocations
.clear();
279 TableIndices
.clear();
280 DataLocations
.clear();
281 CustomSections
.clear();
282 ProducersSection
.reset();
283 TargetFeaturesSection
.reset();
284 CustomSectionsRelocations
.clear();
285 SignatureIndices
.clear();
287 DataSegments
.clear();
288 SectionFunctions
.clear();
289 NumFunctionImports
= 0;
290 NumGlobalImports
= 0;
291 MCObjectWriter::reset();
294 void writeHeader(const MCAssembler
&Asm
);
296 void recordRelocation(MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
297 const MCFragment
*Fragment
, const MCFixup
&Fixup
,
298 MCValue Target
, uint64_t &FixedValue
) override
;
300 void executePostLayoutBinding(MCAssembler
&Asm
,
301 const MCAsmLayout
&Layout
) override
;
303 uint64_t writeObject(MCAssembler
&Asm
, const MCAsmLayout
&Layout
) override
;
305 void writeString(const StringRef Str
) {
306 encodeULEB128(Str
.size(), W
.OS
);
310 void writeValueType(wasm::ValType Ty
) { W
.OS
<< static_cast<char>(Ty
); }
312 void writeTypeSection(ArrayRef
<WasmSignature
> Signatures
);
313 void writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
, uint32_t DataSize
,
314 uint32_t NumElements
);
315 void writeFunctionSection(ArrayRef
<WasmFunction
> Functions
);
316 void writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
);
317 void writeElemSection(ArrayRef
<uint32_t> TableElems
);
318 void writeDataCountSection();
319 void writeCodeSection(const MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
320 ArrayRef
<WasmFunction
> Functions
);
321 void writeDataSection();
322 void writeEventSection(ArrayRef
<wasm::WasmEventType
> Events
);
323 void writeRelocSection(uint32_t SectionIndex
, StringRef Name
,
324 std::vector
<WasmRelocationEntry
> &Relocations
);
325 void writeLinkingMetaDataSection(
326 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
327 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
328 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
);
329 void writeCustomSection(WasmCustomSection
&CustomSection
,
330 const MCAssembler
&Asm
, const MCAsmLayout
&Layout
);
331 void writeCustomRelocSections();
333 updateCustomSectionRelocations(const SmallVector
<WasmFunction
, 4> &Functions
,
334 const MCAsmLayout
&Layout
);
336 uint32_t getProvisionalValue(const WasmRelocationEntry
&RelEntry
);
337 void applyRelocations(ArrayRef
<WasmRelocationEntry
> Relocations
,
338 uint64_t ContentsOffset
);
340 uint32_t getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
);
341 uint32_t getFunctionType(const MCSymbolWasm
&Symbol
);
342 uint32_t getEventType(const MCSymbolWasm
&Symbol
);
343 void registerFunctionType(const MCSymbolWasm
&Symbol
);
344 void registerEventType(const MCSymbolWasm
&Symbol
);
347 } // end anonymous namespace
349 // Write out a section header and a patchable section size field.
350 void WasmObjectWriter::startSection(SectionBookkeeping
&Section
,
351 unsigned SectionId
) {
352 LLVM_DEBUG(dbgs() << "startSection " << SectionId
<< "\n");
353 W
.OS
<< char(SectionId
);
355 Section
.SizeOffset
= W
.OS
.tell();
357 // The section size. We don't know the size yet, so reserve enough space
358 // for any 32-bit value; we'll patch it later.
359 encodeULEB128(0, W
.OS
, 5);
361 // The position where the section starts, for measuring its size.
362 Section
.ContentsOffset
= W
.OS
.tell();
363 Section
.PayloadOffset
= W
.OS
.tell();
364 Section
.Index
= SectionCount
++;
367 void WasmObjectWriter::startCustomSection(SectionBookkeeping
&Section
,
369 LLVM_DEBUG(dbgs() << "startCustomSection " << Name
<< "\n");
370 startSection(Section
, wasm::WASM_SEC_CUSTOM
);
372 // The position where the section header ends, for measuring its size.
373 Section
.PayloadOffset
= W
.OS
.tell();
375 // Custom sections in wasm also have a string identifier.
378 // The position where the custom section starts.
379 Section
.ContentsOffset
= W
.OS
.tell();
382 // Now that the section is complete and we know how big it is, patch up the
383 // section size field at the start of the section.
384 void WasmObjectWriter::endSection(SectionBookkeeping
&Section
) {
385 uint64_t Size
= W
.OS
.tell();
386 // /dev/null doesn't support seek/tell and can report offset of 0.
387 // Simply skip this patching in that case.
391 Size
-= Section
.PayloadOffset
;
392 if (uint32_t(Size
) != Size
)
393 report_fatal_error("section size does not fit in a uint32_t");
395 LLVM_DEBUG(dbgs() << "endSection size=" << Size
<< "\n");
397 // Write the final section size to the payload_len field, which follows
398 // the section id byte.
399 writePatchableLEB(static_cast<raw_pwrite_stream
&>(W
.OS
), Size
,
403 // Emit the Wasm header.
404 void WasmObjectWriter::writeHeader(const MCAssembler
&Asm
) {
405 W
.OS
.write(wasm::WasmMagic
, sizeof(wasm::WasmMagic
));
406 W
.write
<uint32_t>(wasm::WasmVersion
);
409 void WasmObjectWriter::executePostLayoutBinding(MCAssembler
&Asm
,
410 const MCAsmLayout
&Layout
) {
411 // Build a map of sections to the function that defines them, for use
412 // in recordRelocation.
413 for (const MCSymbol
&S
: Asm
.symbols()) {
414 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
415 if (WS
.isDefined() && WS
.isFunction() && !WS
.isVariable()) {
416 const auto &Sec
= static_cast<const MCSectionWasm
&>(S
.getSection());
417 auto Pair
= SectionFunctions
.insert(std::make_pair(&Sec
, &S
));
419 report_fatal_error("section already has a defining function: " +
420 Sec
.getSectionName());
425 void WasmObjectWriter::recordRelocation(MCAssembler
&Asm
,
426 const MCAsmLayout
&Layout
,
427 const MCFragment
*Fragment
,
428 const MCFixup
&Fixup
, MCValue Target
,
429 uint64_t &FixedValue
) {
430 // The WebAssembly backend should never generate FKF_IsPCRel fixups
431 assert(!(Asm
.getBackend().getFixupKindInfo(Fixup
.getKind()).Flags
&
432 MCFixupKindInfo::FKF_IsPCRel
));
434 const auto &FixupSection
= cast
<MCSectionWasm
>(*Fragment
->getParent());
435 uint64_t C
= Target
.getConstant();
436 uint64_t FixupOffset
= Layout
.getFragmentOffset(Fragment
) + Fixup
.getOffset();
437 MCContext
&Ctx
= Asm
.getContext();
439 // The .init_array isn't translated as data, so don't do relocations in it.
440 if (FixupSection
.getSectionName().startswith(".init_array"))
443 if (const MCSymbolRefExpr
*RefB
= Target
.getSymB()) {
444 // To get here the A - B expression must have failed evaluateAsRelocatable.
445 // This means either A or B must be undefined and in WebAssembly we can't
446 // support either of those cases.
447 const auto &SymB
= cast
<MCSymbolWasm
>(RefB
->getSymbol());
450 Twine("symbol '") + SymB
.getName() +
451 "': unsupported subtraction expression used in relocation.");
455 // We either rejected the fixup or folded B into C at this point.
456 const MCSymbolRefExpr
*RefA
= Target
.getSymA();
457 const auto *SymA
= cast
<MCSymbolWasm
>(&RefA
->getSymbol());
459 if (SymA
->isVariable()) {
460 const MCExpr
*Expr
= SymA
->getVariableValue();
461 const auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
462 if (Inner
->getKind() == MCSymbolRefExpr::VK_WEAKREF
)
463 llvm_unreachable("weakref used in reloc not yet implemented");
466 // Put any constant offset in an addend. Offsets can be negative, and
467 // LLVM expects wrapping, in contrast to wasm's immediates which can't
468 // be negative and don't wrap.
471 unsigned Type
= TargetObjectWriter
->getRelocType(Target
, Fixup
);
473 // Absolute offset within a section or a function.
474 // Currently only supported for for metadata sections.
475 // See: test/MC/WebAssembly/blockaddress.ll
476 if (Type
== wasm::R_WASM_FUNCTION_OFFSET_I32
||
477 Type
== wasm::R_WASM_SECTION_OFFSET_I32
) {
478 if (!FixupSection
.getKind().isMetadata())
479 report_fatal_error("relocations for function or section offsets are "
480 "only supported in metadata sections");
482 const MCSymbol
*SectionSymbol
= nullptr;
483 const MCSection
&SecA
= SymA
->getSection();
484 if (SecA
.getKind().isText())
485 SectionSymbol
= SectionFunctions
.find(&SecA
)->second
;
487 SectionSymbol
= SecA
.getBeginSymbol();
489 report_fatal_error("section symbol is required for relocation");
491 C
+= Layout
.getSymbolOffset(*SymA
);
492 SymA
= cast
<MCSymbolWasm
>(SectionSymbol
);
495 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
496 // against a named symbol.
497 if (Type
!= wasm::R_WASM_TYPE_INDEX_LEB
) {
498 if (SymA
->getName().empty())
499 report_fatal_error("relocations against un-named temporaries are not yet "
500 "supported by wasm");
502 SymA
->setUsedInReloc();
505 if (RefA
->getKind() == MCSymbolRefExpr::VK_GOT
)
506 SymA
->setUsedInGOT();
508 WasmRelocationEntry
Rec(FixupOffset
, SymA
, C
, Type
, &FixupSection
);
509 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec
<< "\n");
511 if (FixupSection
.isWasmData()) {
512 DataRelocations
.push_back(Rec
);
513 } else if (FixupSection
.getKind().isText()) {
514 CodeRelocations
.push_back(Rec
);
515 } else if (FixupSection
.getKind().isMetadata()) {
516 CustomSectionsRelocations
[&FixupSection
].push_back(Rec
);
518 llvm_unreachable("unexpected section type");
522 static const MCSymbolWasm
*resolveSymbol(const MCSymbolWasm
&Symbol
) {
523 const MCSymbolWasm
* Ret
= &Symbol
;
524 while (Ret
->isVariable()) {
525 const MCExpr
*Expr
= Ret
->getVariableValue();
526 auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
527 Ret
= cast
<MCSymbolWasm
>(&Inner
->getSymbol());
532 // Compute a value to write into the code at the location covered
533 // by RelEntry. This value isn't used by the static linker; it just serves
534 // to make the object format more readable and more likely to be directly
537 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry
&RelEntry
) {
538 if (RelEntry
.Type
== wasm::R_WASM_GLOBAL_INDEX_LEB
&& !RelEntry
.Symbol
->isGlobal()) {
539 assert(GOTIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in GOT index space");
540 return GOTIndices
[RelEntry
.Symbol
];
543 switch (RelEntry
.Type
) {
544 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
545 case wasm::R_WASM_TABLE_INDEX_SLEB
:
546 case wasm::R_WASM_TABLE_INDEX_I32
: {
547 // Provisional value is table address of the resolved symbol itself
548 const MCSymbolWasm
*Sym
= resolveSymbol(*RelEntry
.Symbol
);
549 assert(Sym
->isFunction());
550 return TableIndices
[Sym
];
552 case wasm::R_WASM_TYPE_INDEX_LEB
:
553 // Provisional value is same as the index
554 return getRelocationIndexValue(RelEntry
);
555 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
556 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
557 case wasm::R_WASM_EVENT_INDEX_LEB
:
558 // Provisional value is function/global/event Wasm index
559 assert(WasmIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in wasm index space");
560 return WasmIndices
[RelEntry
.Symbol
];
561 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
562 case wasm::R_WASM_SECTION_OFFSET_I32
: {
563 const auto &Section
=
564 static_cast<const MCSectionWasm
&>(RelEntry
.Symbol
->getSection());
565 return Section
.getSectionOffset() + RelEntry
.Addend
;
567 case wasm::R_WASM_MEMORY_ADDR_LEB
:
568 case wasm::R_WASM_MEMORY_ADDR_I32
:
569 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
570 case wasm::R_WASM_MEMORY_ADDR_SLEB
: {
571 // Provisional value is address of the global
572 const MCSymbolWasm
*Sym
= resolveSymbol(*RelEntry
.Symbol
);
573 // For undefined symbols, use zero
574 if (!Sym
->isDefined())
576 const wasm::WasmDataReference
&Ref
= DataLocations
[Sym
];
577 const WasmDataSegment
&Segment
= DataSegments
[Ref
.Segment
];
578 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
579 return Segment
.Offset
+ Ref
.Offset
+ RelEntry
.Addend
;
582 llvm_unreachable("invalid relocation type");
586 static void addData(SmallVectorImpl
<char> &DataBytes
,
587 MCSectionWasm
&DataSection
) {
588 LLVM_DEBUG(errs() << "addData: " << DataSection
.getSectionName() << "\n");
590 DataBytes
.resize(alignTo(DataBytes
.size(), DataSection
.getAlignment()));
592 for (const MCFragment
&Frag
: DataSection
) {
593 if (Frag
.hasInstructions())
594 report_fatal_error("only data supported in data sections");
596 if (auto *Align
= dyn_cast
<MCAlignFragment
>(&Frag
)) {
597 if (Align
->getValueSize() != 1)
598 report_fatal_error("only byte values supported for alignment");
599 // If nops are requested, use zeros, as this is the data section.
600 uint8_t Value
= Align
->hasEmitNops() ? 0 : Align
->getValue();
602 std::min
<uint64_t>(alignTo(DataBytes
.size(), Align
->getAlignment()),
603 DataBytes
.size() + Align
->getMaxBytesToEmit());
604 DataBytes
.resize(Size
, Value
);
605 } else if (auto *Fill
= dyn_cast
<MCFillFragment
>(&Frag
)) {
607 if (!Fill
->getNumValues().evaluateAsAbsolute(NumValues
))
608 llvm_unreachable("The fill should be an assembler constant");
609 DataBytes
.insert(DataBytes
.end(), Fill
->getValueSize() * NumValues
,
611 } else if (auto *LEB
= dyn_cast
<MCLEBFragment
>(&Frag
)) {
612 const SmallVectorImpl
<char> &Contents
= LEB
->getContents();
613 DataBytes
.insert(DataBytes
.end(), Contents
.begin(), Contents
.end());
615 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
616 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
617 DataBytes
.insert(DataBytes
.end(), Contents
.begin(), Contents
.end());
621 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes
.size() << "\n");
625 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
) {
626 if (RelEntry
.Type
== wasm::R_WASM_TYPE_INDEX_LEB
) {
627 if (!TypeIndices
.count(RelEntry
.Symbol
))
628 report_fatal_error("symbol not found in type index space: " +
629 RelEntry
.Symbol
->getName());
630 return TypeIndices
[RelEntry
.Symbol
];
633 return RelEntry
.Symbol
->getIndex();
636 // Apply the portions of the relocation records that we can handle ourselves
638 void WasmObjectWriter::applyRelocations(
639 ArrayRef
<WasmRelocationEntry
> Relocations
, uint64_t ContentsOffset
) {
640 auto &Stream
= static_cast<raw_pwrite_stream
&>(W
.OS
);
641 for (const WasmRelocationEntry
&RelEntry
: Relocations
) {
642 uint64_t Offset
= ContentsOffset
+
643 RelEntry
.FixupSection
->getSectionOffset() +
646 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry
<< "\n");
647 uint32_t Value
= getProvisionalValue(RelEntry
);
649 switch (RelEntry
.Type
) {
650 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
651 case wasm::R_WASM_TYPE_INDEX_LEB
:
652 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
653 case wasm::R_WASM_MEMORY_ADDR_LEB
:
654 case wasm::R_WASM_EVENT_INDEX_LEB
:
655 writePatchableLEB(Stream
, Value
, Offset
);
657 case wasm::R_WASM_TABLE_INDEX_I32
:
658 case wasm::R_WASM_MEMORY_ADDR_I32
:
659 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
660 case wasm::R_WASM_SECTION_OFFSET_I32
:
661 writeI32(Stream
, Value
, Offset
);
663 case wasm::R_WASM_TABLE_INDEX_SLEB
:
664 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
665 case wasm::R_WASM_MEMORY_ADDR_SLEB
:
666 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
667 writePatchableSLEB(Stream
, Value
, Offset
);
670 llvm_unreachable("invalid relocation type");
675 void WasmObjectWriter::writeTypeSection(ArrayRef
<WasmSignature
> Signatures
) {
676 if (Signatures
.empty())
679 SectionBookkeeping Section
;
680 startSection(Section
, wasm::WASM_SEC_TYPE
);
682 encodeULEB128(Signatures
.size(), W
.OS
);
684 for (const WasmSignature
&Sig
: Signatures
) {
685 W
.OS
<< char(wasm::WASM_TYPE_FUNC
);
686 encodeULEB128(Sig
.Params
.size(), W
.OS
);
687 for (wasm::ValType Ty
: Sig
.Params
)
689 encodeULEB128(Sig
.Returns
.size(), W
.OS
);
690 for (wasm::ValType Ty
: Sig
.Returns
)
697 void WasmObjectWriter::writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
,
699 uint32_t NumElements
) {
703 uint32_t NumPages
= (DataSize
+ wasm::WasmPageSize
- 1) / wasm::WasmPageSize
;
705 SectionBookkeeping Section
;
706 startSection(Section
, wasm::WASM_SEC_IMPORT
);
708 encodeULEB128(Imports
.size(), W
.OS
);
709 for (const wasm::WasmImport
&Import
: Imports
) {
710 writeString(Import
.Module
);
711 writeString(Import
.Field
);
712 W
.OS
<< char(Import
.Kind
);
714 switch (Import
.Kind
) {
715 case wasm::WASM_EXTERNAL_FUNCTION
:
716 encodeULEB128(Import
.SigIndex
, W
.OS
);
718 case wasm::WASM_EXTERNAL_GLOBAL
:
719 W
.OS
<< char(Import
.Global
.Type
);
720 W
.OS
<< char(Import
.Global
.Mutable
? 1 : 0);
722 case wasm::WASM_EXTERNAL_MEMORY
:
723 encodeULEB128(0, W
.OS
); // flags
724 encodeULEB128(NumPages
, W
.OS
); // initial
726 case wasm::WASM_EXTERNAL_TABLE
:
727 W
.OS
<< char(Import
.Table
.ElemType
);
728 encodeULEB128(0, W
.OS
); // flags
729 encodeULEB128(NumElements
, W
.OS
); // initial
731 case wasm::WASM_EXTERNAL_EVENT
:
732 encodeULEB128(Import
.Event
.Attribute
, W
.OS
);
733 encodeULEB128(Import
.Event
.SigIndex
, W
.OS
);
736 llvm_unreachable("unsupported import kind");
743 void WasmObjectWriter::writeFunctionSection(ArrayRef
<WasmFunction
> Functions
) {
744 if (Functions
.empty())
747 SectionBookkeeping Section
;
748 startSection(Section
, wasm::WASM_SEC_FUNCTION
);
750 encodeULEB128(Functions
.size(), W
.OS
);
751 for (const WasmFunction
&Func
: Functions
)
752 encodeULEB128(Func
.SigIndex
, W
.OS
);
757 void WasmObjectWriter::writeEventSection(ArrayRef
<wasm::WasmEventType
> Events
) {
761 SectionBookkeeping Section
;
762 startSection(Section
, wasm::WASM_SEC_EVENT
);
764 encodeULEB128(Events
.size(), W
.OS
);
765 for (const wasm::WasmEventType
&Event
: Events
) {
766 encodeULEB128(Event
.Attribute
, W
.OS
);
767 encodeULEB128(Event
.SigIndex
, W
.OS
);
773 void WasmObjectWriter::writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
) {
777 SectionBookkeeping Section
;
778 startSection(Section
, wasm::WASM_SEC_EXPORT
);
780 encodeULEB128(Exports
.size(), W
.OS
);
781 for (const wasm::WasmExport
&Export
: Exports
) {
782 writeString(Export
.Name
);
783 W
.OS
<< char(Export
.Kind
);
784 encodeULEB128(Export
.Index
, W
.OS
);
790 void WasmObjectWriter::writeElemSection(ArrayRef
<uint32_t> TableElems
) {
791 if (TableElems
.empty())
794 SectionBookkeeping Section
;
795 startSection(Section
, wasm::WASM_SEC_ELEM
);
797 encodeULEB128(1, W
.OS
); // number of "segments"
798 encodeULEB128(0, W
.OS
); // the table index
800 // init expr for starting offset
801 W
.OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
802 encodeSLEB128(InitialTableOffset
, W
.OS
);
803 W
.OS
<< char(wasm::WASM_OPCODE_END
);
805 encodeULEB128(TableElems
.size(), W
.OS
);
806 for (uint32_t Elem
: TableElems
)
807 encodeULEB128(Elem
, W
.OS
);
812 void WasmObjectWriter::writeDataCountSection() {
813 if (DataSegments
.empty())
816 SectionBookkeeping Section
;
817 startSection(Section
, wasm::WASM_SEC_DATACOUNT
);
818 encodeULEB128(DataSegments
.size(), W
.OS
);
822 void WasmObjectWriter::writeCodeSection(const MCAssembler
&Asm
,
823 const MCAsmLayout
&Layout
,
824 ArrayRef
<WasmFunction
> Functions
) {
825 if (Functions
.empty())
828 SectionBookkeeping Section
;
829 startSection(Section
, wasm::WASM_SEC_CODE
);
830 CodeSectionIndex
= Section
.Index
;
832 encodeULEB128(Functions
.size(), W
.OS
);
834 for (const WasmFunction
&Func
: Functions
) {
835 auto &FuncSection
= static_cast<MCSectionWasm
&>(Func
.Sym
->getSection());
838 if (!Func
.Sym
->getSize()->evaluateAsAbsolute(Size
, Layout
))
839 report_fatal_error(".size expression must be evaluatable");
841 encodeULEB128(Size
, W
.OS
);
842 FuncSection
.setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
843 Asm
.writeSectionData(W
.OS
, &FuncSection
, Layout
);
847 applyRelocations(CodeRelocations
, Section
.ContentsOffset
);
852 void WasmObjectWriter::writeDataSection() {
853 if (DataSegments
.empty())
856 SectionBookkeeping Section
;
857 startSection(Section
, wasm::WASM_SEC_DATA
);
858 DataSectionIndex
= Section
.Index
;
860 encodeULEB128(DataSegments
.size(), W
.OS
); // count
862 for (const WasmDataSegment
&Segment
: DataSegments
) {
863 encodeULEB128(Segment
.InitFlags
, W
.OS
); // flags
864 if (Segment
.InitFlags
& wasm::WASM_SEGMENT_HAS_MEMINDEX
)
865 encodeULEB128(0, W
.OS
); // memory index
866 if ((Segment
.InitFlags
& wasm::WASM_SEGMENT_IS_PASSIVE
) == 0) {
867 W
.OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
868 encodeSLEB128(Segment
.Offset
, W
.OS
); // offset
869 W
.OS
<< char(wasm::WASM_OPCODE_END
);
871 encodeULEB128(Segment
.Data
.size(), W
.OS
); // size
872 Segment
.Section
->setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
873 W
.OS
<< Segment
.Data
; // data
877 applyRelocations(DataRelocations
, Section
.ContentsOffset
);
882 void WasmObjectWriter::writeRelocSection(
883 uint32_t SectionIndex
, StringRef Name
,
884 std::vector
<WasmRelocationEntry
> &Relocs
) {
885 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
886 // for descriptions of the reloc sections.
891 // First, ensure the relocations are sorted in offset order. In general they
892 // should already be sorted since `recordRelocation` is called in offset
893 // order, but for the code section we combine many MC sections into single
894 // wasm section, and this order is determined by the order of Asm.Symbols()
895 // not the sections order.
897 Relocs
, [](const WasmRelocationEntry
&A
, const WasmRelocationEntry
&B
) {
898 return (A
.Offset
+ A
.FixupSection
->getSectionOffset()) <
899 (B
.Offset
+ B
.FixupSection
->getSectionOffset());
902 SectionBookkeeping Section
;
903 startCustomSection(Section
, std::string("reloc.") + Name
.str());
905 encodeULEB128(SectionIndex
, W
.OS
);
906 encodeULEB128(Relocs
.size(), W
.OS
);
907 for (const WasmRelocationEntry
&RelEntry
: Relocs
) {
909 RelEntry
.Offset
+ RelEntry
.FixupSection
->getSectionOffset();
910 uint32_t Index
= getRelocationIndexValue(RelEntry
);
912 W
.OS
<< char(RelEntry
.Type
);
913 encodeULEB128(Offset
, W
.OS
);
914 encodeULEB128(Index
, W
.OS
);
915 if (RelEntry
.hasAddend())
916 encodeSLEB128(RelEntry
.Addend
, W
.OS
);
922 void WasmObjectWriter::writeCustomRelocSections() {
923 for (const auto &Sec
: CustomSections
) {
924 auto &Relocations
= CustomSectionsRelocations
[Sec
.Section
];
925 writeRelocSection(Sec
.OutputIndex
, Sec
.Name
, Relocations
);
929 void WasmObjectWriter::writeLinkingMetaDataSection(
930 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
931 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
932 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
) {
933 SectionBookkeeping Section
;
934 startCustomSection(Section
, "linking");
935 encodeULEB128(wasm::WasmMetadataVersion
, W
.OS
);
937 SectionBookkeeping SubSection
;
938 if (SymbolInfos
.size() != 0) {
939 startSection(SubSection
, wasm::WASM_SYMBOL_TABLE
);
940 encodeULEB128(SymbolInfos
.size(), W
.OS
);
941 for (const wasm::WasmSymbolInfo
&Sym
: SymbolInfos
) {
942 encodeULEB128(Sym
.Kind
, W
.OS
);
943 encodeULEB128(Sym
.Flags
, W
.OS
);
945 case wasm::WASM_SYMBOL_TYPE_FUNCTION
:
946 case wasm::WASM_SYMBOL_TYPE_GLOBAL
:
947 case wasm::WASM_SYMBOL_TYPE_EVENT
:
948 encodeULEB128(Sym
.ElementIndex
, W
.OS
);
949 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0 ||
950 (Sym
.Flags
& wasm::WASM_SYMBOL_EXPLICIT_NAME
) != 0)
951 writeString(Sym
.Name
);
953 case wasm::WASM_SYMBOL_TYPE_DATA
:
954 writeString(Sym
.Name
);
955 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0) {
956 encodeULEB128(Sym
.DataRef
.Segment
, W
.OS
);
957 encodeULEB128(Sym
.DataRef
.Offset
, W
.OS
);
958 encodeULEB128(Sym
.DataRef
.Size
, W
.OS
);
961 case wasm::WASM_SYMBOL_TYPE_SECTION
: {
962 const uint32_t SectionIndex
=
963 CustomSections
[Sym
.ElementIndex
].OutputIndex
;
964 encodeULEB128(SectionIndex
, W
.OS
);
968 llvm_unreachable("unexpected kind");
971 endSection(SubSection
);
974 if (DataSegments
.size()) {
975 startSection(SubSection
, wasm::WASM_SEGMENT_INFO
);
976 encodeULEB128(DataSegments
.size(), W
.OS
);
977 for (const WasmDataSegment
&Segment
: DataSegments
) {
978 writeString(Segment
.Name
);
979 encodeULEB128(Segment
.Alignment
, W
.OS
);
980 encodeULEB128(Segment
.LinkerFlags
, W
.OS
);
982 endSection(SubSection
);
985 if (!InitFuncs
.empty()) {
986 startSection(SubSection
, wasm::WASM_INIT_FUNCS
);
987 encodeULEB128(InitFuncs
.size(), W
.OS
);
988 for (auto &StartFunc
: InitFuncs
) {
989 encodeULEB128(StartFunc
.first
, W
.OS
); // priority
990 encodeULEB128(StartFunc
.second
, W
.OS
); // function index
992 endSection(SubSection
);
995 if (Comdats
.size()) {
996 startSection(SubSection
, wasm::WASM_COMDAT_INFO
);
997 encodeULEB128(Comdats
.size(), W
.OS
);
998 for (const auto &C
: Comdats
) {
999 writeString(C
.first
);
1000 encodeULEB128(0, W
.OS
); // flags for future use
1001 encodeULEB128(C
.second
.size(), W
.OS
);
1002 for (const WasmComdatEntry
&Entry
: C
.second
) {
1003 encodeULEB128(Entry
.Kind
, W
.OS
);
1004 encodeULEB128(Entry
.Index
, W
.OS
);
1007 endSection(SubSection
);
1010 endSection(Section
);
1013 void WasmObjectWriter::writeCustomSection(WasmCustomSection
&CustomSection
,
1014 const MCAssembler
&Asm
,
1015 const MCAsmLayout
&Layout
) {
1016 SectionBookkeeping Section
;
1017 auto *Sec
= CustomSection
.Section
;
1018 startCustomSection(Section
, CustomSection
.Name
);
1020 Sec
->setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
1021 Asm
.writeSectionData(W
.OS
, Sec
, Layout
);
1023 CustomSection
.OutputContentsOffset
= Section
.ContentsOffset
;
1024 CustomSection
.OutputIndex
= Section
.Index
;
1026 endSection(Section
);
1029 auto &Relocations
= CustomSectionsRelocations
[CustomSection
.Section
];
1030 applyRelocations(Relocations
, CustomSection
.OutputContentsOffset
);
1033 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm
&Symbol
) {
1034 assert(Symbol
.isFunction());
1035 assert(TypeIndices
.count(&Symbol
));
1036 return TypeIndices
[&Symbol
];
1039 uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm
&Symbol
) {
1040 assert(Symbol
.isEvent());
1041 assert(TypeIndices
.count(&Symbol
));
1042 return TypeIndices
[&Symbol
];
1045 void WasmObjectWriter::registerFunctionType(const MCSymbolWasm
&Symbol
) {
1046 assert(Symbol
.isFunction());
1049 const MCSymbolWasm
*ResolvedSym
= resolveSymbol(Symbol
);
1050 if (auto *Sig
= ResolvedSym
->getSignature()) {
1051 S
.Returns
= Sig
->Returns
;
1052 S
.Params
= Sig
->Params
;
1055 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1057 Signatures
.push_back(S
);
1058 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1060 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
1061 << " new:" << Pair
.second
<< "\n");
1062 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1065 void WasmObjectWriter::registerEventType(const MCSymbolWasm
&Symbol
) {
1066 assert(Symbol
.isEvent());
1068 // TODO Currently we don't generate imported exceptions, but if we do, we
1069 // should have a way of infering types of imported exceptions.
1071 if (auto *Sig
= Symbol
.getSignature()) {
1072 S
.Returns
= Sig
->Returns
;
1073 S
.Params
= Sig
->Params
;
1076 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1078 Signatures
.push_back(S
);
1079 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1081 LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol
<< " new:" << Pair
.second
1083 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1086 static bool isInSymtab(const MCSymbolWasm
&Sym
) {
1087 if (Sym
.isUsedInReloc())
1090 if (Sym
.isComdat() && !Sym
.isDefined())
1093 if (Sym
.isTemporary() && Sym
.getName().empty())
1096 if (Sym
.isTemporary() && Sym
.isData() && !Sym
.getSize())
1099 if (Sym
.isSection())
1105 uint64_t WasmObjectWriter::writeObject(MCAssembler
&Asm
,
1106 const MCAsmLayout
&Layout
) {
1107 uint64_t StartOffset
= W
.OS
.tell();
1109 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
1111 // Collect information from the available symbols.
1112 SmallVector
<WasmFunction
, 4> Functions
;
1113 SmallVector
<uint32_t, 4> TableElems
;
1114 SmallVector
<wasm::WasmImport
, 4> Imports
;
1115 SmallVector
<wasm::WasmExport
, 4> Exports
;
1116 SmallVector
<wasm::WasmEventType
, 1> Events
;
1117 SmallVector
<wasm::WasmSymbolInfo
, 4> SymbolInfos
;
1118 SmallVector
<std::pair
<uint16_t, uint32_t>, 2> InitFuncs
;
1119 std::map
<StringRef
, std::vector
<WasmComdatEntry
>> Comdats
;
1120 uint32_t DataSize
= 0;
1122 // For now, always emit the memory import, since loads and stores are not
1123 // valid without it. In the future, we could perhaps be more clever and omit
1124 // it if there are no loads or stores.
1125 wasm::WasmImport MemImport
;
1126 MemImport
.Module
= "env";
1127 MemImport
.Field
= "__linear_memory";
1128 MemImport
.Kind
= wasm::WASM_EXTERNAL_MEMORY
;
1129 Imports
.push_back(MemImport
);
1131 // For now, always emit the table section, since indirect calls are not
1132 // valid without it. In the future, we could perhaps be more clever and omit
1133 // it if there are no indirect calls.
1134 wasm::WasmImport TableImport
;
1135 TableImport
.Module
= "env";
1136 TableImport
.Field
= "__indirect_function_table";
1137 TableImport
.Kind
= wasm::WASM_EXTERNAL_TABLE
;
1138 TableImport
.Table
.ElemType
= wasm::WASM_TYPE_FUNCREF
;
1139 Imports
.push_back(TableImport
);
1141 // Populate SignatureIndices, and Imports and WasmIndices for undefined
1142 // symbols. This must be done before populating WasmIndices for defined
1144 for (const MCSymbol
&S
: Asm
.symbols()) {
1145 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1147 // Register types for all functions, including those with private linkage
1148 // (because wasm always needs a type signature).
1149 if (WS
.isFunction())
1150 registerFunctionType(WS
);
1153 registerEventType(WS
);
1155 if (WS
.isTemporary())
1158 // If the symbol is not defined in this translation unit, import it.
1159 if (!WS
.isDefined() && !WS
.isComdat()) {
1160 if (WS
.isFunction()) {
1161 wasm::WasmImport Import
;
1162 Import
.Module
= WS
.getImportModule();
1163 Import
.Field
= WS
.getImportName();
1164 Import
.Kind
= wasm::WASM_EXTERNAL_FUNCTION
;
1165 Import
.SigIndex
= getFunctionType(WS
);
1166 Imports
.push_back(Import
);
1167 assert(WasmIndices
.count(&WS
) == 0);
1168 WasmIndices
[&WS
] = NumFunctionImports
++;
1169 } else if (WS
.isGlobal()) {
1171 report_fatal_error("undefined global symbol cannot be weak");
1173 wasm::WasmImport Import
;
1174 Import
.Field
= WS
.getImportName();
1175 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1176 Import
.Module
= WS
.getImportModule();
1177 Import
.Global
= WS
.getGlobalType();
1178 Imports
.push_back(Import
);
1179 assert(WasmIndices
.count(&WS
) == 0);
1180 WasmIndices
[&WS
] = NumGlobalImports
++;
1181 } else if (WS
.isEvent()) {
1183 report_fatal_error("undefined event symbol cannot be weak");
1185 wasm::WasmImport Import
;
1186 Import
.Module
= WS
.getImportModule();
1187 Import
.Field
= WS
.getImportName();
1188 Import
.Kind
= wasm::WASM_EXTERNAL_EVENT
;
1189 Import
.Event
.Attribute
= wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION
;
1190 Import
.Event
.SigIndex
= getEventType(WS
);
1191 Imports
.push_back(Import
);
1192 assert(WasmIndices
.count(&WS
) == 0);
1193 WasmIndices
[&WS
] = NumEventImports
++;
1198 // Add imports for GOT globals
1199 for (const MCSymbol
&S
: Asm
.symbols()) {
1200 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1201 if (WS
.isUsedInGOT()) {
1202 wasm::WasmImport Import
;
1203 if (WS
.isFunction())
1204 Import
.Module
= "GOT.func";
1206 Import
.Module
= "GOT.mem";
1207 Import
.Field
= WS
.getName();
1208 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1209 Import
.Global
= {wasm::WASM_TYPE_I32
, true};
1210 Imports
.push_back(Import
);
1211 assert(GOTIndices
.count(&WS
) == 0);
1212 GOTIndices
[&WS
] = NumGlobalImports
++;
1216 // Populate DataSegments and CustomSections, which must be done before
1217 // populating DataLocations.
1218 for (MCSection
&Sec
: Asm
) {
1219 auto &Section
= static_cast<MCSectionWasm
&>(Sec
);
1220 StringRef SectionName
= Section
.getSectionName();
1222 // .init_array sections are handled specially elsewhere.
1223 if (SectionName
.startswith(".init_array"))
1226 // Code is handled separately
1227 if (Section
.getKind().isText())
1230 if (Section
.isWasmData()) {
1231 uint32_t SegmentIndex
= DataSegments
.size();
1232 DataSize
= alignTo(DataSize
, Section
.getAlignment());
1233 DataSegments
.emplace_back();
1234 WasmDataSegment
&Segment
= DataSegments
.back();
1235 Segment
.Name
= SectionName
;
1237 Section
.getPassive() ? (uint32_t)wasm::WASM_SEGMENT_IS_PASSIVE
: 0;
1238 Segment
.Offset
= DataSize
;
1239 Segment
.Section
= &Section
;
1240 addData(Segment
.Data
, Section
);
1241 Segment
.Alignment
= Log2_32(Section
.getAlignment());
1242 Segment
.LinkerFlags
= 0;
1243 DataSize
+= Segment
.Data
.size();
1244 Section
.setSegmentIndex(SegmentIndex
);
1246 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1247 Comdats
[C
->getName()].emplace_back(
1248 WasmComdatEntry
{wasm::WASM_COMDAT_DATA
, SegmentIndex
});
1251 // Create custom sections
1252 assert(Sec
.getKind().isMetadata());
1254 StringRef Name
= SectionName
;
1256 // For user-defined custom sections, strip the prefix
1257 if (Name
.startswith(".custom_section."))
1258 Name
= Name
.substr(strlen(".custom_section."));
1260 MCSymbol
*Begin
= Sec
.getBeginSymbol();
1262 WasmIndices
[cast
<MCSymbolWasm
>(Begin
)] = CustomSections
.size();
1263 if (SectionName
!= Begin
->getName())
1264 report_fatal_error("section name and begin symbol should match: " +
1265 Twine(SectionName
));
1268 // Separate out the producers and target features sections
1269 if (Name
== "producers") {
1270 ProducersSection
= std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1273 if (Name
== "target_features") {
1274 TargetFeaturesSection
=
1275 std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1279 CustomSections
.emplace_back(Name
, &Section
);
1283 // Populate WasmIndices and DataLocations for defined symbols.
1284 for (const MCSymbol
&S
: Asm
.symbols()) {
1285 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1286 // or used in relocations.
1287 if (S
.isTemporary() && S
.getName().empty())
1290 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1292 dbgs() << "MCSymbol: " << toString(WS
.getType()) << " '" << S
<< "'"
1293 << " isDefined=" << S
.isDefined() << " isExternal="
1294 << S
.isExternal() << " isTemporary=" << S
.isTemporary()
1295 << " isWeak=" << WS
.isWeak() << " isHidden=" << WS
.isHidden()
1296 << " isVariable=" << WS
.isVariable() << "\n");
1298 if (WS
.isVariable())
1300 if (WS
.isComdat() && !WS
.isDefined())
1303 if (WS
.isFunction()) {
1305 if (WS
.isDefined()) {
1306 if (WS
.getOffset() != 0)
1308 "function sections must contain one function each");
1310 if (WS
.getSize() == nullptr)
1312 "function symbols must have a size set with .size");
1314 // A definition. Write out the function body.
1315 Index
= NumFunctionImports
+ Functions
.size();
1317 Func
.SigIndex
= getFunctionType(WS
);
1319 WasmIndices
[&WS
] = Index
;
1320 Functions
.push_back(Func
);
1322 auto &Section
= static_cast<MCSectionWasm
&>(WS
.getSection());
1323 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1324 Comdats
[C
->getName()].emplace_back(
1325 WasmComdatEntry
{wasm::WASM_COMDAT_FUNCTION
, Index
});
1328 // An import; the index was assigned above.
1329 Index
= WasmIndices
.find(&WS
)->second
;
1332 LLVM_DEBUG(dbgs() << " -> function index: " << Index
<< "\n");
1334 } else if (WS
.isData()) {
1335 if (!isInSymtab(WS
))
1338 if (!WS
.isDefined()) {
1339 LLVM_DEBUG(dbgs() << " -> segment index: -1"
1345 report_fatal_error("data symbols must have a size set with .size: " +
1349 if (!WS
.getSize()->evaluateAsAbsolute(Size
, Layout
))
1350 report_fatal_error(".size expression must be evaluatable");
1352 auto &DataSection
= static_cast<MCSectionWasm
&>(WS
.getSection());
1353 assert(DataSection
.isWasmData());
1355 // For each data symbol, export it in the symtab as a reference to the
1356 // corresponding Wasm data segment.
1357 wasm::WasmDataReference Ref
= wasm::WasmDataReference
{
1358 DataSection
.getSegmentIndex(),
1359 static_cast<uint32_t>(Layout
.getSymbolOffset(WS
)),
1360 static_cast<uint32_t>(Size
)};
1361 DataLocations
[&WS
] = Ref
;
1362 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref
.Segment
<< "\n");
1364 } else if (WS
.isGlobal()) {
1365 // A "true" Wasm global (currently just __stack_pointer)
1367 report_fatal_error("don't yet support defined globals");
1369 // An import; the index was assigned above
1370 LLVM_DEBUG(dbgs() << " -> global index: "
1371 << WasmIndices
.find(&WS
)->second
<< "\n");
1373 } else if (WS
.isEvent()) {
1374 // C++ exception symbol (__cpp_exception)
1376 if (WS
.isDefined()) {
1377 Index
= NumEventImports
+ Events
.size();
1378 wasm::WasmEventType Event
;
1379 Event
.SigIndex
= getEventType(WS
);
1380 Event
.Attribute
= wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION
;
1381 assert(WasmIndices
.count(&WS
) == 0);
1382 WasmIndices
[&WS
] = Index
;
1383 Events
.push_back(Event
);
1385 // An import; the index was assigned above.
1386 assert(WasmIndices
.count(&WS
) > 0);
1388 LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices
.find(&WS
)->second
1392 assert(WS
.isSection());
1396 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1397 // process these in a separate pass because we need to have processed the
1398 // target of the alias before the alias itself and the symbols are not
1399 // necessarily ordered in this way.
1400 for (const MCSymbol
&S
: Asm
.symbols()) {
1401 if (!S
.isVariable())
1404 assert(S
.isDefined());
1406 // Find the target symbol of this weak alias and export that index
1407 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1408 const MCSymbolWasm
*ResolvedSym
= resolveSymbol(WS
);
1409 LLVM_DEBUG(dbgs() << WS
.getName() << ": weak alias of '" << *ResolvedSym
1412 if (ResolvedSym
->isFunction()) {
1413 assert(WasmIndices
.count(ResolvedSym
) > 0);
1414 uint32_t WasmIndex
= WasmIndices
.find(ResolvedSym
)->second
;
1415 assert(WasmIndices
.count(&WS
) == 0);
1416 WasmIndices
[&WS
] = WasmIndex
;
1417 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex
<< "\n");
1418 } else if (ResolvedSym
->isData()) {
1419 assert(DataLocations
.count(ResolvedSym
) > 0);
1420 const wasm::WasmDataReference
&Ref
=
1421 DataLocations
.find(ResolvedSym
)->second
;
1422 DataLocations
[&WS
] = Ref
;
1423 LLVM_DEBUG(dbgs() << " -> index:" << Ref
.Segment
<< "\n");
1425 report_fatal_error("don't yet support global/event aliases");
1429 // Finally, populate the symbol table itself, in its "natural" order.
1430 for (const MCSymbol
&S
: Asm
.symbols()) {
1431 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1432 if (!isInSymtab(WS
)) {
1433 WS
.setIndex(InvalidIndex
);
1436 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS
<< "\n");
1440 Flags
|= wasm::WASM_SYMBOL_BINDING_WEAK
;
1442 Flags
|= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN
;
1443 if (!WS
.isExternal() && WS
.isDefined())
1444 Flags
|= wasm::WASM_SYMBOL_BINDING_LOCAL
;
1445 if (WS
.isUndefined())
1446 Flags
|= wasm::WASM_SYMBOL_UNDEFINED
;
1447 if (WS
.isNoStrip()) {
1448 Flags
|= wasm::WASM_SYMBOL_NO_STRIP
;
1449 if (isEmscripten()) {
1450 Flags
|= wasm::WASM_SYMBOL_EXPORTED
;
1453 if (WS
.getName() != WS
.getImportName())
1454 Flags
|= wasm::WASM_SYMBOL_EXPLICIT_NAME
;
1456 wasm::WasmSymbolInfo Info
;
1457 Info
.Name
= WS
.getName();
1458 Info
.Kind
= WS
.getType();
1461 assert(WasmIndices
.count(&WS
) > 0);
1462 Info
.ElementIndex
= WasmIndices
.find(&WS
)->second
;
1463 } else if (WS
.isDefined()) {
1464 assert(DataLocations
.count(&WS
) > 0);
1465 Info
.DataRef
= DataLocations
.find(&WS
)->second
;
1467 WS
.setIndex(SymbolInfos
.size());
1468 SymbolInfos
.emplace_back(Info
);
1472 auto HandleReloc
= [&](const WasmRelocationEntry
&Rel
) {
1473 // Functions referenced by a relocation need to put in the table. This is
1474 // purely to make the object file's provisional values readable, and is
1475 // ignored by the linker, which re-calculates the relocations itself.
1476 if (Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_I32
&&
1477 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_SLEB
)
1479 assert(Rel
.Symbol
->isFunction());
1480 const MCSymbolWasm
&WS
= *resolveSymbol(*Rel
.Symbol
);
1481 uint32_t FunctionIndex
= WasmIndices
.find(&WS
)->second
;
1482 uint32_t TableIndex
= TableElems
.size() + InitialTableOffset
;
1483 if (TableIndices
.try_emplace(&WS
, TableIndex
).second
) {
1484 LLVM_DEBUG(dbgs() << " -> adding " << WS
.getName()
1485 << " to table: " << TableIndex
<< "\n");
1486 TableElems
.push_back(FunctionIndex
);
1487 registerFunctionType(WS
);
1491 for (const WasmRelocationEntry
&RelEntry
: CodeRelocations
)
1492 HandleReloc(RelEntry
);
1493 for (const WasmRelocationEntry
&RelEntry
: DataRelocations
)
1494 HandleReloc(RelEntry
);
1497 // Translate .init_array section contents into start functions.
1498 for (const MCSection
&S
: Asm
) {
1499 const auto &WS
= static_cast<const MCSectionWasm
&>(S
);
1500 if (WS
.getSectionName().startswith(".fini_array"))
1501 report_fatal_error(".fini_array sections are unsupported");
1502 if (!WS
.getSectionName().startswith(".init_array"))
1504 if (WS
.getFragmentList().empty())
1507 // init_array is expected to contain a single non-empty data fragment
1508 if (WS
.getFragmentList().size() != 3)
1509 report_fatal_error("only one .init_array section fragment supported");
1511 auto IT
= WS
.begin();
1512 const MCFragment
&EmptyFrag
= *IT
;
1513 if (EmptyFrag
.getKind() != MCFragment::FT_Data
)
1514 report_fatal_error(".init_array section should be aligned");
1517 const MCFragment
&AlignFrag
= *IT
;
1518 if (AlignFrag
.getKind() != MCFragment::FT_Align
)
1519 report_fatal_error(".init_array section should be aligned");
1520 if (cast
<MCAlignFragment
>(AlignFrag
).getAlignment() != (is64Bit() ? 8 : 4))
1521 report_fatal_error(".init_array section should be aligned for pointers");
1523 const MCFragment
&Frag
= *std::next(IT
);
1524 if (Frag
.hasInstructions() || Frag
.getKind() != MCFragment::FT_Data
)
1525 report_fatal_error("only data supported in .init_array section");
1527 uint16_t Priority
= UINT16_MAX
;
1528 unsigned PrefixLength
= strlen(".init_array");
1529 if (WS
.getSectionName().size() > PrefixLength
) {
1530 if (WS
.getSectionName()[PrefixLength
] != '.')
1532 ".init_array section priority should start with '.'");
1533 if (WS
.getSectionName()
1534 .substr(PrefixLength
+ 1)
1535 .getAsInteger(10, Priority
))
1536 report_fatal_error("invalid .init_array section priority");
1538 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
1539 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
1540 for (const uint8_t *
1541 P
= (const uint8_t *)Contents
.data(),
1542 *End
= (const uint8_t *)Contents
.data() + Contents
.size();
1545 report_fatal_error("non-symbolic data in .init_array section");
1547 for (const MCFixup
&Fixup
: DataFrag
.getFixups()) {
1548 assert(Fixup
.getKind() ==
1549 MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1550 const MCExpr
*Expr
= Fixup
.getValue();
1551 auto *SymRef
= dyn_cast
<MCSymbolRefExpr
>(Expr
);
1553 report_fatal_error("fixups in .init_array should be symbol references");
1554 const auto &TargetSym
= cast
<const MCSymbolWasm
>(SymRef
->getSymbol());
1555 if (TargetSym
.getIndex() == InvalidIndex
)
1556 report_fatal_error("symbols in .init_array should exist in symbtab");
1557 if (!TargetSym
.isFunction())
1558 report_fatal_error("symbols in .init_array should be for functions");
1559 InitFuncs
.push_back(
1560 std::make_pair(Priority
, TargetSym
.getIndex()));
1564 // Write out the Wasm header.
1567 writeTypeSection(Signatures
);
1568 writeImportSection(Imports
, DataSize
, TableElems
.size());
1569 writeFunctionSection(Functions
);
1570 // Skip the "table" section; we import the table instead.
1571 // Skip the "memory" section; we import the memory instead.
1572 writeEventSection(Events
);
1573 writeExportSection(Exports
);
1574 writeElemSection(TableElems
);
1575 writeDataCountSection();
1576 writeCodeSection(Asm
, Layout
, Functions
);
1578 for (auto &CustomSection
: CustomSections
)
1579 writeCustomSection(CustomSection
, Asm
, Layout
);
1580 writeLinkingMetaDataSection(SymbolInfos
, InitFuncs
, Comdats
);
1581 writeRelocSection(CodeSectionIndex
, "CODE", CodeRelocations
);
1582 writeRelocSection(DataSectionIndex
, "DATA", DataRelocations
);
1583 writeCustomRelocSections();
1584 if (ProducersSection
)
1585 writeCustomSection(*ProducersSection
, Asm
, Layout
);
1586 if (TargetFeaturesSection
)
1587 writeCustomSection(*TargetFeaturesSection
, Asm
, Layout
);
1589 // TODO: Translate the .comment section to the output.
1590 return W
.OS
.tell() - StartOffset
;
1593 std::unique_ptr
<MCObjectWriter
>
1594 llvm::createWasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
1595 raw_pwrite_stream
&OS
) {
1596 return std::make_unique
<WasmObjectWriter
>(std::move(MOTW
), OS
);