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(); }
262 void startSection(SectionBookkeeping
&Section
, unsigned SectionId
);
263 void startCustomSection(SectionBookkeeping
&Section
, StringRef Name
);
264 void endSection(SectionBookkeeping
&Section
);
267 WasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
268 raw_pwrite_stream
&OS
)
269 : W(OS
, support::little
), TargetObjectWriter(std::move(MOTW
)) {}
272 void reset() override
{
273 CodeRelocations
.clear();
274 DataRelocations
.clear();
278 TableIndices
.clear();
279 DataLocations
.clear();
280 CustomSections
.clear();
281 ProducersSection
.reset();
282 TargetFeaturesSection
.reset();
283 CustomSectionsRelocations
.clear();
284 SignatureIndices
.clear();
286 DataSegments
.clear();
287 SectionFunctions
.clear();
288 NumFunctionImports
= 0;
289 NumGlobalImports
= 0;
290 MCObjectWriter::reset();
293 void writeHeader(const MCAssembler
&Asm
);
295 void recordRelocation(MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
296 const MCFragment
*Fragment
, const MCFixup
&Fixup
,
297 MCValue Target
, uint64_t &FixedValue
) override
;
299 void executePostLayoutBinding(MCAssembler
&Asm
,
300 const MCAsmLayout
&Layout
) override
;
302 uint64_t writeObject(MCAssembler
&Asm
, const MCAsmLayout
&Layout
) override
;
304 void writeString(const StringRef Str
) {
305 encodeULEB128(Str
.size(), W
.OS
);
309 void writeValueType(wasm::ValType Ty
) { W
.OS
<< static_cast<char>(Ty
); }
311 void writeTypeSection(ArrayRef
<WasmSignature
> Signatures
);
312 void writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
, uint32_t DataSize
,
313 uint32_t NumElements
);
314 void writeFunctionSection(ArrayRef
<WasmFunction
> Functions
);
315 void writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
);
316 void writeElemSection(ArrayRef
<uint32_t> TableElems
);
317 void writeDataCountSection();
318 void writeCodeSection(const MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
319 ArrayRef
<WasmFunction
> Functions
);
320 void writeDataSection();
321 void writeEventSection(ArrayRef
<wasm::WasmEventType
> Events
);
322 void writeRelocSection(uint32_t SectionIndex
, StringRef Name
,
323 std::vector
<WasmRelocationEntry
> &Relocations
);
324 void writeLinkingMetaDataSection(
325 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
326 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
327 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
);
328 void writeCustomSection(WasmCustomSection
&CustomSection
,
329 const MCAssembler
&Asm
, const MCAsmLayout
&Layout
);
330 void writeCustomRelocSections();
332 updateCustomSectionRelocations(const SmallVector
<WasmFunction
, 4> &Functions
,
333 const MCAsmLayout
&Layout
);
335 uint32_t getProvisionalValue(const WasmRelocationEntry
&RelEntry
);
336 void applyRelocations(ArrayRef
<WasmRelocationEntry
> Relocations
,
337 uint64_t ContentsOffset
);
339 uint32_t getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
);
340 uint32_t getFunctionType(const MCSymbolWasm
&Symbol
);
341 uint32_t getEventType(const MCSymbolWasm
&Symbol
);
342 void registerFunctionType(const MCSymbolWasm
&Symbol
);
343 void registerEventType(const MCSymbolWasm
&Symbol
);
346 } // end anonymous namespace
348 // Write out a section header and a patchable section size field.
349 void WasmObjectWriter::startSection(SectionBookkeeping
&Section
,
350 unsigned SectionId
) {
351 LLVM_DEBUG(dbgs() << "startSection " << SectionId
<< "\n");
352 W
.OS
<< char(SectionId
);
354 Section
.SizeOffset
= W
.OS
.tell();
356 // The section size. We don't know the size yet, so reserve enough space
357 // for any 32-bit value; we'll patch it later.
358 encodeULEB128(0, W
.OS
, 5);
360 // The position where the section starts, for measuring its size.
361 Section
.ContentsOffset
= W
.OS
.tell();
362 Section
.PayloadOffset
= W
.OS
.tell();
363 Section
.Index
= SectionCount
++;
366 void WasmObjectWriter::startCustomSection(SectionBookkeeping
&Section
,
368 LLVM_DEBUG(dbgs() << "startCustomSection " << Name
<< "\n");
369 startSection(Section
, wasm::WASM_SEC_CUSTOM
);
371 // The position where the section header ends, for measuring its size.
372 Section
.PayloadOffset
= W
.OS
.tell();
374 // Custom sections in wasm also have a string identifier.
377 // The position where the custom section starts.
378 Section
.ContentsOffset
= W
.OS
.tell();
381 // Now that the section is complete and we know how big it is, patch up the
382 // section size field at the start of the section.
383 void WasmObjectWriter::endSection(SectionBookkeeping
&Section
) {
384 uint64_t Size
= W
.OS
.tell();
385 // /dev/null doesn't support seek/tell and can report offset of 0.
386 // Simply skip this patching in that case.
390 Size
-= Section
.PayloadOffset
;
391 if (uint32_t(Size
) != Size
)
392 report_fatal_error("section size does not fit in a uint32_t");
394 LLVM_DEBUG(dbgs() << "endSection size=" << Size
<< "\n");
396 // Write the final section size to the payload_len field, which follows
397 // the section id byte.
398 writePatchableLEB(static_cast<raw_pwrite_stream
&>(W
.OS
), Size
,
402 // Emit the Wasm header.
403 void WasmObjectWriter::writeHeader(const MCAssembler
&Asm
) {
404 W
.OS
.write(wasm::WasmMagic
, sizeof(wasm::WasmMagic
));
405 W
.write
<uint32_t>(wasm::WasmVersion
);
408 void WasmObjectWriter::executePostLayoutBinding(MCAssembler
&Asm
,
409 const MCAsmLayout
&Layout
) {
410 // Build a map of sections to the function that defines them, for use
411 // in recordRelocation.
412 for (const MCSymbol
&S
: Asm
.symbols()) {
413 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
414 if (WS
.isDefined() && WS
.isFunction() && !WS
.isVariable()) {
415 const auto &Sec
= static_cast<const MCSectionWasm
&>(S
.getSection());
416 auto Pair
= SectionFunctions
.insert(std::make_pair(&Sec
, &S
));
418 report_fatal_error("section already has a defining function: " +
419 Sec
.getSectionName());
424 void WasmObjectWriter::recordRelocation(MCAssembler
&Asm
,
425 const MCAsmLayout
&Layout
,
426 const MCFragment
*Fragment
,
427 const MCFixup
&Fixup
, MCValue Target
,
428 uint64_t &FixedValue
) {
429 // The WebAssembly backend should never generate FKF_IsPCRel fixups
430 assert(!(Asm
.getBackend().getFixupKindInfo(Fixup
.getKind()).Flags
&
431 MCFixupKindInfo::FKF_IsPCRel
));
433 const auto &FixupSection
= cast
<MCSectionWasm
>(*Fragment
->getParent());
434 uint64_t C
= Target
.getConstant();
435 uint64_t FixupOffset
= Layout
.getFragmentOffset(Fragment
) + Fixup
.getOffset();
436 MCContext
&Ctx
= Asm
.getContext();
438 // The .init_array isn't translated as data, so don't do relocations in it.
439 if (FixupSection
.getSectionName().startswith(".init_array"))
442 if (const MCSymbolRefExpr
*RefB
= Target
.getSymB()) {
443 // To get here the A - B expression must have failed evaluateAsRelocatable.
444 // This means either A or B must be undefined and in WebAssembly we can't
445 // support either of those cases.
446 const auto &SymB
= cast
<MCSymbolWasm
>(RefB
->getSymbol());
449 Twine("symbol '") + SymB
.getName() +
450 "': unsupported subtraction expression used in relocation.");
454 // We either rejected the fixup or folded B into C at this point.
455 const MCSymbolRefExpr
*RefA
= Target
.getSymA();
456 const auto *SymA
= cast
<MCSymbolWasm
>(&RefA
->getSymbol());
458 if (SymA
->isVariable()) {
459 const MCExpr
*Expr
= SymA
->getVariableValue();
460 const auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
461 if (Inner
->getKind() == MCSymbolRefExpr::VK_WEAKREF
)
462 llvm_unreachable("weakref used in reloc not yet implemented");
465 // Put any constant offset in an addend. Offsets can be negative, and
466 // LLVM expects wrapping, in contrast to wasm's immediates which can't
467 // be negative and don't wrap.
470 unsigned Type
= TargetObjectWriter
->getRelocType(Target
, Fixup
);
472 // Absolute offset within a section or a function.
473 // Currently only supported for for metadata sections.
474 // See: test/MC/WebAssembly/blockaddress.ll
475 if (Type
== wasm::R_WASM_FUNCTION_OFFSET_I32
||
476 Type
== wasm::R_WASM_SECTION_OFFSET_I32
) {
477 if (!FixupSection
.getKind().isMetadata())
478 report_fatal_error("relocations for function or section offsets are "
479 "only supported in metadata sections");
481 const MCSymbol
*SectionSymbol
= nullptr;
482 const MCSection
&SecA
= SymA
->getSection();
483 if (SecA
.getKind().isText())
484 SectionSymbol
= SectionFunctions
.find(&SecA
)->second
;
486 SectionSymbol
= SecA
.getBeginSymbol();
488 report_fatal_error("section symbol is required for relocation");
490 C
+= Layout
.getSymbolOffset(*SymA
);
491 SymA
= cast
<MCSymbolWasm
>(SectionSymbol
);
494 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
495 // against a named symbol.
496 if (Type
!= wasm::R_WASM_TYPE_INDEX_LEB
) {
497 if (SymA
->getName().empty())
498 report_fatal_error("relocations against un-named temporaries are not yet "
499 "supported by wasm");
501 SymA
->setUsedInReloc();
504 if (RefA
->getKind() == MCSymbolRefExpr::VK_GOT
)
505 SymA
->setUsedInGOT();
507 WasmRelocationEntry
Rec(FixupOffset
, SymA
, C
, Type
, &FixupSection
);
508 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec
<< "\n");
510 if (FixupSection
.isWasmData()) {
511 DataRelocations
.push_back(Rec
);
512 } else if (FixupSection
.getKind().isText()) {
513 CodeRelocations
.push_back(Rec
);
514 } else if (FixupSection
.getKind().isMetadata()) {
515 CustomSectionsRelocations
[&FixupSection
].push_back(Rec
);
517 llvm_unreachable("unexpected section type");
521 static const MCSymbolWasm
*resolveSymbol(const MCSymbolWasm
&Symbol
) {
522 const MCSymbolWasm
* Ret
= &Symbol
;
523 while (Ret
->isVariable()) {
524 const MCExpr
*Expr
= Ret
->getVariableValue();
525 auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
526 Ret
= cast
<MCSymbolWasm
>(&Inner
->getSymbol());
531 // Compute a value to write into the code at the location covered
532 // by RelEntry. This value isn't used by the static linker; it just serves
533 // to make the object format more readable and more likely to be directly
536 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry
&RelEntry
) {
537 if (RelEntry
.Type
== wasm::R_WASM_GLOBAL_INDEX_LEB
&& !RelEntry
.Symbol
->isGlobal()) {
538 assert(GOTIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in GOT index space");
539 return GOTIndices
[RelEntry
.Symbol
];
542 switch (RelEntry
.Type
) {
543 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
544 case wasm::R_WASM_TABLE_INDEX_SLEB
:
545 case wasm::R_WASM_TABLE_INDEX_I32
: {
546 // Provisional value is table address of the resolved symbol itself
547 const MCSymbolWasm
*Sym
= resolveSymbol(*RelEntry
.Symbol
);
548 assert(Sym
->isFunction());
549 return TableIndices
[Sym
];
551 case wasm::R_WASM_TYPE_INDEX_LEB
:
552 // Provisional value is same as the index
553 return getRelocationIndexValue(RelEntry
);
554 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
555 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
556 case wasm::R_WASM_EVENT_INDEX_LEB
:
557 // Provisional value is function/global/event Wasm index
558 assert(WasmIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in wasm index space");
559 return WasmIndices
[RelEntry
.Symbol
];
560 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
561 case wasm::R_WASM_SECTION_OFFSET_I32
: {
562 const auto &Section
=
563 static_cast<const MCSectionWasm
&>(RelEntry
.Symbol
->getSection());
564 return Section
.getSectionOffset() + RelEntry
.Addend
;
566 case wasm::R_WASM_MEMORY_ADDR_LEB
:
567 case wasm::R_WASM_MEMORY_ADDR_I32
:
568 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
569 case wasm::R_WASM_MEMORY_ADDR_SLEB
: {
570 // Provisional value is address of the global
571 const MCSymbolWasm
*Sym
= resolveSymbol(*RelEntry
.Symbol
);
572 // For undefined symbols, use zero
573 if (!Sym
->isDefined())
575 const wasm::WasmDataReference
&Ref
= DataLocations
[Sym
];
576 const WasmDataSegment
&Segment
= DataSegments
[Ref
.Segment
];
577 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
578 return Segment
.Offset
+ Ref
.Offset
+ RelEntry
.Addend
;
581 llvm_unreachable("invalid relocation type");
585 static void addData(SmallVectorImpl
<char> &DataBytes
,
586 MCSectionWasm
&DataSection
) {
587 LLVM_DEBUG(errs() << "addData: " << DataSection
.getSectionName() << "\n");
589 DataBytes
.resize(alignTo(DataBytes
.size(), DataSection
.getAlignment()));
591 for (const MCFragment
&Frag
: DataSection
) {
592 if (Frag
.hasInstructions())
593 report_fatal_error("only data supported in data sections");
595 if (auto *Align
= dyn_cast
<MCAlignFragment
>(&Frag
)) {
596 if (Align
->getValueSize() != 1)
597 report_fatal_error("only byte values supported for alignment");
598 // If nops are requested, use zeros, as this is the data section.
599 uint8_t Value
= Align
->hasEmitNops() ? 0 : Align
->getValue();
601 std::min
<uint64_t>(alignTo(DataBytes
.size(), Align
->getAlignment()),
602 DataBytes
.size() + Align
->getMaxBytesToEmit());
603 DataBytes
.resize(Size
, Value
);
604 } else if (auto *Fill
= dyn_cast
<MCFillFragment
>(&Frag
)) {
606 if (!Fill
->getNumValues().evaluateAsAbsolute(NumValues
))
607 llvm_unreachable("The fill should be an assembler constant");
608 DataBytes
.insert(DataBytes
.end(), Fill
->getValueSize() * NumValues
,
610 } else if (auto *LEB
= dyn_cast
<MCLEBFragment
>(&Frag
)) {
611 const SmallVectorImpl
<char> &Contents
= LEB
->getContents();
612 DataBytes
.insert(DataBytes
.end(), Contents
.begin(), Contents
.end());
614 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
615 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
616 DataBytes
.insert(DataBytes
.end(), Contents
.begin(), Contents
.end());
620 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes
.size() << "\n");
624 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
) {
625 if (RelEntry
.Type
== wasm::R_WASM_TYPE_INDEX_LEB
) {
626 if (!TypeIndices
.count(RelEntry
.Symbol
))
627 report_fatal_error("symbol not found in type index space: " +
628 RelEntry
.Symbol
->getName());
629 return TypeIndices
[RelEntry
.Symbol
];
632 return RelEntry
.Symbol
->getIndex();
635 // Apply the portions of the relocation records that we can handle ourselves
637 void WasmObjectWriter::applyRelocations(
638 ArrayRef
<WasmRelocationEntry
> Relocations
, uint64_t ContentsOffset
) {
639 auto &Stream
= static_cast<raw_pwrite_stream
&>(W
.OS
);
640 for (const WasmRelocationEntry
&RelEntry
: Relocations
) {
641 uint64_t Offset
= ContentsOffset
+
642 RelEntry
.FixupSection
->getSectionOffset() +
645 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry
<< "\n");
646 uint32_t Value
= getProvisionalValue(RelEntry
);
648 switch (RelEntry
.Type
) {
649 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
650 case wasm::R_WASM_TYPE_INDEX_LEB
:
651 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
652 case wasm::R_WASM_MEMORY_ADDR_LEB
:
653 case wasm::R_WASM_EVENT_INDEX_LEB
:
654 writePatchableLEB(Stream
, Value
, Offset
);
656 case wasm::R_WASM_TABLE_INDEX_I32
:
657 case wasm::R_WASM_MEMORY_ADDR_I32
:
658 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
659 case wasm::R_WASM_SECTION_OFFSET_I32
:
660 writeI32(Stream
, Value
, Offset
);
662 case wasm::R_WASM_TABLE_INDEX_SLEB
:
663 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
664 case wasm::R_WASM_MEMORY_ADDR_SLEB
:
665 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
666 writePatchableSLEB(Stream
, Value
, Offset
);
669 llvm_unreachable("invalid relocation type");
674 void WasmObjectWriter::writeTypeSection(ArrayRef
<WasmSignature
> Signatures
) {
675 if (Signatures
.empty())
678 SectionBookkeeping Section
;
679 startSection(Section
, wasm::WASM_SEC_TYPE
);
681 encodeULEB128(Signatures
.size(), W
.OS
);
683 for (const WasmSignature
&Sig
: Signatures
) {
684 W
.OS
<< char(wasm::WASM_TYPE_FUNC
);
685 encodeULEB128(Sig
.Params
.size(), W
.OS
);
686 for (wasm::ValType Ty
: Sig
.Params
)
688 encodeULEB128(Sig
.Returns
.size(), W
.OS
);
689 for (wasm::ValType Ty
: Sig
.Returns
)
696 void WasmObjectWriter::writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
,
698 uint32_t NumElements
) {
702 uint32_t NumPages
= (DataSize
+ wasm::WasmPageSize
- 1) / wasm::WasmPageSize
;
704 SectionBookkeeping Section
;
705 startSection(Section
, wasm::WASM_SEC_IMPORT
);
707 encodeULEB128(Imports
.size(), W
.OS
);
708 for (const wasm::WasmImport
&Import
: Imports
) {
709 writeString(Import
.Module
);
710 writeString(Import
.Field
);
711 W
.OS
<< char(Import
.Kind
);
713 switch (Import
.Kind
) {
714 case wasm::WASM_EXTERNAL_FUNCTION
:
715 encodeULEB128(Import
.SigIndex
, W
.OS
);
717 case wasm::WASM_EXTERNAL_GLOBAL
:
718 W
.OS
<< char(Import
.Global
.Type
);
719 W
.OS
<< char(Import
.Global
.Mutable
? 1 : 0);
721 case wasm::WASM_EXTERNAL_MEMORY
:
722 encodeULEB128(0, W
.OS
); // flags
723 encodeULEB128(NumPages
, W
.OS
); // initial
725 case wasm::WASM_EXTERNAL_TABLE
:
726 W
.OS
<< char(Import
.Table
.ElemType
);
727 encodeULEB128(0, W
.OS
); // flags
728 encodeULEB128(NumElements
, W
.OS
); // initial
730 case wasm::WASM_EXTERNAL_EVENT
:
731 encodeULEB128(Import
.Event
.Attribute
, W
.OS
);
732 encodeULEB128(Import
.Event
.SigIndex
, W
.OS
);
735 llvm_unreachable("unsupported import kind");
742 void WasmObjectWriter::writeFunctionSection(ArrayRef
<WasmFunction
> Functions
) {
743 if (Functions
.empty())
746 SectionBookkeeping Section
;
747 startSection(Section
, wasm::WASM_SEC_FUNCTION
);
749 encodeULEB128(Functions
.size(), W
.OS
);
750 for (const WasmFunction
&Func
: Functions
)
751 encodeULEB128(Func
.SigIndex
, W
.OS
);
756 void WasmObjectWriter::writeEventSection(ArrayRef
<wasm::WasmEventType
> Events
) {
760 SectionBookkeeping Section
;
761 startSection(Section
, wasm::WASM_SEC_EVENT
);
763 encodeULEB128(Events
.size(), W
.OS
);
764 for (const wasm::WasmEventType
&Event
: Events
) {
765 encodeULEB128(Event
.Attribute
, W
.OS
);
766 encodeULEB128(Event
.SigIndex
, W
.OS
);
772 void WasmObjectWriter::writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
) {
776 SectionBookkeeping Section
;
777 startSection(Section
, wasm::WASM_SEC_EXPORT
);
779 encodeULEB128(Exports
.size(), W
.OS
);
780 for (const wasm::WasmExport
&Export
: Exports
) {
781 writeString(Export
.Name
);
782 W
.OS
<< char(Export
.Kind
);
783 encodeULEB128(Export
.Index
, W
.OS
);
789 void WasmObjectWriter::writeElemSection(ArrayRef
<uint32_t> TableElems
) {
790 if (TableElems
.empty())
793 SectionBookkeeping Section
;
794 startSection(Section
, wasm::WASM_SEC_ELEM
);
796 encodeULEB128(1, W
.OS
); // number of "segments"
797 encodeULEB128(0, W
.OS
); // the table index
799 // init expr for starting offset
800 W
.OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
801 encodeSLEB128(InitialTableOffset
, W
.OS
);
802 W
.OS
<< char(wasm::WASM_OPCODE_END
);
804 encodeULEB128(TableElems
.size(), W
.OS
);
805 for (uint32_t Elem
: TableElems
)
806 encodeULEB128(Elem
, W
.OS
);
811 void WasmObjectWriter::writeDataCountSection() {
812 if (DataSegments
.empty())
815 SectionBookkeeping Section
;
816 startSection(Section
, wasm::WASM_SEC_DATACOUNT
);
817 encodeULEB128(DataSegments
.size(), W
.OS
);
821 void WasmObjectWriter::writeCodeSection(const MCAssembler
&Asm
,
822 const MCAsmLayout
&Layout
,
823 ArrayRef
<WasmFunction
> Functions
) {
824 if (Functions
.empty())
827 SectionBookkeeping Section
;
828 startSection(Section
, wasm::WASM_SEC_CODE
);
829 CodeSectionIndex
= Section
.Index
;
831 encodeULEB128(Functions
.size(), W
.OS
);
833 for (const WasmFunction
&Func
: Functions
) {
834 auto &FuncSection
= static_cast<MCSectionWasm
&>(Func
.Sym
->getSection());
837 if (!Func
.Sym
->getSize()->evaluateAsAbsolute(Size
, Layout
))
838 report_fatal_error(".size expression must be evaluatable");
840 encodeULEB128(Size
, W
.OS
);
841 FuncSection
.setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
842 Asm
.writeSectionData(W
.OS
, &FuncSection
, Layout
);
846 applyRelocations(CodeRelocations
, Section
.ContentsOffset
);
851 void WasmObjectWriter::writeDataSection() {
852 if (DataSegments
.empty())
855 SectionBookkeeping Section
;
856 startSection(Section
, wasm::WASM_SEC_DATA
);
857 DataSectionIndex
= Section
.Index
;
859 encodeULEB128(DataSegments
.size(), W
.OS
); // count
861 for (const WasmDataSegment
&Segment
: DataSegments
) {
862 encodeULEB128(Segment
.InitFlags
, W
.OS
); // flags
863 if (Segment
.InitFlags
& wasm::WASM_SEGMENT_HAS_MEMINDEX
)
864 encodeULEB128(0, W
.OS
); // memory index
865 if ((Segment
.InitFlags
& wasm::WASM_SEGMENT_IS_PASSIVE
) == 0) {
866 W
.OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
867 encodeSLEB128(Segment
.Offset
, W
.OS
); // offset
868 W
.OS
<< char(wasm::WASM_OPCODE_END
);
870 encodeULEB128(Segment
.Data
.size(), W
.OS
); // size
871 Segment
.Section
->setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
872 W
.OS
<< Segment
.Data
; // data
876 applyRelocations(DataRelocations
, Section
.ContentsOffset
);
881 void WasmObjectWriter::writeRelocSection(
882 uint32_t SectionIndex
, StringRef Name
,
883 std::vector
<WasmRelocationEntry
> &Relocs
) {
884 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
885 // for descriptions of the reloc sections.
890 // First, ensure the relocations are sorted in offset order. In general they
891 // should already be sorted since `recordRelocation` is called in offset
892 // order, but for the code section we combine many MC sections into single
893 // wasm section, and this order is determined by the order of Asm.Symbols()
894 // not the sections order.
896 Relocs
, [](const WasmRelocationEntry
&A
, const WasmRelocationEntry
&B
) {
897 return (A
.Offset
+ A
.FixupSection
->getSectionOffset()) <
898 (B
.Offset
+ B
.FixupSection
->getSectionOffset());
901 SectionBookkeeping Section
;
902 startCustomSection(Section
, std::string("reloc.") + Name
.str());
904 encodeULEB128(SectionIndex
, W
.OS
);
905 encodeULEB128(Relocs
.size(), W
.OS
);
906 for (const WasmRelocationEntry
&RelEntry
: Relocs
) {
908 RelEntry
.Offset
+ RelEntry
.FixupSection
->getSectionOffset();
909 uint32_t Index
= getRelocationIndexValue(RelEntry
);
911 W
.OS
<< char(RelEntry
.Type
);
912 encodeULEB128(Offset
, W
.OS
);
913 encodeULEB128(Index
, W
.OS
);
914 if (RelEntry
.hasAddend())
915 encodeSLEB128(RelEntry
.Addend
, W
.OS
);
921 void WasmObjectWriter::writeCustomRelocSections() {
922 for (const auto &Sec
: CustomSections
) {
923 auto &Relocations
= CustomSectionsRelocations
[Sec
.Section
];
924 writeRelocSection(Sec
.OutputIndex
, Sec
.Name
, Relocations
);
928 void WasmObjectWriter::writeLinkingMetaDataSection(
929 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
930 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
931 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
) {
932 SectionBookkeeping Section
;
933 startCustomSection(Section
, "linking");
934 encodeULEB128(wasm::WasmMetadataVersion
, W
.OS
);
936 SectionBookkeeping SubSection
;
937 if (SymbolInfos
.size() != 0) {
938 startSection(SubSection
, wasm::WASM_SYMBOL_TABLE
);
939 encodeULEB128(SymbolInfos
.size(), W
.OS
);
940 for (const wasm::WasmSymbolInfo
&Sym
: SymbolInfos
) {
941 encodeULEB128(Sym
.Kind
, W
.OS
);
942 encodeULEB128(Sym
.Flags
, W
.OS
);
944 case wasm::WASM_SYMBOL_TYPE_FUNCTION
:
945 case wasm::WASM_SYMBOL_TYPE_GLOBAL
:
946 case wasm::WASM_SYMBOL_TYPE_EVENT
:
947 encodeULEB128(Sym
.ElementIndex
, W
.OS
);
948 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0 ||
949 (Sym
.Flags
& wasm::WASM_SYMBOL_EXPLICIT_NAME
) != 0)
950 writeString(Sym
.Name
);
952 case wasm::WASM_SYMBOL_TYPE_DATA
:
953 writeString(Sym
.Name
);
954 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0) {
955 encodeULEB128(Sym
.DataRef
.Segment
, W
.OS
);
956 encodeULEB128(Sym
.DataRef
.Offset
, W
.OS
);
957 encodeULEB128(Sym
.DataRef
.Size
, W
.OS
);
960 case wasm::WASM_SYMBOL_TYPE_SECTION
: {
961 const uint32_t SectionIndex
=
962 CustomSections
[Sym
.ElementIndex
].OutputIndex
;
963 encodeULEB128(SectionIndex
, W
.OS
);
967 llvm_unreachable("unexpected kind");
970 endSection(SubSection
);
973 if (DataSegments
.size()) {
974 startSection(SubSection
, wasm::WASM_SEGMENT_INFO
);
975 encodeULEB128(DataSegments
.size(), W
.OS
);
976 for (const WasmDataSegment
&Segment
: DataSegments
) {
977 writeString(Segment
.Name
);
978 encodeULEB128(Segment
.Alignment
, W
.OS
);
979 encodeULEB128(Segment
.LinkerFlags
, W
.OS
);
981 endSection(SubSection
);
984 if (!InitFuncs
.empty()) {
985 startSection(SubSection
, wasm::WASM_INIT_FUNCS
);
986 encodeULEB128(InitFuncs
.size(), W
.OS
);
987 for (auto &StartFunc
: InitFuncs
) {
988 encodeULEB128(StartFunc
.first
, W
.OS
); // priority
989 encodeULEB128(StartFunc
.second
, W
.OS
); // function index
991 endSection(SubSection
);
994 if (Comdats
.size()) {
995 startSection(SubSection
, wasm::WASM_COMDAT_INFO
);
996 encodeULEB128(Comdats
.size(), W
.OS
);
997 for (const auto &C
: Comdats
) {
998 writeString(C
.first
);
999 encodeULEB128(0, W
.OS
); // flags for future use
1000 encodeULEB128(C
.second
.size(), W
.OS
);
1001 for (const WasmComdatEntry
&Entry
: C
.second
) {
1002 encodeULEB128(Entry
.Kind
, W
.OS
);
1003 encodeULEB128(Entry
.Index
, W
.OS
);
1006 endSection(SubSection
);
1009 endSection(Section
);
1012 void WasmObjectWriter::writeCustomSection(WasmCustomSection
&CustomSection
,
1013 const MCAssembler
&Asm
,
1014 const MCAsmLayout
&Layout
) {
1015 SectionBookkeeping Section
;
1016 auto *Sec
= CustomSection
.Section
;
1017 startCustomSection(Section
, CustomSection
.Name
);
1019 Sec
->setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
1020 Asm
.writeSectionData(W
.OS
, Sec
, Layout
);
1022 CustomSection
.OutputContentsOffset
= Section
.ContentsOffset
;
1023 CustomSection
.OutputIndex
= Section
.Index
;
1025 endSection(Section
);
1028 auto &Relocations
= CustomSectionsRelocations
[CustomSection
.Section
];
1029 applyRelocations(Relocations
, CustomSection
.OutputContentsOffset
);
1032 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm
&Symbol
) {
1033 assert(Symbol
.isFunction());
1034 assert(TypeIndices
.count(&Symbol
));
1035 return TypeIndices
[&Symbol
];
1038 uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm
&Symbol
) {
1039 assert(Symbol
.isEvent());
1040 assert(TypeIndices
.count(&Symbol
));
1041 return TypeIndices
[&Symbol
];
1044 void WasmObjectWriter::registerFunctionType(const MCSymbolWasm
&Symbol
) {
1045 assert(Symbol
.isFunction());
1048 const MCSymbolWasm
*ResolvedSym
= resolveSymbol(Symbol
);
1049 if (auto *Sig
= ResolvedSym
->getSignature()) {
1050 S
.Returns
= Sig
->Returns
;
1051 S
.Params
= Sig
->Params
;
1054 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1056 Signatures
.push_back(S
);
1057 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1059 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
1060 << " new:" << Pair
.second
<< "\n");
1061 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1064 void WasmObjectWriter::registerEventType(const MCSymbolWasm
&Symbol
) {
1065 assert(Symbol
.isEvent());
1067 // TODO Currently we don't generate imported exceptions, but if we do, we
1068 // should have a way of infering types of imported exceptions.
1070 if (auto *Sig
= Symbol
.getSignature()) {
1071 S
.Returns
= Sig
->Returns
;
1072 S
.Params
= Sig
->Params
;
1075 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1077 Signatures
.push_back(S
);
1078 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1080 LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol
<< " new:" << Pair
.second
1082 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1085 static bool isInSymtab(const MCSymbolWasm
&Sym
) {
1086 if (Sym
.isUsedInReloc())
1089 if (Sym
.isComdat() && !Sym
.isDefined())
1092 if (Sym
.isTemporary() && Sym
.getName().empty())
1095 if (Sym
.isTemporary() && Sym
.isData() && !Sym
.getSize())
1098 if (Sym
.isSection())
1104 uint64_t WasmObjectWriter::writeObject(MCAssembler
&Asm
,
1105 const MCAsmLayout
&Layout
) {
1106 uint64_t StartOffset
= W
.OS
.tell();
1108 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
1110 // Collect information from the available symbols.
1111 SmallVector
<WasmFunction
, 4> Functions
;
1112 SmallVector
<uint32_t, 4> TableElems
;
1113 SmallVector
<wasm::WasmImport
, 4> Imports
;
1114 SmallVector
<wasm::WasmExport
, 4> Exports
;
1115 SmallVector
<wasm::WasmEventType
, 1> Events
;
1116 SmallVector
<wasm::WasmSymbolInfo
, 4> SymbolInfos
;
1117 SmallVector
<std::pair
<uint16_t, uint32_t>, 2> InitFuncs
;
1118 std::map
<StringRef
, std::vector
<WasmComdatEntry
>> Comdats
;
1119 uint32_t DataSize
= 0;
1121 // For now, always emit the memory import, since loads and stores are not
1122 // valid without it. In the future, we could perhaps be more clever and omit
1123 // it if there are no loads or stores.
1124 wasm::WasmImport MemImport
;
1125 MemImport
.Module
= "env";
1126 MemImport
.Field
= "__linear_memory";
1127 MemImport
.Kind
= wasm::WASM_EXTERNAL_MEMORY
;
1128 Imports
.push_back(MemImport
);
1130 // For now, always emit the table section, since indirect calls are not
1131 // valid without it. In the future, we could perhaps be more clever and omit
1132 // it if there are no indirect calls.
1133 wasm::WasmImport TableImport
;
1134 TableImport
.Module
= "env";
1135 TableImport
.Field
= "__indirect_function_table";
1136 TableImport
.Kind
= wasm::WASM_EXTERNAL_TABLE
;
1137 TableImport
.Table
.ElemType
= wasm::WASM_TYPE_FUNCREF
;
1138 Imports
.push_back(TableImport
);
1140 // Populate SignatureIndices, and Imports and WasmIndices for undefined
1141 // symbols. This must be done before populating WasmIndices for defined
1143 for (const MCSymbol
&S
: Asm
.symbols()) {
1144 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1146 // Register types for all functions, including those with private linkage
1147 // (because wasm always needs a type signature).
1148 if (WS
.isFunction())
1149 registerFunctionType(WS
);
1152 registerEventType(WS
);
1154 if (WS
.isTemporary())
1157 // If the symbol is not defined in this translation unit, import it.
1158 if (!WS
.isDefined() && !WS
.isComdat()) {
1159 if (WS
.isFunction()) {
1160 wasm::WasmImport Import
;
1161 Import
.Module
= WS
.getImportModule();
1162 Import
.Field
= WS
.getImportName();
1163 Import
.Kind
= wasm::WASM_EXTERNAL_FUNCTION
;
1164 Import
.SigIndex
= getFunctionType(WS
);
1165 Imports
.push_back(Import
);
1166 assert(WasmIndices
.count(&WS
) == 0);
1167 WasmIndices
[&WS
] = NumFunctionImports
++;
1168 } else if (WS
.isGlobal()) {
1170 report_fatal_error("undefined global symbol cannot be weak");
1172 wasm::WasmImport Import
;
1173 Import
.Field
= WS
.getImportName();
1174 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1175 Import
.Module
= WS
.getImportModule();
1176 Import
.Global
= WS
.getGlobalType();
1177 Imports
.push_back(Import
);
1178 assert(WasmIndices
.count(&WS
) == 0);
1179 WasmIndices
[&WS
] = NumGlobalImports
++;
1180 } else if (WS
.isEvent()) {
1182 report_fatal_error("undefined event symbol cannot be weak");
1184 wasm::WasmImport Import
;
1185 Import
.Module
= WS
.getImportModule();
1186 Import
.Field
= WS
.getImportName();
1187 Import
.Kind
= wasm::WASM_EXTERNAL_EVENT
;
1188 Import
.Event
.Attribute
= wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION
;
1189 Import
.Event
.SigIndex
= getEventType(WS
);
1190 Imports
.push_back(Import
);
1191 assert(WasmIndices
.count(&WS
) == 0);
1192 WasmIndices
[&WS
] = NumEventImports
++;
1197 // Add imports for GOT globals
1198 for (const MCSymbol
&S
: Asm
.symbols()) {
1199 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1200 if (WS
.isUsedInGOT()) {
1201 wasm::WasmImport Import
;
1202 if (WS
.isFunction())
1203 Import
.Module
= "GOT.func";
1205 Import
.Module
= "GOT.mem";
1206 Import
.Field
= WS
.getName();
1207 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1208 Import
.Global
= {wasm::WASM_TYPE_I32
, true};
1209 Imports
.push_back(Import
);
1210 assert(GOTIndices
.count(&WS
) == 0);
1211 GOTIndices
[&WS
] = NumGlobalImports
++;
1215 // Populate DataSegments and CustomSections, which must be done before
1216 // populating DataLocations.
1217 for (MCSection
&Sec
: Asm
) {
1218 auto &Section
= static_cast<MCSectionWasm
&>(Sec
);
1219 StringRef SectionName
= Section
.getSectionName();
1221 // .init_array sections are handled specially elsewhere.
1222 if (SectionName
.startswith(".init_array"))
1225 // Code is handled separately
1226 if (Section
.getKind().isText())
1229 if (Section
.isWasmData()) {
1230 uint32_t SegmentIndex
= DataSegments
.size();
1231 DataSize
= alignTo(DataSize
, Section
.getAlignment());
1232 DataSegments
.emplace_back();
1233 WasmDataSegment
&Segment
= DataSegments
.back();
1234 Segment
.Name
= SectionName
;
1236 Section
.getPassive() ? (uint32_t)wasm::WASM_SEGMENT_IS_PASSIVE
: 0;
1237 Segment
.Offset
= DataSize
;
1238 Segment
.Section
= &Section
;
1239 addData(Segment
.Data
, Section
);
1240 Segment
.Alignment
= Log2_32(Section
.getAlignment());
1241 Segment
.LinkerFlags
= 0;
1242 DataSize
+= Segment
.Data
.size();
1243 Section
.setSegmentIndex(SegmentIndex
);
1245 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1246 Comdats
[C
->getName()].emplace_back(
1247 WasmComdatEntry
{wasm::WASM_COMDAT_DATA
, SegmentIndex
});
1250 // Create custom sections
1251 assert(Sec
.getKind().isMetadata());
1253 StringRef Name
= SectionName
;
1255 // For user-defined custom sections, strip the prefix
1256 if (Name
.startswith(".custom_section."))
1257 Name
= Name
.substr(strlen(".custom_section."));
1259 MCSymbol
*Begin
= Sec
.getBeginSymbol();
1261 WasmIndices
[cast
<MCSymbolWasm
>(Begin
)] = CustomSections
.size();
1262 if (SectionName
!= Begin
->getName())
1263 report_fatal_error("section name and begin symbol should match: " +
1264 Twine(SectionName
));
1267 // Separate out the producers and target features sections
1268 if (Name
== "producers") {
1269 ProducersSection
= std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1272 if (Name
== "target_features") {
1273 TargetFeaturesSection
=
1274 std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1278 CustomSections
.emplace_back(Name
, &Section
);
1282 // Populate WasmIndices and DataLocations for defined symbols.
1283 for (const MCSymbol
&S
: Asm
.symbols()) {
1284 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1285 // or used in relocations.
1286 if (S
.isTemporary() && S
.getName().empty())
1289 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1291 dbgs() << "MCSymbol: " << toString(WS
.getType()) << " '" << S
<< "'"
1292 << " isDefined=" << S
.isDefined() << " isExternal="
1293 << S
.isExternal() << " isTemporary=" << S
.isTemporary()
1294 << " isWeak=" << WS
.isWeak() << " isHidden=" << WS
.isHidden()
1295 << " isVariable=" << WS
.isVariable() << "\n");
1297 if (WS
.isVariable())
1299 if (WS
.isComdat() && !WS
.isDefined())
1302 if (WS
.isFunction()) {
1304 if (WS
.isDefined()) {
1305 if (WS
.getOffset() != 0)
1307 "function sections must contain one function each");
1309 if (WS
.getSize() == nullptr)
1311 "function symbols must have a size set with .size");
1313 // A definition. Write out the function body.
1314 Index
= NumFunctionImports
+ Functions
.size();
1316 Func
.SigIndex
= getFunctionType(WS
);
1318 WasmIndices
[&WS
] = Index
;
1319 Functions
.push_back(Func
);
1321 auto &Section
= static_cast<MCSectionWasm
&>(WS
.getSection());
1322 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1323 Comdats
[C
->getName()].emplace_back(
1324 WasmComdatEntry
{wasm::WASM_COMDAT_FUNCTION
, Index
});
1327 // An import; the index was assigned above.
1328 Index
= WasmIndices
.find(&WS
)->second
;
1331 LLVM_DEBUG(dbgs() << " -> function index: " << Index
<< "\n");
1333 } else if (WS
.isData()) {
1334 if (!isInSymtab(WS
))
1337 if (!WS
.isDefined()) {
1338 LLVM_DEBUG(dbgs() << " -> segment index: -1"
1344 report_fatal_error("data symbols must have a size set with .size: " +
1348 if (!WS
.getSize()->evaluateAsAbsolute(Size
, Layout
))
1349 report_fatal_error(".size expression must be evaluatable");
1351 auto &DataSection
= static_cast<MCSectionWasm
&>(WS
.getSection());
1352 assert(DataSection
.isWasmData());
1354 // For each data symbol, export it in the symtab as a reference to the
1355 // corresponding Wasm data segment.
1356 wasm::WasmDataReference Ref
= wasm::WasmDataReference
{
1357 DataSection
.getSegmentIndex(),
1358 static_cast<uint32_t>(Layout
.getSymbolOffset(WS
)),
1359 static_cast<uint32_t>(Size
)};
1360 DataLocations
[&WS
] = Ref
;
1361 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref
.Segment
<< "\n");
1363 } else if (WS
.isGlobal()) {
1364 // A "true" Wasm global (currently just __stack_pointer)
1366 report_fatal_error("don't yet support defined globals");
1368 // An import; the index was assigned above
1369 LLVM_DEBUG(dbgs() << " -> global index: "
1370 << WasmIndices
.find(&WS
)->second
<< "\n");
1372 } else if (WS
.isEvent()) {
1373 // C++ exception symbol (__cpp_exception)
1375 if (WS
.isDefined()) {
1376 Index
= NumEventImports
+ Events
.size();
1377 wasm::WasmEventType Event
;
1378 Event
.SigIndex
= getEventType(WS
);
1379 Event
.Attribute
= wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION
;
1380 assert(WasmIndices
.count(&WS
) == 0);
1381 WasmIndices
[&WS
] = Index
;
1382 Events
.push_back(Event
);
1384 // An import; the index was assigned above.
1385 assert(WasmIndices
.count(&WS
) > 0);
1387 LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices
.find(&WS
)->second
1391 assert(WS
.isSection());
1395 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1396 // process these in a separate pass because we need to have processed the
1397 // target of the alias before the alias itself and the symbols are not
1398 // necessarily ordered in this way.
1399 for (const MCSymbol
&S
: Asm
.symbols()) {
1400 if (!S
.isVariable())
1403 assert(S
.isDefined());
1405 // Find the target symbol of this weak alias and export that index
1406 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1407 const MCSymbolWasm
*ResolvedSym
= resolveSymbol(WS
);
1408 LLVM_DEBUG(dbgs() << WS
.getName() << ": weak alias of '" << *ResolvedSym
1411 if (ResolvedSym
->isFunction()) {
1412 assert(WasmIndices
.count(ResolvedSym
) > 0);
1413 uint32_t WasmIndex
= WasmIndices
.find(ResolvedSym
)->second
;
1414 assert(WasmIndices
.count(&WS
) == 0);
1415 WasmIndices
[&WS
] = WasmIndex
;
1416 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex
<< "\n");
1417 } else if (ResolvedSym
->isData()) {
1418 assert(DataLocations
.count(ResolvedSym
) > 0);
1419 const wasm::WasmDataReference
&Ref
=
1420 DataLocations
.find(ResolvedSym
)->second
;
1421 DataLocations
[&WS
] = Ref
;
1422 LLVM_DEBUG(dbgs() << " -> index:" << Ref
.Segment
<< "\n");
1424 report_fatal_error("don't yet support global/event aliases");
1428 // Finally, populate the symbol table itself, in its "natural" order.
1429 for (const MCSymbol
&S
: Asm
.symbols()) {
1430 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1431 if (!isInSymtab(WS
)) {
1432 WS
.setIndex(InvalidIndex
);
1435 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS
<< "\n");
1439 Flags
|= wasm::WASM_SYMBOL_BINDING_WEAK
;
1441 Flags
|= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN
;
1442 if (!WS
.isExternal() && WS
.isDefined())
1443 Flags
|= wasm::WASM_SYMBOL_BINDING_LOCAL
;
1444 if (WS
.isUndefined())
1445 Flags
|= wasm::WASM_SYMBOL_UNDEFINED
;
1446 if (WS
.isExported())
1447 Flags
|= wasm::WASM_SYMBOL_EXPORTED
;
1448 if (WS
.getName() != WS
.getImportName())
1449 Flags
|= wasm::WASM_SYMBOL_EXPLICIT_NAME
;
1451 wasm::WasmSymbolInfo Info
;
1452 Info
.Name
= WS
.getName();
1453 Info
.Kind
= WS
.getType();
1456 assert(WasmIndices
.count(&WS
) > 0);
1457 Info
.ElementIndex
= WasmIndices
.find(&WS
)->second
;
1458 } else if (WS
.isDefined()) {
1459 assert(DataLocations
.count(&WS
) > 0);
1460 Info
.DataRef
= DataLocations
.find(&WS
)->second
;
1462 WS
.setIndex(SymbolInfos
.size());
1463 SymbolInfos
.emplace_back(Info
);
1467 auto HandleReloc
= [&](const WasmRelocationEntry
&Rel
) {
1468 // Functions referenced by a relocation need to put in the table. This is
1469 // purely to make the object file's provisional values readable, and is
1470 // ignored by the linker, which re-calculates the relocations itself.
1471 if (Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_I32
&&
1472 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_SLEB
)
1474 assert(Rel
.Symbol
->isFunction());
1475 const MCSymbolWasm
&WS
= *resolveSymbol(*Rel
.Symbol
);
1476 uint32_t FunctionIndex
= WasmIndices
.find(&WS
)->second
;
1477 uint32_t TableIndex
= TableElems
.size() + InitialTableOffset
;
1478 if (TableIndices
.try_emplace(&WS
, TableIndex
).second
) {
1479 LLVM_DEBUG(dbgs() << " -> adding " << WS
.getName()
1480 << " to table: " << TableIndex
<< "\n");
1481 TableElems
.push_back(FunctionIndex
);
1482 registerFunctionType(WS
);
1486 for (const WasmRelocationEntry
&RelEntry
: CodeRelocations
)
1487 HandleReloc(RelEntry
);
1488 for (const WasmRelocationEntry
&RelEntry
: DataRelocations
)
1489 HandleReloc(RelEntry
);
1492 // Translate .init_array section contents into start functions.
1493 for (const MCSection
&S
: Asm
) {
1494 const auto &WS
= static_cast<const MCSectionWasm
&>(S
);
1495 if (WS
.getSectionName().startswith(".fini_array"))
1496 report_fatal_error(".fini_array sections are unsupported");
1497 if (!WS
.getSectionName().startswith(".init_array"))
1499 if (WS
.getFragmentList().empty())
1502 // init_array is expected to contain a single non-empty data fragment
1503 if (WS
.getFragmentList().size() != 3)
1504 report_fatal_error("only one .init_array section fragment supported");
1506 auto IT
= WS
.begin();
1507 const MCFragment
&EmptyFrag
= *IT
;
1508 if (EmptyFrag
.getKind() != MCFragment::FT_Data
)
1509 report_fatal_error(".init_array section should be aligned");
1512 const MCFragment
&AlignFrag
= *IT
;
1513 if (AlignFrag
.getKind() != MCFragment::FT_Align
)
1514 report_fatal_error(".init_array section should be aligned");
1515 if (cast
<MCAlignFragment
>(AlignFrag
).getAlignment() != (is64Bit() ? 8 : 4))
1516 report_fatal_error(".init_array section should be aligned for pointers");
1518 const MCFragment
&Frag
= *std::next(IT
);
1519 if (Frag
.hasInstructions() || Frag
.getKind() != MCFragment::FT_Data
)
1520 report_fatal_error("only data supported in .init_array section");
1522 uint16_t Priority
= UINT16_MAX
;
1523 unsigned PrefixLength
= strlen(".init_array");
1524 if (WS
.getSectionName().size() > PrefixLength
) {
1525 if (WS
.getSectionName()[PrefixLength
] != '.')
1527 ".init_array section priority should start with '.'");
1528 if (WS
.getSectionName()
1529 .substr(PrefixLength
+ 1)
1530 .getAsInteger(10, Priority
))
1531 report_fatal_error("invalid .init_array section priority");
1533 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
1534 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
1535 for (const uint8_t *
1536 P
= (const uint8_t *)Contents
.data(),
1537 *End
= (const uint8_t *)Contents
.data() + Contents
.size();
1540 report_fatal_error("non-symbolic data in .init_array section");
1542 for (const MCFixup
&Fixup
: DataFrag
.getFixups()) {
1543 assert(Fixup
.getKind() ==
1544 MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1545 const MCExpr
*Expr
= Fixup
.getValue();
1546 auto *SymRef
= dyn_cast
<MCSymbolRefExpr
>(Expr
);
1548 report_fatal_error("fixups in .init_array should be symbol references");
1549 const auto &TargetSym
= cast
<const MCSymbolWasm
>(SymRef
->getSymbol());
1550 if (TargetSym
.getIndex() == InvalidIndex
)
1551 report_fatal_error("symbols in .init_array should exist in symbtab");
1552 if (!TargetSym
.isFunction())
1553 report_fatal_error("symbols in .init_array should be for functions");
1554 InitFuncs
.push_back(
1555 std::make_pair(Priority
, TargetSym
.getIndex()));
1559 // Write out the Wasm header.
1562 writeTypeSection(Signatures
);
1563 writeImportSection(Imports
, DataSize
, TableElems
.size());
1564 writeFunctionSection(Functions
);
1565 // Skip the "table" section; we import the table instead.
1566 // Skip the "memory" section; we import the memory instead.
1567 writeEventSection(Events
);
1568 writeExportSection(Exports
);
1569 writeElemSection(TableElems
);
1570 writeDataCountSection();
1571 writeCodeSection(Asm
, Layout
, Functions
);
1573 for (auto &CustomSection
: CustomSections
)
1574 writeCustomSection(CustomSection
, Asm
, Layout
);
1575 writeLinkingMetaDataSection(SymbolInfos
, InitFuncs
, Comdats
);
1576 writeRelocSection(CodeSectionIndex
, "CODE", CodeRelocations
);
1577 writeRelocSection(DataSectionIndex
, "DATA", DataRelocations
);
1578 writeCustomRelocSections();
1579 if (ProducersSection
)
1580 writeCustomSection(*ProducersSection
, Asm
, Layout
);
1581 if (TargetFeaturesSection
)
1582 writeCustomSection(*TargetFeaturesSection
, Asm
, Layout
);
1584 // TODO: Translate the .comment section to the output.
1585 return W
.OS
.tell() - StartOffset
;
1588 std::unique_ptr
<MCObjectWriter
>
1589 llvm::createWasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
1590 raw_pwrite_stream
&OS
) {
1591 return std::make_unique
<WasmObjectWriter
>(std::move(MOTW
), OS
);