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/BinaryFormat/Wasm.h"
15 #include "llvm/BinaryFormat/WasmTraits.h"
16 #include "llvm/Config/llvm-config.h"
17 #include "llvm/MC/MCAsmBackend.h"
18 #include "llvm/MC/MCAssembler.h"
19 #include "llvm/MC/MCContext.h"
20 #include "llvm/MC/MCExpr.h"
21 #include "llvm/MC/MCFixupKindInfo.h"
22 #include "llvm/MC/MCObjectWriter.h"
23 #include "llvm/MC/MCSectionWasm.h"
24 #include "llvm/MC/MCSymbolWasm.h"
25 #include "llvm/MC/MCValue.h"
26 #include "llvm/MC/MCWasmObjectWriter.h"
27 #include "llvm/Support/Casting.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/EndianStream.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/LEB128.h"
36 #define DEBUG_TYPE "mc"
40 // When we create the indirect function table we start at 1, so that there is
41 // and empty slot at 0 and therefore calling a null function pointer will trap.
42 static const uint32_t InitialTableOffset
= 1;
44 // For patching purposes, we need to remember where each section starts, both
45 // for patching up the section size field, and for patching up references to
46 // locations within the section.
47 struct SectionBookkeeping
{
48 // Where the size of the section is written.
50 // Where the section header ends (without custom section name).
51 uint64_t PayloadOffset
;
52 // Where the contents of the section starts.
53 uint64_t ContentsOffset
;
57 // A wasm data segment. A wasm binary contains only a single data section
58 // but that can contain many segments, each with their own virtual location
59 // in memory. Each MCSection data created by llvm is modeled as its own
61 struct WasmDataSegment
{
62 MCSectionWasm
*Section
;
67 uint32_t LinkingFlags
;
68 SmallVector
<char, 4> Data
;
71 // A wasm function to be written into the function section.
77 // A wasm global to be written into the global section.
79 wasm::WasmGlobalType Type
;
80 uint64_t InitialValue
;
83 // Information about a single item which is part of a COMDAT. For each data
84 // segment or function which is in the COMDAT, there is a corresponding
86 struct WasmComdatEntry
{
91 // Information about a single relocation.
92 struct WasmRelocationEntry
{
93 uint64_t Offset
; // Where is the relocation.
94 const MCSymbolWasm
*Symbol
; // The symbol to relocate with.
95 int64_t Addend
; // A value to add to the symbol.
96 unsigned Type
; // The type of the relocation.
97 const MCSectionWasm
*FixupSection
; // The section the relocation is targeting.
99 WasmRelocationEntry(uint64_t Offset
, const MCSymbolWasm
*Symbol
,
100 int64_t Addend
, unsigned Type
,
101 const MCSectionWasm
*FixupSection
)
102 : Offset(Offset
), Symbol(Symbol
), Addend(Addend
), Type(Type
),
103 FixupSection(FixupSection
) {}
105 bool hasAddend() const { return wasm::relocTypeHasAddend(Type
); }
107 void print(raw_ostream
&Out
) const {
108 Out
<< wasm::relocTypetoString(Type
) << " Off=" << Offset
109 << ", Sym=" << *Symbol
<< ", Addend=" << Addend
110 << ", FixupSection=" << FixupSection
->getName();
113 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
114 LLVM_DUMP_METHOD
void dump() const { print(dbgs()); }
118 static const uint32_t InvalidIndex
= -1;
120 struct WasmCustomSection
{
123 MCSectionWasm
*Section
;
125 uint32_t OutputContentsOffset
= 0;
126 uint32_t OutputIndex
= InvalidIndex
;
128 WasmCustomSection(StringRef Name
, MCSectionWasm
*Section
)
129 : Name(Name
), Section(Section
) {}
133 raw_ostream
&operator<<(raw_ostream
&OS
, const WasmRelocationEntry
&Rel
) {
139 // Write Value as an (unsigned) LEB value at offset Offset in Stream, padded
140 // to allow patching.
141 template <typename T
, int W
>
142 void writePatchableULEB(raw_pwrite_stream
&Stream
, T Value
, uint64_t Offset
) {
144 unsigned SizeLen
= encodeULEB128(Value
, Buffer
, W
);
145 assert(SizeLen
== W
);
146 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
149 // Write Value as an signed LEB value at offset Offset in Stream, padded
150 // to allow patching.
151 template <typename T
, int W
>
152 void writePatchableSLEB(raw_pwrite_stream
&Stream
, T Value
, uint64_t Offset
) {
154 unsigned SizeLen
= encodeSLEB128(Value
, Buffer
, W
);
155 assert(SizeLen
== W
);
156 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
159 static void writePatchableU32(raw_pwrite_stream
&Stream
, uint32_t Value
,
161 writePatchableULEB
<uint32_t, 5>(Stream
, Value
, Offset
);
164 static void writePatchableS32(raw_pwrite_stream
&Stream
, int32_t Value
,
166 writePatchableSLEB
<int32_t, 5>(Stream
, Value
, Offset
);
169 static void writePatchableU64(raw_pwrite_stream
&Stream
, uint64_t Value
,
171 writePatchableSLEB
<uint64_t, 10>(Stream
, Value
, Offset
);
174 static void writePatchableS64(raw_pwrite_stream
&Stream
, int64_t Value
,
176 writePatchableSLEB
<int64_t, 10>(Stream
, Value
, Offset
);
179 // Write Value as a plain integer value at offset Offset in Stream.
180 static void patchI32(raw_pwrite_stream
&Stream
, uint32_t Value
,
183 support::endian::write32le(Buffer
, Value
);
184 Stream
.pwrite((char *)Buffer
, sizeof(Buffer
), Offset
);
187 static void patchI64(raw_pwrite_stream
&Stream
, uint64_t Value
,
190 support::endian::write64le(Buffer
, Value
);
191 Stream
.pwrite((char *)Buffer
, sizeof(Buffer
), Offset
);
194 bool isDwoSection(const MCSection
&Sec
) {
195 return Sec
.getName().ends_with(".dwo");
198 class WasmObjectWriter
: public MCObjectWriter
{
199 support::endian::Writer
*W
= nullptr;
201 /// The target specific Wasm writer instance.
202 std::unique_ptr
<MCWasmObjectTargetWriter
> TargetObjectWriter
;
204 // Relocations for fixing up references in the code section.
205 std::vector
<WasmRelocationEntry
> CodeRelocations
;
206 // Relocations for fixing up references in the data section.
207 std::vector
<WasmRelocationEntry
> DataRelocations
;
209 // Index values to use for fixing up call_indirect type indices.
210 // Maps function symbols to the index of the type of the function
211 DenseMap
<const MCSymbolWasm
*, uint32_t> TypeIndices
;
212 // Maps function symbols to the table element index space. Used
213 // for TABLE_INDEX relocation types (i.e. address taken functions).
214 DenseMap
<const MCSymbolWasm
*, uint32_t> TableIndices
;
215 // Maps function/global/table symbols to the
216 // function/global/table/tag/section index space.
217 DenseMap
<const MCSymbolWasm
*, uint32_t> WasmIndices
;
218 DenseMap
<const MCSymbolWasm
*, uint32_t> GOTIndices
;
219 // Maps data symbols to the Wasm segment and offset/size with the segment.
220 DenseMap
<const MCSymbolWasm
*, wasm::WasmDataReference
> DataLocations
;
222 // Stores output data (index, relocations, content offset) for custom
224 std::vector
<WasmCustomSection
> CustomSections
;
225 std::unique_ptr
<WasmCustomSection
> ProducersSection
;
226 std::unique_ptr
<WasmCustomSection
> TargetFeaturesSection
;
227 // Relocations for fixing up references in the custom sections.
228 DenseMap
<const MCSectionWasm
*, std::vector
<WasmRelocationEntry
>>
229 CustomSectionsRelocations
;
231 // Map from section to defining function symbol.
232 DenseMap
<const MCSection
*, const MCSymbol
*> SectionFunctions
;
234 DenseMap
<wasm::WasmSignature
, uint32_t> SignatureIndices
;
235 SmallVector
<wasm::WasmSignature
, 4> Signatures
;
236 SmallVector
<WasmDataSegment
, 4> DataSegments
;
237 unsigned NumFunctionImports
= 0;
238 unsigned NumGlobalImports
= 0;
239 unsigned NumTableImports
= 0;
240 unsigned NumTagImports
= 0;
241 uint32_t SectionCount
= 0;
248 bool IsSplitDwarf
= false;
249 raw_pwrite_stream
*OS
= nullptr;
250 raw_pwrite_stream
*DwoOS
= nullptr;
252 // TargetObjectWriter wranppers.
253 bool is64Bit() const { return TargetObjectWriter
->is64Bit(); }
254 bool isEmscripten() const { return TargetObjectWriter
->isEmscripten(); }
256 void startSection(SectionBookkeeping
&Section
, unsigned SectionId
);
257 void startCustomSection(SectionBookkeeping
&Section
, StringRef Name
);
258 void endSection(SectionBookkeeping
&Section
);
261 WasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
262 raw_pwrite_stream
&OS_
)
263 : TargetObjectWriter(std::move(MOTW
)), OS(&OS_
) {}
265 WasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
266 raw_pwrite_stream
&OS_
, raw_pwrite_stream
&DwoOS_
)
267 : TargetObjectWriter(std::move(MOTW
)), IsSplitDwarf(true), OS(&OS_
),
271 void reset() override
{
272 CodeRelocations
.clear();
273 DataRelocations
.clear();
277 TableIndices
.clear();
278 DataLocations
.clear();
279 CustomSections
.clear();
280 ProducersSection
.reset();
281 TargetFeaturesSection
.reset();
282 CustomSectionsRelocations
.clear();
283 SignatureIndices
.clear();
285 DataSegments
.clear();
286 SectionFunctions
.clear();
287 NumFunctionImports
= 0;
288 NumGlobalImports
= 0;
290 MCObjectWriter::reset();
293 void writeHeader(const MCAssembler
&Asm
);
295 void recordRelocation(MCAssembler
&Asm
, const MCFragment
*Fragment
,
296 const MCFixup
&Fixup
, MCValue Target
,
297 uint64_t &FixedValue
) override
;
299 void executePostLayoutBinding(MCAssembler
&Asm
) override
;
300 void prepareImports(SmallVectorImpl
<wasm::WasmImport
> &Imports
,
302 uint64_t writeObject(MCAssembler
&Asm
) override
;
304 uint64_t writeOneObject(MCAssembler
&Asm
, DwoMode Mode
);
306 void writeString(const StringRef Str
) {
307 encodeULEB128(Str
.size(), W
->OS
);
311 void writeStringWithAlignment(const StringRef Str
, unsigned Alignment
);
313 void writeI32(int32_t val
) {
315 support::endian::write32le(Buffer
, val
);
316 W
->OS
.write(Buffer
, sizeof(Buffer
));
319 void writeI64(int64_t val
) {
321 support::endian::write64le(Buffer
, val
);
322 W
->OS
.write(Buffer
, sizeof(Buffer
));
325 void writeValueType(wasm::ValType Ty
) { W
->OS
<< static_cast<char>(Ty
); }
327 void writeTypeSection(ArrayRef
<wasm::WasmSignature
> Signatures
);
328 void writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
, uint64_t DataSize
,
329 uint32_t NumElements
);
330 void writeFunctionSection(ArrayRef
<WasmFunction
> Functions
);
331 void writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
);
332 void writeElemSection(const MCSymbolWasm
*IndirectFunctionTable
,
333 ArrayRef
<uint32_t> TableElems
);
334 void writeDataCountSection();
335 uint32_t writeCodeSection(const MCAssembler
&Asm
,
336 ArrayRef
<WasmFunction
> Functions
);
337 uint32_t writeDataSection(const MCAssembler
&Asm
);
338 void writeTagSection(ArrayRef
<uint32_t> TagTypes
);
339 void writeGlobalSection(ArrayRef
<wasm::WasmGlobal
> Globals
);
340 void writeTableSection(ArrayRef
<wasm::WasmTable
> Tables
);
341 void writeRelocSection(uint32_t SectionIndex
, StringRef Name
,
342 std::vector
<WasmRelocationEntry
> &Relocations
);
343 void writeLinkingMetaDataSection(
344 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
345 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
346 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
);
347 void writeCustomSection(WasmCustomSection
&CustomSection
,
348 const MCAssembler
&Asm
);
349 void writeCustomRelocSections();
351 uint64_t getProvisionalValue(const MCAssembler
&Asm
,
352 const WasmRelocationEntry
&RelEntry
);
353 void applyRelocations(ArrayRef
<WasmRelocationEntry
> Relocations
,
354 uint64_t ContentsOffset
, const MCAssembler
&Asm
);
356 uint32_t getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
);
357 uint32_t getFunctionType(const MCSymbolWasm
&Symbol
);
358 uint32_t getTagType(const MCSymbolWasm
&Symbol
);
359 void registerFunctionType(const MCSymbolWasm
&Symbol
);
360 void registerTagType(const MCSymbolWasm
&Symbol
);
363 } // end anonymous namespace
365 // Write out a section header and a patchable section size field.
366 void WasmObjectWriter::startSection(SectionBookkeeping
&Section
,
367 unsigned SectionId
) {
368 LLVM_DEBUG(dbgs() << "startSection " << SectionId
<< "\n");
369 W
->OS
<< char(SectionId
);
371 Section
.SizeOffset
= W
->OS
.tell();
373 // The section size. We don't know the size yet, so reserve enough space
374 // for any 32-bit value; we'll patch it later.
375 encodeULEB128(0, W
->OS
, 5);
377 // The position where the section starts, for measuring its size.
378 Section
.ContentsOffset
= W
->OS
.tell();
379 Section
.PayloadOffset
= W
->OS
.tell();
380 Section
.Index
= SectionCount
++;
383 // Write a string with extra paddings for trailing alignment
384 // TODO: support alignment at asm and llvm level?
385 void WasmObjectWriter::writeStringWithAlignment(const StringRef Str
,
386 unsigned Alignment
) {
388 // Calculate the encoded size of str length and add pads based on it and
390 raw_null_ostream NullOS
;
391 uint64_t StrSizeLength
= encodeULEB128(Str
.size(), NullOS
);
392 uint64_t Offset
= W
->OS
.tell() + StrSizeLength
+ Str
.size();
393 uint64_t Paddings
= offsetToAlignment(Offset
, Align(Alignment
));
396 // LEB128 greater than 5 bytes is invalid
397 assert((StrSizeLength
+ Paddings
) <= 5 && "too long string to align");
399 encodeSLEB128(Str
.size(), W
->OS
, StrSizeLength
+ Paddings
);
402 assert(W
->OS
.tell() == Offset
&& "invalid padding");
405 void WasmObjectWriter::startCustomSection(SectionBookkeeping
&Section
,
407 LLVM_DEBUG(dbgs() << "startCustomSection " << Name
<< "\n");
408 startSection(Section
, wasm::WASM_SEC_CUSTOM
);
410 // The position where the section header ends, for measuring its size.
411 Section
.PayloadOffset
= W
->OS
.tell();
413 // Custom sections in wasm also have a string identifier.
414 if (Name
!= "__clangast") {
417 // The on-disk hashtable in clangast needs to be aligned by 4 bytes.
418 writeStringWithAlignment(Name
, 4);
421 // The position where the custom section starts.
422 Section
.ContentsOffset
= W
->OS
.tell();
425 // Now that the section is complete and we know how big it is, patch up the
426 // section size field at the start of the section.
427 void WasmObjectWriter::endSection(SectionBookkeeping
&Section
) {
428 uint64_t Size
= W
->OS
.tell();
429 // /dev/null doesn't support seek/tell and can report offset of 0.
430 // Simply skip this patching in that case.
434 Size
-= Section
.PayloadOffset
;
435 if (uint32_t(Size
) != Size
)
436 report_fatal_error("section size does not fit in a uint32_t");
438 LLVM_DEBUG(dbgs() << "endSection size=" << Size
<< "\n");
440 // Write the final section size to the payload_len field, which follows
441 // the section id byte.
442 writePatchableU32(static_cast<raw_pwrite_stream
&>(W
->OS
), Size
,
446 // Emit the Wasm header.
447 void WasmObjectWriter::writeHeader(const MCAssembler
&Asm
) {
448 W
->OS
.write(wasm::WasmMagic
, sizeof(wasm::WasmMagic
));
449 W
->write
<uint32_t>(wasm::WasmVersion
);
452 void WasmObjectWriter::executePostLayoutBinding(MCAssembler
&Asm
) {
453 // Some compilation units require the indirect function table to be present
454 // but don't explicitly reference it. This is the case for call_indirect
455 // without the reference-types feature, and also function bitcasts in all
456 // cases. In those cases the __indirect_function_table has the
457 // WASM_SYMBOL_NO_STRIP attribute. Here we make sure this symbol makes it to
458 // the assembler, if needed.
459 if (auto *Sym
= Asm
.getContext().lookupSymbol("__indirect_function_table")) {
460 const auto *WasmSym
= static_cast<const MCSymbolWasm
*>(Sym
);
461 if (WasmSym
->isNoStrip())
462 Asm
.registerSymbol(*Sym
);
465 // Build a map of sections to the function that defines them, for use
466 // in recordRelocation.
467 for (const MCSymbol
&S
: Asm
.symbols()) {
468 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
469 if (WS
.isDefined() && WS
.isFunction() && !WS
.isVariable()) {
470 const auto &Sec
= static_cast<const MCSectionWasm
&>(S
.getSection());
471 auto Pair
= SectionFunctions
.insert(std::make_pair(&Sec
, &S
));
473 report_fatal_error("section already has a defining function: " +
479 void WasmObjectWriter::recordRelocation(MCAssembler
&Asm
,
480 const MCFragment
*Fragment
,
481 const MCFixup
&Fixup
, MCValue Target
,
482 uint64_t &FixedValue
) {
483 // The WebAssembly backend should never generate FKF_IsPCRel fixups
484 assert(!(Asm
.getBackend().getFixupKindInfo(Fixup
.getKind()).Flags
&
485 MCFixupKindInfo::FKF_IsPCRel
));
487 const auto &FixupSection
= cast
<MCSectionWasm
>(*Fragment
->getParent());
488 uint64_t C
= Target
.getConstant();
489 uint64_t FixupOffset
= Asm
.getFragmentOffset(*Fragment
) + Fixup
.getOffset();
490 MCContext
&Ctx
= Asm
.getContext();
491 bool IsLocRel
= false;
493 if (const MCSymbolRefExpr
*RefB
= Target
.getSymB()) {
495 const auto &SymB
= cast
<MCSymbolWasm
>(RefB
->getSymbol());
497 if (FixupSection
.isText()) {
498 Ctx
.reportError(Fixup
.getLoc(),
499 Twine("symbol '") + SymB
.getName() +
500 "' unsupported subtraction expression used in "
501 "relocation in code section.");
505 if (SymB
.isUndefined()) {
506 Ctx
.reportError(Fixup
.getLoc(),
507 Twine("symbol '") + SymB
.getName() +
508 "' can not be undefined in a subtraction expression");
511 const MCSection
&SecB
= SymB
.getSection();
512 if (&SecB
!= &FixupSection
) {
513 Ctx
.reportError(Fixup
.getLoc(),
514 Twine("symbol '") + SymB
.getName() +
515 "' can not be placed in a different section");
519 C
+= FixupOffset
- Asm
.getSymbolOffset(SymB
);
522 // We either rejected the fixup or folded B into C at this point.
523 const MCSymbolRefExpr
*RefA
= Target
.getSymA();
524 const auto *SymA
= cast
<MCSymbolWasm
>(&RefA
->getSymbol());
526 // The .init_array isn't translated as data, so don't do relocations in it.
527 if (FixupSection
.getName().starts_with(".init_array")) {
528 SymA
->setUsedInInitArray();
532 if (SymA
->isVariable()) {
533 const MCExpr
*Expr
= SymA
->getVariableValue();
534 if (const auto *Inner
= dyn_cast
<MCSymbolRefExpr
>(Expr
))
535 if (Inner
->getKind() == MCSymbolRefExpr::VK_WEAKREF
)
536 llvm_unreachable("weakref used in reloc not yet implemented");
539 // Put any constant offset in an addend. Offsets can be negative, and
540 // LLVM expects wrapping, in contrast to wasm's immediates which can't
541 // be negative and don't wrap.
545 TargetObjectWriter
->getRelocType(Target
, Fixup
, FixupSection
, IsLocRel
);
547 // Absolute offset within a section or a function.
548 // Currently only supported for metadata sections.
549 // See: test/MC/WebAssembly/blockaddress.ll
550 if ((Type
== wasm::R_WASM_FUNCTION_OFFSET_I32
||
551 Type
== wasm::R_WASM_FUNCTION_OFFSET_I64
||
552 Type
== wasm::R_WASM_SECTION_OFFSET_I32
) &&
554 // SymA can be a temp data symbol that represents a function (in which case
555 // it needs to be replaced by the section symbol), [XXX and it apparently
556 // later gets changed again to a func symbol?] or it can be a real
557 // function symbol, in which case it can be left as-is.
559 if (!FixupSection
.isMetadata())
560 report_fatal_error("relocations for function or section offsets are "
561 "only supported in metadata sections");
563 const MCSymbol
*SectionSymbol
= nullptr;
564 const MCSection
&SecA
= SymA
->getSection();
566 auto SecSymIt
= SectionFunctions
.find(&SecA
);
567 if (SecSymIt
== SectionFunctions
.end())
568 report_fatal_error("section doesn\'t have defining symbol");
569 SectionSymbol
= SecSymIt
->second
;
571 SectionSymbol
= SecA
.getBeginSymbol();
574 report_fatal_error("section symbol is required for relocation");
576 C
+= Asm
.getSymbolOffset(*SymA
);
577 SymA
= cast
<MCSymbolWasm
>(SectionSymbol
);
580 if (Type
== wasm::R_WASM_TABLE_INDEX_REL_SLEB
||
581 Type
== wasm::R_WASM_TABLE_INDEX_REL_SLEB64
||
582 Type
== wasm::R_WASM_TABLE_INDEX_SLEB
||
583 Type
== wasm::R_WASM_TABLE_INDEX_SLEB64
||
584 Type
== wasm::R_WASM_TABLE_INDEX_I32
||
585 Type
== wasm::R_WASM_TABLE_INDEX_I64
) {
586 // TABLE_INDEX relocs implicitly use the default indirect function table.
587 // We require the function table to have already been defined.
588 auto TableName
= "__indirect_function_table";
589 MCSymbolWasm
*Sym
= cast_or_null
<MCSymbolWasm
>(Ctx
.lookupSymbol(TableName
));
591 report_fatal_error("missing indirect function table symbol");
593 if (!Sym
->isFunctionTable())
594 report_fatal_error("__indirect_function_table symbol has wrong type");
595 // Ensure that __indirect_function_table reaches the output.
597 Asm
.registerSymbol(*Sym
);
601 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
602 // against a named symbol.
603 if (Type
!= wasm::R_WASM_TYPE_INDEX_LEB
) {
604 if (SymA
->getName().empty())
605 report_fatal_error("relocations against un-named temporaries are not yet "
606 "supported by wasm");
608 SymA
->setUsedInReloc();
611 switch (RefA
->getKind()) {
612 case MCSymbolRefExpr::VK_GOT
:
613 case MCSymbolRefExpr::VK_WASM_GOT_TLS
:
614 SymA
->setUsedInGOT();
620 WasmRelocationEntry
Rec(FixupOffset
, SymA
, C
, Type
, &FixupSection
);
621 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec
<< "\n");
623 if (FixupSection
.isWasmData()) {
624 DataRelocations
.push_back(Rec
);
625 } else if (FixupSection
.isText()) {
626 CodeRelocations
.push_back(Rec
);
627 } else if (FixupSection
.isMetadata()) {
628 CustomSectionsRelocations
[&FixupSection
].push_back(Rec
);
630 llvm_unreachable("unexpected section type");
634 // Compute a value to write into the code at the location covered
635 // by RelEntry. This value isn't used by the static linker; it just serves
636 // to make the object format more readable and more likely to be directly
639 WasmObjectWriter::getProvisionalValue(const MCAssembler
&Asm
,
640 const WasmRelocationEntry
&RelEntry
) {
641 if ((RelEntry
.Type
== wasm::R_WASM_GLOBAL_INDEX_LEB
||
642 RelEntry
.Type
== wasm::R_WASM_GLOBAL_INDEX_I32
) &&
643 !RelEntry
.Symbol
->isGlobal()) {
644 assert(GOTIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in GOT index space");
645 return GOTIndices
[RelEntry
.Symbol
];
648 switch (RelEntry
.Type
) {
649 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
650 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64
:
651 case wasm::R_WASM_TABLE_INDEX_SLEB
:
652 case wasm::R_WASM_TABLE_INDEX_SLEB64
:
653 case wasm::R_WASM_TABLE_INDEX_I32
:
654 case wasm::R_WASM_TABLE_INDEX_I64
: {
655 // Provisional value is table address of the resolved symbol itself
656 const MCSymbolWasm
*Base
=
657 cast
<MCSymbolWasm
>(Asm
.getBaseSymbol(*RelEntry
.Symbol
));
658 assert(Base
->isFunction());
659 if (RelEntry
.Type
== wasm::R_WASM_TABLE_INDEX_REL_SLEB
||
660 RelEntry
.Type
== wasm::R_WASM_TABLE_INDEX_REL_SLEB64
)
661 return TableIndices
[Base
] - InitialTableOffset
;
663 return TableIndices
[Base
];
665 case wasm::R_WASM_TYPE_INDEX_LEB
:
666 // Provisional value is same as the index
667 return getRelocationIndexValue(RelEntry
);
668 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
669 case wasm::R_WASM_FUNCTION_INDEX_I32
:
670 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
671 case wasm::R_WASM_GLOBAL_INDEX_I32
:
672 case wasm::R_WASM_TAG_INDEX_LEB
:
673 case wasm::R_WASM_TABLE_NUMBER_LEB
:
674 // Provisional value is function/global/tag Wasm index
675 assert(WasmIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in wasm index space");
676 return WasmIndices
[RelEntry
.Symbol
];
677 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
678 case wasm::R_WASM_FUNCTION_OFFSET_I64
:
679 case wasm::R_WASM_SECTION_OFFSET_I32
: {
680 if (!RelEntry
.Symbol
->isDefined())
682 const auto &Section
=
683 static_cast<const MCSectionWasm
&>(RelEntry
.Symbol
->getSection());
684 return Section
.getSectionOffset() + RelEntry
.Addend
;
686 case wasm::R_WASM_MEMORY_ADDR_LEB
:
687 case wasm::R_WASM_MEMORY_ADDR_LEB64
:
688 case wasm::R_WASM_MEMORY_ADDR_SLEB
:
689 case wasm::R_WASM_MEMORY_ADDR_SLEB64
:
690 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
691 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64
:
692 case wasm::R_WASM_MEMORY_ADDR_I32
:
693 case wasm::R_WASM_MEMORY_ADDR_I64
:
694 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB
:
695 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64
:
696 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32
: {
697 // Provisional value is address of the global plus the offset
698 // For undefined symbols, use zero
699 if (!RelEntry
.Symbol
->isDefined())
701 const wasm::WasmDataReference
&SymRef
= DataLocations
[RelEntry
.Symbol
];
702 const WasmDataSegment
&Segment
= DataSegments
[SymRef
.Segment
];
703 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
704 return Segment
.Offset
+ SymRef
.Offset
+ RelEntry
.Addend
;
707 llvm_unreachable("invalid relocation type");
711 static void addData(SmallVectorImpl
<char> &DataBytes
,
712 MCSectionWasm
&DataSection
) {
713 LLVM_DEBUG(errs() << "addData: " << DataSection
.getName() << "\n");
715 DataBytes
.resize(alignTo(DataBytes
.size(), DataSection
.getAlign()));
717 for (const MCFragment
&Frag
: DataSection
) {
718 if (Frag
.hasInstructions())
719 report_fatal_error("only data supported in data sections");
721 if (auto *Align
= dyn_cast
<MCAlignFragment
>(&Frag
)) {
722 if (Align
->getValueSize() != 1)
723 report_fatal_error("only byte values supported for alignment");
724 // If nops are requested, use zeros, as this is the data section.
725 uint8_t Value
= Align
->hasEmitNops() ? 0 : Align
->getValue();
727 std::min
<uint64_t>(alignTo(DataBytes
.size(), Align
->getAlignment()),
728 DataBytes
.size() + Align
->getMaxBytesToEmit());
729 DataBytes
.resize(Size
, Value
);
730 } else if (auto *Fill
= dyn_cast
<MCFillFragment
>(&Frag
)) {
732 if (!Fill
->getNumValues().evaluateAsAbsolute(NumValues
))
733 llvm_unreachable("The fill should be an assembler constant");
734 DataBytes
.insert(DataBytes
.end(), Fill
->getValueSize() * NumValues
,
736 } else if (auto *LEB
= dyn_cast
<MCLEBFragment
>(&Frag
)) {
737 const SmallVectorImpl
<char> &Contents
= LEB
->getContents();
738 llvm::append_range(DataBytes
, Contents
);
740 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
741 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
742 llvm::append_range(DataBytes
, Contents
);
746 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes
.size() << "\n");
750 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
) {
751 if (RelEntry
.Type
== wasm::R_WASM_TYPE_INDEX_LEB
) {
752 if (!TypeIndices
.count(RelEntry
.Symbol
))
753 report_fatal_error("symbol not found in type index space: " +
754 RelEntry
.Symbol
->getName());
755 return TypeIndices
[RelEntry
.Symbol
];
758 return RelEntry
.Symbol
->getIndex();
761 // Apply the portions of the relocation records that we can handle ourselves
763 void WasmObjectWriter::applyRelocations(
764 ArrayRef
<WasmRelocationEntry
> Relocations
, uint64_t ContentsOffset
,
765 const MCAssembler
&Asm
) {
766 auto &Stream
= static_cast<raw_pwrite_stream
&>(W
->OS
);
767 for (const WasmRelocationEntry
&RelEntry
: Relocations
) {
768 uint64_t Offset
= ContentsOffset
+
769 RelEntry
.FixupSection
->getSectionOffset() +
772 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry
<< "\n");
773 uint64_t Value
= getProvisionalValue(Asm
, RelEntry
);
775 switch (RelEntry
.Type
) {
776 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
777 case wasm::R_WASM_TYPE_INDEX_LEB
:
778 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
779 case wasm::R_WASM_MEMORY_ADDR_LEB
:
780 case wasm::R_WASM_TAG_INDEX_LEB
:
781 case wasm::R_WASM_TABLE_NUMBER_LEB
:
782 writePatchableU32(Stream
, Value
, Offset
);
784 case wasm::R_WASM_MEMORY_ADDR_LEB64
:
785 writePatchableU64(Stream
, Value
, Offset
);
787 case wasm::R_WASM_TABLE_INDEX_I32
:
788 case wasm::R_WASM_MEMORY_ADDR_I32
:
789 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
790 case wasm::R_WASM_FUNCTION_INDEX_I32
:
791 case wasm::R_WASM_SECTION_OFFSET_I32
:
792 case wasm::R_WASM_GLOBAL_INDEX_I32
:
793 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32
:
794 patchI32(Stream
, Value
, Offset
);
796 case wasm::R_WASM_TABLE_INDEX_I64
:
797 case wasm::R_WASM_MEMORY_ADDR_I64
:
798 case wasm::R_WASM_FUNCTION_OFFSET_I64
:
799 patchI64(Stream
, Value
, Offset
);
801 case wasm::R_WASM_TABLE_INDEX_SLEB
:
802 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
803 case wasm::R_WASM_MEMORY_ADDR_SLEB
:
804 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
805 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB
:
806 writePatchableS32(Stream
, Value
, Offset
);
808 case wasm::R_WASM_TABLE_INDEX_SLEB64
:
809 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64
:
810 case wasm::R_WASM_MEMORY_ADDR_SLEB64
:
811 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64
:
812 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64
:
813 writePatchableS64(Stream
, Value
, Offset
);
816 llvm_unreachable("invalid relocation type");
821 void WasmObjectWriter::writeTypeSection(
822 ArrayRef
<wasm::WasmSignature
> Signatures
) {
823 if (Signatures
.empty())
826 SectionBookkeeping Section
;
827 startSection(Section
, wasm::WASM_SEC_TYPE
);
829 encodeULEB128(Signatures
.size(), W
->OS
);
831 for (const wasm::WasmSignature
&Sig
: Signatures
) {
832 W
->OS
<< char(wasm::WASM_TYPE_FUNC
);
833 encodeULEB128(Sig
.Params
.size(), W
->OS
);
834 for (wasm::ValType Ty
: Sig
.Params
)
836 encodeULEB128(Sig
.Returns
.size(), W
->OS
);
837 for (wasm::ValType Ty
: Sig
.Returns
)
844 void WasmObjectWriter::writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
,
846 uint32_t NumElements
) {
850 uint64_t NumPages
= (DataSize
+ wasm::WasmPageSize
- 1) / wasm::WasmPageSize
;
852 SectionBookkeeping Section
;
853 startSection(Section
, wasm::WASM_SEC_IMPORT
);
855 encodeULEB128(Imports
.size(), W
->OS
);
856 for (const wasm::WasmImport
&Import
: Imports
) {
857 writeString(Import
.Module
);
858 writeString(Import
.Field
);
859 W
->OS
<< char(Import
.Kind
);
861 switch (Import
.Kind
) {
862 case wasm::WASM_EXTERNAL_FUNCTION
:
863 encodeULEB128(Import
.SigIndex
, W
->OS
);
865 case wasm::WASM_EXTERNAL_GLOBAL
:
866 W
->OS
<< char(Import
.Global
.Type
);
867 W
->OS
<< char(Import
.Global
.Mutable
? 1 : 0);
869 case wasm::WASM_EXTERNAL_MEMORY
:
870 encodeULEB128(Import
.Memory
.Flags
, W
->OS
);
871 encodeULEB128(NumPages
, W
->OS
); // initial
873 case wasm::WASM_EXTERNAL_TABLE
:
874 W
->OS
<< char(Import
.Table
.ElemType
);
875 encodeULEB128(Import
.Table
.Limits
.Flags
, W
->OS
);
876 encodeULEB128(NumElements
, W
->OS
); // initial
878 case wasm::WASM_EXTERNAL_TAG
:
879 W
->OS
<< char(0); // Reserved 'attribute' field
880 encodeULEB128(Import
.SigIndex
, W
->OS
);
883 llvm_unreachable("unsupported import kind");
890 void WasmObjectWriter::writeFunctionSection(ArrayRef
<WasmFunction
> Functions
) {
891 if (Functions
.empty())
894 SectionBookkeeping Section
;
895 startSection(Section
, wasm::WASM_SEC_FUNCTION
);
897 encodeULEB128(Functions
.size(), W
->OS
);
898 for (const WasmFunction
&Func
: Functions
)
899 encodeULEB128(Func
.SigIndex
, W
->OS
);
904 void WasmObjectWriter::writeTagSection(ArrayRef
<uint32_t> TagTypes
) {
905 if (TagTypes
.empty())
908 SectionBookkeeping Section
;
909 startSection(Section
, wasm::WASM_SEC_TAG
);
911 encodeULEB128(TagTypes
.size(), W
->OS
);
912 for (uint32_t Index
: TagTypes
) {
913 W
->OS
<< char(0); // Reserved 'attribute' field
914 encodeULEB128(Index
, W
->OS
);
920 void WasmObjectWriter::writeGlobalSection(ArrayRef
<wasm::WasmGlobal
> Globals
) {
924 SectionBookkeeping Section
;
925 startSection(Section
, wasm::WASM_SEC_GLOBAL
);
927 encodeULEB128(Globals
.size(), W
->OS
);
928 for (const wasm::WasmGlobal
&Global
: Globals
) {
929 encodeULEB128(Global
.Type
.Type
, W
->OS
);
930 W
->OS
<< char(Global
.Type
.Mutable
);
931 if (Global
.InitExpr
.Extended
) {
932 llvm_unreachable("extected init expressions not supported");
934 W
->OS
<< char(Global
.InitExpr
.Inst
.Opcode
);
935 switch (Global
.Type
.Type
) {
936 case wasm::WASM_TYPE_I32
:
937 encodeSLEB128(0, W
->OS
);
939 case wasm::WASM_TYPE_I64
:
940 encodeSLEB128(0, W
->OS
);
942 case wasm::WASM_TYPE_F32
:
945 case wasm::WASM_TYPE_F64
:
948 case wasm::WASM_TYPE_EXTERNREF
:
949 writeValueType(wasm::ValType::EXTERNREF
);
952 llvm_unreachable("unexpected type");
955 W
->OS
<< char(wasm::WASM_OPCODE_END
);
961 void WasmObjectWriter::writeTableSection(ArrayRef
<wasm::WasmTable
> Tables
) {
965 SectionBookkeeping Section
;
966 startSection(Section
, wasm::WASM_SEC_TABLE
);
968 encodeULEB128(Tables
.size(), W
->OS
);
969 for (const wasm::WasmTable
&Table
: Tables
) {
970 assert(Table
.Type
.ElemType
!= wasm::ValType::OTHERREF
&&
971 "Cannot encode general ref-typed tables");
972 encodeULEB128((uint32_t)Table
.Type
.ElemType
, W
->OS
);
973 encodeULEB128(Table
.Type
.Limits
.Flags
, W
->OS
);
974 encodeULEB128(Table
.Type
.Limits
.Minimum
, W
->OS
);
975 if (Table
.Type
.Limits
.Flags
& wasm::WASM_LIMITS_FLAG_HAS_MAX
)
976 encodeULEB128(Table
.Type
.Limits
.Maximum
, W
->OS
);
981 void WasmObjectWriter::writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
) {
985 SectionBookkeeping Section
;
986 startSection(Section
, wasm::WASM_SEC_EXPORT
);
988 encodeULEB128(Exports
.size(), W
->OS
);
989 for (const wasm::WasmExport
&Export
: Exports
) {
990 writeString(Export
.Name
);
991 W
->OS
<< char(Export
.Kind
);
992 encodeULEB128(Export
.Index
, W
->OS
);
998 void WasmObjectWriter::writeElemSection(
999 const MCSymbolWasm
*IndirectFunctionTable
, ArrayRef
<uint32_t> TableElems
) {
1000 if (TableElems
.empty())
1003 assert(IndirectFunctionTable
);
1005 SectionBookkeeping Section
;
1006 startSection(Section
, wasm::WASM_SEC_ELEM
);
1008 encodeULEB128(1, W
->OS
); // number of "segments"
1010 assert(WasmIndices
.count(IndirectFunctionTable
));
1011 uint32_t TableNumber
= WasmIndices
.find(IndirectFunctionTable
)->second
;
1014 Flags
|= wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER
;
1015 encodeULEB128(Flags
, W
->OS
);
1016 if (Flags
& wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER
)
1017 encodeULEB128(TableNumber
, W
->OS
); // the table number
1019 // init expr for starting offset
1020 W
->OS
<< char(is64Bit() ? wasm::WASM_OPCODE_I64_CONST
1021 : wasm::WASM_OPCODE_I32_CONST
);
1022 encodeSLEB128(InitialTableOffset
, W
->OS
);
1023 W
->OS
<< char(wasm::WASM_OPCODE_END
);
1025 if (Flags
& wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND
) {
1026 // We only write active function table initializers, for which the elem kind
1027 // is specified to be written as 0x00 and interpreted to mean "funcref".
1028 const uint8_t ElemKind
= 0;
1032 encodeULEB128(TableElems
.size(), W
->OS
);
1033 for (uint32_t Elem
: TableElems
)
1034 encodeULEB128(Elem
, W
->OS
);
1036 endSection(Section
);
1039 void WasmObjectWriter::writeDataCountSection() {
1040 if (DataSegments
.empty())
1043 SectionBookkeeping Section
;
1044 startSection(Section
, wasm::WASM_SEC_DATACOUNT
);
1045 encodeULEB128(DataSegments
.size(), W
->OS
);
1046 endSection(Section
);
1049 uint32_t WasmObjectWriter::writeCodeSection(const MCAssembler
&Asm
,
1050 ArrayRef
<WasmFunction
> Functions
) {
1051 if (Functions
.empty())
1054 SectionBookkeeping Section
;
1055 startSection(Section
, wasm::WASM_SEC_CODE
);
1057 encodeULEB128(Functions
.size(), W
->OS
);
1059 for (const WasmFunction
&Func
: Functions
) {
1060 auto *FuncSection
= static_cast<MCSectionWasm
*>(Func
.Section
);
1062 int64_t Size
= Asm
.getSectionAddressSize(*FuncSection
);
1063 encodeULEB128(Size
, W
->OS
);
1064 FuncSection
->setSectionOffset(W
->OS
.tell() - Section
.ContentsOffset
);
1065 Asm
.writeSectionData(W
->OS
, FuncSection
);
1069 applyRelocations(CodeRelocations
, Section
.ContentsOffset
, Asm
);
1071 endSection(Section
);
1072 return Section
.Index
;
1075 uint32_t WasmObjectWriter::writeDataSection(const MCAssembler
&Asm
) {
1076 if (DataSegments
.empty())
1079 SectionBookkeeping Section
;
1080 startSection(Section
, wasm::WASM_SEC_DATA
);
1082 encodeULEB128(DataSegments
.size(), W
->OS
); // count
1084 for (const WasmDataSegment
&Segment
: DataSegments
) {
1085 encodeULEB128(Segment
.InitFlags
, W
->OS
); // flags
1086 if (Segment
.InitFlags
& wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX
)
1087 encodeULEB128(0, W
->OS
); // memory index
1088 if ((Segment
.InitFlags
& wasm::WASM_DATA_SEGMENT_IS_PASSIVE
) == 0) {
1089 W
->OS
<< char(is64Bit() ? wasm::WASM_OPCODE_I64_CONST
1090 : wasm::WASM_OPCODE_I32_CONST
);
1091 encodeSLEB128(Segment
.Offset
, W
->OS
); // offset
1092 W
->OS
<< char(wasm::WASM_OPCODE_END
);
1094 encodeULEB128(Segment
.Data
.size(), W
->OS
); // size
1095 Segment
.Section
->setSectionOffset(W
->OS
.tell() - Section
.ContentsOffset
);
1096 W
->OS
<< Segment
.Data
; // data
1100 applyRelocations(DataRelocations
, Section
.ContentsOffset
, Asm
);
1102 endSection(Section
);
1103 return Section
.Index
;
1106 void WasmObjectWriter::writeRelocSection(
1107 uint32_t SectionIndex
, StringRef Name
,
1108 std::vector
<WasmRelocationEntry
> &Relocs
) {
1109 // See: https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md
1110 // for descriptions of the reloc sections.
1115 // First, ensure the relocations are sorted in offset order. In general they
1116 // should already be sorted since `recordRelocation` is called in offset
1117 // order, but for the code section we combine many MC sections into single
1118 // wasm section, and this order is determined by the order of Asm.Symbols()
1119 // not the sections order.
1121 Relocs
, [](const WasmRelocationEntry
&A
, const WasmRelocationEntry
&B
) {
1122 return (A
.Offset
+ A
.FixupSection
->getSectionOffset()) <
1123 (B
.Offset
+ B
.FixupSection
->getSectionOffset());
1126 SectionBookkeeping Section
;
1127 startCustomSection(Section
, std::string("reloc.") + Name
.str());
1129 encodeULEB128(SectionIndex
, W
->OS
);
1130 encodeULEB128(Relocs
.size(), W
->OS
);
1131 for (const WasmRelocationEntry
&RelEntry
: Relocs
) {
1133 RelEntry
.Offset
+ RelEntry
.FixupSection
->getSectionOffset();
1134 uint32_t Index
= getRelocationIndexValue(RelEntry
);
1136 W
->OS
<< char(RelEntry
.Type
);
1137 encodeULEB128(Offset
, W
->OS
);
1138 encodeULEB128(Index
, W
->OS
);
1139 if (RelEntry
.hasAddend())
1140 encodeSLEB128(RelEntry
.Addend
, W
->OS
);
1143 endSection(Section
);
1146 void WasmObjectWriter::writeCustomRelocSections() {
1147 for (const auto &Sec
: CustomSections
) {
1148 auto &Relocations
= CustomSectionsRelocations
[Sec
.Section
];
1149 writeRelocSection(Sec
.OutputIndex
, Sec
.Name
, Relocations
);
1153 void WasmObjectWriter::writeLinkingMetaDataSection(
1154 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
1155 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
1156 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
) {
1157 SectionBookkeeping Section
;
1158 startCustomSection(Section
, "linking");
1159 encodeULEB128(wasm::WasmMetadataVersion
, W
->OS
);
1161 SectionBookkeeping SubSection
;
1162 if (SymbolInfos
.size() != 0) {
1163 startSection(SubSection
, wasm::WASM_SYMBOL_TABLE
);
1164 encodeULEB128(SymbolInfos
.size(), W
->OS
);
1165 for (const wasm::WasmSymbolInfo
&Sym
: SymbolInfos
) {
1166 encodeULEB128(Sym
.Kind
, W
->OS
);
1167 encodeULEB128(Sym
.Flags
, W
->OS
);
1169 case wasm::WASM_SYMBOL_TYPE_FUNCTION
:
1170 case wasm::WASM_SYMBOL_TYPE_GLOBAL
:
1171 case wasm::WASM_SYMBOL_TYPE_TAG
:
1172 case wasm::WASM_SYMBOL_TYPE_TABLE
:
1173 encodeULEB128(Sym
.ElementIndex
, W
->OS
);
1174 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0 ||
1175 (Sym
.Flags
& wasm::WASM_SYMBOL_EXPLICIT_NAME
) != 0)
1176 writeString(Sym
.Name
);
1178 case wasm::WASM_SYMBOL_TYPE_DATA
:
1179 writeString(Sym
.Name
);
1180 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0) {
1181 encodeULEB128(Sym
.DataRef
.Segment
, W
->OS
);
1182 encodeULEB128(Sym
.DataRef
.Offset
, W
->OS
);
1183 encodeULEB128(Sym
.DataRef
.Size
, W
->OS
);
1186 case wasm::WASM_SYMBOL_TYPE_SECTION
: {
1187 const uint32_t SectionIndex
=
1188 CustomSections
[Sym
.ElementIndex
].OutputIndex
;
1189 encodeULEB128(SectionIndex
, W
->OS
);
1193 llvm_unreachable("unexpected kind");
1196 endSection(SubSection
);
1199 if (DataSegments
.size()) {
1200 startSection(SubSection
, wasm::WASM_SEGMENT_INFO
);
1201 encodeULEB128(DataSegments
.size(), W
->OS
);
1202 for (const WasmDataSegment
&Segment
: DataSegments
) {
1203 writeString(Segment
.Name
);
1204 encodeULEB128(Segment
.Alignment
, W
->OS
);
1205 encodeULEB128(Segment
.LinkingFlags
, W
->OS
);
1207 endSection(SubSection
);
1210 if (!InitFuncs
.empty()) {
1211 startSection(SubSection
, wasm::WASM_INIT_FUNCS
);
1212 encodeULEB128(InitFuncs
.size(), W
->OS
);
1213 for (auto &StartFunc
: InitFuncs
) {
1214 encodeULEB128(StartFunc
.first
, W
->OS
); // priority
1215 encodeULEB128(StartFunc
.second
, W
->OS
); // function index
1217 endSection(SubSection
);
1220 if (Comdats
.size()) {
1221 startSection(SubSection
, wasm::WASM_COMDAT_INFO
);
1222 encodeULEB128(Comdats
.size(), W
->OS
);
1223 for (const auto &C
: Comdats
) {
1224 writeString(C
.first
);
1225 encodeULEB128(0, W
->OS
); // flags for future use
1226 encodeULEB128(C
.second
.size(), W
->OS
);
1227 for (const WasmComdatEntry
&Entry
: C
.second
) {
1228 encodeULEB128(Entry
.Kind
, W
->OS
);
1229 encodeULEB128(Entry
.Index
, W
->OS
);
1232 endSection(SubSection
);
1235 endSection(Section
);
1238 void WasmObjectWriter::writeCustomSection(WasmCustomSection
&CustomSection
,
1239 const MCAssembler
&Asm
) {
1240 SectionBookkeeping Section
;
1241 auto *Sec
= CustomSection
.Section
;
1242 startCustomSection(Section
, CustomSection
.Name
);
1244 Sec
->setSectionOffset(W
->OS
.tell() - Section
.ContentsOffset
);
1245 Asm
.writeSectionData(W
->OS
, Sec
);
1247 CustomSection
.OutputContentsOffset
= Section
.ContentsOffset
;
1248 CustomSection
.OutputIndex
= Section
.Index
;
1250 endSection(Section
);
1253 auto &Relocations
= CustomSectionsRelocations
[CustomSection
.Section
];
1254 applyRelocations(Relocations
, CustomSection
.OutputContentsOffset
, Asm
);
1257 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm
&Symbol
) {
1258 assert(Symbol
.isFunction());
1259 assert(TypeIndices
.count(&Symbol
));
1260 return TypeIndices
[&Symbol
];
1263 uint32_t WasmObjectWriter::getTagType(const MCSymbolWasm
&Symbol
) {
1264 assert(Symbol
.isTag());
1265 assert(TypeIndices
.count(&Symbol
));
1266 return TypeIndices
[&Symbol
];
1269 void WasmObjectWriter::registerFunctionType(const MCSymbolWasm
&Symbol
) {
1270 assert(Symbol
.isFunction());
1272 wasm::WasmSignature S
;
1274 if (auto *Sig
= Symbol
.getSignature()) {
1275 S
.Returns
= Sig
->Returns
;
1276 S
.Params
= Sig
->Params
;
1279 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1281 Signatures
.push_back(S
);
1282 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1284 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
1285 << " new:" << Pair
.second
<< "\n");
1286 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1289 void WasmObjectWriter::registerTagType(const MCSymbolWasm
&Symbol
) {
1290 assert(Symbol
.isTag());
1292 // TODO Currently we don't generate imported exceptions, but if we do, we
1293 // should have a way of infering types of imported exceptions.
1294 wasm::WasmSignature S
;
1295 if (auto *Sig
= Symbol
.getSignature()) {
1296 S
.Returns
= Sig
->Returns
;
1297 S
.Params
= Sig
->Params
;
1300 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1302 Signatures
.push_back(S
);
1303 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1305 LLVM_DEBUG(dbgs() << "registerTagType: " << Symbol
<< " new:" << Pair
.second
1307 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1310 static bool isInSymtab(const MCSymbolWasm
&Sym
) {
1311 if (Sym
.isUsedInReloc() || Sym
.isUsedInInitArray())
1314 if (Sym
.isComdat() && !Sym
.isDefined())
1317 if (Sym
.isTemporary())
1320 if (Sym
.isSection())
1323 if (Sym
.omitFromLinkingSection())
1329 void WasmObjectWriter::prepareImports(
1330 SmallVectorImpl
<wasm::WasmImport
> &Imports
, MCAssembler
&Asm
) {
1331 // For now, always emit the memory import, since loads and stores are not
1332 // valid without it. In the future, we could perhaps be more clever and omit
1333 // it if there are no loads or stores.
1334 wasm::WasmImport MemImport
;
1335 MemImport
.Module
= "env";
1336 MemImport
.Field
= "__linear_memory";
1337 MemImport
.Kind
= wasm::WASM_EXTERNAL_MEMORY
;
1338 MemImport
.Memory
.Flags
= is64Bit() ? wasm::WASM_LIMITS_FLAG_IS_64
1339 : wasm::WASM_LIMITS_FLAG_NONE
;
1340 Imports
.push_back(MemImport
);
1342 // Populate SignatureIndices, and Imports and WasmIndices for undefined
1343 // symbols. This must be done before populating WasmIndices for defined
1345 for (const MCSymbol
&S
: Asm
.symbols()) {
1346 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1348 // Register types for all functions, including those with private linkage
1349 // (because wasm always needs a type signature).
1350 if (WS
.isFunction()) {
1351 const auto *BS
= Asm
.getBaseSymbol(S
);
1353 report_fatal_error(Twine(S
.getName()) +
1354 ": absolute addressing not supported!");
1355 registerFunctionType(*cast
<MCSymbolWasm
>(BS
));
1359 registerTagType(WS
);
1361 if (WS
.isTemporary())
1364 // If the symbol is not defined in this translation unit, import it.
1365 if (!WS
.isDefined() && !WS
.isComdat()) {
1366 if (WS
.isFunction()) {
1367 wasm::WasmImport Import
;
1368 Import
.Module
= WS
.getImportModule();
1369 Import
.Field
= WS
.getImportName();
1370 Import
.Kind
= wasm::WASM_EXTERNAL_FUNCTION
;
1371 Import
.SigIndex
= getFunctionType(WS
);
1372 Imports
.push_back(Import
);
1373 assert(WasmIndices
.count(&WS
) == 0);
1374 WasmIndices
[&WS
] = NumFunctionImports
++;
1375 } else if (WS
.isGlobal()) {
1377 report_fatal_error("undefined global symbol cannot be weak");
1379 wasm::WasmImport Import
;
1380 Import
.Field
= WS
.getImportName();
1381 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1382 Import
.Module
= WS
.getImportModule();
1383 Import
.Global
= WS
.getGlobalType();
1384 Imports
.push_back(Import
);
1385 assert(WasmIndices
.count(&WS
) == 0);
1386 WasmIndices
[&WS
] = NumGlobalImports
++;
1387 } else if (WS
.isTag()) {
1389 report_fatal_error("undefined tag symbol cannot be weak");
1391 wasm::WasmImport Import
;
1392 Import
.Module
= WS
.getImportModule();
1393 Import
.Field
= WS
.getImportName();
1394 Import
.Kind
= wasm::WASM_EXTERNAL_TAG
;
1395 Import
.SigIndex
= getTagType(WS
);
1396 Imports
.push_back(Import
);
1397 assert(WasmIndices
.count(&WS
) == 0);
1398 WasmIndices
[&WS
] = NumTagImports
++;
1399 } else if (WS
.isTable()) {
1401 report_fatal_error("undefined table symbol cannot be weak");
1403 wasm::WasmImport Import
;
1404 Import
.Module
= WS
.getImportModule();
1405 Import
.Field
= WS
.getImportName();
1406 Import
.Kind
= wasm::WASM_EXTERNAL_TABLE
;
1407 Import
.Table
= WS
.getTableType();
1408 Imports
.push_back(Import
);
1409 assert(WasmIndices
.count(&WS
) == 0);
1410 WasmIndices
[&WS
] = NumTableImports
++;
1415 // Add imports for GOT globals
1416 for (const MCSymbol
&S
: Asm
.symbols()) {
1417 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1418 if (WS
.isUsedInGOT()) {
1419 wasm::WasmImport Import
;
1420 if (WS
.isFunction())
1421 Import
.Module
= "GOT.func";
1423 Import
.Module
= "GOT.mem";
1424 Import
.Field
= WS
.getName();
1425 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1426 Import
.Global
= {wasm::WASM_TYPE_I32
, true};
1427 Imports
.push_back(Import
);
1428 assert(GOTIndices
.count(&WS
) == 0);
1429 GOTIndices
[&WS
] = NumGlobalImports
++;
1434 uint64_t WasmObjectWriter::writeObject(MCAssembler
&Asm
) {
1435 support::endian::Writer
MainWriter(*OS
, llvm::endianness::little
);
1438 uint64_t TotalSize
= writeOneObject(Asm
, DwoMode::NonDwoOnly
);
1440 support::endian::Writer
DwoWriter(*DwoOS
, llvm::endianness::little
);
1442 return TotalSize
+ writeOneObject(Asm
, DwoMode::DwoOnly
);
1444 return writeOneObject(Asm
, DwoMode::AllSections
);
1448 uint64_t WasmObjectWriter::writeOneObject(MCAssembler
&Asm
,
1450 uint64_t StartOffset
= W
->OS
.tell();
1452 CustomSections
.clear();
1454 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
1456 // Collect information from the available symbols.
1457 SmallVector
<WasmFunction
, 4> Functions
;
1458 SmallVector
<uint32_t, 4> TableElems
;
1459 SmallVector
<wasm::WasmImport
, 4> Imports
;
1460 SmallVector
<wasm::WasmExport
, 4> Exports
;
1461 SmallVector
<uint32_t, 2> TagTypes
;
1462 SmallVector
<wasm::WasmGlobal
, 1> Globals
;
1463 SmallVector
<wasm::WasmTable
, 1> Tables
;
1464 SmallVector
<wasm::WasmSymbolInfo
, 4> SymbolInfos
;
1465 SmallVector
<std::pair
<uint16_t, uint32_t>, 2> InitFuncs
;
1466 std::map
<StringRef
, std::vector
<WasmComdatEntry
>> Comdats
;
1467 uint64_t DataSize
= 0;
1468 if (Mode
!= DwoMode::DwoOnly
)
1469 prepareImports(Imports
, Asm
);
1471 // Populate DataSegments and CustomSections, which must be done before
1472 // populating DataLocations.
1473 for (MCSection
&Sec
: Asm
) {
1474 auto &Section
= static_cast<MCSectionWasm
&>(Sec
);
1475 StringRef SectionName
= Section
.getName();
1477 if (Mode
== DwoMode::NonDwoOnly
&& isDwoSection(Sec
))
1479 if (Mode
== DwoMode::DwoOnly
&& !isDwoSection(Sec
))
1482 LLVM_DEBUG(dbgs() << "Processing Section " << SectionName
<< " group "
1483 << Section
.getGroup() << "\n";);
1485 // .init_array sections are handled specially elsewhere.
1486 if (SectionName
.starts_with(".init_array"))
1489 // Code is handled separately
1490 if (Section
.isText())
1493 if (Section
.isWasmData()) {
1494 uint32_t SegmentIndex
= DataSegments
.size();
1495 DataSize
= alignTo(DataSize
, Section
.getAlign());
1496 DataSegments
.emplace_back();
1497 WasmDataSegment
&Segment
= DataSegments
.back();
1498 Segment
.Name
= SectionName
;
1499 Segment
.InitFlags
= Section
.getPassive()
1500 ? (uint32_t)wasm::WASM_DATA_SEGMENT_IS_PASSIVE
1502 Segment
.Offset
= DataSize
;
1503 Segment
.Section
= &Section
;
1504 addData(Segment
.Data
, Section
);
1505 Segment
.Alignment
= Log2(Section
.getAlign());
1506 Segment
.LinkingFlags
= Section
.getSegmentFlags();
1507 DataSize
+= Segment
.Data
.size();
1508 Section
.setSegmentIndex(SegmentIndex
);
1510 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1511 Comdats
[C
->getName()].emplace_back(
1512 WasmComdatEntry
{wasm::WASM_COMDAT_DATA
, SegmentIndex
});
1515 // Create custom sections
1516 assert(Section
.isMetadata());
1518 StringRef Name
= SectionName
;
1520 // For user-defined custom sections, strip the prefix
1521 Name
.consume_front(".custom_section.");
1523 MCSymbol
*Begin
= Sec
.getBeginSymbol();
1525 assert(WasmIndices
.count(cast
<MCSymbolWasm
>(Begin
)) == 0);
1526 WasmIndices
[cast
<MCSymbolWasm
>(Begin
)] = CustomSections
.size();
1529 // Separate out the producers and target features sections
1530 if (Name
== "producers") {
1531 ProducersSection
= std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1534 if (Name
== "target_features") {
1535 TargetFeaturesSection
=
1536 std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1540 // Custom sections can also belong to COMDAT groups. In this case the
1541 // decriptor's "index" field is the section index (in the final object
1542 // file), but that is not known until after layout, so it must be fixed up
1544 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1545 Comdats
[C
->getName()].emplace_back(
1546 WasmComdatEntry
{wasm::WASM_COMDAT_SECTION
,
1547 static_cast<uint32_t>(CustomSections
.size())});
1550 CustomSections
.emplace_back(Name
, &Section
);
1554 if (Mode
!= DwoMode::DwoOnly
) {
1555 // Populate WasmIndices and DataLocations for defined symbols.
1556 for (const MCSymbol
&S
: Asm
.symbols()) {
1557 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1558 // or used in relocations.
1559 if (S
.isTemporary() && S
.getName().empty())
1562 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1564 dbgs() << "MCSymbol: "
1565 << toString(WS
.getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA
))
1567 << " isDefined=" << S
.isDefined() << " isExternal="
1568 << S
.isExternal() << " isTemporary=" << S
.isTemporary()
1569 << " isWeak=" << WS
.isWeak() << " isHidden=" << WS
.isHidden()
1570 << " isVariable=" << WS
.isVariable() << "\n");
1572 if (WS
.isVariable())
1574 if (WS
.isComdat() && !WS
.isDefined())
1577 if (WS
.isFunction()) {
1579 if (WS
.isDefined()) {
1580 if (WS
.getOffset() != 0)
1582 "function sections must contain one function each");
1584 // A definition. Write out the function body.
1585 Index
= NumFunctionImports
+ Functions
.size();
1587 Func
.SigIndex
= getFunctionType(WS
);
1588 Func
.Section
= &WS
.getSection();
1589 assert(WasmIndices
.count(&WS
) == 0);
1590 WasmIndices
[&WS
] = Index
;
1591 Functions
.push_back(Func
);
1593 auto &Section
= static_cast<MCSectionWasm
&>(WS
.getSection());
1594 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1595 Comdats
[C
->getName()].emplace_back(
1596 WasmComdatEntry
{wasm::WASM_COMDAT_FUNCTION
, Index
});
1599 if (WS
.hasExportName()) {
1600 wasm::WasmExport Export
;
1601 Export
.Name
= WS
.getExportName();
1602 Export
.Kind
= wasm::WASM_EXTERNAL_FUNCTION
;
1603 Export
.Index
= Index
;
1604 Exports
.push_back(Export
);
1607 // An import; the index was assigned above.
1608 Index
= WasmIndices
.find(&WS
)->second
;
1611 LLVM_DEBUG(dbgs() << " -> function index: " << Index
<< "\n");
1613 } else if (WS
.isData()) {
1614 if (!isInSymtab(WS
))
1617 if (!WS
.isDefined()) {
1618 LLVM_DEBUG(dbgs() << " -> segment index: -1"
1624 report_fatal_error("data symbols must have a size set with .size: " +
1628 if (!WS
.getSize()->evaluateAsAbsolute(Size
, Asm
))
1629 report_fatal_error(".size expression must be evaluatable");
1631 auto &DataSection
= static_cast<MCSectionWasm
&>(WS
.getSection());
1632 if (!DataSection
.isWasmData())
1633 report_fatal_error("data symbols must live in a data section: " +
1636 // For each data symbol, export it in the symtab as a reference to the
1637 // corresponding Wasm data segment.
1638 wasm::WasmDataReference Ref
= wasm::WasmDataReference
{
1639 DataSection
.getSegmentIndex(), Asm
.getSymbolOffset(WS
),
1640 static_cast<uint64_t>(Size
)};
1641 assert(DataLocations
.count(&WS
) == 0);
1642 DataLocations
[&WS
] = Ref
;
1643 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref
.Segment
<< "\n");
1645 } else if (WS
.isGlobal()) {
1646 // A "true" Wasm global (currently just __stack_pointer)
1647 if (WS
.isDefined()) {
1648 wasm::WasmGlobal Global
;
1649 Global
.Type
= WS
.getGlobalType();
1650 Global
.Index
= NumGlobalImports
+ Globals
.size();
1651 Global
.InitExpr
.Extended
= false;
1652 switch (Global
.Type
.Type
) {
1653 case wasm::WASM_TYPE_I32
:
1654 Global
.InitExpr
.Inst
.Opcode
= wasm::WASM_OPCODE_I32_CONST
;
1656 case wasm::WASM_TYPE_I64
:
1657 Global
.InitExpr
.Inst
.Opcode
= wasm::WASM_OPCODE_I64_CONST
;
1659 case wasm::WASM_TYPE_F32
:
1660 Global
.InitExpr
.Inst
.Opcode
= wasm::WASM_OPCODE_F32_CONST
;
1662 case wasm::WASM_TYPE_F64
:
1663 Global
.InitExpr
.Inst
.Opcode
= wasm::WASM_OPCODE_F64_CONST
;
1665 case wasm::WASM_TYPE_EXTERNREF
:
1666 Global
.InitExpr
.Inst
.Opcode
= wasm::WASM_OPCODE_REF_NULL
;
1669 llvm_unreachable("unexpected type");
1671 assert(WasmIndices
.count(&WS
) == 0);
1672 WasmIndices
[&WS
] = Global
.Index
;
1673 Globals
.push_back(Global
);
1675 // An import; the index was assigned above
1676 LLVM_DEBUG(dbgs() << " -> global index: "
1677 << WasmIndices
.find(&WS
)->second
<< "\n");
1679 } else if (WS
.isTable()) {
1680 if (WS
.isDefined()) {
1681 wasm::WasmTable Table
;
1682 Table
.Index
= NumTableImports
+ Tables
.size();
1683 Table
.Type
= WS
.getTableType();
1684 assert(WasmIndices
.count(&WS
) == 0);
1685 WasmIndices
[&WS
] = Table
.Index
;
1686 Tables
.push_back(Table
);
1688 LLVM_DEBUG(dbgs() << " -> table index: "
1689 << WasmIndices
.find(&WS
)->second
<< "\n");
1690 } else if (WS
.isTag()) {
1691 // C++ exception symbol (__cpp_exception) or longjmp symbol
1694 if (WS
.isDefined()) {
1695 Index
= NumTagImports
+ TagTypes
.size();
1696 uint32_t SigIndex
= getTagType(WS
);
1697 assert(WasmIndices
.count(&WS
) == 0);
1698 WasmIndices
[&WS
] = Index
;
1699 TagTypes
.push_back(SigIndex
);
1701 // An import; the index was assigned above.
1702 assert(WasmIndices
.count(&WS
) > 0);
1704 LLVM_DEBUG(dbgs() << " -> tag index: " << WasmIndices
.find(&WS
)->second
1708 assert(WS
.isSection());
1712 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1713 // process these in a separate pass because we need to have processed the
1714 // target of the alias before the alias itself and the symbols are not
1715 // necessarily ordered in this way.
1716 for (const MCSymbol
&S
: Asm
.symbols()) {
1717 if (!S
.isVariable())
1720 assert(S
.isDefined());
1722 const auto *BS
= Asm
.getBaseSymbol(S
);
1724 report_fatal_error(Twine(S
.getName()) +
1725 ": absolute addressing not supported!");
1726 const MCSymbolWasm
*Base
= cast
<MCSymbolWasm
>(BS
);
1728 // Find the target symbol of this weak alias and export that index
1729 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1730 LLVM_DEBUG(dbgs() << WS
.getName() << ": weak alias of '" << *Base
1733 if (Base
->isFunction()) {
1734 assert(WasmIndices
.count(Base
) > 0);
1735 uint32_t WasmIndex
= WasmIndices
.find(Base
)->second
;
1736 assert(WasmIndices
.count(&WS
) == 0);
1737 WasmIndices
[&WS
] = WasmIndex
;
1738 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex
<< "\n");
1739 } else if (Base
->isData()) {
1740 auto &DataSection
= static_cast<MCSectionWasm
&>(WS
.getSection());
1741 uint64_t Offset
= Asm
.getSymbolOffset(S
);
1743 // For data symbol alias we use the size of the base symbol as the
1744 // size of the alias. When an offset from the base is involved this
1745 // can result in a offset + size goes past the end of the data section
1746 // which out object format doesn't support. So we must clamp it.
1747 if (!Base
->getSize()->evaluateAsAbsolute(Size
, Asm
))
1748 report_fatal_error(".size expression must be evaluatable");
1749 const WasmDataSegment
&Segment
=
1750 DataSegments
[DataSection
.getSegmentIndex()];
1752 std::min(static_cast<uint64_t>(Size
), Segment
.Data
.size() - Offset
);
1753 wasm::WasmDataReference Ref
= wasm::WasmDataReference
{
1754 DataSection
.getSegmentIndex(),
1755 static_cast<uint32_t>(Asm
.getSymbolOffset(S
)),
1756 static_cast<uint32_t>(Size
)};
1757 DataLocations
[&WS
] = Ref
;
1758 LLVM_DEBUG(dbgs() << " -> index:" << Ref
.Segment
<< "\n");
1760 report_fatal_error("don't yet support global/tag aliases");
1765 // Finally, populate the symbol table itself, in its "natural" order.
1766 for (const MCSymbol
&S
: Asm
.symbols()) {
1767 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1768 if (!isInSymtab(WS
)) {
1769 WS
.setIndex(InvalidIndex
);
1772 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS
<< "\n");
1776 Flags
|= wasm::WASM_SYMBOL_BINDING_WEAK
;
1778 Flags
|= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN
;
1779 if (!WS
.isExternal() && WS
.isDefined())
1780 Flags
|= wasm::WASM_SYMBOL_BINDING_LOCAL
;
1781 if (WS
.isUndefined())
1782 Flags
|= wasm::WASM_SYMBOL_UNDEFINED
;
1783 if (WS
.isNoStrip()) {
1784 Flags
|= wasm::WASM_SYMBOL_NO_STRIP
;
1785 if (isEmscripten()) {
1786 Flags
|= wasm::WASM_SYMBOL_EXPORTED
;
1789 if (WS
.hasImportName())
1790 Flags
|= wasm::WASM_SYMBOL_EXPLICIT_NAME
;
1791 if (WS
.hasExportName())
1792 Flags
|= wasm::WASM_SYMBOL_EXPORTED
;
1794 Flags
|= wasm::WASM_SYMBOL_TLS
;
1796 wasm::WasmSymbolInfo Info
;
1797 Info
.Name
= WS
.getName();
1798 Info
.Kind
= WS
.getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA
);
1801 assert(WasmIndices
.count(&WS
) > 0);
1802 Info
.ElementIndex
= WasmIndices
.find(&WS
)->second
;
1803 } else if (WS
.isDefined()) {
1804 assert(DataLocations
.count(&WS
) > 0);
1805 Info
.DataRef
= DataLocations
.find(&WS
)->second
;
1807 WS
.setIndex(SymbolInfos
.size());
1808 SymbolInfos
.emplace_back(Info
);
1812 auto HandleReloc
= [&](const WasmRelocationEntry
&Rel
) {
1813 // Functions referenced by a relocation need to put in the table. This is
1814 // purely to make the object file's provisional values readable, and is
1815 // ignored by the linker, which re-calculates the relocations itself.
1816 if (Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_I32
&&
1817 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_I64
&&
1818 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_SLEB
&&
1819 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_SLEB64
&&
1820 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_REL_SLEB
&&
1821 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_REL_SLEB64
)
1823 assert(Rel
.Symbol
->isFunction());
1824 const MCSymbolWasm
*Base
=
1825 cast
<MCSymbolWasm
>(Asm
.getBaseSymbol(*Rel
.Symbol
));
1826 uint32_t FunctionIndex
= WasmIndices
.find(Base
)->second
;
1827 uint32_t TableIndex
= TableElems
.size() + InitialTableOffset
;
1828 if (TableIndices
.try_emplace(Base
, TableIndex
).second
) {
1829 LLVM_DEBUG(dbgs() << " -> adding " << Base
->getName()
1830 << " to table: " << TableIndex
<< "\n");
1831 TableElems
.push_back(FunctionIndex
);
1832 registerFunctionType(*Base
);
1836 for (const WasmRelocationEntry
&RelEntry
: CodeRelocations
)
1837 HandleReloc(RelEntry
);
1838 for (const WasmRelocationEntry
&RelEntry
: DataRelocations
)
1839 HandleReloc(RelEntry
);
1842 // Translate .init_array section contents into start functions.
1843 for (const MCSection
&S
: Asm
) {
1844 const auto &WS
= static_cast<const MCSectionWasm
&>(S
);
1845 if (WS
.getName().starts_with(".fini_array"))
1846 report_fatal_error(".fini_array sections are unsupported");
1847 if (!WS
.getName().starts_with(".init_array"))
1849 auto IT
= WS
.begin();
1852 const MCFragment
&EmptyFrag
= *IT
;
1853 if (EmptyFrag
.getKind() != MCFragment::FT_Data
)
1854 report_fatal_error(".init_array section should be aligned");
1856 const MCFragment
&AlignFrag
= *EmptyFrag
.getNext();
1857 if (AlignFrag
.getKind() != MCFragment::FT_Align
)
1858 report_fatal_error(".init_array section should be aligned");
1859 if (cast
<MCAlignFragment
>(AlignFrag
).getAlignment() !=
1860 Align(is64Bit() ? 8 : 4))
1861 report_fatal_error(".init_array section should be aligned for pointers");
1863 const MCFragment
&Frag
= *AlignFrag
.getNext();
1864 if (Frag
.hasInstructions() || Frag
.getKind() != MCFragment::FT_Data
)
1865 report_fatal_error("only data supported in .init_array section");
1867 uint16_t Priority
= UINT16_MAX
;
1868 unsigned PrefixLength
= strlen(".init_array");
1869 if (WS
.getName().size() > PrefixLength
) {
1870 if (WS
.getName()[PrefixLength
] != '.')
1872 ".init_array section priority should start with '.'");
1873 if (WS
.getName().substr(PrefixLength
+ 1).getAsInteger(10, Priority
))
1874 report_fatal_error("invalid .init_array section priority");
1876 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
1877 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
1878 for (const uint8_t *
1879 P
= (const uint8_t *)Contents
.data(),
1880 *End
= (const uint8_t *)Contents
.data() + Contents
.size();
1883 report_fatal_error("non-symbolic data in .init_array section");
1885 for (const MCFixup
&Fixup
: DataFrag
.getFixups()) {
1886 assert(Fixup
.getKind() ==
1887 MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1888 const MCExpr
*Expr
= Fixup
.getValue();
1889 auto *SymRef
= dyn_cast
<MCSymbolRefExpr
>(Expr
);
1891 report_fatal_error("fixups in .init_array should be symbol references");
1892 const auto &TargetSym
= cast
<const MCSymbolWasm
>(SymRef
->getSymbol());
1893 if (TargetSym
.getIndex() == InvalidIndex
)
1894 report_fatal_error("symbols in .init_array should exist in symtab");
1895 if (!TargetSym
.isFunction())
1896 report_fatal_error("symbols in .init_array should be for functions");
1897 InitFuncs
.push_back(
1898 std::make_pair(Priority
, TargetSym
.getIndex()));
1902 // Write out the Wasm header.
1905 uint32_t CodeSectionIndex
, DataSectionIndex
;
1906 if (Mode
!= DwoMode::DwoOnly
) {
1907 writeTypeSection(Signatures
);
1908 writeImportSection(Imports
, DataSize
, TableElems
.size());
1909 writeFunctionSection(Functions
);
1910 writeTableSection(Tables
);
1911 // Skip the "memory" section; we import the memory instead.
1912 writeTagSection(TagTypes
);
1913 writeGlobalSection(Globals
);
1914 writeExportSection(Exports
);
1915 const MCSymbol
*IndirectFunctionTable
=
1916 Asm
.getContext().lookupSymbol("__indirect_function_table");
1917 writeElemSection(cast_or_null
<const MCSymbolWasm
>(IndirectFunctionTable
),
1919 writeDataCountSection();
1921 CodeSectionIndex
= writeCodeSection(Asm
, Functions
);
1922 DataSectionIndex
= writeDataSection(Asm
);
1925 // The Sections in the COMDAT list have placeholder indices (their index among
1926 // custom sections, rather than among all sections). Fix them up here.
1927 for (auto &Group
: Comdats
) {
1928 for (auto &Entry
: Group
.second
) {
1929 if (Entry
.Kind
== wasm::WASM_COMDAT_SECTION
) {
1930 Entry
.Index
+= SectionCount
;
1934 for (auto &CustomSection
: CustomSections
)
1935 writeCustomSection(CustomSection
, Asm
);
1937 if (Mode
!= DwoMode::DwoOnly
) {
1938 writeLinkingMetaDataSection(SymbolInfos
, InitFuncs
, Comdats
);
1940 writeRelocSection(CodeSectionIndex
, "CODE", CodeRelocations
);
1941 writeRelocSection(DataSectionIndex
, "DATA", DataRelocations
);
1943 writeCustomRelocSections();
1944 if (ProducersSection
)
1945 writeCustomSection(*ProducersSection
, Asm
);
1946 if (TargetFeaturesSection
)
1947 writeCustomSection(*TargetFeaturesSection
, Asm
);
1949 // TODO: Translate the .comment section to the output.
1950 return W
->OS
.tell() - StartOffset
;
1953 std::unique_ptr
<MCObjectWriter
>
1954 llvm::createWasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
1955 raw_pwrite_stream
&OS
) {
1956 return std::make_unique
<WasmObjectWriter
>(std::move(MOTW
), OS
);
1959 std::unique_ptr
<MCObjectWriter
>
1960 llvm::createWasmDwoObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
1961 raw_pwrite_stream
&OS
,
1962 raw_pwrite_stream
&DwoOS
) {
1963 return std::make_unique
<WasmObjectWriter
>(std::move(MOTW
), OS
, DwoOS
);