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 SmallVector
<char, 4> Data
;
115 // A wasm function to be written into the function section.
116 struct WasmFunction
{
118 const MCSymbolWasm
*Sym
;
121 // A wasm global to be written into the global section.
123 wasm::WasmGlobalType Type
;
124 uint64_t InitialValue
;
127 // Information about a single item which is part of a COMDAT. For each data
128 // segment or function which is in the COMDAT, there is a corresponding
130 struct WasmComdatEntry
{
135 // Information about a single relocation.
136 struct WasmRelocationEntry
{
137 uint64_t Offset
; // Where is the relocation.
138 const MCSymbolWasm
*Symbol
; // The symbol to relocate with.
139 int64_t Addend
; // A value to add to the symbol.
140 unsigned Type
; // The type of the relocation.
141 const MCSectionWasm
*FixupSection
; // The section the relocation is targeting.
143 WasmRelocationEntry(uint64_t Offset
, const MCSymbolWasm
*Symbol
,
144 int64_t Addend
, unsigned Type
,
145 const MCSectionWasm
*FixupSection
)
146 : Offset(Offset
), Symbol(Symbol
), Addend(Addend
), Type(Type
),
147 FixupSection(FixupSection
) {}
149 bool hasAddend() const {
151 case wasm::R_WASM_MEMORY_ADDR_LEB
:
152 case wasm::R_WASM_MEMORY_ADDR_SLEB
:
153 case wasm::R_WASM_MEMORY_ADDR_I32
:
154 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
155 case wasm::R_WASM_SECTION_OFFSET_I32
:
162 void print(raw_ostream
&Out
) const {
163 Out
<< wasm::relocTypetoString(Type
) << " Off=" << Offset
164 << ", Sym=" << *Symbol
<< ", Addend=" << Addend
165 << ", FixupSection=" << FixupSection
->getSectionName();
168 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
169 LLVM_DUMP_METHOD
void dump() const { print(dbgs()); }
173 static const uint32_t InvalidIndex
= -1;
175 struct WasmCustomSection
{
178 MCSectionWasm
*Section
;
180 uint32_t OutputContentsOffset
;
181 uint32_t OutputIndex
;
183 WasmCustomSection(StringRef Name
, MCSectionWasm
*Section
)
184 : Name(Name
), Section(Section
), OutputContentsOffset(0),
185 OutputIndex(InvalidIndex
) {}
189 raw_ostream
&operator<<(raw_ostream
&OS
, const WasmRelocationEntry
&Rel
) {
195 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded
196 // to allow patching.
197 static void writePatchableLEB(raw_pwrite_stream
&Stream
, uint32_t X
,
200 unsigned SizeLen
= encodeULEB128(X
, Buffer
, 5);
201 assert(SizeLen
== 5);
202 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
205 // Write X as an signed LEB value at offset Offset in Stream, padded
206 // to allow patching.
207 static void writePatchableSLEB(raw_pwrite_stream
&Stream
, int32_t X
,
210 unsigned SizeLen
= encodeSLEB128(X
, Buffer
, 5);
211 assert(SizeLen
== 5);
212 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
215 // Write X as a plain integer value at offset Offset in Stream.
216 static void writeI32(raw_pwrite_stream
&Stream
, uint32_t X
, uint64_t Offset
) {
218 support::endian::write32le(Buffer
, X
);
219 Stream
.pwrite((char *)Buffer
, sizeof(Buffer
), Offset
);
222 class WasmObjectWriter
: public MCObjectWriter
{
223 support::endian::Writer W
;
225 /// The target specific Wasm writer instance.
226 std::unique_ptr
<MCWasmObjectTargetWriter
> TargetObjectWriter
;
228 // Relocations for fixing up references in the code section.
229 std::vector
<WasmRelocationEntry
> CodeRelocations
;
230 uint32_t CodeSectionIndex
;
232 // Relocations for fixing up references in the data section.
233 std::vector
<WasmRelocationEntry
> DataRelocations
;
234 uint32_t DataSectionIndex
;
236 // Index values to use for fixing up call_indirect type indices.
237 // Maps function symbols to the index of the type of the function
238 DenseMap
<const MCSymbolWasm
*, uint32_t> TypeIndices
;
239 // Maps function symbols to the table element index space. Used
240 // for TABLE_INDEX relocation types (i.e. address taken functions).
241 DenseMap
<const MCSymbolWasm
*, uint32_t> TableIndices
;
242 // Maps function/global symbols to the function/global/event/section index
244 DenseMap
<const MCSymbolWasm
*, uint32_t> WasmIndices
;
245 // Maps data symbols to the Wasm segment and offset/size with the segment.
246 DenseMap
<const MCSymbolWasm
*, wasm::WasmDataReference
> DataLocations
;
248 // Stores output data (index, relocations, content offset) for custom
250 std::vector
<WasmCustomSection
> CustomSections
;
251 std::unique_ptr
<WasmCustomSection
> ProducersSection
;
252 // Relocations for fixing up references in the custom sections.
253 DenseMap
<const MCSectionWasm
*, std::vector
<WasmRelocationEntry
>>
254 CustomSectionsRelocations
;
256 // Map from section to defining function symbol.
257 DenseMap
<const MCSection
*, const MCSymbol
*> SectionFunctions
;
259 DenseMap
<WasmSignature
, uint32_t, WasmSignatureDenseMapInfo
> SignatureIndices
;
260 SmallVector
<WasmSignature
, 4> Signatures
;
261 SmallVector
<WasmGlobal
, 4> Globals
;
262 SmallVector
<WasmDataSegment
, 4> DataSegments
;
263 unsigned NumFunctionImports
= 0;
264 unsigned NumGlobalImports
= 0;
265 unsigned NumEventImports
= 0;
266 uint32_t SectionCount
= 0;
268 // TargetObjectWriter wrappers.
269 bool is64Bit() const { return TargetObjectWriter
->is64Bit(); }
270 unsigned getRelocType(const MCValue
&Target
, const MCFixup
&Fixup
) const {
271 return TargetObjectWriter
->getRelocType(Target
, Fixup
);
274 void startSection(SectionBookkeeping
&Section
, unsigned SectionId
);
275 void startCustomSection(SectionBookkeeping
&Section
, StringRef Name
);
276 void endSection(SectionBookkeeping
&Section
);
279 WasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
280 raw_pwrite_stream
&OS
)
281 : W(OS
, support::little
), TargetObjectWriter(std::move(MOTW
)) {}
284 void reset() override
{
285 CodeRelocations
.clear();
286 DataRelocations
.clear();
289 TableIndices
.clear();
290 DataLocations
.clear();
291 CustomSections
.clear();
292 ProducersSection
.reset();
293 CustomSectionsRelocations
.clear();
294 SignatureIndices
.clear();
297 DataSegments
.clear();
298 SectionFunctions
.clear();
299 NumFunctionImports
= 0;
300 NumGlobalImports
= 0;
301 MCObjectWriter::reset();
304 void writeHeader(const MCAssembler
&Asm
);
306 void recordRelocation(MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
307 const MCFragment
*Fragment
, const MCFixup
&Fixup
,
308 MCValue Target
, uint64_t &FixedValue
) override
;
310 void executePostLayoutBinding(MCAssembler
&Asm
,
311 const MCAsmLayout
&Layout
) override
;
313 uint64_t writeObject(MCAssembler
&Asm
, const MCAsmLayout
&Layout
) override
;
315 void writeString(const StringRef Str
) {
316 encodeULEB128(Str
.size(), W
.OS
);
320 void writeValueType(wasm::ValType Ty
) { W
.OS
<< static_cast<char>(Ty
); }
322 void writeTypeSection(ArrayRef
<WasmSignature
> Signatures
);
323 void writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
, uint32_t DataSize
,
324 uint32_t NumElements
);
325 void writeFunctionSection(ArrayRef
<WasmFunction
> Functions
);
326 void writeGlobalSection();
327 void writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
);
328 void writeElemSection(ArrayRef
<uint32_t> TableElems
);
329 void writeCodeSection(const MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
330 ArrayRef
<WasmFunction
> Functions
);
331 void writeDataSection();
332 void writeEventSection(ArrayRef
<wasm::WasmEventType
> Events
);
333 void writeRelocSection(uint32_t SectionIndex
, StringRef Name
,
334 std::vector
<WasmRelocationEntry
> &Relocations
);
335 void writeLinkingMetaDataSection(
336 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
337 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
338 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
);
339 void writeCustomSection(WasmCustomSection
&CustomSection
,
340 const MCAssembler
&Asm
, const MCAsmLayout
&Layout
);
341 void writeCustomRelocSections();
343 updateCustomSectionRelocations(const SmallVector
<WasmFunction
, 4> &Functions
,
344 const MCAsmLayout
&Layout
);
346 uint32_t getProvisionalValue(const WasmRelocationEntry
&RelEntry
);
347 void applyRelocations(ArrayRef
<WasmRelocationEntry
> Relocations
,
348 uint64_t ContentsOffset
);
350 uint32_t getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
);
351 uint32_t getFunctionType(const MCSymbolWasm
&Symbol
);
352 uint32_t getEventType(const MCSymbolWasm
&Symbol
);
353 void registerFunctionType(const MCSymbolWasm
&Symbol
);
354 void registerEventType(const MCSymbolWasm
&Symbol
);
357 } // end anonymous namespace
359 // Write out a section header and a patchable section size field.
360 void WasmObjectWriter::startSection(SectionBookkeeping
&Section
,
361 unsigned SectionId
) {
362 LLVM_DEBUG(dbgs() << "startSection " << SectionId
<< "\n");
363 W
.OS
<< char(SectionId
);
365 Section
.SizeOffset
= W
.OS
.tell();
367 // The section size. We don't know the size yet, so reserve enough space
368 // for any 32-bit value; we'll patch it later.
369 encodeULEB128(0, W
.OS
, 5);
371 // The position where the section starts, for measuring its size.
372 Section
.ContentsOffset
= W
.OS
.tell();
373 Section
.PayloadOffset
= W
.OS
.tell();
374 Section
.Index
= SectionCount
++;
377 void WasmObjectWriter::startCustomSection(SectionBookkeeping
&Section
,
379 LLVM_DEBUG(dbgs() << "startCustomSection " << Name
<< "\n");
380 startSection(Section
, wasm::WASM_SEC_CUSTOM
);
382 // The position where the section header ends, for measuring its size.
383 Section
.PayloadOffset
= W
.OS
.tell();
385 // Custom sections in wasm also have a string identifier.
388 // The position where the custom section starts.
389 Section
.ContentsOffset
= W
.OS
.tell();
392 // Now that the section is complete and we know how big it is, patch up the
393 // section size field at the start of the section.
394 void WasmObjectWriter::endSection(SectionBookkeeping
&Section
) {
395 uint64_t Size
= W
.OS
.tell();
396 // /dev/null doesn't support seek/tell and can report offset of 0.
397 // Simply skip this patching in that case.
401 Size
-= Section
.PayloadOffset
;
402 if (uint32_t(Size
) != Size
)
403 report_fatal_error("section size does not fit in a uint32_t");
405 LLVM_DEBUG(dbgs() << "endSection size=" << Size
<< "\n");
407 // Write the final section size to the payload_len field, which follows
408 // the section id byte.
409 writePatchableLEB(static_cast<raw_pwrite_stream
&>(W
.OS
), Size
,
413 // Emit the Wasm header.
414 void WasmObjectWriter::writeHeader(const MCAssembler
&Asm
) {
415 W
.OS
.write(wasm::WasmMagic
, sizeof(wasm::WasmMagic
));
416 W
.write
<uint32_t>(wasm::WasmVersion
);
419 void WasmObjectWriter::executePostLayoutBinding(MCAssembler
&Asm
,
420 const MCAsmLayout
&Layout
) {
421 // Build a map of sections to the function that defines them, for use
422 // in recordRelocation.
423 for (const MCSymbol
&S
: Asm
.symbols()) {
424 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
425 if (WS
.isDefined() && WS
.isFunction() && !WS
.isVariable()) {
426 const auto &Sec
= static_cast<const MCSectionWasm
&>(S
.getSection());
427 auto Pair
= SectionFunctions
.insert(std::make_pair(&Sec
, &S
));
429 report_fatal_error("section already has a defining function: " +
430 Sec
.getSectionName());
435 void WasmObjectWriter::recordRelocation(MCAssembler
&Asm
,
436 const MCAsmLayout
&Layout
,
437 const MCFragment
*Fragment
,
438 const MCFixup
&Fixup
, MCValue Target
,
439 uint64_t &FixedValue
) {
440 MCAsmBackend
&Backend
= Asm
.getBackend();
441 bool IsPCRel
= Backend
.getFixupKindInfo(Fixup
.getKind()).Flags
&
442 MCFixupKindInfo::FKF_IsPCRel
;
443 const auto &FixupSection
= cast
<MCSectionWasm
>(*Fragment
->getParent());
444 uint64_t C
= Target
.getConstant();
445 uint64_t FixupOffset
= Layout
.getFragmentOffset(Fragment
) + Fixup
.getOffset();
446 MCContext
&Ctx
= Asm
.getContext();
448 // The .init_array isn't translated as data, so don't do relocations in it.
449 if (FixupSection
.getSectionName().startswith(".init_array"))
452 if (const MCSymbolRefExpr
*RefB
= Target
.getSymB()) {
453 assert(RefB
->getKind() == MCSymbolRefExpr::VK_None
&&
454 "Should not have constructed this");
456 // Let A, B and C being the components of Target and R be the location of
457 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
458 // If it is pcrel, we want to compute (A - B + C - R).
460 // In general, Wasm has no relocations for -B. It can only represent (A + C)
461 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
462 // replace B to implement it: (A - R - K + C)
466 "No relocation available to represent this relative expression");
470 const auto &SymB
= cast
<MCSymbolWasm
>(RefB
->getSymbol());
472 if (SymB
.isUndefined()) {
473 Ctx
.reportError(Fixup
.getLoc(),
474 Twine("symbol '") + SymB
.getName() +
475 "' can not be undefined in a subtraction expression");
479 assert(!SymB
.isAbsolute() && "Should have been folded");
480 const MCSection
&SecB
= SymB
.getSection();
481 if (&SecB
!= &FixupSection
) {
482 Ctx
.reportError(Fixup
.getLoc(),
483 "Cannot represent a difference across sections");
487 uint64_t SymBOffset
= Layout
.getSymbolOffset(SymB
);
488 uint64_t K
= SymBOffset
- FixupOffset
;
493 // We either rejected the fixup or folded B into C at this point.
494 const MCSymbolRefExpr
*RefA
= Target
.getSymA();
495 const auto *SymA
= RefA
? cast
<MCSymbolWasm
>(&RefA
->getSymbol()) : nullptr;
497 if (SymA
&& SymA
->isVariable()) {
498 const MCExpr
*Expr
= SymA
->getVariableValue();
499 const auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
500 if (Inner
->getKind() == MCSymbolRefExpr::VK_WEAKREF
)
501 llvm_unreachable("weakref used in reloc not yet implemented");
504 // Put any constant offset in an addend. Offsets can be negative, and
505 // LLVM expects wrapping, in contrast to wasm's immediates which can't
506 // be negative and don't wrap.
509 unsigned Type
= getRelocType(Target
, Fixup
);
513 // Absolute offset within a section or a function.
514 // Currently only supported for for metadata sections.
515 // See: test/MC/WebAssembly/blockaddress.ll
516 if (Type
== wasm::R_WASM_FUNCTION_OFFSET_I32
||
517 Type
== wasm::R_WASM_SECTION_OFFSET_I32
) {
518 if (!FixupSection
.getKind().isMetadata())
519 report_fatal_error("relocations for function or section offsets are "
520 "only supported in metadata sections");
522 const MCSymbol
*SectionSymbol
= nullptr;
523 const MCSection
&SecA
= SymA
->getSection();
524 if (SecA
.getKind().isText())
525 SectionSymbol
= SectionFunctions
.find(&SecA
)->second
;
527 SectionSymbol
= SecA
.getBeginSymbol();
529 report_fatal_error("section symbol is required for relocation");
531 C
+= Layout
.getSymbolOffset(*SymA
);
532 SymA
= cast
<MCSymbolWasm
>(SectionSymbol
);
535 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
536 // against a named symbol.
537 if (Type
!= wasm::R_WASM_TYPE_INDEX_LEB
) {
538 if (SymA
->getName().empty())
539 report_fatal_error("relocations against un-named temporaries are not yet "
540 "supported by wasm");
542 SymA
->setUsedInReloc();
545 WasmRelocationEntry
Rec(FixupOffset
, SymA
, C
, Type
, &FixupSection
);
546 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec
<< "\n");
548 if (FixupSection
.isWasmData()) {
549 DataRelocations
.push_back(Rec
);
550 } else if (FixupSection
.getKind().isText()) {
551 CodeRelocations
.push_back(Rec
);
552 } else if (FixupSection
.getKind().isMetadata()) {
553 CustomSectionsRelocations
[&FixupSection
].push_back(Rec
);
555 llvm_unreachable("unexpected section type");
559 static const MCSymbolWasm
*resolveSymbol(const MCSymbolWasm
&Symbol
) {
560 if (Symbol
.isVariable()) {
561 const MCExpr
*Expr
= Symbol
.getVariableValue();
562 auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
563 return cast
<MCSymbolWasm
>(&Inner
->getSymbol());
568 // Compute a value to write into the code at the location covered
569 // by RelEntry. This value isn't used by the static linker; it just serves
570 // to make the object format more readable and more likely to be directly
573 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry
&RelEntry
) {
574 switch (RelEntry
.Type
) {
575 case wasm::R_WASM_TABLE_INDEX_SLEB
:
576 case wasm::R_WASM_TABLE_INDEX_I32
: {
577 // Provisional value is table address of the resolved symbol itself
578 const MCSymbolWasm
*Sym
= resolveSymbol(*RelEntry
.Symbol
);
579 assert(Sym
->isFunction());
580 return TableIndices
[Sym
];
582 case wasm::R_WASM_TYPE_INDEX_LEB
:
583 // Provisional value is same as the index
584 return getRelocationIndexValue(RelEntry
);
585 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
586 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
587 case wasm::R_WASM_EVENT_INDEX_LEB
:
588 // Provisional value is function/global/event Wasm index
589 if (!WasmIndices
.count(RelEntry
.Symbol
))
590 report_fatal_error("symbol not found in wasm index space: " +
591 RelEntry
.Symbol
->getName());
592 return WasmIndices
[RelEntry
.Symbol
];
593 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
594 case wasm::R_WASM_SECTION_OFFSET_I32
: {
595 const auto &Section
=
596 static_cast<const MCSectionWasm
&>(RelEntry
.Symbol
->getSection());
597 return Section
.getSectionOffset() + RelEntry
.Addend
;
599 case wasm::R_WASM_MEMORY_ADDR_LEB
:
600 case wasm::R_WASM_MEMORY_ADDR_I32
:
601 case wasm::R_WASM_MEMORY_ADDR_SLEB
: {
602 // Provisional value is address of the global
603 const MCSymbolWasm
*Sym
= resolveSymbol(*RelEntry
.Symbol
);
604 // For undefined symbols, use zero
605 if (!Sym
->isDefined())
607 const wasm::WasmDataReference
&Ref
= DataLocations
[Sym
];
608 const WasmDataSegment
&Segment
= DataSegments
[Ref
.Segment
];
609 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
610 return Segment
.Offset
+ Ref
.Offset
+ RelEntry
.Addend
;
613 llvm_unreachable("invalid relocation type");
617 static void addData(SmallVectorImpl
<char> &DataBytes
,
618 MCSectionWasm
&DataSection
) {
619 LLVM_DEBUG(errs() << "addData: " << DataSection
.getSectionName() << "\n");
621 DataBytes
.resize(alignTo(DataBytes
.size(), DataSection
.getAlignment()));
623 for (const MCFragment
&Frag
: DataSection
) {
624 if (Frag
.hasInstructions())
625 report_fatal_error("only data supported in data sections");
627 if (auto *Align
= dyn_cast
<MCAlignFragment
>(&Frag
)) {
628 if (Align
->getValueSize() != 1)
629 report_fatal_error("only byte values supported for alignment");
630 // If nops are requested, use zeros, as this is the data section.
631 uint8_t Value
= Align
->hasEmitNops() ? 0 : Align
->getValue();
633 std::min
<uint64_t>(alignTo(DataBytes
.size(), Align
->getAlignment()),
634 DataBytes
.size() + Align
->getMaxBytesToEmit());
635 DataBytes
.resize(Size
, Value
);
636 } else if (auto *Fill
= dyn_cast
<MCFillFragment
>(&Frag
)) {
638 if (!Fill
->getNumValues().evaluateAsAbsolute(NumValues
))
639 llvm_unreachable("The fill should be an assembler constant");
640 DataBytes
.insert(DataBytes
.end(), Fill
->getValueSize() * NumValues
,
642 } else if (auto *LEB
= dyn_cast
<MCLEBFragment
>(&Frag
)) {
643 const SmallVectorImpl
<char> &Contents
= LEB
->getContents();
644 DataBytes
.insert(DataBytes
.end(), Contents
.begin(), Contents
.end());
646 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
647 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
648 DataBytes
.insert(DataBytes
.end(), Contents
.begin(), Contents
.end());
652 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes
.size() << "\n");
656 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
) {
657 if (RelEntry
.Type
== wasm::R_WASM_TYPE_INDEX_LEB
) {
658 if (!TypeIndices
.count(RelEntry
.Symbol
))
659 report_fatal_error("symbol not found in type index space: " +
660 RelEntry
.Symbol
->getName());
661 return TypeIndices
[RelEntry
.Symbol
];
664 return RelEntry
.Symbol
->getIndex();
667 // Apply the portions of the relocation records that we can handle ourselves
669 void WasmObjectWriter::applyRelocations(
670 ArrayRef
<WasmRelocationEntry
> Relocations
, uint64_t ContentsOffset
) {
671 auto &Stream
= static_cast<raw_pwrite_stream
&>(W
.OS
);
672 for (const WasmRelocationEntry
&RelEntry
: Relocations
) {
673 uint64_t Offset
= ContentsOffset
+
674 RelEntry
.FixupSection
->getSectionOffset() +
677 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry
<< "\n");
678 uint32_t Value
= getProvisionalValue(RelEntry
);
680 switch (RelEntry
.Type
) {
681 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
682 case wasm::R_WASM_TYPE_INDEX_LEB
:
683 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
684 case wasm::R_WASM_MEMORY_ADDR_LEB
:
685 case wasm::R_WASM_EVENT_INDEX_LEB
:
686 writePatchableLEB(Stream
, Value
, Offset
);
688 case wasm::R_WASM_TABLE_INDEX_I32
:
689 case wasm::R_WASM_MEMORY_ADDR_I32
:
690 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
691 case wasm::R_WASM_SECTION_OFFSET_I32
:
692 writeI32(Stream
, Value
, Offset
);
694 case wasm::R_WASM_TABLE_INDEX_SLEB
:
695 case wasm::R_WASM_MEMORY_ADDR_SLEB
:
696 writePatchableSLEB(Stream
, Value
, Offset
);
699 llvm_unreachable("invalid relocation type");
704 void WasmObjectWriter::writeTypeSection(ArrayRef
<WasmSignature
> Signatures
) {
705 if (Signatures
.empty())
708 SectionBookkeeping Section
;
709 startSection(Section
, wasm::WASM_SEC_TYPE
);
711 encodeULEB128(Signatures
.size(), W
.OS
);
713 for (const WasmSignature
&Sig
: Signatures
) {
714 W
.OS
<< char(wasm::WASM_TYPE_FUNC
);
715 encodeULEB128(Sig
.Params
.size(), W
.OS
);
716 for (wasm::ValType Ty
: Sig
.Params
)
718 encodeULEB128(Sig
.Returns
.size(), W
.OS
);
719 for (wasm::ValType Ty
: Sig
.Returns
)
726 void WasmObjectWriter::writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
,
728 uint32_t NumElements
) {
732 uint32_t NumPages
= (DataSize
+ wasm::WasmPageSize
- 1) / wasm::WasmPageSize
;
734 SectionBookkeeping Section
;
735 startSection(Section
, wasm::WASM_SEC_IMPORT
);
737 encodeULEB128(Imports
.size(), W
.OS
);
738 for (const wasm::WasmImport
&Import
: Imports
) {
739 writeString(Import
.Module
);
740 writeString(Import
.Field
);
741 W
.OS
<< char(Import
.Kind
);
743 switch (Import
.Kind
) {
744 case wasm::WASM_EXTERNAL_FUNCTION
:
745 encodeULEB128(Import
.SigIndex
, W
.OS
);
747 case wasm::WASM_EXTERNAL_GLOBAL
:
748 W
.OS
<< char(Import
.Global
.Type
);
749 W
.OS
<< char(Import
.Global
.Mutable
? 1 : 0);
751 case wasm::WASM_EXTERNAL_MEMORY
:
752 encodeULEB128(0, W
.OS
); // flags
753 encodeULEB128(NumPages
, W
.OS
); // initial
755 case wasm::WASM_EXTERNAL_TABLE
:
756 W
.OS
<< char(Import
.Table
.ElemType
);
757 encodeULEB128(0, W
.OS
); // flags
758 encodeULEB128(NumElements
, W
.OS
); // initial
760 case wasm::WASM_EXTERNAL_EVENT
:
761 encodeULEB128(Import
.Event
.Attribute
, W
.OS
);
762 encodeULEB128(Import
.Event
.SigIndex
, W
.OS
);
765 llvm_unreachable("unsupported import kind");
772 void WasmObjectWriter::writeFunctionSection(ArrayRef
<WasmFunction
> Functions
) {
773 if (Functions
.empty())
776 SectionBookkeeping Section
;
777 startSection(Section
, wasm::WASM_SEC_FUNCTION
);
779 encodeULEB128(Functions
.size(), W
.OS
);
780 for (const WasmFunction
&Func
: Functions
)
781 encodeULEB128(Func
.SigIndex
, W
.OS
);
786 void WasmObjectWriter::writeGlobalSection() {
790 SectionBookkeeping Section
;
791 startSection(Section
, wasm::WASM_SEC_GLOBAL
);
793 encodeULEB128(Globals
.size(), W
.OS
);
794 for (const WasmGlobal
&Global
: Globals
) {
795 writeValueType(static_cast<wasm::ValType
>(Global
.Type
.Type
));
796 W
.OS
<< char(Global
.Type
.Mutable
);
798 W
.OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
799 encodeSLEB128(Global
.InitialValue
, W
.OS
);
800 W
.OS
<< char(wasm::WASM_OPCODE_END
);
806 void WasmObjectWriter::writeEventSection(ArrayRef
<wasm::WasmEventType
> Events
) {
810 SectionBookkeeping Section
;
811 startSection(Section
, wasm::WASM_SEC_EVENT
);
813 encodeULEB128(Events
.size(), W
.OS
);
814 for (const wasm::WasmEventType
&Event
: Events
) {
815 encodeULEB128(Event
.Attribute
, W
.OS
);
816 encodeULEB128(Event
.SigIndex
, W
.OS
);
822 void WasmObjectWriter::writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
) {
826 SectionBookkeeping Section
;
827 startSection(Section
, wasm::WASM_SEC_EXPORT
);
829 encodeULEB128(Exports
.size(), W
.OS
);
830 for (const wasm::WasmExport
&Export
: Exports
) {
831 writeString(Export
.Name
);
832 W
.OS
<< char(Export
.Kind
);
833 encodeULEB128(Export
.Index
, W
.OS
);
839 void WasmObjectWriter::writeElemSection(ArrayRef
<uint32_t> TableElems
) {
840 if (TableElems
.empty())
843 SectionBookkeeping Section
;
844 startSection(Section
, wasm::WASM_SEC_ELEM
);
846 encodeULEB128(1, W
.OS
); // number of "segments"
847 encodeULEB128(0, W
.OS
); // the table index
849 // init expr for starting offset
850 W
.OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
851 encodeSLEB128(InitialTableOffset
, W
.OS
);
852 W
.OS
<< char(wasm::WASM_OPCODE_END
);
854 encodeULEB128(TableElems
.size(), W
.OS
);
855 for (uint32_t Elem
: TableElems
)
856 encodeULEB128(Elem
, W
.OS
);
861 void WasmObjectWriter::writeCodeSection(const MCAssembler
&Asm
,
862 const MCAsmLayout
&Layout
,
863 ArrayRef
<WasmFunction
> Functions
) {
864 if (Functions
.empty())
867 SectionBookkeeping Section
;
868 startSection(Section
, wasm::WASM_SEC_CODE
);
869 CodeSectionIndex
= Section
.Index
;
871 encodeULEB128(Functions
.size(), W
.OS
);
873 for (const WasmFunction
&Func
: Functions
) {
874 auto &FuncSection
= static_cast<MCSectionWasm
&>(Func
.Sym
->getSection());
877 if (!Func
.Sym
->getSize()->evaluateAsAbsolute(Size
, Layout
))
878 report_fatal_error(".size expression must be evaluatable");
880 encodeULEB128(Size
, W
.OS
);
881 FuncSection
.setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
882 Asm
.writeSectionData(W
.OS
, &FuncSection
, Layout
);
886 applyRelocations(CodeRelocations
, Section
.ContentsOffset
);
891 void WasmObjectWriter::writeDataSection() {
892 if (DataSegments
.empty())
895 SectionBookkeeping Section
;
896 startSection(Section
, wasm::WASM_SEC_DATA
);
897 DataSectionIndex
= Section
.Index
;
899 encodeULEB128(DataSegments
.size(), W
.OS
); // count
901 for (const WasmDataSegment
&Segment
: DataSegments
) {
902 encodeULEB128(0, W
.OS
); // memory index
903 W
.OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
904 encodeSLEB128(Segment
.Offset
, W
.OS
); // offset
905 W
.OS
<< char(wasm::WASM_OPCODE_END
);
906 encodeULEB128(Segment
.Data
.size(), W
.OS
); // size
907 Segment
.Section
->setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
908 W
.OS
<< Segment
.Data
; // data
912 applyRelocations(DataRelocations
, Section
.ContentsOffset
);
917 void WasmObjectWriter::writeRelocSection(
918 uint32_t SectionIndex
, StringRef Name
,
919 std::vector
<WasmRelocationEntry
> &Relocs
) {
920 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
921 // for descriptions of the reloc sections.
926 // First, ensure the relocations are sorted in offset order. In general they
927 // should already be sorted since `recordRelocation` is called in offset
928 // order, but for the code section we combine many MC sections into single
929 // wasm section, and this order is determined by the order of Asm.Symbols()
930 // not the sections order.
932 Relocs
.begin(), Relocs
.end(),
933 [](const WasmRelocationEntry
&A
, const WasmRelocationEntry
&B
) {
934 return (A
.Offset
+ A
.FixupSection
->getSectionOffset()) <
935 (B
.Offset
+ B
.FixupSection
->getSectionOffset());
938 SectionBookkeeping Section
;
939 startCustomSection(Section
, std::string("reloc.") + Name
.str());
941 encodeULEB128(SectionIndex
, W
.OS
);
942 encodeULEB128(Relocs
.size(), W
.OS
);
943 for (const WasmRelocationEntry
&RelEntry
: Relocs
) {
945 RelEntry
.Offset
+ RelEntry
.FixupSection
->getSectionOffset();
946 uint32_t Index
= getRelocationIndexValue(RelEntry
);
948 W
.OS
<< char(RelEntry
.Type
);
949 encodeULEB128(Offset
, W
.OS
);
950 encodeULEB128(Index
, W
.OS
);
951 if (RelEntry
.hasAddend())
952 encodeSLEB128(RelEntry
.Addend
, W
.OS
);
958 void WasmObjectWriter::writeCustomRelocSections() {
959 for (const auto &Sec
: CustomSections
) {
960 auto &Relocations
= CustomSectionsRelocations
[Sec
.Section
];
961 writeRelocSection(Sec
.OutputIndex
, Sec
.Name
, Relocations
);
965 void WasmObjectWriter::writeLinkingMetaDataSection(
966 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
967 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
968 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
) {
969 SectionBookkeeping Section
;
970 startCustomSection(Section
, "linking");
971 encodeULEB128(wasm::WasmMetadataVersion
, W
.OS
);
973 SectionBookkeeping SubSection
;
974 if (SymbolInfos
.size() != 0) {
975 startSection(SubSection
, wasm::WASM_SYMBOL_TABLE
);
976 encodeULEB128(SymbolInfos
.size(), W
.OS
);
977 for (const wasm::WasmSymbolInfo
&Sym
: SymbolInfos
) {
978 encodeULEB128(Sym
.Kind
, W
.OS
);
979 encodeULEB128(Sym
.Flags
, W
.OS
);
981 case wasm::WASM_SYMBOL_TYPE_FUNCTION
:
982 case wasm::WASM_SYMBOL_TYPE_GLOBAL
:
983 case wasm::WASM_SYMBOL_TYPE_EVENT
:
984 encodeULEB128(Sym
.ElementIndex
, W
.OS
);
985 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0 ||
986 (Sym
.Flags
& wasm::WASM_SYMBOL_EXPLICIT_NAME
) != 0)
987 writeString(Sym
.Name
);
989 case wasm::WASM_SYMBOL_TYPE_DATA
:
990 writeString(Sym
.Name
);
991 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0) {
992 encodeULEB128(Sym
.DataRef
.Segment
, W
.OS
);
993 encodeULEB128(Sym
.DataRef
.Offset
, W
.OS
);
994 encodeULEB128(Sym
.DataRef
.Size
, W
.OS
);
997 case wasm::WASM_SYMBOL_TYPE_SECTION
: {
998 const uint32_t SectionIndex
=
999 CustomSections
[Sym
.ElementIndex
].OutputIndex
;
1000 encodeULEB128(SectionIndex
, W
.OS
);
1004 llvm_unreachable("unexpected kind");
1007 endSection(SubSection
);
1010 if (DataSegments
.size()) {
1011 startSection(SubSection
, wasm::WASM_SEGMENT_INFO
);
1012 encodeULEB128(DataSegments
.size(), W
.OS
);
1013 for (const WasmDataSegment
&Segment
: DataSegments
) {
1014 writeString(Segment
.Name
);
1015 encodeULEB128(Segment
.Alignment
, W
.OS
);
1016 encodeULEB128(Segment
.Flags
, W
.OS
);
1018 endSection(SubSection
);
1021 if (!InitFuncs
.empty()) {
1022 startSection(SubSection
, wasm::WASM_INIT_FUNCS
);
1023 encodeULEB128(InitFuncs
.size(), W
.OS
);
1024 for (auto &StartFunc
: InitFuncs
) {
1025 encodeULEB128(StartFunc
.first
, W
.OS
); // priority
1026 encodeULEB128(StartFunc
.second
, W
.OS
); // function index
1028 endSection(SubSection
);
1031 if (Comdats
.size()) {
1032 startSection(SubSection
, wasm::WASM_COMDAT_INFO
);
1033 encodeULEB128(Comdats
.size(), W
.OS
);
1034 for (const auto &C
: Comdats
) {
1035 writeString(C
.first
);
1036 encodeULEB128(0, W
.OS
); // flags for future use
1037 encodeULEB128(C
.second
.size(), W
.OS
);
1038 for (const WasmComdatEntry
&Entry
: C
.second
) {
1039 encodeULEB128(Entry
.Kind
, W
.OS
);
1040 encodeULEB128(Entry
.Index
, W
.OS
);
1043 endSection(SubSection
);
1046 endSection(Section
);
1049 void WasmObjectWriter::writeCustomSection(WasmCustomSection
&CustomSection
,
1050 const MCAssembler
&Asm
,
1051 const MCAsmLayout
&Layout
) {
1052 SectionBookkeeping Section
;
1053 auto *Sec
= CustomSection
.Section
;
1054 startCustomSection(Section
, CustomSection
.Name
);
1056 Sec
->setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
1057 Asm
.writeSectionData(W
.OS
, Sec
, Layout
);
1059 CustomSection
.OutputContentsOffset
= Section
.ContentsOffset
;
1060 CustomSection
.OutputIndex
= Section
.Index
;
1062 endSection(Section
);
1065 auto &Relocations
= CustomSectionsRelocations
[CustomSection
.Section
];
1066 applyRelocations(Relocations
, CustomSection
.OutputContentsOffset
);
1069 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm
&Symbol
) {
1070 assert(Symbol
.isFunction());
1071 assert(TypeIndices
.count(&Symbol
));
1072 return TypeIndices
[&Symbol
];
1075 uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm
&Symbol
) {
1076 assert(Symbol
.isEvent());
1077 assert(TypeIndices
.count(&Symbol
));
1078 return TypeIndices
[&Symbol
];
1081 void WasmObjectWriter::registerFunctionType(const MCSymbolWasm
&Symbol
) {
1082 assert(Symbol
.isFunction());
1085 const MCSymbolWasm
*ResolvedSym
= resolveSymbol(Symbol
);
1086 if (auto *Sig
= ResolvedSym
->getSignature()) {
1087 S
.Returns
= Sig
->Returns
;
1088 S
.Params
= Sig
->Params
;
1091 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1093 Signatures
.push_back(S
);
1094 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1096 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
1097 << " new:" << Pair
.second
<< "\n");
1098 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1101 void WasmObjectWriter::registerEventType(const MCSymbolWasm
&Symbol
) {
1102 assert(Symbol
.isEvent());
1104 // TODO Currently we don't generate imported exceptions, but if we do, we
1105 // should have a way of infering types of imported exceptions.
1107 if (auto *Sig
= Symbol
.getSignature()) {
1108 S
.Returns
= Sig
->Returns
;
1109 S
.Params
= Sig
->Params
;
1112 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1114 Signatures
.push_back(S
);
1115 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1117 LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol
<< " new:" << Pair
.second
1119 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1122 static bool isInSymtab(const MCSymbolWasm
&Sym
) {
1123 if (Sym
.isUsedInReloc())
1126 if (Sym
.isComdat() && !Sym
.isDefined())
1129 if (Sym
.isTemporary() && Sym
.getName().empty())
1132 if (Sym
.isTemporary() && Sym
.isData() && !Sym
.getSize())
1135 if (Sym
.isSection())
1141 uint64_t WasmObjectWriter::writeObject(MCAssembler
&Asm
,
1142 const MCAsmLayout
&Layout
) {
1143 uint64_t StartOffset
= W
.OS
.tell();
1145 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
1146 MCContext
&Ctx
= Asm
.getContext();
1148 // Collect information from the available symbols.
1149 SmallVector
<WasmFunction
, 4> Functions
;
1150 SmallVector
<uint32_t, 4> TableElems
;
1151 SmallVector
<wasm::WasmImport
, 4> Imports
;
1152 SmallVector
<wasm::WasmExport
, 4> Exports
;
1153 SmallVector
<wasm::WasmEventType
, 1> Events
;
1154 SmallVector
<wasm::WasmSymbolInfo
, 4> SymbolInfos
;
1155 SmallVector
<std::pair
<uint16_t, uint32_t>, 2> InitFuncs
;
1156 std::map
<StringRef
, std::vector
<WasmComdatEntry
>> Comdats
;
1157 uint32_t DataSize
= 0;
1159 // For now, always emit the memory import, since loads and stores are not
1160 // valid without it. In the future, we could perhaps be more clever and omit
1161 // it if there are no loads or stores.
1163 cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol("__linear_memory"));
1164 wasm::WasmImport MemImport
;
1165 MemImport
.Module
= MemorySym
->getImportModule();
1166 MemImport
.Field
= MemorySym
->getImportName();
1167 MemImport
.Kind
= wasm::WASM_EXTERNAL_MEMORY
;
1168 Imports
.push_back(MemImport
);
1170 // For now, always emit the table section, since indirect calls are not
1171 // valid without it. In the future, we could perhaps be more clever and omit
1172 // it if there are no indirect calls.
1174 cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol("__indirect_function_table"));
1175 wasm::WasmImport TableImport
;
1176 TableImport
.Module
= TableSym
->getImportModule();
1177 TableImport
.Field
= TableSym
->getImportName();
1178 TableImport
.Kind
= wasm::WASM_EXTERNAL_TABLE
;
1179 TableImport
.Table
.ElemType
= wasm::WASM_TYPE_FUNCREF
;
1180 Imports
.push_back(TableImport
);
1182 // Populate SignatureIndices, and Imports and WasmIndices for undefined
1183 // symbols. This must be done before populating WasmIndices for defined
1185 for (const MCSymbol
&S
: Asm
.symbols()) {
1186 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1188 // Register types for all functions, including those with private linkage
1189 // (because wasm always needs a type signature).
1190 if (WS
.isFunction())
1191 registerFunctionType(WS
);
1194 registerEventType(WS
);
1196 if (WS
.isTemporary())
1199 // If the symbol is not defined in this translation unit, import it.
1200 if (!WS
.isDefined() && !WS
.isComdat()) {
1201 if (WS
.isFunction()) {
1202 wasm::WasmImport Import
;
1203 Import
.Module
= WS
.getImportModule();
1204 Import
.Field
= WS
.getImportName();
1205 Import
.Kind
= wasm::WASM_EXTERNAL_FUNCTION
;
1206 Import
.SigIndex
= getFunctionType(WS
);
1207 Imports
.push_back(Import
);
1208 WasmIndices
[&WS
] = NumFunctionImports
++;
1209 } else if (WS
.isGlobal()) {
1211 report_fatal_error("undefined global symbol cannot be weak");
1213 wasm::WasmImport Import
;
1214 Import
.Module
= WS
.getImportModule();
1215 Import
.Field
= WS
.getImportName();
1216 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1217 Import
.Global
= WS
.getGlobalType();
1218 Imports
.push_back(Import
);
1219 WasmIndices
[&WS
] = NumGlobalImports
++;
1220 } else if (WS
.isEvent()) {
1222 report_fatal_error("undefined event symbol cannot be weak");
1224 wasm::WasmImport Import
;
1225 Import
.Module
= WS
.getImportModule();
1226 Import
.Field
= WS
.getImportName();
1227 Import
.Kind
= wasm::WASM_EXTERNAL_EVENT
;
1228 Import
.Event
.Attribute
= wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION
;
1229 Import
.Event
.SigIndex
= getEventType(WS
);
1230 Imports
.push_back(Import
);
1231 WasmIndices
[&WS
] = NumEventImports
++;
1236 // Populate DataSegments and CustomSections, which must be done before
1237 // populating DataLocations.
1238 for (MCSection
&Sec
: Asm
) {
1239 auto &Section
= static_cast<MCSectionWasm
&>(Sec
);
1240 StringRef SectionName
= Section
.getSectionName();
1242 // .init_array sections are handled specially elsewhere.
1243 if (SectionName
.startswith(".init_array"))
1246 // Code is handled separately
1247 if (Section
.getKind().isText())
1250 if (Section
.isWasmData()) {
1251 uint32_t SegmentIndex
= DataSegments
.size();
1252 DataSize
= alignTo(DataSize
, Section
.getAlignment());
1253 DataSegments
.emplace_back();
1254 WasmDataSegment
&Segment
= DataSegments
.back();
1255 Segment
.Name
= SectionName
;
1256 Segment
.Offset
= DataSize
;
1257 Segment
.Section
= &Section
;
1258 addData(Segment
.Data
, Section
);
1259 Segment
.Alignment
= Log2_32(Section
.getAlignment());
1261 DataSize
+= Segment
.Data
.size();
1262 Section
.setSegmentIndex(SegmentIndex
);
1264 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1265 Comdats
[C
->getName()].emplace_back(
1266 WasmComdatEntry
{wasm::WASM_COMDAT_DATA
, SegmentIndex
});
1269 // Create custom sections
1270 assert(Sec
.getKind().isMetadata());
1272 StringRef Name
= SectionName
;
1274 // For user-defined custom sections, strip the prefix
1275 if (Name
.startswith(".custom_section."))
1276 Name
= Name
.substr(strlen(".custom_section."));
1278 MCSymbol
*Begin
= Sec
.getBeginSymbol();
1280 WasmIndices
[cast
<MCSymbolWasm
>(Begin
)] = CustomSections
.size();
1281 if (SectionName
!= Begin
->getName())
1282 report_fatal_error("section name and begin symbol should match: " +
1283 Twine(SectionName
));
1286 // Separate out the producers section
1287 if (Name
== "producers") {
1288 ProducersSection
= llvm::make_unique
<WasmCustomSection
>(Name
, &Section
);
1292 CustomSections
.emplace_back(Name
, &Section
);
1296 // Populate WasmIndices and DataLocations for defined symbols.
1297 for (const MCSymbol
&S
: Asm
.symbols()) {
1298 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1299 // or used in relocations.
1300 if (S
.isTemporary() && S
.getName().empty())
1303 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1305 dbgs() << "MCSymbol: " << toString(WS
.getType()) << " '" << S
<< "'"
1306 << " isDefined=" << S
.isDefined() << " isExternal="
1307 << S
.isExternal() << " isTemporary=" << S
.isTemporary()
1308 << " isWeak=" << WS
.isWeak() << " isHidden=" << WS
.isHidden()
1309 << " isVariable=" << WS
.isVariable() << "\n");
1311 if (WS
.isVariable())
1313 if (WS
.isComdat() && !WS
.isDefined())
1316 if (WS
.isFunction()) {
1318 if (WS
.isDefined()) {
1319 if (WS
.getOffset() != 0)
1321 "function sections must contain one function each");
1323 if (WS
.getSize() == nullptr)
1325 "function symbols must have a size set with .size");
1327 // A definition. Write out the function body.
1328 Index
= NumFunctionImports
+ Functions
.size();
1330 Func
.SigIndex
= getFunctionType(WS
);
1332 WasmIndices
[&WS
] = Index
;
1333 Functions
.push_back(Func
);
1335 auto &Section
= static_cast<MCSectionWasm
&>(WS
.getSection());
1336 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1337 Comdats
[C
->getName()].emplace_back(
1338 WasmComdatEntry
{wasm::WASM_COMDAT_FUNCTION
, Index
});
1341 // An import; the index was assigned above.
1342 Index
= WasmIndices
.find(&WS
)->second
;
1345 LLVM_DEBUG(dbgs() << " -> function index: " << Index
<< "\n");
1347 } else if (WS
.isData()) {
1348 if (WS
.isTemporary() && !WS
.getSize())
1351 if (!WS
.isDefined()) {
1352 LLVM_DEBUG(dbgs() << " -> segment index: -1"
1358 report_fatal_error("data symbols must have a size set with .size: " +
1362 if (!WS
.getSize()->evaluateAsAbsolute(Size
, Layout
))
1363 report_fatal_error(".size expression must be evaluatable");
1365 auto &DataSection
= static_cast<MCSectionWasm
&>(WS
.getSection());
1366 assert(DataSection
.isWasmData());
1368 // For each data symbol, export it in the symtab as a reference to the
1369 // corresponding Wasm data segment.
1370 wasm::WasmDataReference Ref
= wasm::WasmDataReference
{
1371 DataSection
.getSegmentIndex(),
1372 static_cast<uint32_t>(Layout
.getSymbolOffset(WS
)),
1373 static_cast<uint32_t>(Size
)};
1374 DataLocations
[&WS
] = Ref
;
1375 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref
.Segment
<< "\n");
1377 } else if (WS
.isGlobal()) {
1378 // A "true" Wasm global (currently just __stack_pointer)
1380 report_fatal_error("don't yet support defined globals");
1382 // An import; the index was assigned above
1383 LLVM_DEBUG(dbgs() << " -> global index: "
1384 << WasmIndices
.find(&WS
)->second
<< "\n");
1386 } else if (WS
.isEvent()) {
1387 // C++ exception symbol (__cpp_exception)
1389 if (WS
.isDefined()) {
1390 Index
= NumEventImports
+ Events
.size();
1391 wasm::WasmEventType Event
;
1392 Event
.SigIndex
= getEventType(WS
);
1393 Event
.Attribute
= wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION
;
1394 WasmIndices
[&WS
] = Index
;
1395 Events
.push_back(Event
);
1397 // An import; the index was assigned above.
1398 Index
= WasmIndices
.find(&WS
)->second
;
1400 LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices
.find(&WS
)->second
1404 assert(WS
.isSection());
1408 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1409 // process these in a separate pass because we need to have processed the
1410 // target of the alias before the alias itself and the symbols are not
1411 // necessarily ordered in this way.
1412 for (const MCSymbol
&S
: Asm
.symbols()) {
1413 if (!S
.isVariable())
1416 assert(S
.isDefined());
1418 // Find the target symbol of this weak alias and export that index
1419 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1420 const MCSymbolWasm
*ResolvedSym
= resolveSymbol(WS
);
1421 LLVM_DEBUG(dbgs() << WS
.getName() << ": weak alias of '" << *ResolvedSym
1424 if (WS
.isFunction()) {
1425 assert(WasmIndices
.count(ResolvedSym
) > 0);
1426 uint32_t WasmIndex
= WasmIndices
.find(ResolvedSym
)->second
;
1427 WasmIndices
[&WS
] = WasmIndex
;
1428 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex
<< "\n");
1429 } else if (WS
.isData()) {
1430 assert(DataLocations
.count(ResolvedSym
) > 0);
1431 const wasm::WasmDataReference
&Ref
=
1432 DataLocations
.find(ResolvedSym
)->second
;
1433 DataLocations
[&WS
] = Ref
;
1434 LLVM_DEBUG(dbgs() << " -> index:" << Ref
.Segment
<< "\n");
1436 report_fatal_error("don't yet support global/event aliases");
1440 // Finally, populate the symbol table itself, in its "natural" order.
1441 for (const MCSymbol
&S
: Asm
.symbols()) {
1442 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1443 if (!isInSymtab(WS
)) {
1444 WS
.setIndex(InvalidIndex
);
1447 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS
<< "\n");
1451 Flags
|= wasm::WASM_SYMBOL_BINDING_WEAK
;
1453 Flags
|= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN
;
1454 if (!WS
.isExternal() && WS
.isDefined())
1455 Flags
|= wasm::WASM_SYMBOL_BINDING_LOCAL
;
1456 if (WS
.isUndefined())
1457 Flags
|= wasm::WASM_SYMBOL_UNDEFINED
;
1458 if (WS
.isExported())
1459 Flags
|= wasm::WASM_SYMBOL_EXPORTED
;
1460 if (WS
.getName() != WS
.getImportName())
1461 Flags
|= wasm::WASM_SYMBOL_EXPLICIT_NAME
;
1463 wasm::WasmSymbolInfo Info
;
1464 Info
.Name
= WS
.getName();
1465 Info
.Kind
= WS
.getType();
1468 assert(WasmIndices
.count(&WS
) > 0);
1469 Info
.ElementIndex
= WasmIndices
.find(&WS
)->second
;
1470 } else if (WS
.isDefined()) {
1471 assert(DataLocations
.count(&WS
) > 0);
1472 Info
.DataRef
= DataLocations
.find(&WS
)->second
;
1474 WS
.setIndex(SymbolInfos
.size());
1475 SymbolInfos
.emplace_back(Info
);
1479 auto HandleReloc
= [&](const WasmRelocationEntry
&Rel
) {
1480 // Functions referenced by a relocation need to put in the table. This is
1481 // purely to make the object file's provisional values readable, and is
1482 // ignored by the linker, which re-calculates the relocations itself.
1483 if (Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_I32
&&
1484 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_SLEB
)
1486 assert(Rel
.Symbol
->isFunction());
1487 const MCSymbolWasm
&WS
= *resolveSymbol(*Rel
.Symbol
);
1488 uint32_t FunctionIndex
= WasmIndices
.find(&WS
)->second
;
1489 uint32_t TableIndex
= TableElems
.size() + InitialTableOffset
;
1490 if (TableIndices
.try_emplace(&WS
, TableIndex
).second
) {
1491 LLVM_DEBUG(dbgs() << " -> adding " << WS
.getName()
1492 << " to table: " << TableIndex
<< "\n");
1493 TableElems
.push_back(FunctionIndex
);
1494 registerFunctionType(WS
);
1498 for (const WasmRelocationEntry
&RelEntry
: CodeRelocations
)
1499 HandleReloc(RelEntry
);
1500 for (const WasmRelocationEntry
&RelEntry
: DataRelocations
)
1501 HandleReloc(RelEntry
);
1504 // Translate .init_array section contents into start functions.
1505 for (const MCSection
&S
: Asm
) {
1506 const auto &WS
= static_cast<const MCSectionWasm
&>(S
);
1507 if (WS
.getSectionName().startswith(".fini_array"))
1508 report_fatal_error(".fini_array sections are unsupported");
1509 if (!WS
.getSectionName().startswith(".init_array"))
1511 if (WS
.getFragmentList().empty())
1514 // init_array is expected to contain a single non-empty data fragment
1515 if (WS
.getFragmentList().size() != 3)
1516 report_fatal_error("only one .init_array section fragment supported");
1518 auto IT
= WS
.begin();
1519 const MCFragment
&EmptyFrag
= *IT
;
1520 if (EmptyFrag
.getKind() != MCFragment::FT_Data
)
1521 report_fatal_error(".init_array section should be aligned");
1524 const MCFragment
&AlignFrag
= *IT
;
1525 if (AlignFrag
.getKind() != MCFragment::FT_Align
)
1526 report_fatal_error(".init_array section should be aligned");
1527 if (cast
<MCAlignFragment
>(AlignFrag
).getAlignment() != (is64Bit() ? 8 : 4))
1528 report_fatal_error(".init_array section should be aligned for pointers");
1530 const MCFragment
&Frag
= *std::next(IT
);
1531 if (Frag
.hasInstructions() || Frag
.getKind() != MCFragment::FT_Data
)
1532 report_fatal_error("only data supported in .init_array section");
1534 uint16_t Priority
= UINT16_MAX
;
1535 unsigned PrefixLength
= strlen(".init_array");
1536 if (WS
.getSectionName().size() > PrefixLength
) {
1537 if (WS
.getSectionName()[PrefixLength
] != '.')
1539 ".init_array section priority should start with '.'");
1540 if (WS
.getSectionName()
1541 .substr(PrefixLength
+ 1)
1542 .getAsInteger(10, Priority
))
1543 report_fatal_error("invalid .init_array section priority");
1545 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
1546 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
1547 for (const uint8_t *
1548 P
= (const uint8_t *)Contents
.data(),
1549 *End
= (const uint8_t *)Contents
.data() + Contents
.size();
1552 report_fatal_error("non-symbolic data in .init_array section");
1554 for (const MCFixup
&Fixup
: DataFrag
.getFixups()) {
1555 assert(Fixup
.getKind() ==
1556 MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1557 const MCExpr
*Expr
= Fixup
.getValue();
1558 auto *Sym
= dyn_cast
<MCSymbolRefExpr
>(Expr
);
1560 report_fatal_error("fixups in .init_array should be symbol references");
1561 if (Sym
->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION
)
1562 report_fatal_error("symbols in .init_array should be for functions");
1563 if (Sym
->getSymbol().getIndex() == InvalidIndex
)
1564 report_fatal_error("symbols in .init_array should exist in symbtab");
1565 InitFuncs
.push_back(
1566 std::make_pair(Priority
, Sym
->getSymbol().getIndex()));
1570 // Write out the Wasm header.
1573 writeTypeSection(Signatures
);
1574 writeImportSection(Imports
, DataSize
, TableElems
.size());
1575 writeFunctionSection(Functions
);
1576 // Skip the "table" section; we import the table instead.
1577 // Skip the "memory" section; we import the memory instead.
1578 writeGlobalSection();
1579 writeEventSection(Events
);
1580 writeExportSection(Exports
);
1581 writeElemSection(TableElems
);
1582 writeCodeSection(Asm
, Layout
, Functions
);
1584 for (auto &CustomSection
: CustomSections
)
1585 writeCustomSection(CustomSection
, Asm
, Layout
);
1586 writeLinkingMetaDataSection(SymbolInfos
, InitFuncs
, Comdats
);
1587 writeRelocSection(CodeSectionIndex
, "CODE", CodeRelocations
);
1588 writeRelocSection(DataSectionIndex
, "DATA", DataRelocations
);
1589 writeCustomRelocSections();
1590 if (ProducersSection
)
1591 writeCustomSection(*ProducersSection
, Asm
, Layout
);
1593 // TODO: Translate the .comment section to the output.
1594 return W
.OS
.tell() - StartOffset
;
1597 std::unique_ptr
<MCObjectWriter
>
1598 llvm::createWasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
1599 raw_pwrite_stream
&OS
) {
1600 return llvm::make_unique
<WasmObjectWriter
>(std::move(MOTW
), OS
);