1 //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements Wasm object file writer information.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/SmallPtrSet.h"
15 #include "llvm/BinaryFormat/Wasm.h"
16 #include "llvm/BinaryFormat/WasmTraits.h"
17 #include "llvm/Config/llvm-config.h"
18 #include "llvm/MC/MCAsmBackend.h"
19 #include "llvm/MC/MCAsmLayout.h"
20 #include "llvm/MC/MCAssembler.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCExpr.h"
23 #include "llvm/MC/MCFixupKindInfo.h"
24 #include "llvm/MC/MCObjectWriter.h"
25 #include "llvm/MC/MCSectionWasm.h"
26 #include "llvm/MC/MCSymbolWasm.h"
27 #include "llvm/MC/MCValue.h"
28 #include "llvm/MC/MCWasmObjectWriter.h"
29 #include "llvm/Support/Casting.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/EndianStream.h"
32 #include "llvm/Support/ErrorHandling.h"
33 #include "llvm/Support/LEB128.h"
34 #include "llvm/Support/StringSaver.h"
39 #define DEBUG_TYPE "mc"
43 // When we create the indirect function table we start at 1, so that there is
44 // and empty slot at 0 and therefore calling a null function pointer will trap.
45 static const uint32_t InitialTableOffset
= 1;
47 // For patching purposes, we need to remember where each section starts, both
48 // for patching up the section size field, and for patching up references to
49 // locations within the section.
50 struct SectionBookkeeping
{
51 // Where the size of the section is written.
53 // Where the section header ends (without custom section name).
54 uint64_t PayloadOffset
;
55 // Where the contents of the section starts.
56 uint64_t ContentsOffset
;
60 // A wasm data segment. A wasm binary contains only a single data section
61 // but that can contain many segments, each with their own virtual location
62 // in memory. Each MCSection data created by llvm is modeled as its own
64 struct WasmDataSegment
{
65 MCSectionWasm
*Section
;
70 uint32_t LinkingFlags
;
71 SmallVector
<char, 4> Data
;
74 // A wasm function to be written into the function section.
77 const MCSymbolWasm
*Sym
;
80 // A wasm global to be written into the global section.
82 wasm::WasmGlobalType Type
;
83 uint64_t InitialValue
;
86 // Information about a single item which is part of a COMDAT. For each data
87 // segment or function which is in the COMDAT, there is a corresponding
89 struct WasmComdatEntry
{
94 // Information about a single relocation.
95 struct WasmRelocationEntry
{
96 uint64_t Offset
; // Where is the relocation.
97 const MCSymbolWasm
*Symbol
; // The symbol to relocate with.
98 int64_t Addend
; // A value to add to the symbol.
99 unsigned Type
; // The type of the relocation.
100 const MCSectionWasm
*FixupSection
; // The section the relocation is targeting.
102 WasmRelocationEntry(uint64_t Offset
, const MCSymbolWasm
*Symbol
,
103 int64_t Addend
, unsigned Type
,
104 const MCSectionWasm
*FixupSection
)
105 : Offset(Offset
), Symbol(Symbol
), Addend(Addend
), Type(Type
),
106 FixupSection(FixupSection
) {}
108 bool hasAddend() const { return wasm::relocTypeHasAddend(Type
); }
110 void print(raw_ostream
&Out
) const {
111 Out
<< wasm::relocTypetoString(Type
) << " Off=" << Offset
112 << ", Sym=" << *Symbol
<< ", Addend=" << Addend
113 << ", FixupSection=" << FixupSection
->getName();
116 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
117 LLVM_DUMP_METHOD
void dump() const { print(dbgs()); }
121 static const uint32_t InvalidIndex
= -1;
123 struct WasmCustomSection
{
126 MCSectionWasm
*Section
;
128 uint32_t OutputContentsOffset
;
129 uint32_t OutputIndex
;
131 WasmCustomSection(StringRef Name
, MCSectionWasm
*Section
)
132 : Name(Name
), Section(Section
), OutputContentsOffset(0),
133 OutputIndex(InvalidIndex
) {}
137 raw_ostream
&operator<<(raw_ostream
&OS
, const WasmRelocationEntry
&Rel
) {
143 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded
144 // to allow patching.
146 void writePatchableLEB(raw_pwrite_stream
&Stream
, uint64_t X
, uint64_t Offset
) {
148 unsigned SizeLen
= encodeULEB128(X
, Buffer
, W
);
149 assert(SizeLen
== W
);
150 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
153 // Write X as an signed LEB value at offset Offset in Stream, padded
154 // to allow patching.
156 void writePatchableSLEB(raw_pwrite_stream
&Stream
, int64_t X
, uint64_t Offset
) {
158 unsigned SizeLen
= encodeSLEB128(X
, Buffer
, W
);
159 assert(SizeLen
== W
);
160 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
163 // Write X as a plain integer value at offset Offset in Stream.
164 static void patchI32(raw_pwrite_stream
&Stream
, uint32_t X
, uint64_t Offset
) {
166 support::endian::write32le(Buffer
, X
);
167 Stream
.pwrite((char *)Buffer
, sizeof(Buffer
), Offset
);
170 static void patchI64(raw_pwrite_stream
&Stream
, uint64_t X
, uint64_t Offset
) {
172 support::endian::write64le(Buffer
, X
);
173 Stream
.pwrite((char *)Buffer
, sizeof(Buffer
), Offset
);
176 bool isDwoSection(const MCSection
&Sec
) {
177 return Sec
.getName().endswith(".dwo");
180 class WasmObjectWriter
: public MCObjectWriter
{
181 support::endian::Writer
*W
;
183 /// The target specific Wasm writer instance.
184 std::unique_ptr
<MCWasmObjectTargetWriter
> TargetObjectWriter
;
186 // Relocations for fixing up references in the code section.
187 std::vector
<WasmRelocationEntry
> CodeRelocations
;
188 // Relocations for fixing up references in the data section.
189 std::vector
<WasmRelocationEntry
> DataRelocations
;
191 // Index values to use for fixing up call_indirect type indices.
192 // Maps function symbols to the index of the type of the function
193 DenseMap
<const MCSymbolWasm
*, uint32_t> TypeIndices
;
194 // Maps function symbols to the table element index space. Used
195 // for TABLE_INDEX relocation types (i.e. address taken functions).
196 DenseMap
<const MCSymbolWasm
*, uint32_t> TableIndices
;
197 // Maps function/global/table symbols to the
198 // function/global/table/tag/section index space.
199 DenseMap
<const MCSymbolWasm
*, uint32_t> WasmIndices
;
200 DenseMap
<const MCSymbolWasm
*, uint32_t> GOTIndices
;
201 // Maps data symbols to the Wasm segment and offset/size with the segment.
202 DenseMap
<const MCSymbolWasm
*, wasm::WasmDataReference
> DataLocations
;
204 // Stores output data (index, relocations, content offset) for custom
206 std::vector
<WasmCustomSection
> CustomSections
;
207 std::unique_ptr
<WasmCustomSection
> ProducersSection
;
208 std::unique_ptr
<WasmCustomSection
> TargetFeaturesSection
;
209 // Relocations for fixing up references in the custom sections.
210 DenseMap
<const MCSectionWasm
*, std::vector
<WasmRelocationEntry
>>
211 CustomSectionsRelocations
;
213 // Map from section to defining function symbol.
214 DenseMap
<const MCSection
*, const MCSymbol
*> SectionFunctions
;
216 DenseMap
<wasm::WasmSignature
, uint32_t> SignatureIndices
;
217 SmallVector
<wasm::WasmSignature
, 4> Signatures
;
218 SmallVector
<WasmDataSegment
, 4> DataSegments
;
219 unsigned NumFunctionImports
= 0;
220 unsigned NumGlobalImports
= 0;
221 unsigned NumTableImports
= 0;
222 unsigned NumTagImports
= 0;
223 uint32_t SectionCount
= 0;
230 bool IsSplitDwarf
= false;
231 raw_pwrite_stream
*OS
= nullptr;
232 raw_pwrite_stream
*DwoOS
= nullptr;
234 // TargetObjectWriter wranppers.
235 bool is64Bit() const { return TargetObjectWriter
->is64Bit(); }
236 bool isEmscripten() const { return TargetObjectWriter
->isEmscripten(); }
238 void startSection(SectionBookkeeping
&Section
, unsigned SectionId
);
239 void startCustomSection(SectionBookkeeping
&Section
, StringRef Name
);
240 void endSection(SectionBookkeeping
&Section
);
243 WasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
244 raw_pwrite_stream
&OS_
)
245 : TargetObjectWriter(std::move(MOTW
)), OS(&OS_
) {}
247 WasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
248 raw_pwrite_stream
&OS_
, raw_pwrite_stream
&DwoOS_
)
249 : TargetObjectWriter(std::move(MOTW
)), IsSplitDwarf(true), OS(&OS_
),
253 void reset() override
{
254 CodeRelocations
.clear();
255 DataRelocations
.clear();
259 TableIndices
.clear();
260 DataLocations
.clear();
261 CustomSections
.clear();
262 ProducersSection
.reset();
263 TargetFeaturesSection
.reset();
264 CustomSectionsRelocations
.clear();
265 SignatureIndices
.clear();
267 DataSegments
.clear();
268 SectionFunctions
.clear();
269 NumFunctionImports
= 0;
270 NumGlobalImports
= 0;
272 MCObjectWriter::reset();
275 void writeHeader(const MCAssembler
&Asm
);
277 void recordRelocation(MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
278 const MCFragment
*Fragment
, const MCFixup
&Fixup
,
279 MCValue Target
, uint64_t &FixedValue
) override
;
281 void executePostLayoutBinding(MCAssembler
&Asm
,
282 const MCAsmLayout
&Layout
) override
;
283 void prepareImports(SmallVectorImpl
<wasm::WasmImport
> &Imports
,
284 MCAssembler
&Asm
, const MCAsmLayout
&Layout
);
285 uint64_t writeObject(MCAssembler
&Asm
, const MCAsmLayout
&Layout
) override
;
287 uint64_t writeOneObject(MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
290 void writeString(const StringRef Str
) {
291 encodeULEB128(Str
.size(), W
->OS
);
295 void writeI32(int32_t val
) {
297 support::endian::write32le(Buffer
, val
);
298 W
->OS
.write(Buffer
, sizeof(Buffer
));
301 void writeI64(int64_t val
) {
303 support::endian::write64le(Buffer
, val
);
304 W
->OS
.write(Buffer
, sizeof(Buffer
));
307 void writeValueType(wasm::ValType Ty
) { W
->OS
<< static_cast<char>(Ty
); }
309 void writeTypeSection(ArrayRef
<wasm::WasmSignature
> Signatures
);
310 void writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
, uint64_t DataSize
,
311 uint32_t NumElements
);
312 void writeFunctionSection(ArrayRef
<WasmFunction
> Functions
);
313 void writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
);
314 void writeElemSection(const MCSymbolWasm
*IndirectFunctionTable
,
315 ArrayRef
<uint32_t> TableElems
);
316 void writeDataCountSection();
317 uint32_t writeCodeSection(const MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
318 ArrayRef
<WasmFunction
> Functions
);
319 uint32_t writeDataSection(const MCAsmLayout
&Layout
);
320 void writeTagSection(ArrayRef
<wasm::WasmTagType
> Tags
);
321 void writeGlobalSection(ArrayRef
<wasm::WasmGlobal
> Globals
);
322 void writeTableSection(ArrayRef
<wasm::WasmTable
> Tables
);
323 void writeRelocSection(uint32_t SectionIndex
, StringRef Name
,
324 std::vector
<WasmRelocationEntry
> &Relocations
);
325 void writeLinkingMetaDataSection(
326 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
327 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
328 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
);
329 void writeCustomSection(WasmCustomSection
&CustomSection
,
330 const MCAssembler
&Asm
, const MCAsmLayout
&Layout
);
331 void writeCustomRelocSections();
333 uint64_t getProvisionalValue(const WasmRelocationEntry
&RelEntry
,
334 const MCAsmLayout
&Layout
);
335 void applyRelocations(ArrayRef
<WasmRelocationEntry
> Relocations
,
336 uint64_t ContentsOffset
, const MCAsmLayout
&Layout
);
338 uint32_t getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
);
339 uint32_t getFunctionType(const MCSymbolWasm
&Symbol
);
340 uint32_t getTagType(const MCSymbolWasm
&Symbol
);
341 void registerFunctionType(const MCSymbolWasm
&Symbol
);
342 void registerTagType(const MCSymbolWasm
&Symbol
);
345 } // end anonymous namespace
347 // Write out a section header and a patchable section size field.
348 void WasmObjectWriter::startSection(SectionBookkeeping
&Section
,
349 unsigned SectionId
) {
350 LLVM_DEBUG(dbgs() << "startSection " << SectionId
<< "\n");
351 W
->OS
<< char(SectionId
);
353 Section
.SizeOffset
= W
->OS
.tell();
355 // The section size. We don't know the size yet, so reserve enough space
356 // for any 32-bit value; we'll patch it later.
357 encodeULEB128(0, W
->OS
, 5);
359 // The position where the section starts, for measuring its size.
360 Section
.ContentsOffset
= W
->OS
.tell();
361 Section
.PayloadOffset
= W
->OS
.tell();
362 Section
.Index
= SectionCount
++;
365 void WasmObjectWriter::startCustomSection(SectionBookkeeping
&Section
,
367 LLVM_DEBUG(dbgs() << "startCustomSection " << Name
<< "\n");
368 startSection(Section
, wasm::WASM_SEC_CUSTOM
);
370 // The position where the section header ends, for measuring its size.
371 Section
.PayloadOffset
= W
->OS
.tell();
373 // Custom sections in wasm also have a string identifier.
376 // The position where the custom section starts.
377 Section
.ContentsOffset
= W
->OS
.tell();
380 // Now that the section is complete and we know how big it is, patch up the
381 // section size field at the start of the section.
382 void WasmObjectWriter::endSection(SectionBookkeeping
&Section
) {
383 uint64_t Size
= W
->OS
.tell();
384 // /dev/null doesn't support seek/tell and can report offset of 0.
385 // Simply skip this patching in that case.
389 Size
-= Section
.PayloadOffset
;
390 if (uint32_t(Size
) != Size
)
391 report_fatal_error("section size does not fit in a uint32_t");
393 LLVM_DEBUG(dbgs() << "endSection size=" << Size
<< "\n");
395 // Write the final section size to the payload_len field, which follows
396 // the section id byte.
397 writePatchableLEB
<5>(static_cast<raw_pwrite_stream
&>(W
->OS
), Size
,
401 // Emit the Wasm header.
402 void WasmObjectWriter::writeHeader(const MCAssembler
&Asm
) {
403 W
->OS
.write(wasm::WasmMagic
, sizeof(wasm::WasmMagic
));
404 W
->write
<uint32_t>(wasm::WasmVersion
);
407 void WasmObjectWriter::executePostLayoutBinding(MCAssembler
&Asm
,
408 const MCAsmLayout
&Layout
) {
409 // Some compilation units require the indirect function table to be present
410 // but don't explicitly reference it. This is the case for call_indirect
411 // without the reference-types feature, and also function bitcasts in all
412 // cases. In those cases the __indirect_function_table has the
413 // WASM_SYMBOL_NO_STRIP attribute. Here we make sure this symbol makes it to
414 // the assembler, if needed.
415 if (auto *Sym
= Asm
.getContext().lookupSymbol("__indirect_function_table")) {
416 const auto *WasmSym
= static_cast<const MCSymbolWasm
*>(Sym
);
417 if (WasmSym
->isNoStrip())
418 Asm
.registerSymbol(*Sym
);
421 // Build a map of sections to the function that defines them, for use
422 // in recordRelocation.
423 for (const MCSymbol
&S
: Asm
.symbols()) {
424 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
425 if (WS
.isDefined() && WS
.isFunction() && !WS
.isVariable()) {
426 const auto &Sec
= static_cast<const MCSectionWasm
&>(S
.getSection());
427 auto Pair
= SectionFunctions
.insert(std::make_pair(&Sec
, &S
));
429 report_fatal_error("section already has a defining function: " +
435 void WasmObjectWriter::recordRelocation(MCAssembler
&Asm
,
436 const MCAsmLayout
&Layout
,
437 const MCFragment
*Fragment
,
438 const MCFixup
&Fixup
, MCValue Target
,
439 uint64_t &FixedValue
) {
440 // The WebAssembly backend should never generate FKF_IsPCRel fixups
441 assert(!(Asm
.getBackend().getFixupKindInfo(Fixup
.getKind()).Flags
&
442 MCFixupKindInfo::FKF_IsPCRel
));
444 const auto &FixupSection
= cast
<MCSectionWasm
>(*Fragment
->getParent());
445 uint64_t C
= Target
.getConstant();
446 uint64_t FixupOffset
= Layout
.getFragmentOffset(Fragment
) + Fixup
.getOffset();
447 MCContext
&Ctx
= Asm
.getContext();
448 bool IsLocRel
= false;
450 if (const MCSymbolRefExpr
*RefB
= Target
.getSymB()) {
452 const auto &SymB
= cast
<MCSymbolWasm
>(RefB
->getSymbol());
454 if (FixupSection
.getKind().isText()) {
455 Ctx
.reportError(Fixup
.getLoc(),
456 Twine("symbol '") + SymB
.getName() +
457 "' unsupported subtraction expression used in "
458 "relocation in code section.");
462 if (SymB
.isUndefined()) {
463 Ctx
.reportError(Fixup
.getLoc(),
464 Twine("symbol '") + SymB
.getName() +
465 "' can not be undefined in a subtraction expression");
468 const MCSection
&SecB
= SymB
.getSection();
469 if (&SecB
!= &FixupSection
) {
470 Ctx
.reportError(Fixup
.getLoc(),
471 Twine("symbol '") + SymB
.getName() +
472 "' can not be placed in a different section");
476 C
+= FixupOffset
- Layout
.getSymbolOffset(SymB
);
479 // We either rejected the fixup or folded B into C at this point.
480 const MCSymbolRefExpr
*RefA
= Target
.getSymA();
481 const auto *SymA
= cast
<MCSymbolWasm
>(&RefA
->getSymbol());
483 // The .init_array isn't translated as data, so don't do relocations in it.
484 if (FixupSection
.getName().startswith(".init_array")) {
485 SymA
->setUsedInInitArray();
489 if (SymA
->isVariable()) {
490 const MCExpr
*Expr
= SymA
->getVariableValue();
491 if (const auto *Inner
= dyn_cast
<MCSymbolRefExpr
>(Expr
))
492 if (Inner
->getKind() == MCSymbolRefExpr::VK_WEAKREF
)
493 llvm_unreachable("weakref used in reloc not yet implemented");
496 // Put any constant offset in an addend. Offsets can be negative, and
497 // LLVM expects wrapping, in contrast to wasm's immediates which can't
498 // be negative and don't wrap.
502 TargetObjectWriter
->getRelocType(Target
, Fixup
, FixupSection
, IsLocRel
);
504 // Absolute offset within a section or a function.
505 // Currently only supported for for metadata sections.
506 // See: test/MC/WebAssembly/blockaddress.ll
507 if ((Type
== wasm::R_WASM_FUNCTION_OFFSET_I32
||
508 Type
== wasm::R_WASM_FUNCTION_OFFSET_I64
||
509 Type
== wasm::R_WASM_SECTION_OFFSET_I32
) &&
511 // SymA can be a temp data symbol that represents a function (in which case
512 // it needs to be replaced by the section symbol), [XXX and it apparently
513 // later gets changed again to a func symbol?] or it can be a real
514 // function symbol, in which case it can be left as-is.
516 if (!FixupSection
.getKind().isMetadata())
517 report_fatal_error("relocations for function or section offsets are "
518 "only supported in metadata sections");
520 const MCSymbol
*SectionSymbol
= nullptr;
521 const MCSection
&SecA
= SymA
->getSection();
522 if (SecA
.getKind().isText()) {
523 auto SecSymIt
= SectionFunctions
.find(&SecA
);
524 if (SecSymIt
== SectionFunctions
.end())
525 report_fatal_error("section doesn\'t have defining symbol");
526 SectionSymbol
= SecSymIt
->second
;
528 SectionSymbol
= SecA
.getBeginSymbol();
531 report_fatal_error("section symbol is required for relocation");
533 C
+= Layout
.getSymbolOffset(*SymA
);
534 SymA
= cast
<MCSymbolWasm
>(SectionSymbol
);
537 if (Type
== wasm::R_WASM_TABLE_INDEX_REL_SLEB
||
538 Type
== wasm::R_WASM_TABLE_INDEX_REL_SLEB64
||
539 Type
== wasm::R_WASM_TABLE_INDEX_SLEB
||
540 Type
== wasm::R_WASM_TABLE_INDEX_SLEB64
||
541 Type
== wasm::R_WASM_TABLE_INDEX_I32
||
542 Type
== wasm::R_WASM_TABLE_INDEX_I64
) {
543 // TABLE_INDEX relocs implicitly use the default indirect function table.
544 // We require the function table to have already been defined.
545 auto TableName
= "__indirect_function_table";
546 MCSymbolWasm
*Sym
= cast_or_null
<MCSymbolWasm
>(Ctx
.lookupSymbol(TableName
));
548 report_fatal_error("missing indirect function table symbol");
550 if (!Sym
->isFunctionTable())
551 report_fatal_error("__indirect_function_table symbol has wrong type");
552 // Ensure that __indirect_function_table reaches the output.
554 Asm
.registerSymbol(*Sym
);
558 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
559 // against a named symbol.
560 if (Type
!= wasm::R_WASM_TYPE_INDEX_LEB
) {
561 if (SymA
->getName().empty())
562 report_fatal_error("relocations against un-named temporaries are not yet "
563 "supported by wasm");
565 SymA
->setUsedInReloc();
568 if (RefA
->getKind() == MCSymbolRefExpr::VK_GOT
)
569 SymA
->setUsedInGOT();
571 WasmRelocationEntry
Rec(FixupOffset
, SymA
, C
, Type
, &FixupSection
);
572 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec
<< "\n");
574 if (FixupSection
.isWasmData()) {
575 DataRelocations
.push_back(Rec
);
576 } else if (FixupSection
.getKind().isText()) {
577 CodeRelocations
.push_back(Rec
);
578 } else if (FixupSection
.getKind().isMetadata()) {
579 CustomSectionsRelocations
[&FixupSection
].push_back(Rec
);
581 llvm_unreachable("unexpected section type");
585 // Compute a value to write into the code at the location covered
586 // by RelEntry. This value isn't used by the static linker; it just serves
587 // to make the object format more readable and more likely to be directly
590 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry
&RelEntry
,
591 const MCAsmLayout
&Layout
) {
592 if ((RelEntry
.Type
== wasm::R_WASM_GLOBAL_INDEX_LEB
||
593 RelEntry
.Type
== wasm::R_WASM_GLOBAL_INDEX_I32
) &&
594 !RelEntry
.Symbol
->isGlobal()) {
595 assert(GOTIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in GOT index space");
596 return GOTIndices
[RelEntry
.Symbol
];
599 switch (RelEntry
.Type
) {
600 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
601 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64
:
602 case wasm::R_WASM_TABLE_INDEX_SLEB
:
603 case wasm::R_WASM_TABLE_INDEX_SLEB64
:
604 case wasm::R_WASM_TABLE_INDEX_I32
:
605 case wasm::R_WASM_TABLE_INDEX_I64
: {
606 // Provisional value is table address of the resolved symbol itself
607 const MCSymbolWasm
*Base
=
608 cast
<MCSymbolWasm
>(Layout
.getBaseSymbol(*RelEntry
.Symbol
));
609 assert(Base
->isFunction());
610 if (RelEntry
.Type
== wasm::R_WASM_TABLE_INDEX_REL_SLEB
||
611 RelEntry
.Type
== wasm::R_WASM_TABLE_INDEX_REL_SLEB64
)
612 return TableIndices
[Base
] - InitialTableOffset
;
614 return TableIndices
[Base
];
616 case wasm::R_WASM_TYPE_INDEX_LEB
:
617 // Provisional value is same as the index
618 return getRelocationIndexValue(RelEntry
);
619 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
620 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
621 case wasm::R_WASM_GLOBAL_INDEX_I32
:
622 case wasm::R_WASM_TAG_INDEX_LEB
:
623 case wasm::R_WASM_TABLE_NUMBER_LEB
:
624 // Provisional value is function/global/tag Wasm index
625 assert(WasmIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in wasm index space");
626 return WasmIndices
[RelEntry
.Symbol
];
627 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
628 case wasm::R_WASM_FUNCTION_OFFSET_I64
:
629 case wasm::R_WASM_SECTION_OFFSET_I32
: {
630 if (!RelEntry
.Symbol
->isDefined())
632 const auto &Section
=
633 static_cast<const MCSectionWasm
&>(RelEntry
.Symbol
->getSection());
634 return Section
.getSectionOffset() + RelEntry
.Addend
;
636 case wasm::R_WASM_MEMORY_ADDR_LEB
:
637 case wasm::R_WASM_MEMORY_ADDR_LEB64
:
638 case wasm::R_WASM_MEMORY_ADDR_SLEB
:
639 case wasm::R_WASM_MEMORY_ADDR_SLEB64
:
640 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
641 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64
:
642 case wasm::R_WASM_MEMORY_ADDR_I32
:
643 case wasm::R_WASM_MEMORY_ADDR_I64
:
644 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB
:
645 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64
:
646 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32
: {
647 // Provisional value is address of the global plus the offset
648 // For undefined symbols, use zero
649 if (!RelEntry
.Symbol
->isDefined())
651 const wasm::WasmDataReference
&SymRef
= DataLocations
[RelEntry
.Symbol
];
652 const WasmDataSegment
&Segment
= DataSegments
[SymRef
.Segment
];
653 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
654 return Segment
.Offset
+ SymRef
.Offset
+ RelEntry
.Addend
;
657 llvm_unreachable("invalid relocation type");
661 static void addData(SmallVectorImpl
<char> &DataBytes
,
662 MCSectionWasm
&DataSection
) {
663 LLVM_DEBUG(errs() << "addData: " << DataSection
.getName() << "\n");
665 DataBytes
.resize(alignTo(DataBytes
.size(), DataSection
.getAlignment()));
667 for (const MCFragment
&Frag
: DataSection
) {
668 if (Frag
.hasInstructions())
669 report_fatal_error("only data supported in data sections");
671 if (auto *Align
= dyn_cast
<MCAlignFragment
>(&Frag
)) {
672 if (Align
->getValueSize() != 1)
673 report_fatal_error("only byte values supported for alignment");
674 // If nops are requested, use zeros, as this is the data section.
675 uint8_t Value
= Align
->hasEmitNops() ? 0 : Align
->getValue();
677 std::min
<uint64_t>(alignTo(DataBytes
.size(), Align
->getAlignment()),
678 DataBytes
.size() + Align
->getMaxBytesToEmit());
679 DataBytes
.resize(Size
, Value
);
680 } else if (auto *Fill
= dyn_cast
<MCFillFragment
>(&Frag
)) {
682 if (!Fill
->getNumValues().evaluateAsAbsolute(NumValues
))
683 llvm_unreachable("The fill should be an assembler constant");
684 DataBytes
.insert(DataBytes
.end(), Fill
->getValueSize() * NumValues
,
686 } else if (auto *LEB
= dyn_cast
<MCLEBFragment
>(&Frag
)) {
687 const SmallVectorImpl
<char> &Contents
= LEB
->getContents();
688 llvm::append_range(DataBytes
, Contents
);
690 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
691 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
692 llvm::append_range(DataBytes
, Contents
);
696 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes
.size() << "\n");
700 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
) {
701 if (RelEntry
.Type
== wasm::R_WASM_TYPE_INDEX_LEB
) {
702 if (!TypeIndices
.count(RelEntry
.Symbol
))
703 report_fatal_error("symbol not found in type index space: " +
704 RelEntry
.Symbol
->getName());
705 return TypeIndices
[RelEntry
.Symbol
];
708 return RelEntry
.Symbol
->getIndex();
711 // Apply the portions of the relocation records that we can handle ourselves
713 void WasmObjectWriter::applyRelocations(
714 ArrayRef
<WasmRelocationEntry
> Relocations
, uint64_t ContentsOffset
,
715 const MCAsmLayout
&Layout
) {
716 auto &Stream
= static_cast<raw_pwrite_stream
&>(W
->OS
);
717 for (const WasmRelocationEntry
&RelEntry
: Relocations
) {
718 uint64_t Offset
= ContentsOffset
+
719 RelEntry
.FixupSection
->getSectionOffset() +
722 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry
<< "\n");
723 auto Value
= getProvisionalValue(RelEntry
, Layout
);
725 switch (RelEntry
.Type
) {
726 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
727 case wasm::R_WASM_TYPE_INDEX_LEB
:
728 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
729 case wasm::R_WASM_MEMORY_ADDR_LEB
:
730 case wasm::R_WASM_TAG_INDEX_LEB
:
731 case wasm::R_WASM_TABLE_NUMBER_LEB
:
732 writePatchableLEB
<5>(Stream
, Value
, Offset
);
734 case wasm::R_WASM_MEMORY_ADDR_LEB64
:
735 writePatchableLEB
<10>(Stream
, Value
, Offset
);
737 case wasm::R_WASM_TABLE_INDEX_I32
:
738 case wasm::R_WASM_MEMORY_ADDR_I32
:
739 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
740 case wasm::R_WASM_SECTION_OFFSET_I32
:
741 case wasm::R_WASM_GLOBAL_INDEX_I32
:
742 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32
:
743 patchI32(Stream
, Value
, Offset
);
745 case wasm::R_WASM_TABLE_INDEX_I64
:
746 case wasm::R_WASM_MEMORY_ADDR_I64
:
747 case wasm::R_WASM_FUNCTION_OFFSET_I64
:
748 patchI64(Stream
, Value
, Offset
);
750 case wasm::R_WASM_TABLE_INDEX_SLEB
:
751 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
752 case wasm::R_WASM_MEMORY_ADDR_SLEB
:
753 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
754 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB
:
755 writePatchableSLEB
<5>(Stream
, Value
, Offset
);
757 case wasm::R_WASM_TABLE_INDEX_SLEB64
:
758 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64
:
759 case wasm::R_WASM_MEMORY_ADDR_SLEB64
:
760 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64
:
761 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64
:
762 writePatchableSLEB
<10>(Stream
, Value
, Offset
);
765 llvm_unreachable("invalid relocation type");
770 void WasmObjectWriter::writeTypeSection(
771 ArrayRef
<wasm::WasmSignature
> Signatures
) {
772 if (Signatures
.empty())
775 SectionBookkeeping Section
;
776 startSection(Section
, wasm::WASM_SEC_TYPE
);
778 encodeULEB128(Signatures
.size(), W
->OS
);
780 for (const wasm::WasmSignature
&Sig
: Signatures
) {
781 W
->OS
<< char(wasm::WASM_TYPE_FUNC
);
782 encodeULEB128(Sig
.Params
.size(), W
->OS
);
783 for (wasm::ValType Ty
: Sig
.Params
)
785 encodeULEB128(Sig
.Returns
.size(), W
->OS
);
786 for (wasm::ValType Ty
: Sig
.Returns
)
793 void WasmObjectWriter::writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
,
795 uint32_t NumElements
) {
799 uint64_t NumPages
= (DataSize
+ wasm::WasmPageSize
- 1) / wasm::WasmPageSize
;
801 SectionBookkeeping Section
;
802 startSection(Section
, wasm::WASM_SEC_IMPORT
);
804 encodeULEB128(Imports
.size(), W
->OS
);
805 for (const wasm::WasmImport
&Import
: Imports
) {
806 writeString(Import
.Module
);
807 writeString(Import
.Field
);
808 W
->OS
<< char(Import
.Kind
);
810 switch (Import
.Kind
) {
811 case wasm::WASM_EXTERNAL_FUNCTION
:
812 encodeULEB128(Import
.SigIndex
, W
->OS
);
814 case wasm::WASM_EXTERNAL_GLOBAL
:
815 W
->OS
<< char(Import
.Global
.Type
);
816 W
->OS
<< char(Import
.Global
.Mutable
? 1 : 0);
818 case wasm::WASM_EXTERNAL_MEMORY
:
819 encodeULEB128(Import
.Memory
.Flags
, W
->OS
);
820 encodeULEB128(NumPages
, W
->OS
); // initial
822 case wasm::WASM_EXTERNAL_TABLE
:
823 W
->OS
<< char(Import
.Table
.ElemType
);
824 encodeULEB128(0, W
->OS
); // flags
825 encodeULEB128(NumElements
, W
->OS
); // initial
827 case wasm::WASM_EXTERNAL_TAG
:
828 W
->OS
<< char(Import
.Tag
.Attribute
);
829 encodeULEB128(Import
.Tag
.SigIndex
, W
->OS
);
832 llvm_unreachable("unsupported import kind");
839 void WasmObjectWriter::writeFunctionSection(ArrayRef
<WasmFunction
> Functions
) {
840 if (Functions
.empty())
843 SectionBookkeeping Section
;
844 startSection(Section
, wasm::WASM_SEC_FUNCTION
);
846 encodeULEB128(Functions
.size(), W
->OS
);
847 for (const WasmFunction
&Func
: Functions
)
848 encodeULEB128(Func
.SigIndex
, W
->OS
);
853 void WasmObjectWriter::writeTagSection(ArrayRef
<wasm::WasmTagType
> Tags
) {
857 SectionBookkeeping Section
;
858 startSection(Section
, wasm::WASM_SEC_TAG
);
860 encodeULEB128(Tags
.size(), W
->OS
);
861 for (const wasm::WasmTagType
&Tag
: Tags
) {
862 W
->OS
<< char(Tag
.Attribute
);
863 encodeULEB128(Tag
.SigIndex
, W
->OS
);
869 void WasmObjectWriter::writeGlobalSection(ArrayRef
<wasm::WasmGlobal
> Globals
) {
873 SectionBookkeeping Section
;
874 startSection(Section
, wasm::WASM_SEC_GLOBAL
);
876 encodeULEB128(Globals
.size(), W
->OS
);
877 for (const wasm::WasmGlobal
&Global
: Globals
) {
878 encodeULEB128(Global
.Type
.Type
, W
->OS
);
879 W
->OS
<< char(Global
.Type
.Mutable
);
880 W
->OS
<< char(Global
.InitExpr
.Opcode
);
881 switch (Global
.Type
.Type
) {
882 case wasm::WASM_TYPE_I32
:
883 encodeSLEB128(0, W
->OS
);
885 case wasm::WASM_TYPE_I64
:
886 encodeSLEB128(0, W
->OS
);
888 case wasm::WASM_TYPE_F32
:
891 case wasm::WASM_TYPE_F64
:
894 case wasm::WASM_TYPE_EXTERNREF
:
895 writeValueType(wasm::ValType::EXTERNREF
);
898 llvm_unreachable("unexpected type");
900 W
->OS
<< char(wasm::WASM_OPCODE_END
);
906 void WasmObjectWriter::writeTableSection(ArrayRef
<wasm::WasmTable
> Tables
) {
910 SectionBookkeeping Section
;
911 startSection(Section
, wasm::WASM_SEC_TABLE
);
913 encodeULEB128(Tables
.size(), W
->OS
);
914 for (const wasm::WasmTable
&Table
: Tables
) {
915 encodeULEB128(Table
.Type
.ElemType
, W
->OS
);
916 encodeULEB128(Table
.Type
.Limits
.Flags
, W
->OS
);
917 encodeULEB128(Table
.Type
.Limits
.Minimum
, W
->OS
);
918 if (Table
.Type
.Limits
.Flags
& wasm::WASM_LIMITS_FLAG_HAS_MAX
)
919 encodeULEB128(Table
.Type
.Limits
.Maximum
, W
->OS
);
924 void WasmObjectWriter::writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
) {
928 SectionBookkeeping Section
;
929 startSection(Section
, wasm::WASM_SEC_EXPORT
);
931 encodeULEB128(Exports
.size(), W
->OS
);
932 for (const wasm::WasmExport
&Export
: Exports
) {
933 writeString(Export
.Name
);
934 W
->OS
<< char(Export
.Kind
);
935 encodeULEB128(Export
.Index
, W
->OS
);
941 void WasmObjectWriter::writeElemSection(
942 const MCSymbolWasm
*IndirectFunctionTable
, ArrayRef
<uint32_t> TableElems
) {
943 if (TableElems
.empty())
946 assert(IndirectFunctionTable
);
948 SectionBookkeeping Section
;
949 startSection(Section
, wasm::WASM_SEC_ELEM
);
951 encodeULEB128(1, W
->OS
); // number of "segments"
953 assert(WasmIndices
.count(IndirectFunctionTable
));
954 uint32_t TableNumber
= WasmIndices
.find(IndirectFunctionTable
)->second
;
957 Flags
|= wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER
;
958 encodeULEB128(Flags
, W
->OS
);
959 if (Flags
& wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER
)
960 encodeULEB128(TableNumber
, W
->OS
); // the table number
962 // init expr for starting offset
963 W
->OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
964 encodeSLEB128(InitialTableOffset
, W
->OS
);
965 W
->OS
<< char(wasm::WASM_OPCODE_END
);
967 if (Flags
& wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND
) {
968 // We only write active function table initializers, for which the elem kind
969 // is specified to be written as 0x00 and interpreted to mean "funcref".
970 const uint8_t ElemKind
= 0;
974 encodeULEB128(TableElems
.size(), W
->OS
);
975 for (uint32_t Elem
: TableElems
)
976 encodeULEB128(Elem
, W
->OS
);
981 void WasmObjectWriter::writeDataCountSection() {
982 if (DataSegments
.empty())
985 SectionBookkeeping Section
;
986 startSection(Section
, wasm::WASM_SEC_DATACOUNT
);
987 encodeULEB128(DataSegments
.size(), W
->OS
);
991 uint32_t WasmObjectWriter::writeCodeSection(const MCAssembler
&Asm
,
992 const MCAsmLayout
&Layout
,
993 ArrayRef
<WasmFunction
> Functions
) {
994 if (Functions
.empty())
997 SectionBookkeeping Section
;
998 startSection(Section
, wasm::WASM_SEC_CODE
);
1000 encodeULEB128(Functions
.size(), W
->OS
);
1002 for (const WasmFunction
&Func
: Functions
) {
1003 auto &FuncSection
= static_cast<MCSectionWasm
&>(Func
.Sym
->getSection());
1006 if (!Func
.Sym
->getSize()->evaluateAsAbsolute(Size
, Layout
))
1007 report_fatal_error(".size expression must be evaluatable");
1009 encodeULEB128(Size
, W
->OS
);
1010 FuncSection
.setSectionOffset(W
->OS
.tell() - Section
.ContentsOffset
);
1011 Asm
.writeSectionData(W
->OS
, &FuncSection
, Layout
);
1015 applyRelocations(CodeRelocations
, Section
.ContentsOffset
, Layout
);
1017 endSection(Section
);
1018 return Section
.Index
;
1021 uint32_t WasmObjectWriter::writeDataSection(const MCAsmLayout
&Layout
) {
1022 if (DataSegments
.empty())
1025 SectionBookkeeping Section
;
1026 startSection(Section
, wasm::WASM_SEC_DATA
);
1028 encodeULEB128(DataSegments
.size(), W
->OS
); // count
1030 for (const WasmDataSegment
&Segment
: DataSegments
) {
1031 encodeULEB128(Segment
.InitFlags
, W
->OS
); // flags
1032 if (Segment
.InitFlags
& wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX
)
1033 encodeULEB128(0, W
->OS
); // memory index
1034 if ((Segment
.InitFlags
& wasm::WASM_DATA_SEGMENT_IS_PASSIVE
) == 0) {
1035 W
->OS
<< char(is64Bit() ? wasm::WASM_OPCODE_I64_CONST
1036 : wasm::WASM_OPCODE_I32_CONST
);
1037 encodeSLEB128(Segment
.Offset
, W
->OS
); // offset
1038 W
->OS
<< char(wasm::WASM_OPCODE_END
);
1040 encodeULEB128(Segment
.Data
.size(), W
->OS
); // size
1041 Segment
.Section
->setSectionOffset(W
->OS
.tell() - Section
.ContentsOffset
);
1042 W
->OS
<< Segment
.Data
; // data
1046 applyRelocations(DataRelocations
, Section
.ContentsOffset
, Layout
);
1048 endSection(Section
);
1049 return Section
.Index
;
1052 void WasmObjectWriter::writeRelocSection(
1053 uint32_t SectionIndex
, StringRef Name
,
1054 std::vector
<WasmRelocationEntry
> &Relocs
) {
1055 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
1056 // for descriptions of the reloc sections.
1061 // First, ensure the relocations are sorted in offset order. In general they
1062 // should already be sorted since `recordRelocation` is called in offset
1063 // order, but for the code section we combine many MC sections into single
1064 // wasm section, and this order is determined by the order of Asm.Symbols()
1065 // not the sections order.
1067 Relocs
, [](const WasmRelocationEntry
&A
, const WasmRelocationEntry
&B
) {
1068 return (A
.Offset
+ A
.FixupSection
->getSectionOffset()) <
1069 (B
.Offset
+ B
.FixupSection
->getSectionOffset());
1072 SectionBookkeeping Section
;
1073 startCustomSection(Section
, std::string("reloc.") + Name
.str());
1075 encodeULEB128(SectionIndex
, W
->OS
);
1076 encodeULEB128(Relocs
.size(), W
->OS
);
1077 for (const WasmRelocationEntry
&RelEntry
: Relocs
) {
1079 RelEntry
.Offset
+ RelEntry
.FixupSection
->getSectionOffset();
1080 uint32_t Index
= getRelocationIndexValue(RelEntry
);
1082 W
->OS
<< char(RelEntry
.Type
);
1083 encodeULEB128(Offset
, W
->OS
);
1084 encodeULEB128(Index
, W
->OS
);
1085 if (RelEntry
.hasAddend())
1086 encodeSLEB128(RelEntry
.Addend
, W
->OS
);
1089 endSection(Section
);
1092 void WasmObjectWriter::writeCustomRelocSections() {
1093 for (const auto &Sec
: CustomSections
) {
1094 auto &Relocations
= CustomSectionsRelocations
[Sec
.Section
];
1095 writeRelocSection(Sec
.OutputIndex
, Sec
.Name
, Relocations
);
1099 void WasmObjectWriter::writeLinkingMetaDataSection(
1100 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
1101 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
1102 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
) {
1103 SectionBookkeeping Section
;
1104 startCustomSection(Section
, "linking");
1105 encodeULEB128(wasm::WasmMetadataVersion
, W
->OS
);
1107 SectionBookkeeping SubSection
;
1108 if (SymbolInfos
.size() != 0) {
1109 startSection(SubSection
, wasm::WASM_SYMBOL_TABLE
);
1110 encodeULEB128(SymbolInfos
.size(), W
->OS
);
1111 for (const wasm::WasmSymbolInfo
&Sym
: SymbolInfos
) {
1112 encodeULEB128(Sym
.Kind
, W
->OS
);
1113 encodeULEB128(Sym
.Flags
, W
->OS
);
1115 case wasm::WASM_SYMBOL_TYPE_FUNCTION
:
1116 case wasm::WASM_SYMBOL_TYPE_GLOBAL
:
1117 case wasm::WASM_SYMBOL_TYPE_TAG
:
1118 case wasm::WASM_SYMBOL_TYPE_TABLE
:
1119 encodeULEB128(Sym
.ElementIndex
, W
->OS
);
1120 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0 ||
1121 (Sym
.Flags
& wasm::WASM_SYMBOL_EXPLICIT_NAME
) != 0)
1122 writeString(Sym
.Name
);
1124 case wasm::WASM_SYMBOL_TYPE_DATA
:
1125 writeString(Sym
.Name
);
1126 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0) {
1127 encodeULEB128(Sym
.DataRef
.Segment
, W
->OS
);
1128 encodeULEB128(Sym
.DataRef
.Offset
, W
->OS
);
1129 encodeULEB128(Sym
.DataRef
.Size
, W
->OS
);
1132 case wasm::WASM_SYMBOL_TYPE_SECTION
: {
1133 const uint32_t SectionIndex
=
1134 CustomSections
[Sym
.ElementIndex
].OutputIndex
;
1135 encodeULEB128(SectionIndex
, W
->OS
);
1139 llvm_unreachable("unexpected kind");
1142 endSection(SubSection
);
1145 if (DataSegments
.size()) {
1146 startSection(SubSection
, wasm::WASM_SEGMENT_INFO
);
1147 encodeULEB128(DataSegments
.size(), W
->OS
);
1148 for (const WasmDataSegment
&Segment
: DataSegments
) {
1149 writeString(Segment
.Name
);
1150 encodeULEB128(Segment
.Alignment
, W
->OS
);
1151 encodeULEB128(Segment
.LinkingFlags
, W
->OS
);
1153 endSection(SubSection
);
1156 if (!InitFuncs
.empty()) {
1157 startSection(SubSection
, wasm::WASM_INIT_FUNCS
);
1158 encodeULEB128(InitFuncs
.size(), W
->OS
);
1159 for (auto &StartFunc
: InitFuncs
) {
1160 encodeULEB128(StartFunc
.first
, W
->OS
); // priority
1161 encodeULEB128(StartFunc
.second
, W
->OS
); // function index
1163 endSection(SubSection
);
1166 if (Comdats
.size()) {
1167 startSection(SubSection
, wasm::WASM_COMDAT_INFO
);
1168 encodeULEB128(Comdats
.size(), W
->OS
);
1169 for (const auto &C
: Comdats
) {
1170 writeString(C
.first
);
1171 encodeULEB128(0, W
->OS
); // flags for future use
1172 encodeULEB128(C
.second
.size(), W
->OS
);
1173 for (const WasmComdatEntry
&Entry
: C
.second
) {
1174 encodeULEB128(Entry
.Kind
, W
->OS
);
1175 encodeULEB128(Entry
.Index
, W
->OS
);
1178 endSection(SubSection
);
1181 endSection(Section
);
1184 void WasmObjectWriter::writeCustomSection(WasmCustomSection
&CustomSection
,
1185 const MCAssembler
&Asm
,
1186 const MCAsmLayout
&Layout
) {
1187 SectionBookkeeping Section
;
1188 auto *Sec
= CustomSection
.Section
;
1189 startCustomSection(Section
, CustomSection
.Name
);
1191 Sec
->setSectionOffset(W
->OS
.tell() - Section
.ContentsOffset
);
1192 Asm
.writeSectionData(W
->OS
, Sec
, Layout
);
1194 CustomSection
.OutputContentsOffset
= Section
.ContentsOffset
;
1195 CustomSection
.OutputIndex
= Section
.Index
;
1197 endSection(Section
);
1200 auto &Relocations
= CustomSectionsRelocations
[CustomSection
.Section
];
1201 applyRelocations(Relocations
, CustomSection
.OutputContentsOffset
, Layout
);
1204 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm
&Symbol
) {
1205 assert(Symbol
.isFunction());
1206 assert(TypeIndices
.count(&Symbol
));
1207 return TypeIndices
[&Symbol
];
1210 uint32_t WasmObjectWriter::getTagType(const MCSymbolWasm
&Symbol
) {
1211 assert(Symbol
.isTag());
1212 assert(TypeIndices
.count(&Symbol
));
1213 return TypeIndices
[&Symbol
];
1216 void WasmObjectWriter::registerFunctionType(const MCSymbolWasm
&Symbol
) {
1217 assert(Symbol
.isFunction());
1219 wasm::WasmSignature S
;
1221 if (auto *Sig
= Symbol
.getSignature()) {
1222 S
.Returns
= Sig
->Returns
;
1223 S
.Params
= Sig
->Params
;
1226 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1228 Signatures
.push_back(S
);
1229 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1231 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
1232 << " new:" << Pair
.second
<< "\n");
1233 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1236 void WasmObjectWriter::registerTagType(const MCSymbolWasm
&Symbol
) {
1237 assert(Symbol
.isTag());
1239 // TODO Currently we don't generate imported exceptions, but if we do, we
1240 // should have a way of infering types of imported exceptions.
1241 wasm::WasmSignature S
;
1242 if (auto *Sig
= Symbol
.getSignature()) {
1243 S
.Returns
= Sig
->Returns
;
1244 S
.Params
= Sig
->Params
;
1247 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1249 Signatures
.push_back(S
);
1250 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1252 LLVM_DEBUG(dbgs() << "registerTagType: " << Symbol
<< " new:" << Pair
.second
1254 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1257 static bool isInSymtab(const MCSymbolWasm
&Sym
) {
1258 if (Sym
.isUsedInReloc() || Sym
.isUsedInInitArray())
1261 if (Sym
.isComdat() && !Sym
.isDefined())
1264 if (Sym
.isTemporary())
1267 if (Sym
.isSection())
1270 if (Sym
.omitFromLinkingSection())
1276 void WasmObjectWriter::prepareImports(
1277 SmallVectorImpl
<wasm::WasmImport
> &Imports
, MCAssembler
&Asm
,
1278 const MCAsmLayout
&Layout
) {
1279 // For now, always emit the memory import, since loads and stores are not
1280 // valid without it. In the future, we could perhaps be more clever and omit
1281 // it if there are no loads or stores.
1282 wasm::WasmImport MemImport
;
1283 MemImport
.Module
= "env";
1284 MemImport
.Field
= "__linear_memory";
1285 MemImport
.Kind
= wasm::WASM_EXTERNAL_MEMORY
;
1286 MemImport
.Memory
.Flags
= is64Bit() ? wasm::WASM_LIMITS_FLAG_IS_64
1287 : wasm::WASM_LIMITS_FLAG_NONE
;
1288 Imports
.push_back(MemImport
);
1290 // Populate SignatureIndices, and Imports and WasmIndices for undefined
1291 // symbols. This must be done before populating WasmIndices for defined
1293 for (const MCSymbol
&S
: Asm
.symbols()) {
1294 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1296 // Register types for all functions, including those with private linkage
1297 // (because wasm always needs a type signature).
1298 if (WS
.isFunction()) {
1299 const auto *BS
= Layout
.getBaseSymbol(S
);
1301 report_fatal_error(Twine(S
.getName()) +
1302 ": absolute addressing not supported!");
1303 registerFunctionType(*cast
<MCSymbolWasm
>(BS
));
1307 registerTagType(WS
);
1309 if (WS
.isTemporary())
1312 // If the symbol is not defined in this translation unit, import it.
1313 if (!WS
.isDefined() && !WS
.isComdat()) {
1314 if (WS
.isFunction()) {
1315 wasm::WasmImport Import
;
1316 Import
.Module
= WS
.getImportModule();
1317 Import
.Field
= WS
.getImportName();
1318 Import
.Kind
= wasm::WASM_EXTERNAL_FUNCTION
;
1319 Import
.SigIndex
= getFunctionType(WS
);
1320 Imports
.push_back(Import
);
1321 assert(WasmIndices
.count(&WS
) == 0);
1322 WasmIndices
[&WS
] = NumFunctionImports
++;
1323 } else if (WS
.isGlobal()) {
1325 report_fatal_error("undefined global symbol cannot be weak");
1327 wasm::WasmImport Import
;
1328 Import
.Field
= WS
.getImportName();
1329 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1330 Import
.Module
= WS
.getImportModule();
1331 Import
.Global
= WS
.getGlobalType();
1332 Imports
.push_back(Import
);
1333 assert(WasmIndices
.count(&WS
) == 0);
1334 WasmIndices
[&WS
] = NumGlobalImports
++;
1335 } else if (WS
.isTag()) {
1337 report_fatal_error("undefined tag symbol cannot be weak");
1339 wasm::WasmImport Import
;
1340 Import
.Module
= WS
.getImportModule();
1341 Import
.Field
= WS
.getImportName();
1342 Import
.Kind
= wasm::WASM_EXTERNAL_TAG
;
1343 Import
.Tag
.Attribute
= wasm::WASM_TAG_ATTRIBUTE_EXCEPTION
;
1344 Import
.Tag
.SigIndex
= getTagType(WS
);
1345 Imports
.push_back(Import
);
1346 assert(WasmIndices
.count(&WS
) == 0);
1347 WasmIndices
[&WS
] = NumTagImports
++;
1348 } else if (WS
.isTable()) {
1350 report_fatal_error("undefined table symbol cannot be weak");
1352 wasm::WasmImport Import
;
1353 Import
.Module
= WS
.getImportModule();
1354 Import
.Field
= WS
.getImportName();
1355 Import
.Kind
= wasm::WASM_EXTERNAL_TABLE
;
1356 Import
.Table
= WS
.getTableType();
1357 Imports
.push_back(Import
);
1358 assert(WasmIndices
.count(&WS
) == 0);
1359 WasmIndices
[&WS
] = NumTableImports
++;
1364 // Add imports for GOT globals
1365 for (const MCSymbol
&S
: Asm
.symbols()) {
1366 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1367 if (WS
.isUsedInGOT()) {
1368 wasm::WasmImport Import
;
1369 if (WS
.isFunction())
1370 Import
.Module
= "GOT.func";
1372 Import
.Module
= "GOT.mem";
1373 Import
.Field
= WS
.getName();
1374 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1375 Import
.Global
= {wasm::WASM_TYPE_I32
, true};
1376 Imports
.push_back(Import
);
1377 assert(GOTIndices
.count(&WS
) == 0);
1378 GOTIndices
[&WS
] = NumGlobalImports
++;
1383 uint64_t WasmObjectWriter::writeObject(MCAssembler
&Asm
,
1384 const MCAsmLayout
&Layout
) {
1385 support::endian::Writer
MainWriter(*OS
, support::little
);
1388 uint64_t TotalSize
= writeOneObject(Asm
, Layout
, DwoMode::NonDwoOnly
);
1390 support::endian::Writer
DwoWriter(*DwoOS
, support::little
);
1392 return TotalSize
+ writeOneObject(Asm
, Layout
, DwoMode::DwoOnly
);
1394 return writeOneObject(Asm
, Layout
, DwoMode::AllSections
);
1398 uint64_t WasmObjectWriter::writeOneObject(MCAssembler
&Asm
,
1399 const MCAsmLayout
&Layout
,
1401 uint64_t StartOffset
= W
->OS
.tell();
1403 CustomSections
.clear();
1405 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
1407 // Collect information from the available symbols.
1408 SmallVector
<WasmFunction
, 4> Functions
;
1409 SmallVector
<uint32_t, 4> TableElems
;
1410 SmallVector
<wasm::WasmImport
, 4> Imports
;
1411 SmallVector
<wasm::WasmExport
, 4> Exports
;
1412 SmallVector
<wasm::WasmTagType
, 1> Tags
;
1413 SmallVector
<wasm::WasmGlobal
, 1> Globals
;
1414 SmallVector
<wasm::WasmTable
, 1> Tables
;
1415 SmallVector
<wasm::WasmSymbolInfo
, 4> SymbolInfos
;
1416 SmallVector
<std::pair
<uint16_t, uint32_t>, 2> InitFuncs
;
1417 std::map
<StringRef
, std::vector
<WasmComdatEntry
>> Comdats
;
1418 uint64_t DataSize
= 0;
1419 if (Mode
!= DwoMode::DwoOnly
) {
1420 prepareImports(Imports
, Asm
, Layout
);
1423 // Populate DataSegments and CustomSections, which must be done before
1424 // populating DataLocations.
1425 for (MCSection
&Sec
: Asm
) {
1426 auto &Section
= static_cast<MCSectionWasm
&>(Sec
);
1427 StringRef SectionName
= Section
.getName();
1429 if (Mode
== DwoMode::NonDwoOnly
&& isDwoSection(Sec
))
1431 if (Mode
== DwoMode::DwoOnly
&& !isDwoSection(Sec
))
1434 LLVM_DEBUG(dbgs() << "Processing Section " << SectionName
<< " group "
1435 << Section
.getGroup() << "\n";);
1437 // .init_array sections are handled specially elsewhere.
1438 if (SectionName
.startswith(".init_array"))
1441 // Code is handled separately
1442 if (Section
.getKind().isText())
1445 if (Section
.isWasmData()) {
1446 uint32_t SegmentIndex
= DataSegments
.size();
1447 DataSize
= alignTo(DataSize
, Section
.getAlignment());
1448 DataSegments
.emplace_back();
1449 WasmDataSegment
&Segment
= DataSegments
.back();
1450 Segment
.Name
= SectionName
;
1451 Segment
.InitFlags
= Section
.getPassive()
1452 ? (uint32_t)wasm::WASM_DATA_SEGMENT_IS_PASSIVE
1454 Segment
.Offset
= DataSize
;
1455 Segment
.Section
= &Section
;
1456 addData(Segment
.Data
, Section
);
1457 Segment
.Alignment
= Log2_32(Section
.getAlignment());
1458 Segment
.LinkingFlags
= Section
.getSegmentFlags();
1459 DataSize
+= Segment
.Data
.size();
1460 Section
.setSegmentIndex(SegmentIndex
);
1462 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1463 Comdats
[C
->getName()].emplace_back(
1464 WasmComdatEntry
{wasm::WASM_COMDAT_DATA
, SegmentIndex
});
1467 // Create custom sections
1468 assert(Sec
.getKind().isMetadata());
1470 StringRef Name
= SectionName
;
1472 // For user-defined custom sections, strip the prefix
1473 if (Name
.startswith(".custom_section."))
1474 Name
= Name
.substr(strlen(".custom_section."));
1476 MCSymbol
*Begin
= Sec
.getBeginSymbol();
1478 assert(WasmIndices
.count(cast
<MCSymbolWasm
>(Begin
)) == 0);
1479 WasmIndices
[cast
<MCSymbolWasm
>(Begin
)] = CustomSections
.size();
1482 // Separate out the producers and target features sections
1483 if (Name
== "producers") {
1484 ProducersSection
= std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1487 if (Name
== "target_features") {
1488 TargetFeaturesSection
=
1489 std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1493 // Custom sections can also belong to COMDAT groups. In this case the
1494 // decriptor's "index" field is the section index (in the final object
1495 // file), but that is not known until after layout, so it must be fixed up
1497 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1498 Comdats
[C
->getName()].emplace_back(
1499 WasmComdatEntry
{wasm::WASM_COMDAT_SECTION
,
1500 static_cast<uint32_t>(CustomSections
.size())});
1503 CustomSections
.emplace_back(Name
, &Section
);
1507 if (Mode
!= DwoMode::DwoOnly
) {
1508 // Populate WasmIndices and DataLocations for defined symbols.
1509 for (const MCSymbol
&S
: Asm
.symbols()) {
1510 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1511 // or used in relocations.
1512 if (S
.isTemporary() && S
.getName().empty())
1515 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1518 << toString(WS
.getType().getValueOr(wasm::WASM_SYMBOL_TYPE_DATA
))
1520 << " isDefined=" << S
.isDefined() << " isExternal="
1521 << S
.isExternal() << " isTemporary=" << S
.isTemporary()
1522 << " isWeak=" << WS
.isWeak() << " isHidden=" << WS
.isHidden()
1523 << " isVariable=" << WS
.isVariable() << "\n");
1525 if (WS
.isVariable())
1527 if (WS
.isComdat() && !WS
.isDefined())
1530 if (WS
.isFunction()) {
1532 if (WS
.isDefined()) {
1533 if (WS
.getOffset() != 0)
1535 "function sections must contain one function each");
1537 if (WS
.getSize() == nullptr)
1539 "function symbols must have a size set with .size");
1541 // A definition. Write out the function body.
1542 Index
= NumFunctionImports
+ Functions
.size();
1544 Func
.SigIndex
= getFunctionType(WS
);
1546 assert(WasmIndices
.count(&WS
) == 0);
1547 WasmIndices
[&WS
] = Index
;
1548 Functions
.push_back(Func
);
1550 auto &Section
= static_cast<MCSectionWasm
&>(WS
.getSection());
1551 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1552 Comdats
[C
->getName()].emplace_back(
1553 WasmComdatEntry
{wasm::WASM_COMDAT_FUNCTION
, Index
});
1556 if (WS
.hasExportName()) {
1557 wasm::WasmExport Export
;
1558 Export
.Name
= WS
.getExportName();
1559 Export
.Kind
= wasm::WASM_EXTERNAL_FUNCTION
;
1560 Export
.Index
= Index
;
1561 Exports
.push_back(Export
);
1564 // An import; the index was assigned above.
1565 Index
= WasmIndices
.find(&WS
)->second
;
1568 LLVM_DEBUG(dbgs() << " -> function index: " << Index
<< "\n");
1570 } else if (WS
.isData()) {
1571 if (!isInSymtab(WS
))
1574 if (!WS
.isDefined()) {
1575 LLVM_DEBUG(dbgs() << " -> segment index: -1"
1581 report_fatal_error("data symbols must have a size set with .size: " +
1585 if (!WS
.getSize()->evaluateAsAbsolute(Size
, Layout
))
1586 report_fatal_error(".size expression must be evaluatable");
1588 auto &DataSection
= static_cast<MCSectionWasm
&>(WS
.getSection());
1589 if (!DataSection
.isWasmData())
1590 report_fatal_error("data symbols must live in a data section: " +
1593 // For each data symbol, export it in the symtab as a reference to the
1594 // corresponding Wasm data segment.
1595 wasm::WasmDataReference Ref
= wasm::WasmDataReference
{
1596 DataSection
.getSegmentIndex(), Layout
.getSymbolOffset(WS
),
1597 static_cast<uint64_t>(Size
)};
1598 assert(DataLocations
.count(&WS
) == 0);
1599 DataLocations
[&WS
] = Ref
;
1600 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref
.Segment
<< "\n");
1602 } else if (WS
.isGlobal()) {
1603 // A "true" Wasm global (currently just __stack_pointer)
1604 if (WS
.isDefined()) {
1605 wasm::WasmGlobal Global
;
1606 Global
.Type
= WS
.getGlobalType();
1607 Global
.Index
= NumGlobalImports
+ Globals
.size();
1608 switch (Global
.Type
.Type
) {
1609 case wasm::WASM_TYPE_I32
:
1610 Global
.InitExpr
.Opcode
= wasm::WASM_OPCODE_I32_CONST
;
1612 case wasm::WASM_TYPE_I64
:
1613 Global
.InitExpr
.Opcode
= wasm::WASM_OPCODE_I64_CONST
;
1615 case wasm::WASM_TYPE_F32
:
1616 Global
.InitExpr
.Opcode
= wasm::WASM_OPCODE_F32_CONST
;
1618 case wasm::WASM_TYPE_F64
:
1619 Global
.InitExpr
.Opcode
= wasm::WASM_OPCODE_F64_CONST
;
1621 case wasm::WASM_TYPE_EXTERNREF
:
1622 Global
.InitExpr
.Opcode
= wasm::WASM_OPCODE_REF_NULL
;
1625 llvm_unreachable("unexpected type");
1627 assert(WasmIndices
.count(&WS
) == 0);
1628 WasmIndices
[&WS
] = Global
.Index
;
1629 Globals
.push_back(Global
);
1631 // An import; the index was assigned above
1632 LLVM_DEBUG(dbgs() << " -> global index: "
1633 << WasmIndices
.find(&WS
)->second
<< "\n");
1635 } else if (WS
.isTable()) {
1636 if (WS
.isDefined()) {
1637 wasm::WasmTable Table
;
1638 Table
.Index
= NumTableImports
+ Tables
.size();
1639 Table
.Type
= WS
.getTableType();
1640 assert(WasmIndices
.count(&WS
) == 0);
1641 WasmIndices
[&WS
] = Table
.Index
;
1642 Tables
.push_back(Table
);
1644 LLVM_DEBUG(dbgs() << " -> table index: "
1645 << WasmIndices
.find(&WS
)->second
<< "\n");
1646 } else if (WS
.isTag()) {
1647 // C++ exception symbol (__cpp_exception)
1649 if (WS
.isDefined()) {
1650 Index
= NumTagImports
+ Tags
.size();
1651 wasm::WasmTagType Tag
;
1652 Tag
.SigIndex
= getTagType(WS
);
1653 Tag
.Attribute
= wasm::WASM_TAG_ATTRIBUTE_EXCEPTION
;
1654 assert(WasmIndices
.count(&WS
) == 0);
1655 WasmIndices
[&WS
] = Index
;
1656 Tags
.push_back(Tag
);
1658 // An import; the index was assigned above.
1659 assert(WasmIndices
.count(&WS
) > 0);
1661 LLVM_DEBUG(dbgs() << " -> tag index: " << WasmIndices
.find(&WS
)->second
1665 assert(WS
.isSection());
1669 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1670 // process these in a separate pass because we need to have processed the
1671 // target of the alias before the alias itself and the symbols are not
1672 // necessarily ordered in this way.
1673 for (const MCSymbol
&S
: Asm
.symbols()) {
1674 if (!S
.isVariable())
1677 assert(S
.isDefined());
1679 const auto *BS
= Layout
.getBaseSymbol(S
);
1681 report_fatal_error(Twine(S
.getName()) +
1682 ": absolute addressing not supported!");
1683 const MCSymbolWasm
*Base
= cast
<MCSymbolWasm
>(BS
);
1685 // Find the target symbol of this weak alias and export that index
1686 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1687 LLVM_DEBUG(dbgs() << WS
.getName() << ": weak alias of '" << *Base
1690 if (Base
->isFunction()) {
1691 assert(WasmIndices
.count(Base
) > 0);
1692 uint32_t WasmIndex
= WasmIndices
.find(Base
)->second
;
1693 assert(WasmIndices
.count(&WS
) == 0);
1694 WasmIndices
[&WS
] = WasmIndex
;
1695 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex
<< "\n");
1696 } else if (Base
->isData()) {
1697 auto &DataSection
= static_cast<MCSectionWasm
&>(WS
.getSection());
1698 uint64_t Offset
= Layout
.getSymbolOffset(S
);
1700 // For data symbol alias we use the size of the base symbol as the
1701 // size of the alias. When an offset from the base is involved this
1702 // can result in a offset + size goes past the end of the data section
1703 // which out object format doesn't support. So we must clamp it.
1704 if (!Base
->getSize()->evaluateAsAbsolute(Size
, Layout
))
1705 report_fatal_error(".size expression must be evaluatable");
1706 const WasmDataSegment
&Segment
=
1707 DataSegments
[DataSection
.getSegmentIndex()];
1709 std::min(static_cast<uint64_t>(Size
), Segment
.Data
.size() - Offset
);
1710 wasm::WasmDataReference Ref
= wasm::WasmDataReference
{
1711 DataSection
.getSegmentIndex(),
1712 static_cast<uint32_t>(Layout
.getSymbolOffset(S
)),
1713 static_cast<uint32_t>(Size
)};
1714 DataLocations
[&WS
] = Ref
;
1715 LLVM_DEBUG(dbgs() << " -> index:" << Ref
.Segment
<< "\n");
1717 report_fatal_error("don't yet support global/tag aliases");
1722 // Finally, populate the symbol table itself, in its "natural" order.
1723 for (const MCSymbol
&S
: Asm
.symbols()) {
1724 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1725 if (!isInSymtab(WS
)) {
1726 WS
.setIndex(InvalidIndex
);
1729 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS
<< "\n");
1733 Flags
|= wasm::WASM_SYMBOL_BINDING_WEAK
;
1735 Flags
|= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN
;
1736 if (!WS
.isExternal() && WS
.isDefined())
1737 Flags
|= wasm::WASM_SYMBOL_BINDING_LOCAL
;
1738 if (WS
.isUndefined())
1739 Flags
|= wasm::WASM_SYMBOL_UNDEFINED
;
1740 if (WS
.isNoStrip()) {
1741 Flags
|= wasm::WASM_SYMBOL_NO_STRIP
;
1742 if (isEmscripten()) {
1743 Flags
|= wasm::WASM_SYMBOL_EXPORTED
;
1746 if (WS
.hasImportName())
1747 Flags
|= wasm::WASM_SYMBOL_EXPLICIT_NAME
;
1748 if (WS
.hasExportName())
1749 Flags
|= wasm::WASM_SYMBOL_EXPORTED
;
1751 wasm::WasmSymbolInfo Info
;
1752 Info
.Name
= WS
.getName();
1753 Info
.Kind
= WS
.getType().getValueOr(wasm::WASM_SYMBOL_TYPE_DATA
);
1756 assert(WasmIndices
.count(&WS
) > 0);
1757 Info
.ElementIndex
= WasmIndices
.find(&WS
)->second
;
1758 } else if (WS
.isDefined()) {
1759 assert(DataLocations
.count(&WS
) > 0);
1760 Info
.DataRef
= DataLocations
.find(&WS
)->second
;
1762 WS
.setIndex(SymbolInfos
.size());
1763 SymbolInfos
.emplace_back(Info
);
1767 auto HandleReloc
= [&](const WasmRelocationEntry
&Rel
) {
1768 // Functions referenced by a relocation need to put in the table. This is
1769 // purely to make the object file's provisional values readable, and is
1770 // ignored by the linker, which re-calculates the relocations itself.
1771 if (Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_I32
&&
1772 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_I64
&&
1773 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_SLEB
&&
1774 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_SLEB64
&&
1775 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_REL_SLEB
&&
1776 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_REL_SLEB64
)
1778 assert(Rel
.Symbol
->isFunction());
1779 const MCSymbolWasm
*Base
=
1780 cast
<MCSymbolWasm
>(Layout
.getBaseSymbol(*Rel
.Symbol
));
1781 uint32_t FunctionIndex
= WasmIndices
.find(Base
)->second
;
1782 uint32_t TableIndex
= TableElems
.size() + InitialTableOffset
;
1783 if (TableIndices
.try_emplace(Base
, TableIndex
).second
) {
1784 LLVM_DEBUG(dbgs() << " -> adding " << Base
->getName()
1785 << " to table: " << TableIndex
<< "\n");
1786 TableElems
.push_back(FunctionIndex
);
1787 registerFunctionType(*Base
);
1791 for (const WasmRelocationEntry
&RelEntry
: CodeRelocations
)
1792 HandleReloc(RelEntry
);
1793 for (const WasmRelocationEntry
&RelEntry
: DataRelocations
)
1794 HandleReloc(RelEntry
);
1797 // Translate .init_array section contents into start functions.
1798 for (const MCSection
&S
: Asm
) {
1799 const auto &WS
= static_cast<const MCSectionWasm
&>(S
);
1800 if (WS
.getName().startswith(".fini_array"))
1801 report_fatal_error(".fini_array sections are unsupported");
1802 if (!WS
.getName().startswith(".init_array"))
1804 if (WS
.getFragmentList().empty())
1807 // init_array is expected to contain a single non-empty data fragment
1808 if (WS
.getFragmentList().size() != 3)
1809 report_fatal_error("only one .init_array section fragment supported");
1811 auto IT
= WS
.begin();
1812 const MCFragment
&EmptyFrag
= *IT
;
1813 if (EmptyFrag
.getKind() != MCFragment::FT_Data
)
1814 report_fatal_error(".init_array section should be aligned");
1817 const MCFragment
&AlignFrag
= *IT
;
1818 if (AlignFrag
.getKind() != MCFragment::FT_Align
)
1819 report_fatal_error(".init_array section should be aligned");
1820 if (cast
<MCAlignFragment
>(AlignFrag
).getAlignment() != (is64Bit() ? 8 : 4))
1821 report_fatal_error(".init_array section should be aligned for pointers");
1823 const MCFragment
&Frag
= *std::next(IT
);
1824 if (Frag
.hasInstructions() || Frag
.getKind() != MCFragment::FT_Data
)
1825 report_fatal_error("only data supported in .init_array section");
1827 uint16_t Priority
= UINT16_MAX
;
1828 unsigned PrefixLength
= strlen(".init_array");
1829 if (WS
.getName().size() > PrefixLength
) {
1830 if (WS
.getName()[PrefixLength
] != '.')
1832 ".init_array section priority should start with '.'");
1833 if (WS
.getName().substr(PrefixLength
+ 1).getAsInteger(10, Priority
))
1834 report_fatal_error("invalid .init_array section priority");
1836 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
1837 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
1838 for (const uint8_t *
1839 P
= (const uint8_t *)Contents
.data(),
1840 *End
= (const uint8_t *)Contents
.data() + Contents
.size();
1843 report_fatal_error("non-symbolic data in .init_array section");
1845 for (const MCFixup
&Fixup
: DataFrag
.getFixups()) {
1846 assert(Fixup
.getKind() ==
1847 MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1848 const MCExpr
*Expr
= Fixup
.getValue();
1849 auto *SymRef
= dyn_cast
<MCSymbolRefExpr
>(Expr
);
1851 report_fatal_error("fixups in .init_array should be symbol references");
1852 const auto &TargetSym
= cast
<const MCSymbolWasm
>(SymRef
->getSymbol());
1853 if (TargetSym
.getIndex() == InvalidIndex
)
1854 report_fatal_error("symbols in .init_array should exist in symtab");
1855 if (!TargetSym
.isFunction())
1856 report_fatal_error("symbols in .init_array should be for functions");
1857 InitFuncs
.push_back(
1858 std::make_pair(Priority
, TargetSym
.getIndex()));
1862 // Write out the Wasm header.
1865 uint32_t CodeSectionIndex
, DataSectionIndex
;
1866 if (Mode
!= DwoMode::DwoOnly
) {
1867 writeTypeSection(Signatures
);
1868 writeImportSection(Imports
, DataSize
, TableElems
.size());
1869 writeFunctionSection(Functions
);
1870 writeTableSection(Tables
);
1871 // Skip the "memory" section; we import the memory instead.
1872 writeTagSection(Tags
);
1873 writeGlobalSection(Globals
);
1874 writeExportSection(Exports
);
1875 const MCSymbol
*IndirectFunctionTable
=
1876 Asm
.getContext().lookupSymbol("__indirect_function_table");
1877 writeElemSection(cast_or_null
<const MCSymbolWasm
>(IndirectFunctionTable
),
1879 writeDataCountSection();
1881 CodeSectionIndex
= writeCodeSection(Asm
, Layout
, Functions
);
1882 DataSectionIndex
= writeDataSection(Layout
);
1885 // The Sections in the COMDAT list have placeholder indices (their index among
1886 // custom sections, rather than among all sections). Fix them up here.
1887 for (auto &Group
: Comdats
) {
1888 for (auto &Entry
: Group
.second
) {
1889 if (Entry
.Kind
== wasm::WASM_COMDAT_SECTION
) {
1890 Entry
.Index
+= SectionCount
;
1894 for (auto &CustomSection
: CustomSections
)
1895 writeCustomSection(CustomSection
, Asm
, Layout
);
1897 if (Mode
!= DwoMode::DwoOnly
) {
1898 writeLinkingMetaDataSection(SymbolInfos
, InitFuncs
, Comdats
);
1900 writeRelocSection(CodeSectionIndex
, "CODE", CodeRelocations
);
1901 writeRelocSection(DataSectionIndex
, "DATA", DataRelocations
);
1903 writeCustomRelocSections();
1904 if (ProducersSection
)
1905 writeCustomSection(*ProducersSection
, Asm
, Layout
);
1906 if (TargetFeaturesSection
)
1907 writeCustomSection(*TargetFeaturesSection
, Asm
, Layout
);
1909 // TODO: Translate the .comment section to the output.
1910 return W
->OS
.tell() - StartOffset
;
1913 std::unique_ptr
<MCObjectWriter
>
1914 llvm::createWasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
1915 raw_pwrite_stream
&OS
) {
1916 return std::make_unique
<WasmObjectWriter
>(std::move(MOTW
), OS
);
1919 std::unique_ptr
<MCObjectWriter
>
1920 llvm::createWasmDwoObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
1921 raw_pwrite_stream
&OS
,
1922 raw_pwrite_stream
&DwoOS
) {
1923 return std::make_unique
<WasmObjectWriter
>(std::move(MOTW
), OS
, DwoOS
);