1 | //===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// |
9 | /// \file |
10 | /// This file handles Wasm-specific object emission, converting LLVM's |
11 | /// internal fixups into the appropriate relocations. |
12 | /// |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "MCTargetDesc/WebAssemblyFixupKinds.h" |
16 | #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" |
17 | #include "llvm/BinaryFormat/Wasm.h" |
18 | #include "llvm/MC/MCAsmBackend.h" |
19 | #include "llvm/MC/MCFixup.h" |
20 | #include "llvm/MC/MCFixupKindInfo.h" |
21 | #include "llvm/MC/MCObjectWriter.h" |
22 | #include "llvm/MC/MCSectionWasm.h" |
23 | #include "llvm/MC/MCSymbolWasm.h" |
24 | #include "llvm/MC/MCValue.h" |
25 | #include "llvm/MC/MCWasmObjectWriter.h" |
26 | #include "llvm/Support/Casting.h" |
27 | #include "llvm/Support/ErrorHandling.h" |
28 | |
29 | using namespace llvm; |
30 | |
31 | namespace { |
32 | class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter { |
33 | public: |
34 | explicit WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten); |
35 | |
36 | private: |
37 | unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, |
38 | const MCSectionWasm &FixupSection, |
39 | bool IsLocRel) const override; |
40 | }; |
41 | } // end anonymous namespace |
42 | |
43 | WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit, |
44 | bool IsEmscripten) |
45 | : MCWasmObjectTargetWriter(Is64Bit, IsEmscripten) {} |
46 | |
47 | static const MCSection *getTargetSection(const MCExpr *Expr) { |
48 | if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Val: Expr)) { |
49 | if (SyExp->getSymbol().isInSection()) |
50 | return &SyExp->getSymbol().getSection(); |
51 | return nullptr; |
52 | } |
53 | |
54 | if (auto BinOp = dyn_cast<MCBinaryExpr>(Val: Expr)) { |
55 | auto SectionLHS = getTargetSection(Expr: BinOp->getLHS()); |
56 | auto SectionRHS = getTargetSection(Expr: BinOp->getRHS()); |
57 | return SectionLHS == SectionRHS ? nullptr : SectionLHS; |
58 | } |
59 | |
60 | if (auto UnOp = dyn_cast<MCUnaryExpr>(Val: Expr)) |
61 | return getTargetSection(Expr: UnOp->getSubExpr()); |
62 | |
63 | return nullptr; |
64 | } |
65 | |
66 | unsigned WebAssemblyWasmObjectWriter::getRelocType( |
67 | const MCValue &Target, const MCFixup &Fixup, |
68 | const MCSectionWasm &FixupSection, bool IsLocRel) const { |
69 | const MCSymbolRefExpr *RefA = Target.getSymA(); |
70 | assert(RefA); |
71 | auto& SymA = cast<MCSymbolWasm>(Val: RefA->getSymbol()); |
72 | |
73 | MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); |
74 | |
75 | switch (Modifier) { |
76 | case MCSymbolRefExpr::VK_GOT: |
77 | case MCSymbolRefExpr::VK_WASM_GOT_TLS: |
78 | return wasm::R_WASM_GLOBAL_INDEX_LEB; |
79 | case MCSymbolRefExpr::VK_WASM_TBREL: |
80 | assert(SymA.isFunction()); |
81 | return is64Bit() ? wasm::R_WASM_TABLE_INDEX_REL_SLEB64 |
82 | : wasm::R_WASM_TABLE_INDEX_REL_SLEB; |
83 | case MCSymbolRefExpr::VK_WASM_TLSREL: |
84 | return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64 |
85 | : wasm::R_WASM_MEMORY_ADDR_TLS_SLEB; |
86 | case MCSymbolRefExpr::VK_WASM_MBREL: |
87 | assert(SymA.isData()); |
88 | return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_REL_SLEB64 |
89 | : wasm::R_WASM_MEMORY_ADDR_REL_SLEB; |
90 | case MCSymbolRefExpr::VK_WASM_TYPEINDEX: |
91 | return wasm::R_WASM_TYPE_INDEX_LEB; |
92 | case MCSymbolRefExpr::VK_None: |
93 | break; |
94 | case MCSymbolRefExpr::VK_WASM_FUNCINDEX: |
95 | return wasm::R_WASM_FUNCTION_INDEX_I32; |
96 | default: |
97 | report_fatal_error(reason: "unknown VariantKind" ); |
98 | break; |
99 | } |
100 | |
101 | switch (unsigned(Fixup.getKind())) { |
102 | case WebAssembly::fixup_sleb128_i32: |
103 | if (SymA.isFunction()) |
104 | return wasm::R_WASM_TABLE_INDEX_SLEB; |
105 | return wasm::R_WASM_MEMORY_ADDR_SLEB; |
106 | case WebAssembly::fixup_sleb128_i64: |
107 | if (SymA.isFunction()) |
108 | return wasm::R_WASM_TABLE_INDEX_SLEB64; |
109 | return wasm::R_WASM_MEMORY_ADDR_SLEB64; |
110 | case WebAssembly::fixup_uleb128_i32: |
111 | if (SymA.isGlobal()) |
112 | return wasm::R_WASM_GLOBAL_INDEX_LEB; |
113 | if (SymA.isFunction()) |
114 | return wasm::R_WASM_FUNCTION_INDEX_LEB; |
115 | if (SymA.isTag()) |
116 | return wasm::R_WASM_TAG_INDEX_LEB; |
117 | if (SymA.isTable()) |
118 | return wasm::R_WASM_TABLE_NUMBER_LEB; |
119 | return wasm::R_WASM_MEMORY_ADDR_LEB; |
120 | case WebAssembly::fixup_uleb128_i64: |
121 | assert(SymA.isData()); |
122 | return wasm::R_WASM_MEMORY_ADDR_LEB64; |
123 | case FK_Data_4: |
124 | if (SymA.isFunction()) { |
125 | if (FixupSection.isMetadata()) |
126 | return wasm::R_WASM_FUNCTION_OFFSET_I32; |
127 | assert(FixupSection.isWasmData()); |
128 | return wasm::R_WASM_TABLE_INDEX_I32; |
129 | } |
130 | if (SymA.isGlobal()) |
131 | return wasm::R_WASM_GLOBAL_INDEX_I32; |
132 | if (auto Section = static_cast<const MCSectionWasm *>( |
133 | getTargetSection(Expr: Fixup.getValue()))) { |
134 | if (Section->isText()) |
135 | return wasm::R_WASM_FUNCTION_OFFSET_I32; |
136 | else if (!Section->isWasmData()) |
137 | return wasm::R_WASM_SECTION_OFFSET_I32; |
138 | } |
139 | return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 |
140 | : wasm::R_WASM_MEMORY_ADDR_I32; |
141 | case FK_Data_8: |
142 | if (SymA.isFunction()) { |
143 | if (FixupSection.isMetadata()) |
144 | return wasm::R_WASM_FUNCTION_OFFSET_I64; |
145 | return wasm::R_WASM_TABLE_INDEX_I64; |
146 | } |
147 | if (SymA.isGlobal()) |
148 | llvm_unreachable("unimplemented R_WASM_GLOBAL_INDEX_I64" ); |
149 | if (auto Section = static_cast<const MCSectionWasm *>( |
150 | getTargetSection(Expr: Fixup.getValue()))) { |
151 | if (Section->isText()) |
152 | return wasm::R_WASM_FUNCTION_OFFSET_I64; |
153 | else if (!Section->isWasmData()) |
154 | llvm_unreachable("unimplemented R_WASM_SECTION_OFFSET_I64" ); |
155 | } |
156 | assert(SymA.isData()); |
157 | return wasm::R_WASM_MEMORY_ADDR_I64; |
158 | default: |
159 | llvm_unreachable("unimplemented fixup kind" ); |
160 | } |
161 | } |
162 | |
163 | std::unique_ptr<MCObjectTargetWriter> |
164 | llvm::createWebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten) { |
165 | return std::make_unique<WebAssemblyWasmObjectWriter>(args&: Is64Bit, args&: IsEmscripten); |
166 | } |
167 | |