1 //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements Wasm object file writer information.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/SmallPtrSet.h"
16 #include "llvm/BinaryFormat/Wasm.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 kInitialTableOffset
= 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 contents of the section starts (after the header).
52 uint64_t ContentsOffset
;
55 // The signature of a wasm function, in a struct capable of being used as a
57 struct WasmFunctionType
{
58 // Support empty and tombstone instances, needed by DenseMap.
59 enum { Plain
, Empty
, Tombstone
} State
;
61 // The return types of the function.
62 SmallVector
<wasm::ValType
, 1> Returns
;
64 // The parameter types of the function.
65 SmallVector
<wasm::ValType
, 4> Params
;
67 WasmFunctionType() : State(Plain
) {}
69 bool operator==(const WasmFunctionType
&Other
) const {
70 return State
== Other
.State
&& Returns
== Other
.Returns
&&
71 Params
== Other
.Params
;
75 // Traits for using WasmFunctionType in a DenseMap.
76 struct WasmFunctionTypeDenseMapInfo
{
77 static WasmFunctionType
getEmptyKey() {
78 WasmFunctionType FuncTy
;
79 FuncTy
.State
= WasmFunctionType::Empty
;
82 static WasmFunctionType
getTombstoneKey() {
83 WasmFunctionType FuncTy
;
84 FuncTy
.State
= WasmFunctionType::Tombstone
;
87 static unsigned getHashValue(const WasmFunctionType
&FuncTy
) {
88 uintptr_t Value
= FuncTy
.State
;
89 for (wasm::ValType Ret
: FuncTy
.Returns
)
90 Value
+= DenseMapInfo
<int32_t>::getHashValue(int32_t(Ret
));
91 for (wasm::ValType Param
: FuncTy
.Params
)
92 Value
+= DenseMapInfo
<int32_t>::getHashValue(int32_t(Param
));
95 static bool isEqual(const WasmFunctionType
&LHS
,
96 const WasmFunctionType
&RHS
) {
101 // A wasm data segment. A wasm binary contains only a single data section
102 // but that can contain many segments, each with their own virtual location
103 // in memory. Each MCSection data created by llvm is modeled as its own
104 // wasm data segment.
105 struct WasmDataSegment
{
106 MCSectionWasm
*Section
;
111 SmallVector
<char, 4> Data
;
114 // A wasm function to be written into the function section.
115 struct WasmFunction
{
117 const MCSymbolWasm
*Sym
;
120 // A wasm global to be written into the global section.
122 wasm::WasmGlobalType Type
;
123 uint64_t InitialValue
;
126 // Information about a single item which is part of a COMDAT. For each data
127 // segment or function which is in the COMDAT, there is a corresponding
129 struct WasmComdatEntry
{
134 // Information about a single relocation.
135 struct WasmRelocationEntry
{
136 uint64_t Offset
; // Where is the relocation.
137 const MCSymbolWasm
*Symbol
; // The symbol to relocate with.
138 int64_t Addend
; // A value to add to the symbol.
139 unsigned Type
; // The type of the relocation.
140 const MCSectionWasm
*FixupSection
;// The section the relocation is targeting.
142 WasmRelocationEntry(uint64_t Offset
, const MCSymbolWasm
*Symbol
,
143 int64_t Addend
, unsigned Type
,
144 const MCSectionWasm
*FixupSection
)
145 : Offset(Offset
), Symbol(Symbol
), Addend(Addend
), Type(Type
),
146 FixupSection(FixupSection
) {}
148 bool hasAddend() const {
150 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB
:
151 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB
:
152 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32
:
159 void print(raw_ostream
&Out
) const {
160 Out
<< "Off=" << Offset
<< ", Sym=" << *Symbol
<< ", Addend=" << Addend
162 << ", FixupSection=" << FixupSection
->getSectionName();
165 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
166 LLVM_DUMP_METHOD
void dump() const { print(dbgs()); }
171 raw_ostream
&operator<<(raw_ostream
&OS
, const WasmRelocationEntry
&Rel
) {
177 class WasmObjectWriter
: public MCObjectWriter
{
178 /// The target specific Wasm writer instance.
179 std::unique_ptr
<MCWasmObjectTargetWriter
> TargetObjectWriter
;
181 // Relocations for fixing up references in the code section.
182 std::vector
<WasmRelocationEntry
> CodeRelocations
;
184 // Relocations for fixing up references in the data section.
185 std::vector
<WasmRelocationEntry
> DataRelocations
;
187 // Index values to use for fixing up call_indirect type indices.
188 // Maps function symbols to the index of the type of the function
189 DenseMap
<const MCSymbolWasm
*, uint32_t> TypeIndices
;
190 // Maps function symbols to the table element index space. Used
191 // for TABLE_INDEX relocation types (i.e. address taken functions).
192 DenseMap
<const MCSymbolWasm
*, uint32_t> TableIndices
;
193 // Maps function/global symbols to the (shared) Symbol index space.
194 DenseMap
<const MCSymbolWasm
*, uint32_t> SymbolIndices
;
195 // Maps function/global symbols to the function/global Wasm index space.
196 DenseMap
<const MCSymbolWasm
*, uint32_t> WasmIndices
;
197 // Maps data symbols to the Wasm segment and offset/size with the segment.
198 DenseMap
<const MCSymbolWasm
*, wasm::WasmDataReference
> DataLocations
;
200 DenseMap
<WasmFunctionType
, int32_t, WasmFunctionTypeDenseMapInfo
>
202 SmallVector
<WasmFunctionType
, 4> FunctionTypes
;
203 SmallVector
<WasmGlobal
, 4> Globals
;
204 SmallVector
<WasmDataSegment
, 4> DataSegments
;
205 unsigned NumFunctionImports
= 0;
206 unsigned NumGlobalImports
= 0;
208 // TargetObjectWriter wrappers.
209 bool is64Bit() const { return TargetObjectWriter
->is64Bit(); }
210 unsigned getRelocType(const MCValue
&Target
, const MCFixup
&Fixup
) const {
211 return TargetObjectWriter
->getRelocType(Target
, Fixup
);
214 void startSection(SectionBookkeeping
&Section
, unsigned SectionId
,
215 const char *Name
= nullptr);
216 void endSection(SectionBookkeeping
&Section
);
219 WasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
220 raw_pwrite_stream
&OS
)
221 : MCObjectWriter(OS
, /*IsLittleEndian=*/true),
222 TargetObjectWriter(std::move(MOTW
)) {}
224 ~WasmObjectWriter() override
;
227 void reset() override
{
228 CodeRelocations
.clear();
229 DataRelocations
.clear();
231 SymbolIndices
.clear();
233 TableIndices
.clear();
234 DataLocations
.clear();
235 FunctionTypeIndices
.clear();
236 FunctionTypes
.clear();
238 DataSegments
.clear();
239 MCObjectWriter::reset();
240 NumFunctionImports
= 0;
241 NumGlobalImports
= 0;
244 void writeHeader(const MCAssembler
&Asm
);
246 void recordRelocation(MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
247 const MCFragment
*Fragment
, const MCFixup
&Fixup
,
248 MCValue Target
, uint64_t &FixedValue
) override
;
250 void executePostLayoutBinding(MCAssembler
&Asm
,
251 const MCAsmLayout
&Layout
) override
;
253 void writeObject(MCAssembler
&Asm
, const MCAsmLayout
&Layout
) override
;
255 void writeString(const StringRef Str
) {
256 encodeULEB128(Str
.size(), getStream());
260 void writeValueType(wasm::ValType Ty
) {
261 encodeSLEB128(int32_t(Ty
), getStream());
264 void writeTypeSection(ArrayRef
<WasmFunctionType
> FunctionTypes
);
265 void writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
, uint32_t DataSize
,
266 uint32_t NumElements
);
267 void writeFunctionSection(ArrayRef
<WasmFunction
> Functions
);
268 void writeGlobalSection();
269 void writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
);
270 void writeElemSection(ArrayRef
<uint32_t> TableElems
);
271 void writeCodeSection(const MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
272 ArrayRef
<WasmFunction
> Functions
);
273 void writeDataSection();
274 void writeCodeRelocSection();
275 void writeDataRelocSection();
276 void writeLinkingMetaDataSection(
277 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
278 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
279 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
);
281 uint32_t getProvisionalValue(const WasmRelocationEntry
&RelEntry
);
282 void applyRelocations(ArrayRef
<WasmRelocationEntry
> Relocations
,
283 uint64_t ContentsOffset
);
285 void writeRelocations(ArrayRef
<WasmRelocationEntry
> Relocations
);
286 uint32_t getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
);
287 uint32_t getFunctionType(const MCSymbolWasm
& Symbol
);
288 uint32_t registerFunctionType(const MCSymbolWasm
& Symbol
);
291 } // end anonymous namespace
293 WasmObjectWriter::~WasmObjectWriter() {}
295 // Write out a section header and a patchable section size field.
296 void WasmObjectWriter::startSection(SectionBookkeeping
&Section
,
299 assert((Name
!= nullptr) == (SectionId
== wasm::WASM_SEC_CUSTOM
) &&
300 "Only custom sections can have names");
302 DEBUG(dbgs() << "startSection " << SectionId
<< ": " << Name
<< "\n");
303 encodeULEB128(SectionId
, getStream());
305 Section
.SizeOffset
= getStream().tell();
307 // The section size. We don't know the size yet, so reserve enough space
308 // for any 32-bit value; we'll patch it later.
309 encodeULEB128(UINT32_MAX
, getStream());
311 // The position where the section starts, for measuring its size.
312 Section
.ContentsOffset
= getStream().tell();
314 // Custom sections in wasm also have a string identifier.
315 if (SectionId
== wasm::WASM_SEC_CUSTOM
) {
317 writeString(StringRef(Name
));
321 // Now that the section is complete and we know how big it is, patch up the
322 // section size field at the start of the section.
323 void WasmObjectWriter::endSection(SectionBookkeeping
&Section
) {
324 uint64_t Size
= getStream().tell() - Section
.ContentsOffset
;
325 if (uint32_t(Size
) != Size
)
326 report_fatal_error("section size does not fit in a uint32_t");
328 DEBUG(dbgs() << "endSection size=" << Size
<< "\n");
330 // Write the final section size to the payload_len field, which follows
331 // the section id byte.
333 unsigned SizeLen
= encodeULEB128(Size
, Buffer
, 5);
334 assert(SizeLen
== 5);
335 getStream().pwrite((char *)Buffer
, SizeLen
, Section
.SizeOffset
);
338 // Emit the Wasm header.
339 void WasmObjectWriter::writeHeader(const MCAssembler
&Asm
) {
340 writeBytes(StringRef(wasm::WasmMagic
, sizeof(wasm::WasmMagic
)));
341 writeLE32(wasm::WasmVersion
);
344 void WasmObjectWriter::executePostLayoutBinding(MCAssembler
&Asm
,
345 const MCAsmLayout
&Layout
) {
348 void WasmObjectWriter::recordRelocation(MCAssembler
&Asm
,
349 const MCAsmLayout
&Layout
,
350 const MCFragment
*Fragment
,
351 const MCFixup
&Fixup
, MCValue Target
,
352 uint64_t &FixedValue
) {
353 MCAsmBackend
&Backend
= Asm
.getBackend();
354 bool IsPCRel
= Backend
.getFixupKindInfo(Fixup
.getKind()).Flags
&
355 MCFixupKindInfo::FKF_IsPCRel
;
356 const auto &FixupSection
= cast
<MCSectionWasm
>(*Fragment
->getParent());
357 uint64_t C
= Target
.getConstant();
358 uint64_t FixupOffset
= Layout
.getFragmentOffset(Fragment
) + Fixup
.getOffset();
359 MCContext
&Ctx
= Asm
.getContext();
361 // The .init_array isn't translated as data, so don't do relocations in it.
362 if (FixupSection
.getSectionName().startswith(".init_array"))
365 // TODO(sbc): Add support for debug sections.
366 if (FixupSection
.getKind().isMetadata())
369 if (const MCSymbolRefExpr
*RefB
= Target
.getSymB()) {
370 assert(RefB
->getKind() == MCSymbolRefExpr::VK_None
&&
371 "Should not have constructed this");
373 // Let A, B and C being the components of Target and R be the location of
374 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
375 // If it is pcrel, we want to compute (A - B + C - R).
377 // In general, Wasm has no relocations for -B. It can only represent (A + C)
378 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
379 // replace B to implement it: (A - R - K + C)
383 "No relocation available to represent this relative expression");
387 const auto &SymB
= cast
<MCSymbolWasm
>(RefB
->getSymbol());
389 if (SymB
.isUndefined()) {
390 Ctx
.reportError(Fixup
.getLoc(),
391 Twine("symbol '") + SymB
.getName() +
392 "' can not be undefined in a subtraction expression");
396 assert(!SymB
.isAbsolute() && "Should have been folded");
397 const MCSection
&SecB
= SymB
.getSection();
398 if (&SecB
!= &FixupSection
) {
399 Ctx
.reportError(Fixup
.getLoc(),
400 "Cannot represent a difference across sections");
404 uint64_t SymBOffset
= Layout
.getSymbolOffset(SymB
);
405 uint64_t K
= SymBOffset
- FixupOffset
;
410 // We either rejected the fixup or folded B into C at this point.
411 const MCSymbolRefExpr
*RefA
= Target
.getSymA();
412 const auto *SymA
= RefA
? cast
<MCSymbolWasm
>(&RefA
->getSymbol()) : nullptr;
414 if (SymA
&& SymA
->isVariable()) {
415 const MCExpr
*Expr
= SymA
->getVariableValue();
416 const auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
417 if (Inner
->getKind() == MCSymbolRefExpr::VK_WEAKREF
)
418 llvm_unreachable("weakref used in reloc not yet implemented");
421 // Put any constant offset in an addend. Offsets can be negative, and
422 // LLVM expects wrapping, in contrast to wasm's immediates which can't
423 // be negative and don't wrap.
427 SymA
->setUsedInReloc();
432 unsigned Type
= getRelocType(Target
, Fixup
);
434 WasmRelocationEntry
Rec(FixupOffset
, SymA
, C
, Type
, &FixupSection
);
435 DEBUG(dbgs() << "WasmReloc: " << Rec
<< "\n");
437 // Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are currently required
438 // to be against a named symbol.
439 // TODO(sbc): Add support for relocations against unnamed temporaries such
440 // as those generated by llvm's `blockaddress`.
441 // See: test/MC/WebAssembly/blockaddress.ll
442 if (SymA
->getName().empty() && Type
!= wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB
)
443 report_fatal_error("relocations against un-named temporaries are not yet "
444 "supported by wasm");
446 if (FixupSection
.isWasmData())
447 DataRelocations
.push_back(Rec
);
448 else if (FixupSection
.getKind().isText())
449 CodeRelocations
.push_back(Rec
);
451 llvm_unreachable("unexpected section type");
454 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded
455 // to allow patching.
457 WritePatchableLEB(raw_pwrite_stream
&Stream
, uint32_t X
, uint64_t Offset
) {
459 unsigned SizeLen
= encodeULEB128(X
, Buffer
, 5);
460 assert(SizeLen
== 5);
461 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
464 // Write X as an signed LEB value at offset Offset in Stream, padded
465 // to allow patching.
467 WritePatchableSLEB(raw_pwrite_stream
&Stream
, int32_t X
, uint64_t Offset
) {
469 unsigned SizeLen
= encodeSLEB128(X
, Buffer
, 5);
470 assert(SizeLen
== 5);
471 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
474 // Write X as a plain integer value at offset Offset in Stream.
475 static void WriteI32(raw_pwrite_stream
&Stream
, uint32_t X
, uint64_t Offset
) {
477 support::endian::write32le(Buffer
, X
);
478 Stream
.pwrite((char *)Buffer
, sizeof(Buffer
), Offset
);
481 static const MCSymbolWasm
* ResolveSymbol(const MCSymbolWasm
& Symbol
) {
482 if (Symbol
.isVariable()) {
483 const MCExpr
*Expr
= Symbol
.getVariableValue();
484 auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
485 return cast
<MCSymbolWasm
>(&Inner
->getSymbol());
490 // Compute a value to write into the code at the location covered
491 // by RelEntry. This value isn't used by the static linker; it just serves
492 // to make the object format more readable and more likely to be directly
495 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry
&RelEntry
) {
496 switch (RelEntry
.Type
) {
497 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB
:
498 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32
: {
499 // Provisional value is table address of the resolved symbol itself
500 const MCSymbolWasm
*Sym
= ResolveSymbol(*RelEntry
.Symbol
);
501 assert(Sym
->isFunction());
502 return TableIndices
[Sym
];
504 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB
:
505 // Provisional value is same as the index
506 return getRelocationIndexValue(RelEntry
);
507 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB
:
508 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB
:
509 // Provisional value is function/global Wasm index
510 if (!WasmIndices
.count(RelEntry
.Symbol
))
511 report_fatal_error("symbol not found in wasm index space: " +
512 RelEntry
.Symbol
->getName());
513 return WasmIndices
[RelEntry
.Symbol
];
514 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB
:
515 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32
:
516 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB
: {
517 // Provisional value is address of the global
518 const MCSymbolWasm
*Sym
= ResolveSymbol(*RelEntry
.Symbol
);
519 // For undefined symbols, use zero
520 if (!Sym
->isDefined())
522 const wasm::WasmDataReference
&Ref
= DataLocations
[Sym
];
523 const WasmDataSegment
&Segment
= DataSegments
[Ref
.Segment
];
524 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
525 return Segment
.Offset
+ Ref
.Offset
+ RelEntry
.Addend
;
528 llvm_unreachable("invalid relocation type");
532 static void addData(SmallVectorImpl
<char> &DataBytes
,
533 MCSectionWasm
&DataSection
) {
534 DEBUG(errs() << "addData: " << DataSection
.getSectionName() << "\n");
536 DataBytes
.resize(alignTo(DataBytes
.size(), DataSection
.getAlignment()));
538 for (const MCFragment
&Frag
: DataSection
) {
539 if (Frag
.hasInstructions())
540 report_fatal_error("only data supported in data sections");
542 if (auto *Align
= dyn_cast
<MCAlignFragment
>(&Frag
)) {
543 if (Align
->getValueSize() != 1)
544 report_fatal_error("only byte values supported for alignment");
545 // If nops are requested, use zeros, as this is the data section.
546 uint8_t Value
= Align
->hasEmitNops() ? 0 : Align
->getValue();
547 uint64_t Size
= std::min
<uint64_t>(alignTo(DataBytes
.size(),
548 Align
->getAlignment()),
550 Align
->getMaxBytesToEmit());
551 DataBytes
.resize(Size
, Value
);
552 } else if (auto *Fill
= dyn_cast
<MCFillFragment
>(&Frag
)) {
554 if (!Fill
->getSize().evaluateAsAbsolute(Size
))
555 llvm_unreachable("The fill should be an assembler constant");
556 DataBytes
.insert(DataBytes
.end(), Size
, Fill
->getValue());
558 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
559 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
561 DataBytes
.insert(DataBytes
.end(), Contents
.begin(), Contents
.end());
565 DEBUG(dbgs() << "addData -> " << DataBytes
.size() << "\n");
569 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
) {
570 if (RelEntry
.Type
== wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB
) {
571 if (!TypeIndices
.count(RelEntry
.Symbol
))
572 report_fatal_error("symbol not found in type index space: " +
573 RelEntry
.Symbol
->getName());
574 return TypeIndices
[RelEntry
.Symbol
];
577 if (!SymbolIndices
.count(RelEntry
.Symbol
))
578 report_fatal_error("symbol not found in symbol index space: " +
579 RelEntry
.Symbol
->getName());
580 return SymbolIndices
[RelEntry
.Symbol
];
583 // Apply the portions of the relocation records that we can handle ourselves
585 void WasmObjectWriter::applyRelocations(
586 ArrayRef
<WasmRelocationEntry
> Relocations
, uint64_t ContentsOffset
) {
587 raw_pwrite_stream
&Stream
= getStream();
588 for (const WasmRelocationEntry
&RelEntry
: Relocations
) {
589 uint64_t Offset
= ContentsOffset
+
590 RelEntry
.FixupSection
->getSectionOffset() +
593 DEBUG(dbgs() << "applyRelocation: " << RelEntry
<< "\n");
594 uint32_t Value
= getProvisionalValue(RelEntry
);
596 switch (RelEntry
.Type
) {
597 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB
:
598 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB
:
599 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB
:
600 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB
:
601 WritePatchableLEB(Stream
, Value
, Offset
);
603 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32
:
604 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32
:
605 WriteI32(Stream
, Value
, Offset
);
607 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB
:
608 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB
:
609 WritePatchableSLEB(Stream
, Value
, Offset
);
612 llvm_unreachable("invalid relocation type");
617 // Write out the portions of the relocation records that the linker will
619 void WasmObjectWriter::writeRelocations(
620 ArrayRef
<WasmRelocationEntry
> Relocations
) {
621 raw_pwrite_stream
&Stream
= getStream();
622 for (const WasmRelocationEntry
& RelEntry
: Relocations
) {
624 uint64_t Offset
= RelEntry
.Offset
+
625 RelEntry
.FixupSection
->getSectionOffset();
626 uint32_t Index
= getRelocationIndexValue(RelEntry
);
628 encodeULEB128(RelEntry
.Type
, Stream
);
629 encodeULEB128(Offset
, Stream
);
630 encodeULEB128(Index
, Stream
);
631 if (RelEntry
.hasAddend())
632 encodeSLEB128(RelEntry
.Addend
, Stream
);
636 void WasmObjectWriter::writeTypeSection(
637 ArrayRef
<WasmFunctionType
> FunctionTypes
) {
638 if (FunctionTypes
.empty())
641 SectionBookkeeping Section
;
642 startSection(Section
, wasm::WASM_SEC_TYPE
);
644 encodeULEB128(FunctionTypes
.size(), getStream());
646 for (const WasmFunctionType
&FuncTy
: FunctionTypes
) {
647 encodeSLEB128(wasm::WASM_TYPE_FUNC
, getStream());
648 encodeULEB128(FuncTy
.Params
.size(), getStream());
649 for (wasm::ValType Ty
: FuncTy
.Params
)
651 encodeULEB128(FuncTy
.Returns
.size(), getStream());
652 for (wasm::ValType Ty
: FuncTy
.Returns
)
659 void WasmObjectWriter::writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
,
661 uint32_t NumElements
) {
665 uint32_t NumPages
= (DataSize
+ wasm::WasmPageSize
- 1) / wasm::WasmPageSize
;
667 SectionBookkeeping Section
;
668 startSection(Section
, wasm::WASM_SEC_IMPORT
);
670 encodeULEB128(Imports
.size(), getStream());
671 for (const wasm::WasmImport
&Import
: Imports
) {
672 writeString(Import
.Module
);
673 writeString(Import
.Field
);
674 encodeULEB128(Import
.Kind
, getStream());
676 switch (Import
.Kind
) {
677 case wasm::WASM_EXTERNAL_FUNCTION
:
678 encodeULEB128(Import
.SigIndex
, getStream());
680 case wasm::WASM_EXTERNAL_GLOBAL
:
681 encodeSLEB128(Import
.Global
.Type
, getStream());
682 encodeULEB128(uint32_t(Import
.Global
.Mutable
), getStream());
684 case wasm::WASM_EXTERNAL_MEMORY
:
685 encodeULEB128(0, getStream()); // flags
686 encodeULEB128(NumPages
, getStream()); // initial
688 case wasm::WASM_EXTERNAL_TABLE
:
689 encodeSLEB128(Import
.Table
.ElemType
, getStream());
690 encodeULEB128(0, getStream()); // flags
691 encodeULEB128(NumElements
, getStream()); // initial
694 llvm_unreachable("unsupported import kind");
701 void WasmObjectWriter::writeFunctionSection(ArrayRef
<WasmFunction
> Functions
) {
702 if (Functions
.empty())
705 SectionBookkeeping Section
;
706 startSection(Section
, wasm::WASM_SEC_FUNCTION
);
708 encodeULEB128(Functions
.size(), getStream());
709 for (const WasmFunction
&Func
: Functions
)
710 encodeULEB128(Func
.Type
, getStream());
715 void WasmObjectWriter::writeGlobalSection() {
719 SectionBookkeeping Section
;
720 startSection(Section
, wasm::WASM_SEC_GLOBAL
);
722 encodeULEB128(Globals
.size(), getStream());
723 for (const WasmGlobal
&Global
: Globals
) {
724 writeValueType(static_cast<wasm::ValType
>(Global
.Type
.Type
));
725 write8(Global
.Type
.Mutable
);
727 write8(wasm::WASM_OPCODE_I32_CONST
);
728 encodeSLEB128(Global
.InitialValue
, getStream());
729 write8(wasm::WASM_OPCODE_END
);
735 void WasmObjectWriter::writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
) {
739 SectionBookkeeping Section
;
740 startSection(Section
, wasm::WASM_SEC_EXPORT
);
742 encodeULEB128(Exports
.size(), getStream());
743 for (const wasm::WasmExport
&Export
: Exports
) {
744 writeString(Export
.Name
);
745 encodeSLEB128(Export
.Kind
, getStream());
746 encodeULEB128(Export
.Index
, getStream());
752 void WasmObjectWriter::writeElemSection(ArrayRef
<uint32_t> TableElems
) {
753 if (TableElems
.empty())
756 SectionBookkeeping Section
;
757 startSection(Section
, wasm::WASM_SEC_ELEM
);
759 encodeULEB128(1, getStream()); // number of "segments"
760 encodeULEB128(0, getStream()); // the table index
762 // init expr for starting offset
763 write8(wasm::WASM_OPCODE_I32_CONST
);
764 encodeSLEB128(kInitialTableOffset
, getStream());
765 write8(wasm::WASM_OPCODE_END
);
767 encodeULEB128(TableElems
.size(), getStream());
768 for (uint32_t Elem
: TableElems
)
769 encodeULEB128(Elem
, getStream());
774 void WasmObjectWriter::writeCodeSection(const MCAssembler
&Asm
,
775 const MCAsmLayout
&Layout
,
776 ArrayRef
<WasmFunction
> Functions
) {
777 if (Functions
.empty())
780 SectionBookkeeping Section
;
781 startSection(Section
, wasm::WASM_SEC_CODE
);
783 encodeULEB128(Functions
.size(), getStream());
785 for (const WasmFunction
&Func
: Functions
) {
786 auto &FuncSection
= static_cast<MCSectionWasm
&>(Func
.Sym
->getSection());
789 if (!Func
.Sym
->getSize()->evaluateAsAbsolute(Size
, Layout
))
790 report_fatal_error(".size expression must be evaluatable");
792 encodeULEB128(Size
, getStream());
793 FuncSection
.setSectionOffset(getStream().tell() - Section
.ContentsOffset
);
794 Asm
.writeSectionData(&FuncSection
, Layout
);
798 applyRelocations(CodeRelocations
, Section
.ContentsOffset
);
803 void WasmObjectWriter::writeDataSection() {
804 if (DataSegments
.empty())
807 SectionBookkeeping Section
;
808 startSection(Section
, wasm::WASM_SEC_DATA
);
810 encodeULEB128(DataSegments
.size(), getStream()); // count
812 for (const WasmDataSegment
&Segment
: DataSegments
) {
813 encodeULEB128(0, getStream()); // memory index
814 write8(wasm::WASM_OPCODE_I32_CONST
);
815 encodeSLEB128(Segment
.Offset
, getStream()); // offset
816 write8(wasm::WASM_OPCODE_END
);
817 encodeULEB128(Segment
.Data
.size(), getStream()); // size
818 Segment
.Section
->setSectionOffset(getStream().tell() - Section
.ContentsOffset
);
819 writeBytes(Segment
.Data
); // data
823 applyRelocations(DataRelocations
, Section
.ContentsOffset
);
828 void WasmObjectWriter::writeCodeRelocSection() {
829 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
830 // for descriptions of the reloc sections.
832 if (CodeRelocations
.empty())
835 SectionBookkeeping Section
;
836 startSection(Section
, wasm::WASM_SEC_CUSTOM
, "reloc.CODE");
838 encodeULEB128(wasm::WASM_SEC_CODE
, getStream());
839 encodeULEB128(CodeRelocations
.size(), getStream());
841 writeRelocations(CodeRelocations
);
846 void WasmObjectWriter::writeDataRelocSection() {
847 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
848 // for descriptions of the reloc sections.
850 if (DataRelocations
.empty())
853 SectionBookkeeping Section
;
854 startSection(Section
, wasm::WASM_SEC_CUSTOM
, "reloc.DATA");
856 encodeULEB128(wasm::WASM_SEC_DATA
, getStream());
857 encodeULEB128(DataRelocations
.size(), getStream());
859 writeRelocations(DataRelocations
);
864 void WasmObjectWriter::writeLinkingMetaDataSection(
865 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
866 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
867 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
) {
868 SectionBookkeeping Section
;
869 startSection(Section
, wasm::WASM_SEC_CUSTOM
, "linking");
870 SectionBookkeeping SubSection
;
872 if (SymbolInfos
.size() != 0) {
873 startSection(SubSection
, wasm::WASM_SYMBOL_TABLE
);
874 encodeULEB128(SymbolInfos
.size(), getStream());
875 for (const wasm::WasmSymbolInfo
&Sym
: SymbolInfos
) {
876 encodeULEB128(Sym
.Kind
, getStream());
877 encodeULEB128(Sym
.Flags
, getStream());
879 case wasm::WASM_SYMBOL_TYPE_FUNCTION
:
880 case wasm::WASM_SYMBOL_TYPE_GLOBAL
:
881 encodeULEB128(Sym
.ElementIndex
, getStream());
882 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0)
883 writeString(Sym
.Name
);
885 case wasm::WASM_SYMBOL_TYPE_DATA
:
886 writeString(Sym
.Name
);
887 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0) {
888 encodeULEB128(Sym
.DataRef
.Segment
, getStream());
889 encodeULEB128(Sym
.DataRef
.Offset
, getStream());
890 encodeULEB128(Sym
.DataRef
.Size
, getStream());
894 llvm_unreachable("unexpected kind");
897 endSection(SubSection
);
900 if (DataSegments
.size()) {
901 startSection(SubSection
, wasm::WASM_SEGMENT_INFO
);
902 encodeULEB128(DataSegments
.size(), getStream());
903 for (const WasmDataSegment
&Segment
: DataSegments
) {
904 writeString(Segment
.Name
);
905 encodeULEB128(Segment
.Alignment
, getStream());
906 encodeULEB128(Segment
.Flags
, getStream());
908 endSection(SubSection
);
911 if (!InitFuncs
.empty()) {
912 startSection(SubSection
, wasm::WASM_INIT_FUNCS
);
913 encodeULEB128(InitFuncs
.size(), getStream());
914 for (auto &StartFunc
: InitFuncs
) {
915 encodeULEB128(StartFunc
.first
, getStream()); // priority
916 encodeULEB128(StartFunc
.second
, getStream()); // function index
918 endSection(SubSection
);
921 if (Comdats
.size()) {
922 startSection(SubSection
, wasm::WASM_COMDAT_INFO
);
923 encodeULEB128(Comdats
.size(), getStream());
924 for (const auto &C
: Comdats
) {
925 writeString(C
.first
);
926 encodeULEB128(0, getStream()); // flags for future use
927 encodeULEB128(C
.second
.size(), getStream());
928 for (const WasmComdatEntry
&Entry
: C
.second
) {
929 encodeULEB128(Entry
.Kind
, getStream());
930 encodeULEB128(Entry
.Index
, getStream());
933 endSection(SubSection
);
939 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm
& Symbol
) {
940 assert(Symbol
.isFunction());
941 assert(TypeIndices
.count(&Symbol
));
942 return TypeIndices
[&Symbol
];
945 uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm
& Symbol
) {
946 assert(Symbol
.isFunction());
949 const MCSymbolWasm
* ResolvedSym
= ResolveSymbol(Symbol
);
950 F
.Returns
= ResolvedSym
->getReturns();
951 F
.Params
= ResolvedSym
->getParams();
954 FunctionTypeIndices
.insert(std::make_pair(F
, FunctionTypes
.size()));
956 FunctionTypes
.push_back(F
);
957 TypeIndices
[&Symbol
] = Pair
.first
->second
;
959 DEBUG(dbgs() << "registerFunctionType: " << Symbol
<< " new:" << Pair
.second
<< "\n");
960 DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
961 return Pair
.first
->second
;
964 void WasmObjectWriter::writeObject(MCAssembler
&Asm
,
965 const MCAsmLayout
&Layout
) {
966 DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
967 MCContext
&Ctx
= Asm
.getContext();
969 // Collect information from the available symbols.
970 SmallVector
<WasmFunction
, 4> Functions
;
971 SmallVector
<uint32_t, 4> TableElems
;
972 SmallVector
<wasm::WasmImport
, 4> Imports
;
973 SmallVector
<wasm::WasmExport
, 4> Exports
;
974 SmallVector
<wasm::WasmSymbolInfo
, 4> SymbolInfos
;
975 SmallVector
<std::pair
<uint16_t, uint32_t>, 2> InitFuncs
;
976 std::map
<StringRef
, std::vector
<WasmComdatEntry
>> Comdats
;
977 unsigned NumSymbols
= 0;
978 uint32_t DataSize
= 0;
980 auto AddSymbol
= [&](const MCSymbolWasm
&WS
) {
983 Flags
|= wasm::WASM_SYMBOL_BINDING_WEAK
;
985 Flags
|= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN
;
986 if (!WS
.isExternal() && WS
.isDefined())
987 Flags
|= wasm::WASM_SYMBOL_BINDING_LOCAL
;
988 if (WS
.isUndefined())
989 Flags
|= wasm::WASM_SYMBOL_UNDEFINED
;
991 wasm::WasmSymbolInfo Info
;
992 Info
.Name
= WS
.getName();
993 Info
.Kind
= WS
.getType();
996 Info
.ElementIndex
= WasmIndices
[&WS
];
997 else if (WS
.isDefined())
998 Info
.DataRef
= DataLocations
[&WS
];
999 SymbolInfos
.emplace_back(Info
);
1000 SymbolIndices
[&WS
] = NumSymbols
++;
1003 // For now, always emit the memory import, since loads and stores are not
1004 // valid without it. In the future, we could perhaps be more clever and omit
1005 // it if there are no loads or stores.
1006 MCSymbolWasm
*MemorySym
=
1007 cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol("__linear_memory"));
1008 wasm::WasmImport MemImport
;
1009 MemImport
.Module
= MemorySym
->getModuleName();
1010 MemImport
.Field
= MemorySym
->getName();
1011 MemImport
.Kind
= wasm::WASM_EXTERNAL_MEMORY
;
1012 Imports
.push_back(MemImport
);
1014 // For now, always emit the table section, since indirect calls are not
1015 // valid without it. In the future, we could perhaps be more clever and omit
1016 // it if there are no indirect calls.
1017 MCSymbolWasm
*TableSym
=
1018 cast
<MCSymbolWasm
>(Ctx
.getOrCreateSymbol("__indirect_function_table"));
1019 wasm::WasmImport TableImport
;
1020 TableImport
.Module
= TableSym
->getModuleName();
1021 TableImport
.Field
= TableSym
->getName();
1022 TableImport
.Kind
= wasm::WASM_EXTERNAL_TABLE
;
1023 TableImport
.Table
.ElemType
= wasm::WASM_TYPE_ANYFUNC
;
1024 Imports
.push_back(TableImport
);
1026 // Populate FunctionTypeIndices and Imports.
1027 for (const MCSymbol
&S
: Asm
.symbols()) {
1028 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1030 // Register types for all functions, including those with private linkage
1031 // (because wasm always needs a type signature).
1032 if (WS
.isFunction())
1033 registerFunctionType(WS
);
1035 if (WS
.isTemporary())
1038 // If the symbol is not defined in this translation unit, import it.
1039 if (!WS
.isDefined() && !WS
.isComdat()) {
1040 if (WS
.isFunction()) {
1041 wasm::WasmImport Import
;
1042 Import
.Module
= WS
.getModuleName();
1043 Import
.Field
= WS
.getName();
1044 Import
.Kind
= wasm::WASM_EXTERNAL_FUNCTION
;
1045 Import
.SigIndex
= getFunctionType(WS
);
1046 Imports
.push_back(Import
);
1047 WasmIndices
[&WS
] = NumFunctionImports
++;
1048 } else if (WS
.isGlobal()) {
1049 wasm::WasmImport Import
;
1050 Import
.Module
= WS
.getModuleName();
1051 Import
.Field
= WS
.getName();
1052 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1053 Import
.Global
= WS
.getGlobalType();
1054 Imports
.push_back(Import
);
1055 WasmIndices
[&WS
] = NumGlobalImports
++;
1058 // TODO(ncw) We shouldn't be adding the symbol to the symbol table here!
1059 // Instead it should be done by removing the "if (WS.isDefined())" block
1060 // in the big loop below (line ~1284). However - that would reorder all
1061 // the symbols and thus require all the tests to be updated. I think it's
1062 // better to make that change therefore in a future commit, to isolate
1063 // each test update from the change that caused it.
1068 for (MCSection
&Sec
: Asm
) {
1069 auto &Section
= static_cast<MCSectionWasm
&>(Sec
);
1070 if (!Section
.isWasmData())
1073 // .init_array sections are handled specially elsewhere.
1074 if (cast
<MCSectionWasm
>(Sec
).getSectionName().startswith(".init_array"))
1077 uint32_t SegmentIndex
= DataSegments
.size();
1078 DataSize
= alignTo(DataSize
, Section
.getAlignment());
1079 DataSegments
.emplace_back();
1080 WasmDataSegment
&Segment
= DataSegments
.back();
1081 Segment
.Name
= Section
.getSectionName();
1082 Segment
.Offset
= DataSize
;
1083 Segment
.Section
= &Section
;
1084 addData(Segment
.Data
, Section
);
1085 Segment
.Alignment
= Section
.getAlignment();
1087 DataSize
+= Segment
.Data
.size();
1088 Section
.setSegmentIndex(SegmentIndex
);
1090 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1091 Comdats
[C
->getName()].emplace_back(
1092 WasmComdatEntry
{wasm::WASM_COMDAT_DATA
, SegmentIndex
});
1096 // Handle regular defined and undefined symbols.
1097 for (const MCSymbol
&S
: Asm
.symbols()) {
1098 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1099 // or used in relocations.
1100 if (S
.isTemporary() && S
.getName().empty())
1103 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1104 DEBUG(dbgs() << "MCSymbol: '" << S
<< "'"
1105 << " isDefined=" << S
.isDefined()
1106 << " isExternal=" << S
.isExternal()
1107 << " isTemporary=" << S
.isTemporary()
1108 << " isFunction=" << WS
.isFunction()
1109 << " isWeak=" << WS
.isWeak()
1110 << " isHidden=" << WS
.isHidden()
1111 << " isVariable=" << WS
.isVariable() << "\n");
1113 if (WS
.isVariable())
1115 if (WS
.isComdat() && !WS
.isDefined())
1118 if (WS
.isFunction()) {
1120 if (WS
.isDefined()) {
1121 if (WS
.getOffset() != 0)
1123 "function sections must contain one function each");
1125 if (WS
.getSize() == 0)
1127 "function symbols must have a size set with .size");
1129 // A definition. Write out the function body.
1130 Index
= NumFunctionImports
+ Functions
.size();
1132 Func
.Type
= getFunctionType(WS
);
1134 WasmIndices
[&WS
] = Index
;
1135 Functions
.push_back(Func
);
1137 auto &Section
= static_cast<MCSectionWasm
&>(WS
.getSection());
1138 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1139 Comdats
[C
->getName()].emplace_back(
1140 WasmComdatEntry
{wasm::WASM_COMDAT_FUNCTION
, Index
});
1143 // An import; the index was assigned above.
1144 Index
= WasmIndices
.find(&WS
)->second
;
1147 DEBUG(dbgs() << " -> function index: " << Index
<< "\n");
1148 } else if (WS
.isData()) {
1149 if (WS
.isTemporary() && !WS
.getSize())
1152 if (!WS
.isDefined()) {
1153 DEBUG(dbgs() << " -> segment index: -1");
1158 report_fatal_error("data symbols must have a size set with .size: " +
1162 if (!WS
.getSize()->evaluateAsAbsolute(Size
, Layout
))
1163 report_fatal_error(".size expression must be evaluatable");
1165 auto &DataSection
= static_cast<MCSectionWasm
&>(WS
.getSection());
1166 assert(DataSection
.isWasmData());
1168 // For each data symbol, export it in the symtab as a reference to the
1169 // corresponding Wasm data segment.
1170 wasm::WasmDataReference Ref
= wasm::WasmDataReference
{
1171 DataSection
.getSegmentIndex(),
1172 static_cast<uint32_t>(Layout
.getSymbolOffset(WS
)),
1173 static_cast<uint32_t>(Size
)};
1174 DataLocations
[&WS
] = Ref
;
1175 DEBUG(dbgs() << " -> segment index: " << Ref
.Segment
);
1177 // A "true" Wasm global (currently just __stack_pointer)
1179 report_fatal_error("don't yet support defined globals");
1181 // An import; the index was assigned above
1182 DEBUG(dbgs() << " -> global index: " << WasmIndices
.find(&WS
)->second
1190 // Handle weak aliases. We need to process these in a separate pass because
1191 // we need to have processed the target of the alias before the alias itself
1192 // and the symbols are not necessarily ordered in this way.
1193 for (const MCSymbol
&S
: Asm
.symbols()) {
1194 if (!S
.isVariable())
1197 assert(S
.isDefined());
1199 // Find the target symbol of this weak alias and export that index
1200 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1201 const MCSymbolWasm
*ResolvedSym
= ResolveSymbol(WS
);
1202 DEBUG(dbgs() << WS
.getName() << ": weak alias of '" << *ResolvedSym
<< "'\n");
1204 if (WS
.isFunction()) {
1205 assert(WasmIndices
.count(ResolvedSym
) > 0);
1206 uint32_t WasmIndex
= WasmIndices
.find(ResolvedSym
)->second
;
1207 WasmIndices
[&WS
] = WasmIndex
;
1208 DEBUG(dbgs() << " -> index:" << WasmIndex
<< "\n");
1209 } else if (WS
.isData()) {
1210 assert(DataLocations
.count(ResolvedSym
) > 0);
1211 const wasm::WasmDataReference
&Ref
=
1212 DataLocations
.find(ResolvedSym
)->second
;
1213 DataLocations
[&WS
] = Ref
;
1214 DEBUG(dbgs() << " -> index:" << Ref
.Segment
<< "\n");
1216 report_fatal_error("don't yet support global aliases");
1223 auto HandleReloc
= [&](const WasmRelocationEntry
&Rel
) {
1224 // Functions referenced by a relocation need to put in the table. This is
1225 // purely to make the object file's provisional values readable, and is
1226 // ignored by the linker, which re-calculates the relocations itself.
1227 if (Rel
.Type
!= wasm::R_WEBASSEMBLY_TABLE_INDEX_I32
&&
1228 Rel
.Type
!= wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB
)
1230 assert(Rel
.Symbol
->isFunction());
1231 const MCSymbolWasm
&WS
= *ResolveSymbol(*Rel
.Symbol
);
1232 uint32_t FunctionIndex
= WasmIndices
.find(&WS
)->second
;
1233 uint32_t TableIndex
= TableElems
.size() + kInitialTableOffset
;
1234 if (TableIndices
.try_emplace(&WS
, TableIndex
).second
) {
1235 DEBUG(dbgs() << " -> adding " << WS
.getName()
1236 << " to table: " << TableIndex
<< "\n");
1237 TableElems
.push_back(FunctionIndex
);
1238 registerFunctionType(WS
);
1242 for (const WasmRelocationEntry
&RelEntry
: CodeRelocations
)
1243 HandleReloc(RelEntry
);
1244 for (const WasmRelocationEntry
&RelEntry
: DataRelocations
)
1245 HandleReloc(RelEntry
);
1248 // Translate .init_array section contents into start functions.
1249 for (const MCSection
&S
: Asm
) {
1250 const auto &WS
= static_cast<const MCSectionWasm
&>(S
);
1251 if (WS
.getSectionName().startswith(".fini_array"))
1252 report_fatal_error(".fini_array sections are unsupported");
1253 if (!WS
.getSectionName().startswith(".init_array"))
1255 if (WS
.getFragmentList().empty())
1257 if (WS
.getFragmentList().size() != 2)
1258 report_fatal_error("only one .init_array section fragment supported");
1259 const MCFragment
&AlignFrag
= *WS
.begin();
1260 if (AlignFrag
.getKind() != MCFragment::FT_Align
)
1261 report_fatal_error(".init_array section should be aligned");
1262 if (cast
<MCAlignFragment
>(AlignFrag
).getAlignment() != (is64Bit() ? 8 : 4))
1263 report_fatal_error(".init_array section should be aligned for pointers");
1264 const MCFragment
&Frag
= *std::next(WS
.begin());
1265 if (Frag
.hasInstructions() || Frag
.getKind() != MCFragment::FT_Data
)
1266 report_fatal_error("only data supported in .init_array section");
1267 uint16_t Priority
= UINT16_MAX
;
1268 if (WS
.getSectionName().size() != 11) {
1269 if (WS
.getSectionName()[11] != '.')
1270 report_fatal_error(".init_array section priority should start with '.'");
1271 if (WS
.getSectionName().substr(12).getAsInteger(10, Priority
))
1272 report_fatal_error("invalid .init_array section priority");
1274 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
1275 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
1276 for (const uint8_t *p
= (const uint8_t *)Contents
.data(),
1277 *end
= (const uint8_t *)Contents
.data() + Contents
.size();
1280 report_fatal_error("non-symbolic data in .init_array section");
1282 for (const MCFixup
&Fixup
: DataFrag
.getFixups()) {
1283 assert(Fixup
.getKind() == MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1284 const MCExpr
*Expr
= Fixup
.getValue();
1285 auto *Sym
= dyn_cast
<MCSymbolRefExpr
>(Expr
);
1287 report_fatal_error("fixups in .init_array should be symbol references");
1288 if (Sym
->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION
)
1289 report_fatal_error("symbols in .init_array should be for functions");
1290 auto I
= SymbolIndices
.find(cast
<MCSymbolWasm
>(&Sym
->getSymbol()));
1291 if (I
== SymbolIndices
.end())
1292 report_fatal_error("symbols in .init_array should be defined");
1293 uint32_t Index
= I
->second
;
1294 InitFuncs
.push_back(std::make_pair(Priority
, Index
));
1298 // Write out the Wasm header.
1301 writeTypeSection(FunctionTypes
);
1302 writeImportSection(Imports
, DataSize
, TableElems
.size());
1303 writeFunctionSection(Functions
);
1304 // Skip the "table" section; we import the table instead.
1305 // Skip the "memory" section; we import the memory instead.
1306 writeGlobalSection();
1307 writeExportSection(Exports
);
1308 writeElemSection(TableElems
);
1309 writeCodeSection(Asm
, Layout
, Functions
);
1311 writeCodeRelocSection();
1312 writeDataRelocSection();
1313 writeLinkingMetaDataSection(SymbolInfos
, InitFuncs
, Comdats
);
1315 // TODO: Translate the .comment section to the output.
1316 // TODO: Translate debug sections to the output.
1319 std::unique_ptr
<MCObjectWriter
>
1320 llvm::createWasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
1321 raw_pwrite_stream
&OS
) {
1322 return llvm::make_unique
<WasmObjectWriter
>(std::move(MOTW
), OS
);