1 //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements Wasm object file writer information.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/SmallPtrSet.h"
15 #include "llvm/BinaryFormat/Wasm.h"
16 #include "llvm/Config/llvm-config.h"
17 #include "llvm/MC/MCAsmBackend.h"
18 #include "llvm/MC/MCAsmLayout.h"
19 #include "llvm/MC/MCAssembler.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCExpr.h"
22 #include "llvm/MC/MCFixupKindInfo.h"
23 #include "llvm/MC/MCObjectWriter.h"
24 #include "llvm/MC/MCSectionWasm.h"
25 #include "llvm/MC/MCSymbolWasm.h"
26 #include "llvm/MC/MCValue.h"
27 #include "llvm/MC/MCWasmObjectWriter.h"
28 #include "llvm/Support/Casting.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/LEB128.h"
32 #include "llvm/Support/StringSaver.h"
37 #define DEBUG_TYPE "mc"
41 // Went we ceate the indirect function table we start at 1, so that there is
42 // and emtpy slot at 0 and therefore calling a null function pointer will trap.
43 static const uint32_t InitialTableOffset
= 1;
45 // For patching purposes, we need to remember where each section starts, both
46 // for patching up the section size field, and for patching up references to
47 // locations within the section.
48 struct SectionBookkeeping
{
49 // Where the size of the section is written.
51 // Where the section header ends (without custom section name).
52 uint64_t PayloadOffset
;
53 // Where the contents of the section starts.
54 uint64_t ContentsOffset
;
58 // The signature of a wasm function or event, in a struct capable of being used
60 // TODO: Consider using wasm::WasmSignature directly instead.
61 struct WasmSignature
{
62 // Support empty and tombstone instances, needed by DenseMap.
63 enum { Plain
, Empty
, Tombstone
} State
= Plain
;
65 // The return types of the function.
66 SmallVector
<wasm::ValType
, 1> Returns
;
68 // The parameter types of the function.
69 SmallVector
<wasm::ValType
, 4> Params
;
71 bool operator==(const WasmSignature
&Other
) const {
72 return State
== Other
.State
&& Returns
== Other
.Returns
&&
73 Params
== Other
.Params
;
77 // Traits for using WasmSignature in a DenseMap.
78 struct WasmSignatureDenseMapInfo
{
79 static WasmSignature
getEmptyKey() {
81 Sig
.State
= WasmSignature::Empty
;
84 static WasmSignature
getTombstoneKey() {
86 Sig
.State
= WasmSignature::Tombstone
;
89 static unsigned getHashValue(const WasmSignature
&Sig
) {
90 uintptr_t Value
= Sig
.State
;
91 for (wasm::ValType Ret
: Sig
.Returns
)
92 Value
+= DenseMapInfo
<uint32_t>::getHashValue(uint32_t(Ret
));
93 for (wasm::ValType Param
: Sig
.Params
)
94 Value
+= DenseMapInfo
<uint32_t>::getHashValue(uint32_t(Param
));
97 static bool isEqual(const WasmSignature
&LHS
, const WasmSignature
&RHS
) {
102 // A wasm data segment. A wasm binary contains only a single data section
103 // but that can contain many segments, each with their own virtual location
104 // in memory. Each MCSection data created by llvm is modeled as its own
105 // wasm data segment.
106 struct WasmDataSegment
{
107 MCSectionWasm
*Section
;
112 uint32_t LinkerFlags
;
113 SmallVector
<char, 4> Data
;
116 // A wasm function to be written into the function section.
117 struct WasmFunction
{
119 const MCSymbolWasm
*Sym
;
122 // A wasm global to be written into the global section.
124 wasm::WasmGlobalType Type
;
125 uint64_t InitialValue
;
128 // Information about a single item which is part of a COMDAT. For each data
129 // segment or function which is in the COMDAT, there is a corresponding
131 struct WasmComdatEntry
{
136 // Information about a single relocation.
137 struct WasmRelocationEntry
{
138 uint64_t Offset
; // Where is the relocation.
139 const MCSymbolWasm
*Symbol
; // The symbol to relocate with.
140 int64_t Addend
; // A value to add to the symbol.
141 unsigned Type
; // The type of the relocation.
142 const MCSectionWasm
*FixupSection
; // The section the relocation is targeting.
144 WasmRelocationEntry(uint64_t Offset
, const MCSymbolWasm
*Symbol
,
145 int64_t Addend
, unsigned Type
,
146 const MCSectionWasm
*FixupSection
)
147 : Offset(Offset
), Symbol(Symbol
), Addend(Addend
), Type(Type
),
148 FixupSection(FixupSection
) {}
150 bool hasAddend() const { return wasm::relocTypeHasAddend(Type
); }
152 void print(raw_ostream
&Out
) const {
153 Out
<< wasm::relocTypetoString(Type
) << " Off=" << Offset
154 << ", Sym=" << *Symbol
<< ", Addend=" << Addend
155 << ", FixupSection=" << FixupSection
->getSectionName();
158 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
159 LLVM_DUMP_METHOD
void dump() const { print(dbgs()); }
163 static const uint32_t InvalidIndex
= -1;
165 struct WasmCustomSection
{
168 MCSectionWasm
*Section
;
170 uint32_t OutputContentsOffset
;
171 uint32_t OutputIndex
;
173 WasmCustomSection(StringRef Name
, MCSectionWasm
*Section
)
174 : Name(Name
), Section(Section
), OutputContentsOffset(0),
175 OutputIndex(InvalidIndex
) {}
179 raw_ostream
&operator<<(raw_ostream
&OS
, const WasmRelocationEntry
&Rel
) {
185 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded
186 // to allow patching.
187 static void writePatchableLEB(raw_pwrite_stream
&Stream
, uint32_t X
,
190 unsigned SizeLen
= encodeULEB128(X
, Buffer
, 5);
191 assert(SizeLen
== 5);
192 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
195 // Write X as an signed LEB value at offset Offset in Stream, padded
196 // to allow patching.
197 static void writePatchableSLEB(raw_pwrite_stream
&Stream
, int32_t X
,
200 unsigned SizeLen
= encodeSLEB128(X
, Buffer
, 5);
201 assert(SizeLen
== 5);
202 Stream
.pwrite((char *)Buffer
, SizeLen
, Offset
);
205 // Write X as a plain integer value at offset Offset in Stream.
206 static void writeI32(raw_pwrite_stream
&Stream
, uint32_t X
, uint64_t Offset
) {
208 support::endian::write32le(Buffer
, X
);
209 Stream
.pwrite((char *)Buffer
, sizeof(Buffer
), Offset
);
212 class WasmObjectWriter
: public MCObjectWriter
{
213 support::endian::Writer W
;
215 /// The target specific Wasm writer instance.
216 std::unique_ptr
<MCWasmObjectTargetWriter
> TargetObjectWriter
;
218 // Relocations for fixing up references in the code section.
219 std::vector
<WasmRelocationEntry
> CodeRelocations
;
220 uint32_t CodeSectionIndex
;
222 // Relocations for fixing up references in the data section.
223 std::vector
<WasmRelocationEntry
> DataRelocations
;
224 uint32_t DataSectionIndex
;
226 // Index values to use for fixing up call_indirect type indices.
227 // Maps function symbols to the index of the type of the function
228 DenseMap
<const MCSymbolWasm
*, uint32_t> TypeIndices
;
229 // Maps function symbols to the table element index space. Used
230 // for TABLE_INDEX relocation types (i.e. address taken functions).
231 DenseMap
<const MCSymbolWasm
*, uint32_t> TableIndices
;
232 // Maps function/global symbols to the function/global/event/section index
234 DenseMap
<const MCSymbolWasm
*, uint32_t> WasmIndices
;
235 DenseMap
<const MCSymbolWasm
*, uint32_t> GOTIndices
;
236 // Maps data symbols to the Wasm segment and offset/size with the segment.
237 DenseMap
<const MCSymbolWasm
*, wasm::WasmDataReference
> DataLocations
;
239 // Stores output data (index, relocations, content offset) for custom
241 std::vector
<WasmCustomSection
> CustomSections
;
242 std::unique_ptr
<WasmCustomSection
> ProducersSection
;
243 std::unique_ptr
<WasmCustomSection
> TargetFeaturesSection
;
244 // Relocations for fixing up references in the custom sections.
245 DenseMap
<const MCSectionWasm
*, std::vector
<WasmRelocationEntry
>>
246 CustomSectionsRelocations
;
248 // Map from section to defining function symbol.
249 DenseMap
<const MCSection
*, const MCSymbol
*> SectionFunctions
;
251 DenseMap
<WasmSignature
, uint32_t, WasmSignatureDenseMapInfo
> SignatureIndices
;
252 SmallVector
<WasmSignature
, 4> Signatures
;
253 SmallVector
<WasmDataSegment
, 4> DataSegments
;
254 unsigned NumFunctionImports
= 0;
255 unsigned NumGlobalImports
= 0;
256 unsigned NumEventImports
= 0;
257 uint32_t SectionCount
= 0;
259 // TargetObjectWriter wrappers.
260 bool is64Bit() const { return TargetObjectWriter
->is64Bit(); }
262 void startSection(SectionBookkeeping
&Section
, unsigned SectionId
);
263 void startCustomSection(SectionBookkeeping
&Section
, StringRef Name
);
264 void endSection(SectionBookkeeping
&Section
);
267 WasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
268 raw_pwrite_stream
&OS
)
269 : W(OS
, support::little
), TargetObjectWriter(std::move(MOTW
)) {}
272 void reset() override
{
273 CodeRelocations
.clear();
274 DataRelocations
.clear();
278 TableIndices
.clear();
279 DataLocations
.clear();
280 CustomSections
.clear();
281 ProducersSection
.reset();
282 TargetFeaturesSection
.reset();
283 CustomSectionsRelocations
.clear();
284 SignatureIndices
.clear();
286 DataSegments
.clear();
287 SectionFunctions
.clear();
288 NumFunctionImports
= 0;
289 NumGlobalImports
= 0;
290 MCObjectWriter::reset();
293 void writeHeader(const MCAssembler
&Asm
);
295 void recordRelocation(MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
296 const MCFragment
*Fragment
, const MCFixup
&Fixup
,
297 MCValue Target
, uint64_t &FixedValue
) override
;
299 void executePostLayoutBinding(MCAssembler
&Asm
,
300 const MCAsmLayout
&Layout
) override
;
302 uint64_t writeObject(MCAssembler
&Asm
, const MCAsmLayout
&Layout
) override
;
304 void writeString(const StringRef Str
) {
305 encodeULEB128(Str
.size(), W
.OS
);
309 void writeValueType(wasm::ValType Ty
) { W
.OS
<< static_cast<char>(Ty
); }
311 void writeTypeSection(ArrayRef
<WasmSignature
> Signatures
);
312 void writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
, uint32_t DataSize
,
313 uint32_t NumElements
);
314 void writeFunctionSection(ArrayRef
<WasmFunction
> Functions
);
315 void writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
);
316 void writeElemSection(ArrayRef
<uint32_t> TableElems
);
317 void writeDataCountSection();
318 void writeCodeSection(const MCAssembler
&Asm
, const MCAsmLayout
&Layout
,
319 ArrayRef
<WasmFunction
> Functions
);
320 void writeDataSection();
321 void writeEventSection(ArrayRef
<wasm::WasmEventType
> Events
);
322 void writeRelocSection(uint32_t SectionIndex
, StringRef Name
,
323 std::vector
<WasmRelocationEntry
> &Relocations
);
324 void writeLinkingMetaDataSection(
325 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
326 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
327 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
);
328 void writeCustomSection(WasmCustomSection
&CustomSection
,
329 const MCAssembler
&Asm
, const MCAsmLayout
&Layout
);
330 void writeCustomRelocSections();
332 updateCustomSectionRelocations(const SmallVector
<WasmFunction
, 4> &Functions
,
333 const MCAsmLayout
&Layout
);
335 uint32_t getProvisionalValue(const WasmRelocationEntry
&RelEntry
);
336 void applyRelocations(ArrayRef
<WasmRelocationEntry
> Relocations
,
337 uint64_t ContentsOffset
);
339 uint32_t getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
);
340 uint32_t getFunctionType(const MCSymbolWasm
&Symbol
);
341 uint32_t getEventType(const MCSymbolWasm
&Symbol
);
342 void registerFunctionType(const MCSymbolWasm
&Symbol
);
343 void registerEventType(const MCSymbolWasm
&Symbol
);
346 } // end anonymous namespace
348 // Write out a section header and a patchable section size field.
349 void WasmObjectWriter::startSection(SectionBookkeeping
&Section
,
350 unsigned SectionId
) {
351 LLVM_DEBUG(dbgs() << "startSection " << SectionId
<< "\n");
352 W
.OS
<< char(SectionId
);
354 Section
.SizeOffset
= W
.OS
.tell();
356 // The section size. We don't know the size yet, so reserve enough space
357 // for any 32-bit value; we'll patch it later.
358 encodeULEB128(0, W
.OS
, 5);
360 // The position where the section starts, for measuring its size.
361 Section
.ContentsOffset
= W
.OS
.tell();
362 Section
.PayloadOffset
= W
.OS
.tell();
363 Section
.Index
= SectionCount
++;
366 void WasmObjectWriter::startCustomSection(SectionBookkeeping
&Section
,
368 LLVM_DEBUG(dbgs() << "startCustomSection " << Name
<< "\n");
369 startSection(Section
, wasm::WASM_SEC_CUSTOM
);
371 // The position where the section header ends, for measuring its size.
372 Section
.PayloadOffset
= W
.OS
.tell();
374 // Custom sections in wasm also have a string identifier.
377 // The position where the custom section starts.
378 Section
.ContentsOffset
= W
.OS
.tell();
381 // Now that the section is complete and we know how big it is, patch up the
382 // section size field at the start of the section.
383 void WasmObjectWriter::endSection(SectionBookkeeping
&Section
) {
384 uint64_t Size
= W
.OS
.tell();
385 // /dev/null doesn't support seek/tell and can report offset of 0.
386 // Simply skip this patching in that case.
390 Size
-= Section
.PayloadOffset
;
391 if (uint32_t(Size
) != Size
)
392 report_fatal_error("section size does not fit in a uint32_t");
394 LLVM_DEBUG(dbgs() << "endSection size=" << Size
<< "\n");
396 // Write the final section size to the payload_len field, which follows
397 // the section id byte.
398 writePatchableLEB(static_cast<raw_pwrite_stream
&>(W
.OS
), Size
,
402 // Emit the Wasm header.
403 void WasmObjectWriter::writeHeader(const MCAssembler
&Asm
) {
404 W
.OS
.write(wasm::WasmMagic
, sizeof(wasm::WasmMagic
));
405 W
.write
<uint32_t>(wasm::WasmVersion
);
408 void WasmObjectWriter::executePostLayoutBinding(MCAssembler
&Asm
,
409 const MCAsmLayout
&Layout
) {
410 // Build a map of sections to the function that defines them, for use
411 // in recordRelocation.
412 for (const MCSymbol
&S
: Asm
.symbols()) {
413 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
414 if (WS
.isDefined() && WS
.isFunction() && !WS
.isVariable()) {
415 const auto &Sec
= static_cast<const MCSectionWasm
&>(S
.getSection());
416 auto Pair
= SectionFunctions
.insert(std::make_pair(&Sec
, &S
));
418 report_fatal_error("section already has a defining function: " +
419 Sec
.getSectionName());
424 void WasmObjectWriter::recordRelocation(MCAssembler
&Asm
,
425 const MCAsmLayout
&Layout
,
426 const MCFragment
*Fragment
,
427 const MCFixup
&Fixup
, MCValue Target
,
428 uint64_t &FixedValue
) {
429 MCAsmBackend
&Backend
= Asm
.getBackend();
430 bool IsPCRel
= Backend
.getFixupKindInfo(Fixup
.getKind()).Flags
&
431 MCFixupKindInfo::FKF_IsPCRel
;
432 const auto &FixupSection
= cast
<MCSectionWasm
>(*Fragment
->getParent());
433 uint64_t C
= Target
.getConstant();
434 uint64_t FixupOffset
= Layout
.getFragmentOffset(Fragment
) + Fixup
.getOffset();
435 MCContext
&Ctx
= Asm
.getContext();
437 // The .init_array isn't translated as data, so don't do relocations in it.
438 if (FixupSection
.getSectionName().startswith(".init_array"))
441 if (const MCSymbolRefExpr
*RefB
= Target
.getSymB()) {
442 assert(RefB
->getKind() == MCSymbolRefExpr::VK_None
&&
443 "Should not have constructed this");
445 // Let A, B and C being the components of Target and R be the location of
446 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
447 // If it is pcrel, we want to compute (A - B + C - R).
449 // In general, Wasm has no relocations for -B. It can only represent (A + C)
450 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
451 // replace B to implement it: (A - R - K + C)
455 "No relocation available to represent this relative expression");
459 const auto &SymB
= cast
<MCSymbolWasm
>(RefB
->getSymbol());
461 if (SymB
.isUndefined()) {
462 Ctx
.reportError(Fixup
.getLoc(),
463 Twine("symbol '") + SymB
.getName() +
464 "' can not be undefined in a subtraction expression");
468 assert(!SymB
.isAbsolute() && "Should have been folded");
469 const MCSection
&SecB
= SymB
.getSection();
470 if (&SecB
!= &FixupSection
) {
471 Ctx
.reportError(Fixup
.getLoc(),
472 "Cannot represent a difference across sections");
476 uint64_t SymBOffset
= Layout
.getSymbolOffset(SymB
);
477 uint64_t K
= SymBOffset
- FixupOffset
;
482 // We either rejected the fixup or folded B into C at this point.
483 const MCSymbolRefExpr
*RefA
= Target
.getSymA();
484 const auto *SymA
= RefA
? cast
<MCSymbolWasm
>(&RefA
->getSymbol()) : nullptr;
486 if (SymA
&& SymA
->isVariable()) {
487 const MCExpr
*Expr
= SymA
->getVariableValue();
488 const auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
489 if (Inner
->getKind() == MCSymbolRefExpr::VK_WEAKREF
)
490 llvm_unreachable("weakref used in reloc not yet implemented");
493 // Put any constant offset in an addend. Offsets can be negative, and
494 // LLVM expects wrapping, in contrast to wasm's immediates which can't
495 // be negative and don't wrap.
498 unsigned Type
= TargetObjectWriter
->getRelocType(Target
, Fixup
);
502 // Absolute offset within a section or a function.
503 // Currently only supported for for metadata sections.
504 // See: test/MC/WebAssembly/blockaddress.ll
505 if (Type
== wasm::R_WASM_FUNCTION_OFFSET_I32
||
506 Type
== wasm::R_WASM_SECTION_OFFSET_I32
) {
507 if (!FixupSection
.getKind().isMetadata())
508 report_fatal_error("relocations for function or section offsets are "
509 "only supported in metadata sections");
511 const MCSymbol
*SectionSymbol
= nullptr;
512 const MCSection
&SecA
= SymA
->getSection();
513 if (SecA
.getKind().isText())
514 SectionSymbol
= SectionFunctions
.find(&SecA
)->second
;
516 SectionSymbol
= SecA
.getBeginSymbol();
518 report_fatal_error("section symbol is required for relocation");
520 C
+= Layout
.getSymbolOffset(*SymA
);
521 SymA
= cast
<MCSymbolWasm
>(SectionSymbol
);
524 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
525 // against a named symbol.
526 if (Type
!= wasm::R_WASM_TYPE_INDEX_LEB
) {
527 if (SymA
->getName().empty())
528 report_fatal_error("relocations against un-named temporaries are not yet "
529 "supported by wasm");
531 SymA
->setUsedInReloc();
534 if (RefA
->getKind() == MCSymbolRefExpr::VK_GOT
)
535 SymA
->setUsedInGOT();
537 WasmRelocationEntry
Rec(FixupOffset
, SymA
, C
, Type
, &FixupSection
);
538 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec
<< "\n");
540 if (FixupSection
.isWasmData()) {
541 DataRelocations
.push_back(Rec
);
542 } else if (FixupSection
.getKind().isText()) {
543 CodeRelocations
.push_back(Rec
);
544 } else if (FixupSection
.getKind().isMetadata()) {
545 CustomSectionsRelocations
[&FixupSection
].push_back(Rec
);
547 llvm_unreachable("unexpected section type");
551 static const MCSymbolWasm
*resolveSymbol(const MCSymbolWasm
&Symbol
) {
552 const MCSymbolWasm
* Ret
= &Symbol
;
553 while (Ret
->isVariable()) {
554 const MCExpr
*Expr
= Ret
->getVariableValue();
555 auto *Inner
= cast
<MCSymbolRefExpr
>(Expr
);
556 Ret
= cast
<MCSymbolWasm
>(&Inner
->getSymbol());
561 // Compute a value to write into the code at the location covered
562 // by RelEntry. This value isn't used by the static linker; it just serves
563 // to make the object format more readable and more likely to be directly
566 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry
&RelEntry
) {
567 if (RelEntry
.Type
== wasm::R_WASM_GLOBAL_INDEX_LEB
&& !RelEntry
.Symbol
->isGlobal()) {
568 assert(GOTIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in GOT index space");
569 return GOTIndices
[RelEntry
.Symbol
];
572 switch (RelEntry
.Type
) {
573 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
574 case wasm::R_WASM_TABLE_INDEX_SLEB
:
575 case wasm::R_WASM_TABLE_INDEX_I32
: {
576 // Provisional value is table address of the resolved symbol itself
577 const MCSymbolWasm
*Sym
= resolveSymbol(*RelEntry
.Symbol
);
578 assert(Sym
->isFunction());
579 return TableIndices
[Sym
];
581 case wasm::R_WASM_TYPE_INDEX_LEB
:
582 // Provisional value is same as the index
583 return getRelocationIndexValue(RelEntry
);
584 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
585 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
586 case wasm::R_WASM_EVENT_INDEX_LEB
:
587 // Provisional value is function/global/event Wasm index
588 assert(WasmIndices
.count(RelEntry
.Symbol
) > 0 && "symbol not found in wasm index space");
589 return WasmIndices
[RelEntry
.Symbol
];
590 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
591 case wasm::R_WASM_SECTION_OFFSET_I32
: {
592 const auto &Section
=
593 static_cast<const MCSectionWasm
&>(RelEntry
.Symbol
->getSection());
594 return Section
.getSectionOffset() + RelEntry
.Addend
;
596 case wasm::R_WASM_MEMORY_ADDR_LEB
:
597 case wasm::R_WASM_MEMORY_ADDR_I32
:
598 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
599 case wasm::R_WASM_MEMORY_ADDR_SLEB
: {
600 // Provisional value is address of the global
601 const MCSymbolWasm
*Sym
= resolveSymbol(*RelEntry
.Symbol
);
602 // For undefined symbols, use zero
603 if (!Sym
->isDefined())
605 const wasm::WasmDataReference
&Ref
= DataLocations
[Sym
];
606 const WasmDataSegment
&Segment
= DataSegments
[Ref
.Segment
];
607 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
608 return Segment
.Offset
+ Ref
.Offset
+ RelEntry
.Addend
;
611 llvm_unreachable("invalid relocation type");
615 static void addData(SmallVectorImpl
<char> &DataBytes
,
616 MCSectionWasm
&DataSection
) {
617 LLVM_DEBUG(errs() << "addData: " << DataSection
.getSectionName() << "\n");
619 DataBytes
.resize(alignTo(DataBytes
.size(), DataSection
.getAlignment()));
621 for (const MCFragment
&Frag
: DataSection
) {
622 if (Frag
.hasInstructions())
623 report_fatal_error("only data supported in data sections");
625 if (auto *Align
= dyn_cast
<MCAlignFragment
>(&Frag
)) {
626 if (Align
->getValueSize() != 1)
627 report_fatal_error("only byte values supported for alignment");
628 // If nops are requested, use zeros, as this is the data section.
629 uint8_t Value
= Align
->hasEmitNops() ? 0 : Align
->getValue();
631 std::min
<uint64_t>(alignTo(DataBytes
.size(), Align
->getAlignment()),
632 DataBytes
.size() + Align
->getMaxBytesToEmit());
633 DataBytes
.resize(Size
, Value
);
634 } else if (auto *Fill
= dyn_cast
<MCFillFragment
>(&Frag
)) {
636 if (!Fill
->getNumValues().evaluateAsAbsolute(NumValues
))
637 llvm_unreachable("The fill should be an assembler constant");
638 DataBytes
.insert(DataBytes
.end(), Fill
->getValueSize() * NumValues
,
640 } else if (auto *LEB
= dyn_cast
<MCLEBFragment
>(&Frag
)) {
641 const SmallVectorImpl
<char> &Contents
= LEB
->getContents();
642 DataBytes
.insert(DataBytes
.end(), Contents
.begin(), Contents
.end());
644 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
645 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
646 DataBytes
.insert(DataBytes
.end(), Contents
.begin(), Contents
.end());
650 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes
.size() << "\n");
654 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry
&RelEntry
) {
655 if (RelEntry
.Type
== wasm::R_WASM_TYPE_INDEX_LEB
) {
656 if (!TypeIndices
.count(RelEntry
.Symbol
))
657 report_fatal_error("symbol not found in type index space: " +
658 RelEntry
.Symbol
->getName());
659 return TypeIndices
[RelEntry
.Symbol
];
662 return RelEntry
.Symbol
->getIndex();
665 // Apply the portions of the relocation records that we can handle ourselves
667 void WasmObjectWriter::applyRelocations(
668 ArrayRef
<WasmRelocationEntry
> Relocations
, uint64_t ContentsOffset
) {
669 auto &Stream
= static_cast<raw_pwrite_stream
&>(W
.OS
);
670 for (const WasmRelocationEntry
&RelEntry
: Relocations
) {
671 uint64_t Offset
= ContentsOffset
+
672 RelEntry
.FixupSection
->getSectionOffset() +
675 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry
<< "\n");
676 uint32_t Value
= getProvisionalValue(RelEntry
);
678 switch (RelEntry
.Type
) {
679 case wasm::R_WASM_FUNCTION_INDEX_LEB
:
680 case wasm::R_WASM_TYPE_INDEX_LEB
:
681 case wasm::R_WASM_GLOBAL_INDEX_LEB
:
682 case wasm::R_WASM_MEMORY_ADDR_LEB
:
683 case wasm::R_WASM_EVENT_INDEX_LEB
:
684 writePatchableLEB(Stream
, Value
, Offset
);
686 case wasm::R_WASM_TABLE_INDEX_I32
:
687 case wasm::R_WASM_MEMORY_ADDR_I32
:
688 case wasm::R_WASM_FUNCTION_OFFSET_I32
:
689 case wasm::R_WASM_SECTION_OFFSET_I32
:
690 writeI32(Stream
, Value
, Offset
);
692 case wasm::R_WASM_TABLE_INDEX_SLEB
:
693 case wasm::R_WASM_TABLE_INDEX_REL_SLEB
:
694 case wasm::R_WASM_MEMORY_ADDR_SLEB
:
695 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB
:
696 writePatchableSLEB(Stream
, Value
, Offset
);
699 llvm_unreachable("invalid relocation type");
704 void WasmObjectWriter::writeTypeSection(ArrayRef
<WasmSignature
> Signatures
) {
705 if (Signatures
.empty())
708 SectionBookkeeping Section
;
709 startSection(Section
, wasm::WASM_SEC_TYPE
);
711 encodeULEB128(Signatures
.size(), W
.OS
);
713 for (const WasmSignature
&Sig
: Signatures
) {
714 W
.OS
<< char(wasm::WASM_TYPE_FUNC
);
715 encodeULEB128(Sig
.Params
.size(), W
.OS
);
716 for (wasm::ValType Ty
: Sig
.Params
)
718 encodeULEB128(Sig
.Returns
.size(), W
.OS
);
719 for (wasm::ValType Ty
: Sig
.Returns
)
726 void WasmObjectWriter::writeImportSection(ArrayRef
<wasm::WasmImport
> Imports
,
728 uint32_t NumElements
) {
732 uint32_t NumPages
= (DataSize
+ wasm::WasmPageSize
- 1) / wasm::WasmPageSize
;
734 SectionBookkeeping Section
;
735 startSection(Section
, wasm::WASM_SEC_IMPORT
);
737 encodeULEB128(Imports
.size(), W
.OS
);
738 for (const wasm::WasmImport
&Import
: Imports
) {
739 writeString(Import
.Module
);
740 writeString(Import
.Field
);
741 W
.OS
<< char(Import
.Kind
);
743 switch (Import
.Kind
) {
744 case wasm::WASM_EXTERNAL_FUNCTION
:
745 encodeULEB128(Import
.SigIndex
, W
.OS
);
747 case wasm::WASM_EXTERNAL_GLOBAL
:
748 W
.OS
<< char(Import
.Global
.Type
);
749 W
.OS
<< char(Import
.Global
.Mutable
? 1 : 0);
751 case wasm::WASM_EXTERNAL_MEMORY
:
752 encodeULEB128(0, W
.OS
); // flags
753 encodeULEB128(NumPages
, W
.OS
); // initial
755 case wasm::WASM_EXTERNAL_TABLE
:
756 W
.OS
<< char(Import
.Table
.ElemType
);
757 encodeULEB128(0, W
.OS
); // flags
758 encodeULEB128(NumElements
, W
.OS
); // initial
760 case wasm::WASM_EXTERNAL_EVENT
:
761 encodeULEB128(Import
.Event
.Attribute
, W
.OS
);
762 encodeULEB128(Import
.Event
.SigIndex
, W
.OS
);
765 llvm_unreachable("unsupported import kind");
772 void WasmObjectWriter::writeFunctionSection(ArrayRef
<WasmFunction
> Functions
) {
773 if (Functions
.empty())
776 SectionBookkeeping Section
;
777 startSection(Section
, wasm::WASM_SEC_FUNCTION
);
779 encodeULEB128(Functions
.size(), W
.OS
);
780 for (const WasmFunction
&Func
: Functions
)
781 encodeULEB128(Func
.SigIndex
, W
.OS
);
786 void WasmObjectWriter::writeEventSection(ArrayRef
<wasm::WasmEventType
> Events
) {
790 SectionBookkeeping Section
;
791 startSection(Section
, wasm::WASM_SEC_EVENT
);
793 encodeULEB128(Events
.size(), W
.OS
);
794 for (const wasm::WasmEventType
&Event
: Events
) {
795 encodeULEB128(Event
.Attribute
, W
.OS
);
796 encodeULEB128(Event
.SigIndex
, W
.OS
);
802 void WasmObjectWriter::writeExportSection(ArrayRef
<wasm::WasmExport
> Exports
) {
806 SectionBookkeeping Section
;
807 startSection(Section
, wasm::WASM_SEC_EXPORT
);
809 encodeULEB128(Exports
.size(), W
.OS
);
810 for (const wasm::WasmExport
&Export
: Exports
) {
811 writeString(Export
.Name
);
812 W
.OS
<< char(Export
.Kind
);
813 encodeULEB128(Export
.Index
, W
.OS
);
819 void WasmObjectWriter::writeElemSection(ArrayRef
<uint32_t> TableElems
) {
820 if (TableElems
.empty())
823 SectionBookkeeping Section
;
824 startSection(Section
, wasm::WASM_SEC_ELEM
);
826 encodeULEB128(1, W
.OS
); // number of "segments"
827 encodeULEB128(0, W
.OS
); // the table index
829 // init expr for starting offset
830 W
.OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
831 encodeSLEB128(InitialTableOffset
, W
.OS
);
832 W
.OS
<< char(wasm::WASM_OPCODE_END
);
834 encodeULEB128(TableElems
.size(), W
.OS
);
835 for (uint32_t Elem
: TableElems
)
836 encodeULEB128(Elem
, W
.OS
);
841 void WasmObjectWriter::writeDataCountSection() {
842 if (DataSegments
.empty())
845 SectionBookkeeping Section
;
846 startSection(Section
, wasm::WASM_SEC_DATACOUNT
);
847 encodeULEB128(DataSegments
.size(), W
.OS
);
851 void WasmObjectWriter::writeCodeSection(const MCAssembler
&Asm
,
852 const MCAsmLayout
&Layout
,
853 ArrayRef
<WasmFunction
> Functions
) {
854 if (Functions
.empty())
857 SectionBookkeeping Section
;
858 startSection(Section
, wasm::WASM_SEC_CODE
);
859 CodeSectionIndex
= Section
.Index
;
861 encodeULEB128(Functions
.size(), W
.OS
);
863 for (const WasmFunction
&Func
: Functions
) {
864 auto &FuncSection
= static_cast<MCSectionWasm
&>(Func
.Sym
->getSection());
867 if (!Func
.Sym
->getSize()->evaluateAsAbsolute(Size
, Layout
))
868 report_fatal_error(".size expression must be evaluatable");
870 encodeULEB128(Size
, W
.OS
);
871 FuncSection
.setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
872 Asm
.writeSectionData(W
.OS
, &FuncSection
, Layout
);
876 applyRelocations(CodeRelocations
, Section
.ContentsOffset
);
881 void WasmObjectWriter::writeDataSection() {
882 if (DataSegments
.empty())
885 SectionBookkeeping Section
;
886 startSection(Section
, wasm::WASM_SEC_DATA
);
887 DataSectionIndex
= Section
.Index
;
889 encodeULEB128(DataSegments
.size(), W
.OS
); // count
891 for (const WasmDataSegment
&Segment
: DataSegments
) {
892 encodeULEB128(Segment
.InitFlags
, W
.OS
); // flags
893 if (Segment
.InitFlags
& wasm::WASM_SEGMENT_HAS_MEMINDEX
)
894 encodeULEB128(0, W
.OS
); // memory index
895 if ((Segment
.InitFlags
& wasm::WASM_SEGMENT_IS_PASSIVE
) == 0) {
896 W
.OS
<< char(wasm::WASM_OPCODE_I32_CONST
);
897 encodeSLEB128(Segment
.Offset
, W
.OS
); // offset
898 W
.OS
<< char(wasm::WASM_OPCODE_END
);
900 encodeULEB128(Segment
.Data
.size(), W
.OS
); // size
901 Segment
.Section
->setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
902 W
.OS
<< Segment
.Data
; // data
906 applyRelocations(DataRelocations
, Section
.ContentsOffset
);
911 void WasmObjectWriter::writeRelocSection(
912 uint32_t SectionIndex
, StringRef Name
,
913 std::vector
<WasmRelocationEntry
> &Relocs
) {
914 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
915 // for descriptions of the reloc sections.
920 // First, ensure the relocations are sorted in offset order. In general they
921 // should already be sorted since `recordRelocation` is called in offset
922 // order, but for the code section we combine many MC sections into single
923 // wasm section, and this order is determined by the order of Asm.Symbols()
924 // not the sections order.
926 Relocs
, [](const WasmRelocationEntry
&A
, const WasmRelocationEntry
&B
) {
927 return (A
.Offset
+ A
.FixupSection
->getSectionOffset()) <
928 (B
.Offset
+ B
.FixupSection
->getSectionOffset());
931 SectionBookkeeping Section
;
932 startCustomSection(Section
, std::string("reloc.") + Name
.str());
934 encodeULEB128(SectionIndex
, W
.OS
);
935 encodeULEB128(Relocs
.size(), W
.OS
);
936 for (const WasmRelocationEntry
&RelEntry
: Relocs
) {
938 RelEntry
.Offset
+ RelEntry
.FixupSection
->getSectionOffset();
939 uint32_t Index
= getRelocationIndexValue(RelEntry
);
941 W
.OS
<< char(RelEntry
.Type
);
942 encodeULEB128(Offset
, W
.OS
);
943 encodeULEB128(Index
, W
.OS
);
944 if (RelEntry
.hasAddend())
945 encodeSLEB128(RelEntry
.Addend
, W
.OS
);
951 void WasmObjectWriter::writeCustomRelocSections() {
952 for (const auto &Sec
: CustomSections
) {
953 auto &Relocations
= CustomSectionsRelocations
[Sec
.Section
];
954 writeRelocSection(Sec
.OutputIndex
, Sec
.Name
, Relocations
);
958 void WasmObjectWriter::writeLinkingMetaDataSection(
959 ArrayRef
<wasm::WasmSymbolInfo
> SymbolInfos
,
960 ArrayRef
<std::pair
<uint16_t, uint32_t>> InitFuncs
,
961 const std::map
<StringRef
, std::vector
<WasmComdatEntry
>> &Comdats
) {
962 SectionBookkeeping Section
;
963 startCustomSection(Section
, "linking");
964 encodeULEB128(wasm::WasmMetadataVersion
, W
.OS
);
966 SectionBookkeeping SubSection
;
967 if (SymbolInfos
.size() != 0) {
968 startSection(SubSection
, wasm::WASM_SYMBOL_TABLE
);
969 encodeULEB128(SymbolInfos
.size(), W
.OS
);
970 for (const wasm::WasmSymbolInfo
&Sym
: SymbolInfos
) {
971 encodeULEB128(Sym
.Kind
, W
.OS
);
972 encodeULEB128(Sym
.Flags
, W
.OS
);
974 case wasm::WASM_SYMBOL_TYPE_FUNCTION
:
975 case wasm::WASM_SYMBOL_TYPE_GLOBAL
:
976 case wasm::WASM_SYMBOL_TYPE_EVENT
:
977 encodeULEB128(Sym
.ElementIndex
, W
.OS
);
978 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0 ||
979 (Sym
.Flags
& wasm::WASM_SYMBOL_EXPLICIT_NAME
) != 0)
980 writeString(Sym
.Name
);
982 case wasm::WASM_SYMBOL_TYPE_DATA
:
983 writeString(Sym
.Name
);
984 if ((Sym
.Flags
& wasm::WASM_SYMBOL_UNDEFINED
) == 0) {
985 encodeULEB128(Sym
.DataRef
.Segment
, W
.OS
);
986 encodeULEB128(Sym
.DataRef
.Offset
, W
.OS
);
987 encodeULEB128(Sym
.DataRef
.Size
, W
.OS
);
990 case wasm::WASM_SYMBOL_TYPE_SECTION
: {
991 const uint32_t SectionIndex
=
992 CustomSections
[Sym
.ElementIndex
].OutputIndex
;
993 encodeULEB128(SectionIndex
, W
.OS
);
997 llvm_unreachable("unexpected kind");
1000 endSection(SubSection
);
1003 if (DataSegments
.size()) {
1004 startSection(SubSection
, wasm::WASM_SEGMENT_INFO
);
1005 encodeULEB128(DataSegments
.size(), W
.OS
);
1006 for (const WasmDataSegment
&Segment
: DataSegments
) {
1007 writeString(Segment
.Name
);
1008 encodeULEB128(Segment
.Alignment
, W
.OS
);
1009 encodeULEB128(Segment
.LinkerFlags
, W
.OS
);
1011 endSection(SubSection
);
1014 if (!InitFuncs
.empty()) {
1015 startSection(SubSection
, wasm::WASM_INIT_FUNCS
);
1016 encodeULEB128(InitFuncs
.size(), W
.OS
);
1017 for (auto &StartFunc
: InitFuncs
) {
1018 encodeULEB128(StartFunc
.first
, W
.OS
); // priority
1019 encodeULEB128(StartFunc
.second
, W
.OS
); // function index
1021 endSection(SubSection
);
1024 if (Comdats
.size()) {
1025 startSection(SubSection
, wasm::WASM_COMDAT_INFO
);
1026 encodeULEB128(Comdats
.size(), W
.OS
);
1027 for (const auto &C
: Comdats
) {
1028 writeString(C
.first
);
1029 encodeULEB128(0, W
.OS
); // flags for future use
1030 encodeULEB128(C
.second
.size(), W
.OS
);
1031 for (const WasmComdatEntry
&Entry
: C
.second
) {
1032 encodeULEB128(Entry
.Kind
, W
.OS
);
1033 encodeULEB128(Entry
.Index
, W
.OS
);
1036 endSection(SubSection
);
1039 endSection(Section
);
1042 void WasmObjectWriter::writeCustomSection(WasmCustomSection
&CustomSection
,
1043 const MCAssembler
&Asm
,
1044 const MCAsmLayout
&Layout
) {
1045 SectionBookkeeping Section
;
1046 auto *Sec
= CustomSection
.Section
;
1047 startCustomSection(Section
, CustomSection
.Name
);
1049 Sec
->setSectionOffset(W
.OS
.tell() - Section
.ContentsOffset
);
1050 Asm
.writeSectionData(W
.OS
, Sec
, Layout
);
1052 CustomSection
.OutputContentsOffset
= Section
.ContentsOffset
;
1053 CustomSection
.OutputIndex
= Section
.Index
;
1055 endSection(Section
);
1058 auto &Relocations
= CustomSectionsRelocations
[CustomSection
.Section
];
1059 applyRelocations(Relocations
, CustomSection
.OutputContentsOffset
);
1062 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm
&Symbol
) {
1063 assert(Symbol
.isFunction());
1064 assert(TypeIndices
.count(&Symbol
));
1065 return TypeIndices
[&Symbol
];
1068 uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm
&Symbol
) {
1069 assert(Symbol
.isEvent());
1070 assert(TypeIndices
.count(&Symbol
));
1071 return TypeIndices
[&Symbol
];
1074 void WasmObjectWriter::registerFunctionType(const MCSymbolWasm
&Symbol
) {
1075 assert(Symbol
.isFunction());
1078 const MCSymbolWasm
*ResolvedSym
= resolveSymbol(Symbol
);
1079 if (auto *Sig
= ResolvedSym
->getSignature()) {
1080 S
.Returns
= Sig
->Returns
;
1081 S
.Params
= Sig
->Params
;
1084 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1086 Signatures
.push_back(S
);
1087 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1089 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
1090 << " new:" << Pair
.second
<< "\n");
1091 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1094 void WasmObjectWriter::registerEventType(const MCSymbolWasm
&Symbol
) {
1095 assert(Symbol
.isEvent());
1097 // TODO Currently we don't generate imported exceptions, but if we do, we
1098 // should have a way of infering types of imported exceptions.
1100 if (auto *Sig
= Symbol
.getSignature()) {
1101 S
.Returns
= Sig
->Returns
;
1102 S
.Params
= Sig
->Params
;
1105 auto Pair
= SignatureIndices
.insert(std::make_pair(S
, Signatures
.size()));
1107 Signatures
.push_back(S
);
1108 TypeIndices
[&Symbol
] = Pair
.first
->second
;
1110 LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol
<< " new:" << Pair
.second
1112 LLVM_DEBUG(dbgs() << " -> type index: " << Pair
.first
->second
<< "\n");
1115 static bool isInSymtab(const MCSymbolWasm
&Sym
) {
1116 if (Sym
.isUsedInReloc())
1119 if (Sym
.isComdat() && !Sym
.isDefined())
1122 if (Sym
.isTemporary() && Sym
.getName().empty())
1125 if (Sym
.isTemporary() && Sym
.isData() && !Sym
.getSize())
1128 if (Sym
.isSection())
1134 uint64_t WasmObjectWriter::writeObject(MCAssembler
&Asm
,
1135 const MCAsmLayout
&Layout
) {
1136 uint64_t StartOffset
= W
.OS
.tell();
1138 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
1140 // Collect information from the available symbols.
1141 SmallVector
<WasmFunction
, 4> Functions
;
1142 SmallVector
<uint32_t, 4> TableElems
;
1143 SmallVector
<wasm::WasmImport
, 4> Imports
;
1144 SmallVector
<wasm::WasmExport
, 4> Exports
;
1145 SmallVector
<wasm::WasmEventType
, 1> Events
;
1146 SmallVector
<wasm::WasmSymbolInfo
, 4> SymbolInfos
;
1147 SmallVector
<std::pair
<uint16_t, uint32_t>, 2> InitFuncs
;
1148 std::map
<StringRef
, std::vector
<WasmComdatEntry
>> Comdats
;
1149 uint32_t DataSize
= 0;
1151 // For now, always emit the memory import, since loads and stores are not
1152 // valid without it. In the future, we could perhaps be more clever and omit
1153 // it if there are no loads or stores.
1154 wasm::WasmImport MemImport
;
1155 MemImport
.Module
= "env";
1156 MemImport
.Field
= "__linear_memory";
1157 MemImport
.Kind
= wasm::WASM_EXTERNAL_MEMORY
;
1158 Imports
.push_back(MemImport
);
1160 // For now, always emit the table section, since indirect calls are not
1161 // valid without it. In the future, we could perhaps be more clever and omit
1162 // it if there are no indirect calls.
1163 wasm::WasmImport TableImport
;
1164 TableImport
.Module
= "env";
1165 TableImport
.Field
= "__indirect_function_table";
1166 TableImport
.Kind
= wasm::WASM_EXTERNAL_TABLE
;
1167 TableImport
.Table
.ElemType
= wasm::WASM_TYPE_FUNCREF
;
1168 Imports
.push_back(TableImport
);
1170 // Populate SignatureIndices, and Imports and WasmIndices for undefined
1171 // symbols. This must be done before populating WasmIndices for defined
1173 for (const MCSymbol
&S
: Asm
.symbols()) {
1174 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1176 // Register types for all functions, including those with private linkage
1177 // (because wasm always needs a type signature).
1178 if (WS
.isFunction())
1179 registerFunctionType(WS
);
1182 registerEventType(WS
);
1184 if (WS
.isTemporary())
1187 // If the symbol is not defined in this translation unit, import it.
1188 if (!WS
.isDefined() && !WS
.isComdat()) {
1189 if (WS
.isFunction()) {
1190 wasm::WasmImport Import
;
1191 Import
.Module
= WS
.getImportModule();
1192 Import
.Field
= WS
.getImportName();
1193 Import
.Kind
= wasm::WASM_EXTERNAL_FUNCTION
;
1194 Import
.SigIndex
= getFunctionType(WS
);
1195 Imports
.push_back(Import
);
1196 assert(WasmIndices
.count(&WS
) == 0);
1197 WasmIndices
[&WS
] = NumFunctionImports
++;
1198 } else if (WS
.isGlobal()) {
1200 report_fatal_error("undefined global symbol cannot be weak");
1202 wasm::WasmImport Import
;
1203 Import
.Field
= WS
.getImportName();
1204 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1205 Import
.Module
= WS
.getImportModule();
1206 Import
.Global
= WS
.getGlobalType();
1207 Imports
.push_back(Import
);
1208 assert(WasmIndices
.count(&WS
) == 0);
1209 WasmIndices
[&WS
] = NumGlobalImports
++;
1210 } else if (WS
.isEvent()) {
1212 report_fatal_error("undefined event symbol cannot be weak");
1214 wasm::WasmImport Import
;
1215 Import
.Module
= WS
.getImportModule();
1216 Import
.Field
= WS
.getImportName();
1217 Import
.Kind
= wasm::WASM_EXTERNAL_EVENT
;
1218 Import
.Event
.Attribute
= wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION
;
1219 Import
.Event
.SigIndex
= getEventType(WS
);
1220 Imports
.push_back(Import
);
1221 assert(WasmIndices
.count(&WS
) == 0);
1222 WasmIndices
[&WS
] = NumEventImports
++;
1227 // Add imports for GOT globals
1228 for (const MCSymbol
&S
: Asm
.symbols()) {
1229 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1230 if (WS
.isUsedInGOT()) {
1231 wasm::WasmImport Import
;
1232 if (WS
.isFunction())
1233 Import
.Module
= "GOT.func";
1235 Import
.Module
= "GOT.mem";
1236 Import
.Field
= WS
.getName();
1237 Import
.Kind
= wasm::WASM_EXTERNAL_GLOBAL
;
1238 Import
.Global
= {wasm::WASM_TYPE_I32
, true};
1239 Imports
.push_back(Import
);
1240 assert(GOTIndices
.count(&WS
) == 0);
1241 GOTIndices
[&WS
] = NumGlobalImports
++;
1245 // Populate DataSegments and CustomSections, which must be done before
1246 // populating DataLocations.
1247 for (MCSection
&Sec
: Asm
) {
1248 auto &Section
= static_cast<MCSectionWasm
&>(Sec
);
1249 StringRef SectionName
= Section
.getSectionName();
1251 // .init_array sections are handled specially elsewhere.
1252 if (SectionName
.startswith(".init_array"))
1255 // Code is handled separately
1256 if (Section
.getKind().isText())
1259 if (Section
.isWasmData()) {
1260 uint32_t SegmentIndex
= DataSegments
.size();
1261 DataSize
= alignTo(DataSize
, Section
.getAlignment());
1262 DataSegments
.emplace_back();
1263 WasmDataSegment
&Segment
= DataSegments
.back();
1264 Segment
.Name
= SectionName
;
1266 Section
.getPassive() ? (uint32_t)wasm::WASM_SEGMENT_IS_PASSIVE
: 0;
1267 Segment
.Offset
= DataSize
;
1268 Segment
.Section
= &Section
;
1269 addData(Segment
.Data
, Section
);
1270 Segment
.Alignment
= Log2_32(Section
.getAlignment());
1271 Segment
.LinkerFlags
= 0;
1272 DataSize
+= Segment
.Data
.size();
1273 Section
.setSegmentIndex(SegmentIndex
);
1275 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1276 Comdats
[C
->getName()].emplace_back(
1277 WasmComdatEntry
{wasm::WASM_COMDAT_DATA
, SegmentIndex
});
1280 // Create custom sections
1281 assert(Sec
.getKind().isMetadata());
1283 StringRef Name
= SectionName
;
1285 // For user-defined custom sections, strip the prefix
1286 if (Name
.startswith(".custom_section."))
1287 Name
= Name
.substr(strlen(".custom_section."));
1289 MCSymbol
*Begin
= Sec
.getBeginSymbol();
1291 WasmIndices
[cast
<MCSymbolWasm
>(Begin
)] = CustomSections
.size();
1292 if (SectionName
!= Begin
->getName())
1293 report_fatal_error("section name and begin symbol should match: " +
1294 Twine(SectionName
));
1297 // Separate out the producers and target features sections
1298 if (Name
== "producers") {
1299 ProducersSection
= std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1302 if (Name
== "target_features") {
1303 TargetFeaturesSection
=
1304 std::make_unique
<WasmCustomSection
>(Name
, &Section
);
1308 CustomSections
.emplace_back(Name
, &Section
);
1312 // Populate WasmIndices and DataLocations for defined symbols.
1313 for (const MCSymbol
&S
: Asm
.symbols()) {
1314 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1315 // or used in relocations.
1316 if (S
.isTemporary() && S
.getName().empty())
1319 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1321 dbgs() << "MCSymbol: " << toString(WS
.getType()) << " '" << S
<< "'"
1322 << " isDefined=" << S
.isDefined() << " isExternal="
1323 << S
.isExternal() << " isTemporary=" << S
.isTemporary()
1324 << " isWeak=" << WS
.isWeak() << " isHidden=" << WS
.isHidden()
1325 << " isVariable=" << WS
.isVariable() << "\n");
1327 if (WS
.isVariable())
1329 if (WS
.isComdat() && !WS
.isDefined())
1332 if (WS
.isFunction()) {
1334 if (WS
.isDefined()) {
1335 if (WS
.getOffset() != 0)
1337 "function sections must contain one function each");
1339 if (WS
.getSize() == nullptr)
1341 "function symbols must have a size set with .size");
1343 // A definition. Write out the function body.
1344 Index
= NumFunctionImports
+ Functions
.size();
1346 Func
.SigIndex
= getFunctionType(WS
);
1348 WasmIndices
[&WS
] = Index
;
1349 Functions
.push_back(Func
);
1351 auto &Section
= static_cast<MCSectionWasm
&>(WS
.getSection());
1352 if (const MCSymbolWasm
*C
= Section
.getGroup()) {
1353 Comdats
[C
->getName()].emplace_back(
1354 WasmComdatEntry
{wasm::WASM_COMDAT_FUNCTION
, Index
});
1357 // An import; the index was assigned above.
1358 Index
= WasmIndices
.find(&WS
)->second
;
1361 LLVM_DEBUG(dbgs() << " -> function index: " << Index
<< "\n");
1363 } else if (WS
.isData()) {
1364 if (!isInSymtab(WS
))
1367 if (!WS
.isDefined()) {
1368 LLVM_DEBUG(dbgs() << " -> segment index: -1"
1374 report_fatal_error("data symbols must have a size set with .size: " +
1378 if (!WS
.getSize()->evaluateAsAbsolute(Size
, Layout
))
1379 report_fatal_error(".size expression must be evaluatable");
1381 auto &DataSection
= static_cast<MCSectionWasm
&>(WS
.getSection());
1382 assert(DataSection
.isWasmData());
1384 // For each data symbol, export it in the symtab as a reference to the
1385 // corresponding Wasm data segment.
1386 wasm::WasmDataReference Ref
= wasm::WasmDataReference
{
1387 DataSection
.getSegmentIndex(),
1388 static_cast<uint32_t>(Layout
.getSymbolOffset(WS
)),
1389 static_cast<uint32_t>(Size
)};
1390 DataLocations
[&WS
] = Ref
;
1391 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref
.Segment
<< "\n");
1393 } else if (WS
.isGlobal()) {
1394 // A "true" Wasm global (currently just __stack_pointer)
1396 report_fatal_error("don't yet support defined globals");
1398 // An import; the index was assigned above
1399 LLVM_DEBUG(dbgs() << " -> global index: "
1400 << WasmIndices
.find(&WS
)->second
<< "\n");
1402 } else if (WS
.isEvent()) {
1403 // C++ exception symbol (__cpp_exception)
1405 if (WS
.isDefined()) {
1406 Index
= NumEventImports
+ Events
.size();
1407 wasm::WasmEventType Event
;
1408 Event
.SigIndex
= getEventType(WS
);
1409 Event
.Attribute
= wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION
;
1410 assert(WasmIndices
.count(&WS
) == 0);
1411 WasmIndices
[&WS
] = Index
;
1412 Events
.push_back(Event
);
1414 // An import; the index was assigned above.
1415 assert(WasmIndices
.count(&WS
) > 0);
1417 LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices
.find(&WS
)->second
1421 assert(WS
.isSection());
1425 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1426 // process these in a separate pass because we need to have processed the
1427 // target of the alias before the alias itself and the symbols are not
1428 // necessarily ordered in this way.
1429 for (const MCSymbol
&S
: Asm
.symbols()) {
1430 if (!S
.isVariable())
1433 assert(S
.isDefined());
1435 // Find the target symbol of this weak alias and export that index
1436 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1437 const MCSymbolWasm
*ResolvedSym
= resolveSymbol(WS
);
1438 LLVM_DEBUG(dbgs() << WS
.getName() << ": weak alias of '" << *ResolvedSym
1441 if (ResolvedSym
->isFunction()) {
1442 assert(WasmIndices
.count(ResolvedSym
) > 0);
1443 uint32_t WasmIndex
= WasmIndices
.find(ResolvedSym
)->second
;
1444 assert(WasmIndices
.count(&WS
) == 0);
1445 WasmIndices
[&WS
] = WasmIndex
;
1446 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex
<< "\n");
1447 } else if (ResolvedSym
->isData()) {
1448 assert(DataLocations
.count(ResolvedSym
) > 0);
1449 const wasm::WasmDataReference
&Ref
=
1450 DataLocations
.find(ResolvedSym
)->second
;
1451 DataLocations
[&WS
] = Ref
;
1452 LLVM_DEBUG(dbgs() << " -> index:" << Ref
.Segment
<< "\n");
1454 report_fatal_error("don't yet support global/event aliases");
1458 // Finally, populate the symbol table itself, in its "natural" order.
1459 for (const MCSymbol
&S
: Asm
.symbols()) {
1460 const auto &WS
= static_cast<const MCSymbolWasm
&>(S
);
1461 if (!isInSymtab(WS
)) {
1462 WS
.setIndex(InvalidIndex
);
1465 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS
<< "\n");
1469 Flags
|= wasm::WASM_SYMBOL_BINDING_WEAK
;
1471 Flags
|= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN
;
1472 if (!WS
.isExternal() && WS
.isDefined())
1473 Flags
|= wasm::WASM_SYMBOL_BINDING_LOCAL
;
1474 if (WS
.isUndefined())
1475 Flags
|= wasm::WASM_SYMBOL_UNDEFINED
;
1476 if (WS
.isExported())
1477 Flags
|= wasm::WASM_SYMBOL_EXPORTED
;
1478 if (WS
.getName() != WS
.getImportName())
1479 Flags
|= wasm::WASM_SYMBOL_EXPLICIT_NAME
;
1481 wasm::WasmSymbolInfo Info
;
1482 Info
.Name
= WS
.getName();
1483 Info
.Kind
= WS
.getType();
1486 assert(WasmIndices
.count(&WS
) > 0);
1487 Info
.ElementIndex
= WasmIndices
.find(&WS
)->second
;
1488 } else if (WS
.isDefined()) {
1489 assert(DataLocations
.count(&WS
) > 0);
1490 Info
.DataRef
= DataLocations
.find(&WS
)->second
;
1492 WS
.setIndex(SymbolInfos
.size());
1493 SymbolInfos
.emplace_back(Info
);
1497 auto HandleReloc
= [&](const WasmRelocationEntry
&Rel
) {
1498 // Functions referenced by a relocation need to put in the table. This is
1499 // purely to make the object file's provisional values readable, and is
1500 // ignored by the linker, which re-calculates the relocations itself.
1501 if (Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_I32
&&
1502 Rel
.Type
!= wasm::R_WASM_TABLE_INDEX_SLEB
)
1504 assert(Rel
.Symbol
->isFunction());
1505 const MCSymbolWasm
&WS
= *resolveSymbol(*Rel
.Symbol
);
1506 uint32_t FunctionIndex
= WasmIndices
.find(&WS
)->second
;
1507 uint32_t TableIndex
= TableElems
.size() + InitialTableOffset
;
1508 if (TableIndices
.try_emplace(&WS
, TableIndex
).second
) {
1509 LLVM_DEBUG(dbgs() << " -> adding " << WS
.getName()
1510 << " to table: " << TableIndex
<< "\n");
1511 TableElems
.push_back(FunctionIndex
);
1512 registerFunctionType(WS
);
1516 for (const WasmRelocationEntry
&RelEntry
: CodeRelocations
)
1517 HandleReloc(RelEntry
);
1518 for (const WasmRelocationEntry
&RelEntry
: DataRelocations
)
1519 HandleReloc(RelEntry
);
1522 // Translate .init_array section contents into start functions.
1523 for (const MCSection
&S
: Asm
) {
1524 const auto &WS
= static_cast<const MCSectionWasm
&>(S
);
1525 if (WS
.getSectionName().startswith(".fini_array"))
1526 report_fatal_error(".fini_array sections are unsupported");
1527 if (!WS
.getSectionName().startswith(".init_array"))
1529 if (WS
.getFragmentList().empty())
1532 // init_array is expected to contain a single non-empty data fragment
1533 if (WS
.getFragmentList().size() != 3)
1534 report_fatal_error("only one .init_array section fragment supported");
1536 auto IT
= WS
.begin();
1537 const MCFragment
&EmptyFrag
= *IT
;
1538 if (EmptyFrag
.getKind() != MCFragment::FT_Data
)
1539 report_fatal_error(".init_array section should be aligned");
1542 const MCFragment
&AlignFrag
= *IT
;
1543 if (AlignFrag
.getKind() != MCFragment::FT_Align
)
1544 report_fatal_error(".init_array section should be aligned");
1545 if (cast
<MCAlignFragment
>(AlignFrag
).getAlignment() != (is64Bit() ? 8 : 4))
1546 report_fatal_error(".init_array section should be aligned for pointers");
1548 const MCFragment
&Frag
= *std::next(IT
);
1549 if (Frag
.hasInstructions() || Frag
.getKind() != MCFragment::FT_Data
)
1550 report_fatal_error("only data supported in .init_array section");
1552 uint16_t Priority
= UINT16_MAX
;
1553 unsigned PrefixLength
= strlen(".init_array");
1554 if (WS
.getSectionName().size() > PrefixLength
) {
1555 if (WS
.getSectionName()[PrefixLength
] != '.')
1557 ".init_array section priority should start with '.'");
1558 if (WS
.getSectionName()
1559 .substr(PrefixLength
+ 1)
1560 .getAsInteger(10, Priority
))
1561 report_fatal_error("invalid .init_array section priority");
1563 const auto &DataFrag
= cast
<MCDataFragment
>(Frag
);
1564 const SmallVectorImpl
<char> &Contents
= DataFrag
.getContents();
1565 for (const uint8_t *
1566 P
= (const uint8_t *)Contents
.data(),
1567 *End
= (const uint8_t *)Contents
.data() + Contents
.size();
1570 report_fatal_error("non-symbolic data in .init_array section");
1572 for (const MCFixup
&Fixup
: DataFrag
.getFixups()) {
1573 assert(Fixup
.getKind() ==
1574 MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1575 const MCExpr
*Expr
= Fixup
.getValue();
1576 auto *SymRef
= dyn_cast
<MCSymbolRefExpr
>(Expr
);
1578 report_fatal_error("fixups in .init_array should be symbol references");
1579 const auto &TargetSym
= cast
<const MCSymbolWasm
>(SymRef
->getSymbol());
1580 if (TargetSym
.getIndex() == InvalidIndex
)
1581 report_fatal_error("symbols in .init_array should exist in symbtab");
1582 if (!TargetSym
.isFunction())
1583 report_fatal_error("symbols in .init_array should be for functions");
1584 InitFuncs
.push_back(
1585 std::make_pair(Priority
, TargetSym
.getIndex()));
1589 // Write out the Wasm header.
1592 writeTypeSection(Signatures
);
1593 writeImportSection(Imports
, DataSize
, TableElems
.size());
1594 writeFunctionSection(Functions
);
1595 // Skip the "table" section; we import the table instead.
1596 // Skip the "memory" section; we import the memory instead.
1597 writeEventSection(Events
);
1598 writeExportSection(Exports
);
1599 writeElemSection(TableElems
);
1600 writeDataCountSection();
1601 writeCodeSection(Asm
, Layout
, Functions
);
1603 for (auto &CustomSection
: CustomSections
)
1604 writeCustomSection(CustomSection
, Asm
, Layout
);
1605 writeLinkingMetaDataSection(SymbolInfos
, InitFuncs
, Comdats
);
1606 writeRelocSection(CodeSectionIndex
, "CODE", CodeRelocations
);
1607 writeRelocSection(DataSectionIndex
, "DATA", DataRelocations
);
1608 writeCustomRelocSections();
1609 if (ProducersSection
)
1610 writeCustomSection(*ProducersSection
, Asm
, Layout
);
1611 if (TargetFeaturesSection
)
1612 writeCustomSection(*TargetFeaturesSection
, Asm
, Layout
);
1614 // TODO: Translate the .comment section to the output.
1615 return W
.OS
.tell() - StartOffset
;
1618 std::unique_ptr
<MCObjectWriter
>
1619 llvm::createWasmObjectWriter(std::unique_ptr
<MCWasmObjectTargetWriter
> MOTW
,
1620 raw_pwrite_stream
&OS
) {
1621 return std::make_unique
<WasmObjectWriter
>(std::move(MOTW
), OS
);